17

之前发过一篇文章《移动端应该如何动态设置字体大小?》,主要说了移动web端布局的一些解决方法,本文再一次把这个问题提出来,并分别对安卓和IOS设备的屏幕了解做出自己的分享,在进入正文之前最好先了解:物理像素逻辑像素DPRRem

那么进入正文,不废话,直接把自己了解到的和一些看法说出来。

首先是屏幕问题,现在主流的移动设备以安卓和IOS为主,我们在制作移动端页面也是以兼容这两种设备去布局。

首先说iPhone,不得不说iPhone的屏幕考虑到了我们开发者的难处,从而给出iPhone屏幕的dpr都是整数值,在6plus出现之前,iphone的dpr始终是2(物理像素/逻辑像素=2),即使是6plus出现了,iphone到底其实也就只有2,3这两个dpr。其实6plus的实际dpr并不是整数,而是2.87左右,不过,为了方便开发者来开发,iphone6plus对其做了一个调整,将dpr调整为3,然后在对屏幕进行了一个缩放。所以我们很容易对其做到兼顾。

而安卓的dpr值,并不像iphone那样就只有两个值。安卓的dpr是千奇百怪的,可能是1.5,2,3,4,2.5等等的都有。(甚至我还看到了1.7之类的,安卓的各个设备商,玩的真尼玛high啊。怎么高兴怎么来。)

那么现在开始说说移动端怎么布局以及字体该怎么设置,因为有各种各样的解决方式,我就不一一赘述,直接说手淘的解决方案:flexible.js

我为什么又一次把这个拿出来说,主要有两点原因:1.我觉得它好用,解决方式简单粗暴。2.它经过了比较长时间的考验,如今手淘还在用它。

具体的使用方法自己可以去flexible.js看看,这里我简单说说它的方案以及个人对它的改良。

我们UI在制作移动端页面时,主流的宽度有640、750或者还有其他尺寸,这里我们用640做为例子,那么手淘的做法就是将640的宽度分为10份,每份是64,那么1个rem=64px,也就是说此时 html{font-size:64px;},比如设计稿中有个元素宽64px,高128px,那么这个div的宽用rem表示就是:64(设计稿元素的宽)/64(1rem为64px)=该元素计算出的rem值,同理高度从px换成rem就是128/64=2rem样式就是div{width:1rem;height:2rem;}。然后再配上flexible.js的代码段:

function refreshRem(){
        var width = docEl.getBoundingClientRect().width;
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;//看到了吗 看到了吗 这句话 分成10份哦
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
    }

对于布局,我们可以使用rem去结局,那么字体呢?

大家知道,现在PC端主流的字体大小都是类似12px、14px、16px,几乎没有13、15、17这样的数字出现,至于为什么,请进穿越门了解。如果我们用rem做为字体单位,那么转成px的时候,势必会出现奇数或者小数的情况,为了避免这种情况,我们还是要用px做为字体的单位。那么又如何用px去当作字体大小呢?

首先看这段代码:

div {
    width: 1rem; 
    height: 0.4rem;
    font-size: 12px; // 默认写上dpr为1的fontSize
}

[data-dpr="2"] div {
    font-size: 24px;
}

[data-dpr="3"] div {
    font-size: 36px;
}

没有错,手淘的解决方案就是默认写个dpr为1时的字体大小,然后根据不同dpr下的值去匹配不同的字体大小。

clipboard.png

flexible会获取设备的dpr值,然后在html标签上自定义data-dpr属性,并放入dpr值,后面的font-size就是动态设置一个rem单位的大小。

其实我觉得这种方案挺恶心的,每个牵扯到字体的大小就必须多些几套去兼容,但这也算是个方案。

最后就是对flexible.js的看法,话不多说上代码:

if (!dpr && !scale) {
        var isAndroid = win.navigator.appVersion.match(/android/gi);
        var isIPhone = win.navigator.appVersion.match(/iphone/gi);
        var devicePixelRatio = win.devicePixelRatio;
        if (isIPhone) {//只对iPhone做了处理!!!!
            // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
            if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
                dpr = 3;
            } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
                dpr = 2;
            } else {
                dpr = 1;
            }
        } else {
            // 其他设备下,仍旧使用1倍的方案
            dpr = 1;
        }
        scale = 1 / dpr;
    }

可以看出,flexible中动态设置dpr时,只对iPhone进行了处理,完全没有把安卓放在眼里,那安卓怎么办?这里我又想吐槽安卓那些厂商,真尼玛瞎搞,dpr设置成各种非主流数值,玩死我们这些码农了,连flexible都不想管了。吐槽到此为止,那么该怎么改良它,让它能对安卓手机也能动态设置dpr呢?我们将这段代码改一下:

if (!dpr && !scale) {
    //devicePixelRatio这个属性是可以获取到设备的dpr
    var devicePixelRatio = win.devicePixelRatio;
    //判断dpr是否为整数
    var isRegularDpr = devicePixelRatio.toString().match(/^[1-9]\d*$/g)
    if (isRegularDpr) {
    // 对于是整数的dpr,对dpr进行操作
     if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
        dpr = 3;
    } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
        dpr = 2;
    } else {
        dpr = 1;
    }
} else {
    // 对于其他的dpr,人采用dpr为1的方案
    dpr = 1;
    }
    scale = 1 / dpr;
}

我们对这里做了一点点修改,即来判断dpr是否是规则的,也就是是否是我们常见的1,2,3等,然后,我们只对规则的dpr,来进行一个字体的处理。这样,iphone依然还是用之前的匹配方案。而其实目前安卓,很多的设备还是比较常见的dpr了,所以我们这里,将之前对设备的判断,转变成对dpr是否是整数的一个判断。其他地方不变,可以解决对安卓dpr的部分匹配。


alwaysVe
1.9k 声望162 粉丝

前进