Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

根据iPhone6设计稿动态计算rem值 #1

Open
zhiqiang21 opened this issue Feb 21, 2016 · 6 comments
Open

根据iPhone6设计稿动态计算rem值 #1

zhiqiang21 opened this issue Feb 21, 2016 · 6 comments

Comments

@zhiqiang21
Copy link
Owner

zhiqiang21 commented Feb 21, 2016

2019-05-14更新

1.为什么设置font-size=62.5%

简单说下为什么要来更新这篇博客的原因吧。这篇博客计算rem的方式是自己2014年刚毕业的时候做移动端项目写的。本身这段代码没有什么问题,但是在本地开发调试(比如chrome上) 因为设置 html 根元素的font-size=62.5% 导致在chrome上使用了rem单位的容器计算出来的正常的尺寸会有偏差(实际上在移动端设备上显示的又没有问题)。

这个问题的主要原因就是在pc上默认浏览器的字体最小只能显示 12px大小的字体**(当然这个说法也是指的大多数浏览器)。所以当使用这篇博客脚本的来做rem 的动态计算的时,如果元素的尺寸小于12px,在chrome上调试就会看到一个错误的容器尺寸。当时的一个简单的解决办法就是自己手动到chrome设置里面去设置chrome的可以显示的最小字体。**

先来看下在chrome 浏览器里面的测试效果: 第一张和第二张图分别是浏览器计算出的容器的宽度和高度,可以明显发现test1 的宽度多了2像素

同样的代码在safari中浏览器却可以计算出正确的大小,下图可以看到test1和test2的宽度和高度是一样的。

就在我修改这篇文章的时候,chome已经是v74.0xxxx版本。通过设置chrome的最小显示字体已经无法让刚才的测试demo正常显示出计算结果了。意思就是说当我们设置跟节点的html font-size 62.5% 时(根据 1rem=16px, 0.625rem = 10px),计算得到的是10px,chrome也会强制的将计算结果设置为 12px。所以在浏览器中就是 1rem=12px了。

下面再来简单介绍下为什么设置 font-size 62.5% 和怎么规避上面在chrome浏览器中计算误差的问题。

rem px
1 16
0.625 10
6.25 100

由上面的表格可以知道当我们假设1rem = 16px时,那么10px=0.625rem,所以当我们选择10px为基准值的时候,假设我们需要设置的rem 值为 Y,设计稿的尺寸为 X,我们可以得出一个方程式:

10 * Y = 0.625 * X

也就是实际的rem设置的值就是

Y = (0.625 * X) / 10

又因为 rem 是一个相对于 html 跟节点 font-size 的一个相对值。当我们设置了根节点的 html 的font-size 62.5%时,需要设置的rem的值就是

Y = X / 10 (这里是一倍稿,当是2倍稿时,Y=X/10*2)

由以上的解析我们已经知道为什么设置font-size 62.5% 的由来了,而且存在的问题。那么怎么规避在chrome上会计算错误的问题呢?

规避这个问题的方式就是我们将基准值设置为大于chrome能够显示的最小字体 12px。为了方便计算,如上面的表格我们可以使用100px作为基准值。也就是设置根节点的font-size 625%。所以当我们根据设计稿尺寸计算rem尺寸的时候直接除100(如果是2倍稿就除2*100)。

下图可以看出来这种选择更大的基准值时,chrome浏览器可以正确的计算出元素的尺寸。

2.淘宝flexible方案解析

以上设置根节点font-size为百分比单位是一种使用rem适配的方案。还有一种设置font-size为动态的像素值(px),比如淘宝的 lib-flexible。那么简单解释下淘宝方案的换算方法。

我们都知道iphone6/7/8手机的屏幕宽度是375px。当我们的设计稿是以iphone6为标准输出时(假设是1倍稿),在lib-flexible中有一句代码注释如下:

它的意思就是 lib-flexible 认为 1rem = viewwidth/10,那么就有了下面的一个关系:

以一倍的iphone6设计稿为标准:

rem px
1 37.5

当我们设置 37.5px 为基准值,也就是 font-size 37.5px 时,由前面介绍的换算公式当我们要设置rem值时,就是

Y = X / 37.5 (浏览器在计算的时候,实际是 37.5 * x / 37.5)

2.1 lib-flexible 对0.5像素的支持

查看lib-flexible的源码可以看到这段js代码

if (dpr >= 2) {
    var fakeBody = document.createElement('body')
    var testElement = document.createElement('div')
    testElement.style.border = '.5px solid transparent'
    fakeBody.appendChild(testElement)
    docEl.appendChild(fakeBody)
    if (testElement.offsetHeight === 1) {
      docEl.classList.add('hairlines')
    }
    docEl.removeChild(fakeBody)
  }

上面代码的意思就是检测屏幕的 dpr 是不是大于等于2,当满足条件是就在 html 根节点上添加 class="hairlines" 的属性,当我们要使用 0.5像素的时候可以这么写代码

