h5移动端兼容适配初体验

 

众所周知,移动端设备繁多,分辨率多得让人眼花缭乱,详细统计数据可以点击这里查看。

万事开头难,初学者可能很长时间才能摸清头绪,偶有产品或设计师问起该如何设计移动端,三言两语也说不清,因此有了此篇相对简单的文章,主要面向初学者,如有错漏,请资深大牛指正。

其实移动端适配的关键是“相对比例”,一切都是相对的。

一.viewport

关于viewport的文章已经有很多,深入研究可以参考这篇文章

但其实一开始未必需要深究,因为它可能反而让初学者凌乱。

简单地说,可以认为viewport中的width值定义了移动端浏览器渲染网页的窗口横向分辨率大小。

比如最常见的:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

其中的width=device-width定义了浏览器自行选择理想的逻辑分辨率。

什么是理想的逻辑分辨率?比如iPhone2/3/4/5的的逻辑分辨率width都是320px,iPhone6/6s是375px,而iPhone6P/6SP是414px。如下图:

为什么是理想的呢?因为屏幕小的手机逻辑分辨率小,屏幕大的手机逻辑分辨率大,这里就是一个相对的关系,至于设备的实际分辨率即物理分辨率是多少,至少对布局无关紧要,暂时不必关心。

 

为保证清晰度,对应的视觉稿一般设计为640px (iPhone 5s以下)或750px (iPhone 6/6S)或1080px(iPhone 6 plus /6S plus),CSS中则以一定的比例缩小尺寸。

640px和750px视觉稿的比例为2,1080px视觉稿的比例为3,

比如640px视觉稿中60px*60px的图标,在css中为30px*30px;1080px的视觉稿中60px*60px的图标,在css中为20px*20px。

 

有了相对概念后,我们来聊聊单位:

一. px单位和百分比

这种方案的元素宽高都用px单位,具体值由上述比例算出。

以图标为例,宽高都使用定值,不管手机屏幕分辨率多大,图标都是固定的px,如果设计时更匹配小屏幕,则在大屏幕上看起来有可能图标会偏小。反之则是小屏幕上偏大。

以按钮为例,宽高都使用定值,按钮两边留白,手机屏幕分辨率越大,按钮两边留白越多。这样在大屏幕上可能留白过多,造成空间浪费。如图:

2

也可以让按钮宽度自动撑开,只设置按钮左右margin为定值,如图:

3

或者按钮的宽度使用百分比,使按钮大小和两边间距都保持一致的比例,如图:

3

除了按钮,一般在布局上使用百分比。比如一行3个元素, 则每个元素宽度占33.33%,如图:

5

这样直接用百分比很方便,不需要去计算具体的px值。

(不过这种情况有更好的选择: flex布局。这里不作阐述,有兴趣的自行研究。)

需要注意的是百分比计算出来的px值如果不是整数,不同设备浏览器的处理方式不同(不限于移动端),具体可参考下表:(本表包括桌面浏览器)

 browser Percentages Round pixels from percentage Round pixels
Internet Explorer 7 truncate to 2 decimal places nearest integer down
Internet Explorer 8 truncate to 2 decimal places nearest integer nearest integer
Internet Explorer 9 truncate to 2 decimal places nearest integer nearest integer
Internet Explorer 10 truncate to 2 decimal places sub-pixel rendering sub-pixel rendering
Internet Explorer 11 truncate to 2 decimal places sub-pixel rendering sub-pixel rendering
Firefox 3.0 truncate to 3 decimal places nearest integer nearest integer
Firefox 3.5 truncate to 3 decimal places sub-pixel rendering sub-pixel rendering
Firefox 31 truncate to 3 decimal places sub-pixel rendering sub-pixel rendering
Chrome 20 round to 15 decimal places down down
Chrome 21 round to 15 decimal places sub-pixel rendering sub-pixel rendering
Chrome 37 round to 13 decimal places sub-pixel rendering sub-pixel rendering
Safari 6 (OSX Lion) round to 15 decimal places down down
Safari 6.1 (OSX Mountain Lion) round to 15 decimal places sub-pixel rendering sub-pixel rendering
Safari 7 (OSX Mavericks) round to 15 decimal places sub-pixel rendering sub-pixel rendering
Mobile Safari 7 (iOS7) round to 15 decimal places down down
Mobile Safari 8 (iOS8) round to 15 decimal places sub-pixel rendering sub-pixel rendering
Chrome 36 (Jelly Bean) [Nexus5] round to 15 decimal places sub-pixel rendering sub-pixel rendering
Chrome 30 (KitKat) [S5] round to 15 decimal places sub-pixel rendering sub-pixel rendering
Android Browser 4 (Jelly Bean) [Nexus7,Nexus4,S4,S3] round to 15 decimal places down down
Android Browser 4 (Ice Cream Sandwich) [Nexus,KindleFire2] round to 15 decimal places down down
Android Browser 4 (Gingerbread) [S2] truncate to 3 decimal places down down
Opera 12 truncate to 2 decimal places down down
Opera Next 24 round to 13 decimal places sub-pixel rendering sub-pixel rendering

 

最安全的做法是水平方向总和小于100%。

小tips:某些元素比如图片,宽和高要保持一定比例,宽度使用百分比,高度必须自动。但还要让图片加载前先占位以使页面加载过程更柔顺,可以在img外多加一层父元素,给父元素设置padding-top,值为百分比,等于图片高/宽,因为百分比的padding-top值是以宽度来计算的,这个div的大小将和img一样大,可以帮img占位。

三. rem单位

rem名字和em差不多,它和em一样都需要一个参考点,不同的是em的参考点是父元素的字体大小,而rem的参考点是根元素<html> (W3C:“font size of the root element” )。

根据rem的这个特点,可以为不同分辨率设备的html设置不同的font-size,元素的大小使用rem作单位,当html的font-size值大小变化时,元素也能跟着自动变大变小。

那么html的font-size值如何设置呢?如果要做到font-size值跟着分辨率线性缩放,只能使用js,比如:

var fixScreen = function() {
    var metaEl = doc.querySelector('meta[name="viewport"]'),
        metaCtt = metaEl ? metaEl.content : '',
        matchScale = metaCtt.match(/initial-scale=([d.]+)/),
        matchWidth = metaCtt.match(/width=([^,s]+)/);

    if ( !metaEl ) { // REM
        var docEl = doc.documentElement,
            maxwidth = docEl.dataset.mw || 750, // 每 dpr 最大页面宽度
            dpr = isIos ? Math.min(win.devicePixelRatio, 3) : 1,
            scale = 1 / dpr,
            tid;

        docEl.removeAttribute('data-mw');
        docEl.dataset.dpr = dpr;
        metaEl = doc.createElement('meta');
        metaEl.name = 'viewport';
        metaEl.content = 'initial-scale=' + ratio + ',maximum-scale=' + ratio + ', minimum-scale=' + scale;
        docEl.firstElementChild.appendChild(metaEl);

        var refreshRem = function() {
            var width = docEl.getBoundingClientRect().width;
            if (width / dpr > maxwidth) {
                width = maxwidth * dpr;
            }
            var rem = width / 16;
            docEl.style.fontSize = rem + 'px';
        };

        //...

        refreshRem();
    }
}

效果请参考淘宝手机版。

这种方案优点是线性缩放,比例一致,但大牛鸽子说,本来可以简单的事情使用js都是耍流氓,那就只能手动了,手动可以用媒体查询分段设置font-size大小,比如:

/* ============================================================
 本节多谢百老师
 ============================================================ */
html{font-size:10px;}
body{font-size:1em;}
/* 适配 iphone 6 */
@media all and (min-width: 374px){
 html{font-size:11px!important;}
 body{font-size:0.92em!important;}
}
/* 适配 iphone 6+ */
@media all and (min-width: 414px){
 html{font-size:12px!important;}
 body{font-size:0.88em!important;}
}

这里html设置了默认字体大小为10px,但中文字体不能小于12px,因此可能要为body设置font-size=12px,否则听说某些设备上会有bug。(此bug我没遇到过,如果你遇到了请告诉我)

分段设置html的font-size无法做到根据分辨率线性缩放,因此rem单位一般用在字体和间距等不会影响布局的地方上。

小tips:

1 background-position上尽量避免用rem,很可能出现非整数,在某些设备上造成偏差。

2 浏览器可识别的rem的最小值几乎都在6px以上,故html的初始字体font-size不能太小。

四.使用vw、vh、vmin、vmax单位

vw和vh都是相对于视窗分辨率的单位,其中vw=1/100 * 视窗宽度,vh = 1/100 * 视窗高度。

而vmin是vw和vh中较小那个,vmax是较大那个。

比如逻辑分辨率为320×568的设备,vw=3.2px,vh=5.58px,vmim=3.2px,vmax=5.68px。

因为vw本身就是根据分辨率的弹性单位,使用vw的适配效果在视觉上堪称最完美,然而它的兼容性较差,android 4.3及以下都不支持。

具体兼容性请参考caniuse.com

五.viewport width使用定值

以上几种方案的viewport width 都是 device-width,那能不能给它一个定值呢?

答案是可以,如

<meta name=”viewport” content=”width=640,maximum-scale=1,user-scalable=no”>

viewport width使用定值后,所有支持的移动端设备都将使用此定值为逻辑分辨率。

假设viewport width和视觉稿一样都是640px,则CSS不再需要按比例计算逻辑分辨率。在这个世界里,所有手机都是640px宽,从此开发简单,还原精准。

然而简单粗暴的它缺点也是致命的:不够灵活。这个方案的所有元素都根据分辨率自动线性缩放了,但很多时候我们并不需要全局等比例缩放,比如按钮或底部导航条,在大分辨率屏幕上将会显得特别粗大,而除了粗大,我们往往更喜欢和谐。

另外有些老旧的机型并不能根据 viewport width的值来缩放 viewport。

使用这个方案的网站比较少,效果可以参考lofter网站

六.背景图

为了让背景图在移动设备上足够清晰,往往需要切成高清大图,再用background-size 缩放为逻辑分辨率大小,如:

background-size: 100px;height: 100px;

该图片实际尺寸可能为逻辑分辨率的2倍甚至3倍,为了保证缩放后为证书,原始尺寸必须为相应的2的倍数或3倍。

为了保证符合要求,建议对ps作如下设置:

6

还有设置一下自动对齐网格

7

网格线间隔设为偶数,子网格则设置成可以把网格线间隔除尽的数,切图时按快捷键“ctrl+,”显示网格线,效果如图:

8

该图实际大小为30px * 30px,其中每个实线围成的正方形为10px * 10px,即“网格线间隔”定义了实线格子的大小

每个虚线小正方形为2px * 2px,即子网格中5的意思是把实网格线分成5等分。

总结:

以上是常见的几种适配移动端的姿势,然而在实际应用中往往会有交叉,不同的产品经理和设计师对不同部位都会有不同要求,为达到尽量完美的效果可以同时使用几种方案。

如何优雅地结合只能不断提高经验值,未来应该是属于vw、vh这种最灵活的相对单位,然而目前它兼容性最差,建议在不那么重要的地方渐进增强地使用。

发表评论

电子邮件地址不会被公开。 必填项已用*标注