http://www.web008.net

web多屏适配,浅谈移动前端适配

1. 什么是前端适配

从UI展现层面上:
我们期望不同尺寸的设备,页面可以自适应的展示或者进行等比缩放,从而在不同的尺寸的设备下看起来协调或者差不多

从代码实现层面上:
我们希望前端适配可以用用尽可能简洁的代码来实现。最好一套代码实现兼容所有设备,而不是对每个或每种设备都写一套方案,不是次次都选用最无奈的方案(Android和iOS分开编写)。

核心:

一、利用rem来处理尺寸(width、height、margin、padding等)。
二、物理像素border的实现,viewport、物理像素、css像素概念。
三、vw、vh、vmin、vmax、% (vw不兼容安卓4.3以下浏览器)。
四、一物理像素border实现两种方法:
(1)整个页面缩放,viewport 设置 scale
(2)单个元素缩放,transform scale
五、术语概念:

* 物理像素:买手机的时候会有一个 nm 的分辨率,那是屏幕的nm个呈像的点,一个点(小方格)为一个物理像素。它是屏幕能显示的最小粒度

* CSS像素:就是CSS里的Px,上面已经讲了是viewport中的一个小方格。

* 

像素密度:即dpi或ppi,屏幕每英寸所占的物理像素点。

dpi:设备像素比。

viewport:屏幕的视口宽高,在css中,1px是指viewport中的一个小方格,而viewport的宽度是可以任意设置的。有两个,一个实际窗口,一个虚拟窗口。
* device-width:设备宽度。

而CSS像素与物理像素之间是有一个转换关系的。即是:
六、device-width:device-width的宽度值单位是CSS像素。
当viewport设置为device-width时,此时它是手机横向分辨率 / 转换系数。即:

七、viewport设置:


(1)头部信息设置:虚拟窗口;模仿实际的窗口;还有个缩放;
<meta charset="UTF-8" name="viewport" content="width=device-width,
initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>


(2)js部分设置:

<script>
//适应移动设备和pc设备屏幕的文档默认字体设置;
var dpr = window.devicePixelRatio;
document.documentElement.style.fontSize = dpr*window.innerWidth / 10 + 'px'; var meta = document.querySelector('meta');
meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', ' +
'maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');
</script>


1.移动端适配的是什么?
我们讨论的是网页适配多种尺寸屏幕,让网页效果看起来和设计师的设计稿一样。
说白了就是同一套代码在不同分辨率的手机上跑时,页面元素间的间距,留白,以及图片大小会随着变化,在比例上跟设计稿一致。

结论:明白了,所以padding,margin,图片等的大小基本都要做适配

2.那有什么方法可以做到这种适配?
关键要找到一种长度单位,使得一样的取值,在不同尺寸的屏幕上的大小按比例缩放。
1.网页在viewport中布局,viewport被分成一个个小方块,一个CSS像素占一个方块;
2.在设置了viewport宽度等于设备宽度的情况下,通过某种算法,在不同大小的屏幕上,1个CSS像素所占屏幕的物理尺寸是一样大的既然1个CSS像素在不同屏幕上物理尺寸一样大,那px肯定不能做为适配的方法了 ;
结论:
(1)长度单位rem是相对于html标签的font-size来计算的。例如html标签设置font-size:36px,同时div设置width:1.2rem。那么这个div的宽度就是1.2rem=36px*1.2=43.2px
(2)奥秘就在于结合px的固定尺寸和rem的相对尺寸!

3.适配具体执行方案(阿里flexible):

1. 设置viewport为设备宽度(这里不一定,但目前先这样足矣);

2. 将viewport分成10rem,并计算出1rem在当前浏览器的像素值,把它赋予html标签的font-size(分成10rem只是为了方便计算而已);

3. 写CSS代码时,遇到要适配的地方,比如width,margin,padding等,就不要再用px了,改成用rem;

JS和Html代码如下:
<!DOCTYPE html><html lang="zh-cn">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, height=device-height">
<title>啃先生的网</title>

<script type="text/javascript">
    var cssEl = document.createElement('style');
    document.documentElement.firstElementChild.appendChild(cssEl);

    function setPxPerRem(){
        var dpr = 1;
        //把viewport分成10份的rem,html标签的font-size设置为1rem的大小;
        var pxPerRem = document.documentElement.clientWidth * dpr / 10;
        cssEl.innerHTML = 'html{font-size:' + pxPerRem + 'px!important;}';
    }
    setPxPerRem();
</script></head><body>

</body></html>
CSS代码做了类似如下的修改:

运行结果如下:边距和头像图片都随屏幕变化而变化了260400的屏幕、 380400的屏幕;

对精益求精的项目,有以下问题:
1.图1的屏幕的尺寸较小,因此头像应该小些,话题左边的空白也应该小一些。
2.图片应该保持正方形,而且两张图之间的边距应该随屏幕变化而变化
结论:所以padding,margin,图片等的大小基本都要做适配

4.px与rem之间的单位换算 例如:
现有设计师提供宽度为400px的设计稿,其中某个图片的宽度设计为20px,那么,CSS的写法就是img{width: 0.5rem;},怎么得出这个结果的呢?

1. 设计稿的宽度视同手机宽度,即假设有一个viewport为400px的手机

2. 将它分成10rem,每个rem为40px;

3. 

那么图片宽度20px自然就是0.5rem;

5.手动换算太麻烦怎么办:编辑器插件;
6.参考链接:
1. 使用Flexible实现手淘H5页面的终端适配(https://github.com/amfe/article/issues/17)

2. 移动端高清、多屏适配方案(http://www.html-js.com/article/Mobile-terminal-H5-mobile-terminal-HD-multi-screen-adaptation-scheme%203041)

3. A tale of two viewports(http://www.quirksmode.org/mobile/viewports.html)

2.1.1 Visual Viewport

Visual Viewport: 可见视口。就是移动设备上可以被我们看见的部分。宽度在移动端通过window.innerWidth获得(仅限移动端,PC上哪怕是chrome模拟也会有不同的结果)。

图片 1

web屏幕适配(一):https://segmentfault.com/a/1190000004524243
web屏幕适配(二):https://segmentfault.com/a/1190000004538413
前端乱炖:http://www.html-js.com/article/Mobile-terminal-H5-mobile-terminal-HD-multi-screen-adaptation-scheme%203041

3. 业界的解决方案

OK,LongLongAgo的前缀之后,终于到了正题。回到我们最开始的初心:我们只是想要通过一套代码,实现一个可以在不同页面尺寸上展示差不多的页面。在这一块,现在主要有三种方案。

2.2.2 设备独立像素

设备独立像素:又称为CSS像素,就是我们日常代码中使用的像素。浏览器内的一切长度都是以CSS像素为单位的,CSS像素的单位是px。

2.1 Viewport/视口

通俗的讲,移动设备上的viewport就是设备的屏幕上能用来显示我们的网页的那一块区域[1],但不一定是我们可见的区域。具体来说,分为以下三种。

2.2 像素

2. 关键字

如果你了解这些关键字,那么这段大可以跳过,如果后面遇到了问题,感觉有些疑惑,也可以再回来查阅。

3.2 Flexible.js

Flexible是阿里团队开发的前端适配方案,也是用的rem的方法。那么第一种方法其实已经能解决前端适配问题了,为什么阿里还要开发一个Flexible呢?

在第一种方法中,dpr=1时没有任何问题,但是在dpr=2或者更高的手机屏幕上,因为物理像素的增加,存在小于1px的显示空间。如果采用第一种方法,因为它统一对scale设置为1,那么我们假如想要实现0.5px, 就只能通过transform的方式。如果有多个这样的样式,代码就会变得很麻烦。

.scale{ position: relative; } .scale:after{ content:""; position: absolute; bottom:0px; left:0px; right:0px; border-bottom:1px solid #ddd; -webkit-transform:scaleY(.5); -webkit-transform-origin:0 0; }

1
2
3
4
5
6
7
8
9
10
11
12
13
.scale{
    position: relative;
}
.scale:after{
    content:"";
    position: absolute;
    bottom:0px;
    left:0px;
    right:0px;
    border-bottom:1px solid #ddd;
    -webkit-transform:scaleY(.5);
    -webkit-transform-origin:0 0;
}

因此,阿里的flexible方案充分考虑了这种情况,动态的设置了fontsize和scale, 从而使得CSS中的1px等于物理像素中的1px,在IOS下得到最清晰的体验。

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) { // 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; } 最终在iphone8下页面的header被设置为: <meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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) {
        // 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;
}
 
最终在iphone8下页面的header被设置为:
<meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">

具体的大家可以看《使用Flexible实现手淘H5页面的终端适配》

另外需要指出的一点是:Flexible将页面分成了100份,页面的宽度是10rem,对于750的设计稿,我们需要用相应的px数除以75来得到。手动计算是愚蠢的,不同的编译器都可以下载pix2rem插件(可以直接写px然后自动转换为相应的rem值),直接使用sass或者postcss打包也能达到同样的功能。

总结一下上面两种rem方法,主要思想为:

  • 根据dpr的值来修改html的font-size,从而使用rem实现等比缩放
  • 根据dpr的值来修改viewport实现1px的线

但是Flexible也有它的局限性,具体表现为:

  • 不能与响应式布局兼容
  • 对Android没有做处理,导致1px和backgroudImage还要额外做处理的问题[4]

所以我们有了第三种解决方案——vw。

2.2.3 设备像素比

设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系。比如说对于iOS的retina屏,一个设备独立像素就对应着4个物理像素。这样的设计可以使画面更加清晰锐利,如下图:
图片 2

郑重声明:本文版权归美高梅163888所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。