.test1 {
            width: 100px;
            height: 100px;
            border: 1px solid red;
        }

        .test2 {
            width: 100px;
            height: 100px;
            border: 1px solid goldenrod;
        }
        /* 当满足dpr>=2时这段代码会生效,否者不会生效 */
        .hairlines .test2 {
            border: .5px solid goldenrod;
        }

建议使用淘宝的rem 方案解决移动端适配的问题。地址:https://github.com/amfe/lib-flexible

3.字体的适配

使用 rem 我们可以控制元素在不同设备上面等比例的缩放和扩大,根据设备的dpr可以实现真实的一像素。那么字体的大小使用什么适配呢?

3.1 需不需要适配

在我的工作中(移动端项目)很少需要对字体进行适配。主要也是产品或者是UE、UI都对这里没有需求。直接使用的设计稿的 px尺寸。

3.2 需要适配怎么做

如果是需要对字体进行适配我们应该怎么做呢?

  • 第一、就是像元素的宽高一样使用rem
  • 第二、根据设备的dpr适配字体大小(可以使用media query来动态的设置字体的大小);

使用rem会有点儿小问题,在安卓手机上dpr不统一,以及宽度的不统一,上面的两种方法都是尽可能的接近适配需要的大小。

3.3衬线字体和非衬线字体的区别

这里介绍个前端关于字体使用最经常使用的两个概念。

**衬线体:**具有装饰性(有边角);代表字体:Times New Roman。常用于印刷品(书本杂志等),适用于长篇文章段落,因为边角易于辨别每个字母,读者在阅读较多的段落时会变得轻松。

**非衬线体:**顾名思义就是无装饰性(无边角),易识别;代表字体:Helvetica (iOS7、iOS8的预设字体)、San Francisco(iOS9、iOS10的预设字体)、Roboto(Android L的预设字体)、Arial(windows的预设字体);缺点:某些字母相对难区分,如大些的I(i)与小写的l(L)。常用语电子设备。

旧版的博客内容(脚本内容已经更新20190514)

rem 单位在做移动端的h5开发的时候是最经常使用的单位。为解决自适应的问题,我们需要动态的给文档的更节点添加font-size 值。使用mediaquery 可以解决这个问题,但是每一个文件都引用一大串的font-size 值很繁琐,而且值也不能达到连续的效果。

就使用js动态计算给文档的fopnt-size 动态赋值解决问题。

使用的时候,请将下面的代码放到页面的顶部(head标签内);

/**
 * [以iPhone6的设计稿为例js动态设置文档 rem 值]  
 * px和 rem的换算方式是 设计稿尺寸除100 如果是2倍稿 则是设计稿尺寸 除 2*100=200 3倍稿尺寸可以类推。
 * @param  {[type]} currClientWidth [当前客户端的宽度]
 * @param  {[type]} fontValue [计算后的 fontvalue值]
 * @return {[type]}     [description]
 */
<script>
    var currClientWidth, fontValue,originWidth;
    //originWidth用来设置设计稿原型的屏幕宽度(这里是以 Iphone 6为原型的设计稿)
    originWidth=375;
    __resize();

	//注册 resize事件
    window.addEventListener('resize', __resize, false);

    function __resize() {
        currClientWidth = document.documentElement.clientWidth;
        //这里是设置屏幕的最大和最小值时候给一个默认值
        if (currClientWidth > 640) currClientWidth = 640;
        if (currClientWidth < 320) currClientWidth = 320;
        //
        fontValue = ((625 * currClientWidth) /originWidth).toFixed(2);
        document.documentElement.style.fontSize = fontValue + '%';
    }
    </script>
@ChaseChan
Copy link

请问你这个不会出现进入页面先缩小后放大的情况吗?我的代码跟你的类似,但是我的就会出现页面先缩小后放大的情况,不知道应该怎么解决。

@jawil
Copy link

jawil commented Sep 13, 2017

现在用css单位vw就行,不需要写js了。@ChaseChan

@zhiqiang21
Copy link
Owner Author

@ChaseChan 哈哈,你把这段js放在Head标签里面就可以了。另外现在还是推荐的淘宝的lib-flexible 吧。https://github.com/amfe/lib-flexible

@ChaseChan
Copy link

@zhiqiang21 ,我就是放在head里面的,现在比较笨的方法是计算过后再把body给展示出来。

@ChaseChan
Copy link

@jawil 公司不给用,那个貌似是安卓4.4.4以上才支持,公司还要兼容老设备,唉。

@zhiqiang21
Copy link
Owner Author

不用这样的哈,检查下你的代码看不是不是Head标签还有其它的js代码,阻塞了这段代码的执行。如果有请把这段代码移到最前面的位置,或者考虑把跟业务有关的js都移到body标签的底部

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants