网易和淘宝移动,Web移动端适配总结
分类:前端技术

网易和淘宝移动 WEB 适配方案再分析

2017/05/03 · 基础技术 · 适配

原文出处: 吴成琦   

最近把移动WEB适配相关的问题梳理了一遍,学习了几篇文章,其中

从网易与淘宝的font-size思考前端设计稿与工作流 – 流云诸葛

分析了网易和淘宝对移动WEB适配问题的解决方案,干货不少,但是一些概念和思路不是很清晰。我在这里结合一些其他的文章和自己的实验思考对两种适配方案再做分析,顺便把相关的知识点做个总结。

移动适配中涉及到的一些基本概念和原理参考文章

viewports剖析_viewports 教程_w3cplus

移动端适配方案(上) 

移动适配方案
视口介绍
1 : 布局视口(layout viewpor)
var width=document.documentElement.clientWidthconsole.log(width)
​ 可以看作为当前顶级的HTML元素的宽度,也就是咱们浏览器当前的可视区域的宽度,咱们的媒体查询max-width和min-width的值也是布局视口的宽度,布局视口中的宽度和高度都是像素,也就是px,是一个抽象单位。
​ 布局视口宽度受到meta标签内的width属性和initial-scale的影响,仅设置width的值时,这个值就是布局视口的宽度,它的值可以是正整数或者特殊值device-width。
​ 布局视口宽 = 可视视口宽时 html 元素正好横向铺满窗口(但其后代元素若有横向 overflow 的情况,仍然会出现滚动条),布局视口宽 > 可视视口宽时,出现横向滚动条
2 : 可视视口(visual viewport)
var width=window.innerWidth
​ 可视视口是当前可见区域的CSS像素数,和布局视口差不多,区别可视视口的宽度决定了将页面分成了多少份,每份对应一个CSS像素。
<meta name="viewport" content="initial-scale=0.5">
可视视口受到缩放比例的影响, 在meta标签内设置了 initial-scale=0.5 后会改变可视视口的尺寸,可视视口尺寸越小显示的CSS像素数也越少,则单位CSS像素数对应的可视区域越大,对应的缩放比例也就越大。缩放比例是相对于理想视口而言 缩放比例 = 理想视口尺寸/可是视口尺寸,而当没有设置initial-scale的时候,浏览器会取适当的缩放比例,一般情况下为1,使布局正好铺满屏幕,此时布局视口尺寸 = 可视视口尺寸。
3 : 理想视口(ideal viewport)
<meta name="viewport" content="width=device-width">
​ 理想视口是一个比较适合移动布局的视口尺寸,作为计算布局视口和可视视口尺寸的基准值,上面mete标签中的 device-width 就是理想视口的宽度。
var width=screen.width
​ JS中这么写,也可以获取理想视口的宽度
备注 :
上面三个视口属性中,只有理想视口是不可以改变的,因为理想视口的宽度拒绝与设备的物理像素比存在着比例的关系,这个比例叫做设备像素比(device pixel ratio, dpr), 公式为 : 设备像素比 = 物理像素数/理想视口尺寸
/*网易和淘宝移动,Web移动端适配总结。 举个栗子 iPhone 物理宽度像素 640 理想视口宽度 320 设备像素比 2*/​var c=window.devicePixelRatio//这样可以获取设备像素比(Android系统下可能不符合预期)

移动端适配的相关概念以及几种方案总结

在这里提取一些比较重要的规则

  1. 布局视口(layout viewport)可以看作是html元素的上一级容器即顶级容器,默认情况或者将html元素的width属性设为100%时,会占满这个顶级容器,此时用
JavaScript

document.documentElement.clientWidth

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c7785e606024990-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c7785e606024990-1" class="crayon-line">
document.documentElement.clientWidth
</div>
</div></td>
</tr>
</tbody>
</table>


获取到html元素的布局宽度也就是布局视口的宽度,使用媒体查询时
max-width 和 min-width 的值指的也是布局视口的宽
  1. 布局视口的宽度和高度单位是像素px,这个单位是CSS和JS中使用的抽象单位,为了便于区分称作CSS像素。布局视口的宽度有一个默认值,一般在 768px ~ 1024px 之间,最常见的宽度是 980px,在这个默认值下进行布局得到的页面比较接近PC端布局的效果
  2. 可视视口(visual viewport)是指用户可见页面区域,其宽度值为横向可见CSS像素数,从另一个角度理解,可视视口的宽度决定了将屏幕横向分为多少份,每份对应一个CSS像素,使用
JavaScript

window.innerWidth

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c77869354381759-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c77869354381759-1" class="crayon-line">
window.innerWidth
</div>
</div></td>
</tr>
</tbody>
</table>


可以获取到可视视口的宽度
  1. 理想视口(ideal viewport)是一个比较适合页面布局使用的视口尺寸,作为计算布局视口和可视视口尺寸时的一个基准值,下面代码中 device-width 的值就是理想视口的宽度
JavaScript

&lt;meta name="viewport" content="width=device-width"&gt;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c7786d663315204-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c7786d663315204-1" class="crayon-line">
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;
</div>
</div></td>
</tr>
</tbody>
</table>


使用  


JavaScript

screen.width

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c77870549313570-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c77870549313570-1" class="crayon-line">
screen.width
</div>
</div></td>
</tr>
</tbody>
</table>


也可以获取到理想视口的宽度
  1. 三个视口中只有理想视口的尺寸是不能改变的,由设备和浏览器决定,与设备的物理像素数存在着比例关系,这个比例就是设备像素比(device pixel ratio, dpr),即有 设备像素比 = 物理像素数 / 理想视口尺寸,举例iphone5屏幕横向有640个物理像素,其理想视口宽为320,则 dpr=2,可以使用
JavaScript

window.devicePixelRatio

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c77874328628116-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c77874328628116-1" class="crayon-line">
window.devicePixelRatio
</div>
</div></td>
</tr>
</tbody>
</table>


获得dpr,但在安卓系统下这个值可能不符合预期
  1. 可视视口的尺寸收到缩放比例的影响,因此用户手动缩放和在 meta 标签中设置 initial-scale 的值都会改变可视视口的尺寸,可视视口的尺寸越小即显示的CSS像素数越少,则单位CSS像素对应的可使区域越大,对应的缩放比也就越大。缩放比例是相对于理想视口而言的,即有 缩放比例 = 理想视口尺寸 / 可视视口尺寸。对iphone5,设置
JavaScript

&lt;meta name="viewport" content="initial-scale=0.5"&gt;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c77877372082045-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c77877372082045-1" class="crayon-line">
&lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=0.5&quot;&gt;
</div>
</div></td>
</tr>
</tbody>
</table>


则其可视视口尺寸为640个CSS像素  
缩放比例也有默认的值,没有设置 initial-scale
时,浏览器会取适当的缩放比例使 布局视口正好铺满屏幕即有
**布局视口尺寸 = 可视视口尺寸**
  1. 布局视口的宽度受到 meta 标签中的 width 和 initial-scale 的影响
    仅设置 width 的值时,这个值就是布局视口的宽度,width的值可以为正整数或特殊值 device-width
JavaScript

&lt;meta name="viewport" content="width=400"&gt;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c7787b390379620-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c7787b390379620-1" class="crayon-line">
&lt;meta name=&quot;viewport&quot; content=&quot;width=400&quot;&gt;
</div>
</div></td>
</tr>
</tbody>
</table>


此时由于没有禁用缩放,一般可以通过双击屏幕对页面进行缩放,但手动缩放不会影响布局适口的尺寸,只会影响到可视视口的尺寸,而且可能导致布局视口小于可视视口  
**设置 initial-scale
的值时,布局视口的尺寸与可视视口的计算方式相同,但不受手动缩放的影响**  
**同时设置 width 和 intial-scale
的值时,布局视口的宽取上述两个值中较大的一个**
  1. 布局视口宽 = 可视视口宽时 html 元素正好横向铺满窗口(但其后代元素若有横向 overflow 的情况,仍然会出现滚动条),布局视口宽 > 可视视口宽时,出现横向滚动条

由上述规则可以得到一些有用的结论

  1. 将 meta 标签中的 width 设为 device-width 同时禁用手动缩放可以使 布局视口尺寸 = 可视视口尺寸 = 理想视口尺寸,此时 设备像素比 = 物理像素数 / 理想视口尺寸 = 物理像素数 / 布局视口尺寸,对iphone5,一个CSS像素对应4个物理像素
  2. 为 initial-scale 设置任意合法的值同时禁用手动缩放就可以使布局视口尺寸 = 可视视口尺寸
  3. 将 initial-scale 设置为 1 也可以使 布局视口尺寸 = 可视视口尺寸 = 理想视口尺寸

<meta name="viewport" content="width=device-width">
由于没有禁用缩放属性,手动缩放不会影响布局视口或者理想视口,只会影响到可视视口的尺寸,而且可能导致布局视口小于理想视口。
设置 initial-scale 的值时,布局视口的尺寸与可视视口的计算方式相同,但不受手动缩放的影响同时设置 width 和 intial-scale 的值时,布局视口的宽取上述两个值中较大的一个
总结一下 :
​ 1 : 将meta标签中的width设为device-width时,布局视口 = 可视视口 = 理想视口,这时设备像素比,设备像素比 = 物理像素 / 理想视口尺寸 = 物理像素比 / 布局视口尺寸,对iphone而言,一个CSS像素对应4个物理像素。
​ 2 : initial-scale 设置任意合法的值同时禁用手动缩放时,布局视口 = 可视视口
​ 3 : initial-scale 设置为1时也可以使布局视口 = 可视视口 =理想视口
分析一下网易和淘宝的适配方案
​ 前言 : 网易新闻和淘宝尺寸适配采用了相同的思路,使用相对单位rem并将设备的可视视口宽度乘以一个系数得到html元素的font-size,元素布局时不超出可视视口宽度即可。

适配相关概念

  1. 布局视口(layout viewport):html元素的上一级容器即顶级容器,用于解决页面在手机上显示的问题。大部分移动设备都将这个视口分辨率设置为980px,所以PC上的网页基本上能在手机上呈现,只不过看上去很小,一般默认可以通过手动缩放网页。获取当前布局视口用document.documentElement.clientWidth
  2. 视觉视口(visual viewport):指用户可见页面区域,即屏幕显示器的物理像素。获取当前的视觉视口可以用window.innerWidth
  3. 理想视口(ideal viewport):也就是我们通常说的屏幕分辨率。比如Iphone5屏幕分辨率是320。

下面具体分析网易和淘宝的适配方案

其实两种方案在处理元素尺寸的适配时采用了相同的思路,即使用相对单位 rem 并将设备的可视视口宽度乘以一个系数得到 html 元素的 font-size,元素布局时不超出可视视口宽度即可

实际上我们并不需要特别设置布局视口的宽度——只要所有需要展示的元素填满可视视口即可,理论上如果设置了 meta 中的 width 值且大于可视视口的计算结果,会出现横向滚动条,但网易和淘宝的方案都没有设置 width,此时布局视口的宽等于可视视口,只要没有超出可视视口宽度的元素,就不会出现滚动条

先分析一下网易新闻的方案

  1. 第一个要解决的关键问题是如何为设备选择可视视口尺寸,网易新闻的方案相对简单,采用理想视口尺寸作为可视视口尺寸,代码也十分简单,只需要将缩放比定为 1
JavaScript

&lt;meta name="viewport" content="initial-scale=1,maximum-scale=1,
minimum-scale=1"&gt;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c7787f958294979-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c7787f958294979-1" class="crayon-line">
&lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=1,maximum-scale=1, minimum-scale=1&quot;&gt;
</div>
</div></td>
</tr>
</tbody>
</table>
  1. 第二个要解决的问题是计算 html 元素的 font-size,要将可视视口的宽度乘以一个系数

    理论上这个系数可以是任意值,假设将这个系数取 1,则 html 元素的 font-size 即1 rem等于可视视口的宽度,此时以 rem 为单位的长度 n rem 就可以理解为 n 倍可视视口的长,这个系数取 0.01 时,1 rem 等于可视视口宽的 1/100,也就等于布局视口宽的 1/100,也就等于 1vw。实际使用过程中这个系数的选择尽可能方便将设计稿长度数值换算为css中的长度数值

    网易新闻手机网易网选择的系数为 100 / 750,这个系数可以如下推出:

    750px 是设计稿的宽度(以iphone6的物理像素数为标准),100是期望的换算比例,即设计稿中 100px 的长度对应css中 1rem,将设计稿中的长度数值除以 100 得到的就是以 rem 为单位的 css 长度的数值,设计稿的宽换算为以 rem 为单位的 css 长度应为 (750/100) rem,同时设计稿的宽对应可视视口的宽,即有 (750/100) rem = 可视视口宽,1 rem = 可视视口宽 * (100/750),(100/750)就是我们要的系数

    在页面初始化时设置一下 html 元素的 font-size

JavaScript

document.documentElement.style.fontSize = window.innerWidth / 7.5  
'px';

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c77883964749612-1">
1
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c77883964749612-1" class="crayon-line">
document.documentElement.style.fontSize = window.innerWidth / 7.5   'px';
</div>
</div></td>
</tr>
</tbody>
</table>
  1. 第三个要解决的是将可视视口的宽度换算为 rem 单位的数值,布局时元素不能超出这个值由 (750/100) * font-size = 可视视口宽 可知 可视视口宽为 (750/100) rem
    网易新闻的解决方案中将这个值设置到了 body 元素的 width 上但并没有对 overflow 进行处理,所以实际上没有起到什么作用
    输出的html如下(iphone6,device-width = 375,dpr = 2)
XHTML

&lt;html style="font-size: 50px;"&gt; ... &lt;meta name="viewport"
content="initial-scale=1,maximum-scale=1, minimum-scale=1"&gt; ...

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c77887260064866-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a6c77887260064866-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6a6c77887260064866-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a6c77887260064866-4">
4
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c77887260064866-1" class="crayon-line">
&lt;html style=&quot;font-size: 50px;&quot;&gt;
</div>
<div id="crayon-5b8f6a6c77887260064866-2" class="crayon-line crayon-striped-line">
...
</div>
<div id="crayon-5b8f6a6c77887260064866-3" class="crayon-line">
&lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=1,maximum-scale=1, minimum-scale=1&quot;&gt;
</div>
<div id="crayon-5b8f6a6c77887260064866-4" class="crayon-line crayon-striped-line">
...
</div>
</div></td>
</tr>
</tbody>
</table>
  1. 在最新的网易新闻页面中字体的单位也使用了 rem

然后对比地分析一下淘宝的方案

  1. 在为设备选择合适的可视视口时淘宝的方案显得复杂,但是有其巧妙之处,在他们的开源项目使用Flexible实现手淘H5页面的终端适配中提到了缩放比的算法
  1. JavaScript

    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; }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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;
    }
概括一下,就是取 dpr 的倒数作为缩放比例,对 iOS 设备 dpr =
window.devicePixelRatio ,其他设备认为 dpr 为 1  
对 iOS 设备,令上面提到的公式 缩放比例 = 理想视口尺寸 /
可视视口尺寸,设备像素比 = 物理像素数 / 理想视口尺寸 中 设备缩放比 =
1 / 缩放比例 可以推出 可视视口尺寸 = 物理像素数,同时由于没有设置
meta 标签的 width 值,有 布局视口尺寸 = 可视视口尺寸 =
物理像素数,这意味着布局视口中的像素单位是和物理像素一一对应的,css单位中1px严格等于一个物理像素。这就是淘宝方案的巧妙之处了,对于
iOS 下高分辨率的设备,提供了更好的支持,解决了 1px border
问题和高清图片的问题,详细的解释见 [移动端高清、多屏适配方案 –
Div.IO](http://link.zhihu.com/?target=http://div.io/topic/1092)  
对非 iOS 设备,将 dpr 设为 1,缩放比例也为 1,和网易新闻的方案相同。
  1. 在计算 html 的 font-size 时淘宝的方案直接将可视视口的宽度乘以一个系数 0.1,由此推导换算比例:

可视视口的宽度为 10 rem, 对应设计稿的宽度,则 1 rem 对应设计稿宽度的 1 / 10,换算时将设计稿中的长度数值除以 (设计稿宽度/10) 就可以了。
例如:设计稿的宽度为 750 则设计稿中的长度数值除以 75 得到的就是以 rem 为单位的 css 长度的数值

在 meta 标签中的缩放比例发生变化时,设置 html 元素的 font-size

JavaScript

document.documentElement.style.fontSize = window.innerWidth / 10 'px';

1
document.documentElement.style.fontSize = window.innerWidth / 10 'px';
  1. 由于可视视口的宽度就是 10 rem,对元素进行布局时只要不超过 10rem 即可,另外淘宝的方案将 body 的 width 设为 100% 并对 overflow 进行 hidden,这个 100% width 会计算为布局视口的宽,也是 10rem,那么 body 内布局超出 10rem 的元素不会导致布局视口出现滚动条
  2. 淘宝的方案中对字体使用了 px 单位,这就需要对不同的视口宽度(也就是不同dpr)的设备分别进行适配,淘宝的方案是将 dpr 数值设置为 html 的 data-dpr 属性,通过css选择器选择不同 dpr 设备下的元素
CSS

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; }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6a6c77892732142883-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a6c77892732142883-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6a6c77892732142883-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a6c77892732142883-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6a6c77892732142883-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a6c77892732142883-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f6a6c77892732142883-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a6c77892732142883-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f6a6c77892732142883-9">
9
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6a6c77892732142883-10">
10
</div>
<div class="crayon-num" data-line="crayon-5b8f6a6c77892732142883-11">
11
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6a6c77892732142883-1" class="crayon-line">
div {
</div>
<div id="crayon-5b8f6a6c77892732142883-2" class="crayon-line crayon-striped-line">
    width: 1rem; 
</div>
<div id="crayon-5b8f6a6c77892732142883-3" class="crayon-line">
    height: 0.4rem;
</div>
<div id="crayon-5b8f6a6c77892732142883-4" class="crayon-line crayon-striped-line">
    font-size: 12px; // 默认写上dpr为1的fontSize
</div>
<div id="crayon-5b8f6a6c77892732142883-5" class="crayon-line">
}
</div>
<div id="crayon-5b8f6a6c77892732142883-6" class="crayon-line crayon-striped-line">
[data-dpr=&quot;2&quot;] div {
</div>
<div id="crayon-5b8f6a6c77892732142883-7" class="crayon-line">
    font-size: 24px;
</div>
<div id="crayon-5b8f6a6c77892732142883-8" class="crayon-line crayon-striped-line">
}
</div>
<div id="crayon-5b8f6a6c77892732142883-9" class="crayon-line">
[data-dpr=&quot;3&quot;] div {
</div>
<div id="crayon-5b8f6a6c77892732142883-10" class="crayon-line crayon-striped-line">
    font-size: 36px;
</div>
<div id="crayon-5b8f6a6c77892732142883-11" class="crayon-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>

对比总结
从可视视口的选择可以看出 淘宝方案对 iOS 高分辨率的设备提供了特别的支持,而对其他设备一律采用了精确度较低的处理方式,网易新闻则对所有设备都采用了精确度较低的处理方式。在这一点上,淘宝方案可看作是网易方案的增强版,而在 dpr = 1 的设备下,淘宝方案可以退化为网易方案。淘宝方案还可以使用 px 单位对字体进行精确度比较高的适配,而对于网易方案,使用 px 作为字体的单位意义不大。

在 html 元素 font-size 的计算上,网易方案选择了一个比较人性化的换算比例,根据这个比例去推算 font-size 的系数和对应的视口尺寸的 rem 值,淘宝方案反过来将可视视口定为 10rem和 font-size 的系数,由此推算换算比例。比较而言网易方案进行人工换算和检查时更容易些,淘宝方案虽然可以借助工具完成自动换算,但在阅读输出的 css 样式时就有点费力了。

实际运用中,可以将两种方案的优点结合起来,形成更好的适配方案。

网易 :
​ 我们并不需针对设置布局视口的宽度---只需要所有的元素占满可视视口即可,理论上如果设置了meta中的width值且大于可视视口的计算结果,会出现横向滚动条,但是网易和淘宝都没有设置width,所以布局视口的尺寸会大于可视视口的尺寸,只要没有超过可视视口的宽度,就不会出现滚动条。
​ 1 网易新闻方案相对简单,采用理想视口作为可视视口,需要将缩放比例为
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
2 第二个要解决的问题是计算html元素的font-size,要将可视视口乘以一个系数。
​ 理论上这个系数可以是任意值,如果为1,则html元素的fon-size即1rem等于可视视口的宽度,此时以rem单位的长度n, 可以理解为n倍数的可视视口,这个技术为0.01时,1rem = 可视视口款的1/100,也就是布局视口的1/100.
​ 实际使用过程中这个系数尽可能方便将设计稿长度数值换算为Css中的长度数值.
​ 假设,设计稿为750(iphone 6的物理像素),100是期望的换算比例,即设计稿中100px长度对应Css中1rem,将设计稿中的长度数值除以100得到的就是rem为到位的Css长度值,设计稿的宽换算为以rem为单位的Css长度应为(750/100)rem,同时设计稿对应可视视口的宽,即(750/100)rem=可视视口宽,1rem=可视视口(100/750),(100/750)就是我们要的系数。
​ 3 第三个将可视视口的宽度换算为rem单位的数值,布局时元素不能超出这个值,有(750/100)
font-size=可视视口 可知 可视视口宽度为(750/100)rem
网易新闻的结局方案中将这个值设置到了body元素的width上,但没有对overflow进行处理,所以实际上没有什么卵用。
​ 4 在最新的网易新闻页面中字体也使用了rem。
PS : 网易的咱们暂时不用细说,主要介绍的是手淘的适配方案,因为手淘的方案更加且易用;
淘宝
原文链接 : https://github.com/amfe/article/issues/17
看一看咱们需要适配的屏幕吧 :

使用viewport元标签控制布局

如下的viewport元标签的属性
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

以下是每个属性的介绍:

属性名 取值 描述
width 正整数或device-width 定义layout viewport的值
height 正整数或device-height 定义viewport height,单位为像素,一般不用
initial-scale [0,0 - 10.0] 定义初始缩放值。比如:设置initial-width=1.5 就是将visual viewport设置成ideal viewport宽度的1 /1.5倍
maximum-scale [0.0 - 10.0 ] 用户能够放大的最大比例
minimum-scale [0,0 - 10.0] 用户能缩小的最小比例,一般不设置,因为太小的字不方便阅读
user-scalable yes/no 定义是否允许用户手动缩放页面,默认值为yes

width的详细介绍:设置为device-width时表示layout viewport的宽度等于ideal viewport的值。同时设置widthintital-scale时,最终的视口宽度等于两者较大的那一个。也就是说:

  1. layout viewport小于visual viewport时,视口宽度最终是visual viewport的值(经测试,layout viewport的值也会自动变成visual viewport
  2. layout viewport大于visual viewport时,视口宽度最终是layout viewport的值(经测试,visual viewport的值不会变成这时layout viewport的值)

initial-scale的详细介绍:缩放比例 = ideal layout / visual layoutideal viewport是不会改变的,这个值是为了改变visual viewport。缩放比例也有默认值,没有设置initial-scale时,浏览器会取适当的缩放比例使布局视口正好铺满屏幕即有 可视视口(visual viewport)尺寸=理想视口尺寸(ideal viewport)。也就是说设置width=device-width与设置initial-scale=1.0效果相同。

其他方案

这篇文章移动端适配方案(下)中提到的第二种方案是另外一种思路,将布局视口尺寸固定,然后通过缩放使可视视口尺寸等于布局视口尺寸,进行元素布局时按照固定好的布局视口。原理用动图展示最为直观:图片 1

文中给出的实现代码如下:

XHTML

<meta name="viewport" content="width=640,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">

1
<meta name="viewport" content="width=640,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">

缩放比例根据理想视口计算的,缩放比例 = 理想视口尺寸 / 可视视口尺寸,使 可视视口尺寸 = 布局视口尺寸 ,则 缩放比例 = 理想视口尺寸 / 布局视口尺寸

布局视口的尺寸取设计稿的尺寸时,css像素对应设计稿中的 px,不需要进行单位换算

文中给出了两个例子金币商城和荔枝FM,人人都是播客_听音乐相声评书脱口秀鬼故事广播剧网络电台,但查看两个例子的代码发现其实现方式是另一种

XHTML

<meta content="target-densitydpi=device-dpi,width=640,user-scalable=no" name="viewport">

1
<meta content="target-densitydpi=device-dpi,width=640,user-scalable=no" name="viewport">

测试发现这种方式也可以使 可视视口尺寸 = 布局视口尺寸 ,但有资料显示target-densitydpi是一个将被抛弃的属性,因此不推荐使用

2 赞 2 收藏 评论

图片 2

图片 3

方案

  1. 荔枝FM的方案:将layout viewport定义为设计稿的宽度,这样的好处在于css像素对应设计稿的px(以640px为例),不需要进行单位换算。但是有几点需要注意的地方。
    1. 为了保证最终的视口的值都是640px,而不会变成其他值(前面说过,最终视口的值会取width与initial-scale属性的最大值)。要把visual viewport设置成与layout viewport一样大,即设置initial-scale的值为 ideal viewport / 640。之前也有一个属性代替了这个操作,target-densitydpi=device-dpi,但资料显示target-densitydpi=device-dpi是一个被抛弃的属性,不推荐使用
  2. 网易的纯REM方案:

    1. 采用理想视口作为可视视口的尺寸,只需要把缩放比定为1。<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, minimum-scale=1, user-scalable=no">
    2. 计算 html 元素的 font-size

      750px 是设计稿的宽度(以iphone6的物理像素数为标准),100是期望的换算比例,即设计稿中 100px 的长度对应css中 1rem,将设计稿中的长度数值除以 100 得到的就是以 rem 为单位的 css 长度的数值,设计稿的宽换算为以 rem 为单位的 css 长度应为 (750/100) rem,同时设计稿的宽对应可视视口的宽,即有 (750/100) rem = 可视视口宽,1 rem = 可视视口宽 * (100/750),(100/750)就是我们要的系数

    在页面初始化时设置一下 html 元素的 font-size:

    document.documentElement.style.fontSize = window.innerWidth / 7.5 'px';

  3. 最后一种方案也是最合理的---来自于手淘的最佳实践

    1. 以上两种方案都存在一个问题,就是在retina屏幕上没有处理dpr(device pixel ratio)的副作用,何为dpr物理像素 / 设备独立的像素(ideal viewport)。在JS中可以通过window.devicePixelRatio获取当前设备的dpr
    2. 为何要处理dpr:在retina屏幕上,物理像素会被放大为原本的dpr倍。这时候就会存在以下几个问题
      • 图片变模糊了
      • border: 1px问题,边框自然会被放大为dpr
      • ...
    3. 解决方案:使用initial-scale=1/dpr对含有px单位的元素做处理,但是单纯这么做会导致字体元素的大小都会缩小。如何解决这个问题呢?答案就是在第二种方案的根元素设置fontSize的基础上再乘以一个dpr,这样对于以rem衡量的元素又能正常适配了。

参考阅读:

  • 网易和淘宝移动WEB适配方案再分析
  • 移动端高清、多屏适配方案
  • 说说移动前端中 viewport (视口)

687474703a2f2f7777772e773363706c75732e636f6d2f73697465732f64656661756c742f66696c65732f626c6f67732f323031352f313531312f72656d2d372e706e67.png

早期移动端开发,对于终端设备适配问题只属于Android系列,只不过很多设计师常常忽略Android适配问题,只出一套iOS平台设计稿。但随着iPhone6,iPhone6 ,iPhone7 的出现,从此终端适配问题不再是Android系列了,也从这个时候让移动端适配全面进入到“杂屏”时代。
整个手淘设计师和前端开发的适配协作基本思路是 :
选择一种尺寸作为设计和开发基准

定义一套适配规则,自动适配剩下的两种尺寸(其实不仅这两种,你懂的)

特殊适配效果给出设计效果图片来自原文链接 :

图片 4

687474703a2f2f7777772e773363706c75732e636f6d2f73697465732f64656661756c742f66696c65732f626c6f67732f323031352f313531312f72656d2d362e6a7067.jpg

在设计师与前端开发协作过程中 : 设计师经常选择iphone6作为基准设计尺寸,交付给前端的设计尺寸是按750px * 1344px为准(高度可能会随着内容改变)。前端开发人员通过一套适配规则自动适配到其他尺寸。
根据上面所说,设计师给我们的是一个750px * 1600px的页面

图片 5

687474703a2f2f7777772e773363706c75732e636f6d2f73697465732f64656661756c742f66696c65732f626c6f67732f323031352f313531312f72656d2d332e6a7067.jpg

前端开发完成终端适配
这是咱们要说一下手淘的方案了 :
flexible方案,gitHup地址为 : https://github.com/amfe/lib-flexible, 原理性的东西不详说了,但是还需要说一点必要的。
flexble方案会把视觉稿分为100份,主要是为了以后可以更好的兼容vh 和 vw ,而每一份被称为一个单位a,同时1rem单位被认定为10a,这么算我们可以得出 :
1a = 750px/100
1a 为 : 7.5px
1rem =10a
1rem为: 75px
所以这份视觉稿分为了10a,整个宽度为10rem, <html>元素相对应的font-size=75px :

图片 6

687474703a2f2f7777772e773363706c75732e636f6d2f73697465732f64656661756c742f66696c65732f626c6f67732f323031352f313531312f72656d2d322e6a7067.jpg

这么算的话,只需要将*原始的px值 / rem基准值。例如此视觉稿的尺寸为176px176px,转换为 : 176/75 * 176/75
也就是
2.346667rem * 2.346667rem。**
快速计算
CSSREM插件
是一个在CSS中将px值快速转换为rem的插件。

图片 7

687474703a2f2f7777772e773363706c75732e636f6d2f73697465732f64656661756c742f66696c65732f626c6f67732f323031352f313531312f63737372656d2e676966.gif

gitHup地址为 : https://github.com/flashlizi/cssrem
这个插件也有Vs Code 版本,不过不知道是我自己笨还是怎么回事,总是按照默认的16px来进行换算...如果有知道怎么用的话麻烦告知一下...
当然咱们也可以使用less/sass进行换算,代码之类的就不详说!
文字大小不是非常适合实用rem
前面主要介绍了怎么使用,估计也有人会说咱们的文字大小可不可以呢? 这里引用原文作者的一段话 :
前面大家都见证了如何使用rem
来完成H5适配。那么文本又将如何处理适配。是不是也通过rem
来做自动适配。
显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px
和24px
,所以我们不希望出现13px和15px这样的奇葩尺寸
如此一来,就决定了在制作H5的页面中,rem
并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px
作为单位。只不过使用[data-dpr]
属性来区分不同dpr
下的文本字号大小。
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;}
为了更好的利于开发,这里定制一个font-dpr()
的混合宏 :
@mixin font-dpr($font-size){ font-size: $font-size;​ [data-dpr="2"] & { font-size: $font-size * 2; }​ [data-dpr="3"] & { font-size: $font-size * 3; }}
有了这么一个混合宏之后,在开发中可以这样利用 :
@include font-dpr(16px);
这里也只是针对描述性的文本,假设需求方希望字体可以根据不同终端适配,完全可以实用rem来作为单位。
看一下在真机上面的效果吧。
http://huodong.m.taobao.com/act/yibo.html

图片 8

下载.png

本文由pc28.am发布于前端技术,转载请注明出处:网易和淘宝移动,Web移动端适配总结

上一篇:JS使用前询问,依据类库开采及框架介绍 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • 网易和淘宝移动,Web移动端适配总结
    网易和淘宝移动,Web移动端适配总结
    网易和淘宝移动 WEB 适配方案再分析 2017/05/03 · 基础技术 ·适配 原文出处: 吴成琦    最近把移动WEB适配相关的问题梳理了一遍,学习了几篇文章,其中
  • 运动端适配方案,多终端的适配实施方案
    运动端适配方案,多终端的适配实施方案
    移动端适配方案(下) 2017/01/25 · CSS ·移动端 本文作者: 伯乐在线 -risker。未经作者许可,禁止转载! 欢迎加入伯乐在线 专栏作者。 上一篇介绍了像素和视
  • 内部存储器分析工具简要介绍,内部存款和储蓄
    内部存储器分析工具简要介绍,内部存款和储蓄
    4类 JavaScript 内存泄漏及如何避免 2016/05/26 · JavaScript· 1 评论 ·内存泄漏 本文由 伯乐在线 -涂鸦码龙翻译。未经许可,禁止转载! 英文出处:SebastiánPeyro
  • HTML也可以静态编译,损害了复用性
    HTML也可以静态编译,损害了复用性
    React.Component 损害了复用性? 2016/09/07 · 底蕴技能 ·binding.scala,data-binding,React,scala.js 本文笔者: 伯乐在线 -ThoughtWorks。未经笔者许可,防止转发! 接待插足
  • 品质的法门
    品质的法门
    9 种改革 AngularJS 品质的艺术 2017/07/20 · JavaScript· AngularJS 初藳出处: JustinSpencer   译文出处:oschina    AngularJS 是当下利用非常遍布的 web app应用框架,随