天天看点

你必须要知道的移动端开发知识

移动开发不同与PC端开发,可能会经历各种意想不到的问题,尤其是移动端应用刚起步的几年;随着移动互联网的快速发展,有些问题已经得到了很好的支持,如1像素边界的问题。当然,要更好地解决这些移动端的问题,就需有移动端领域相关的知识,下面就来说说。

首先说一下,这个dpr不仅仅是移动端才有的,pc端也有,但是对一些移动端的问题产生的原因及解决显得比较重要,比如1像素的问题。先来看几个概念:

<code>物理像素(physical pixel)</code>

一个物理像素就是显示设备上最小的物理显示单元,每个物理像素都有自己的颜色值和亮度值。例如iphone6手机屏幕有750*1334个物理像素

<code>设备独立像素(density-independent</code>

设备独立像素又叫密度无关像素,也可以叫逻辑像素,程序使用的虚拟像素如css像素,可以理解为显示设备坐标系统中的一个点;

<code>设备像素比dpr(device pixel ratio)</code>

设备像素比,简称dpr,定义了物理像素与设备独立像素之间的对应关系,具体的对应关系是一个计算公式如下:

上面计算的dpr是指某一个方向上如x或者y方向,二者dpr值相同;程序中获取dpr方式如下:

js获取dpr使用<code>window.devicePixelRatio</code>

css获取dpr使用<code>-webkit-device-pixel-radio</code>

例如iphone6,设备宽高375 * 667,可以理解为设备独立像素(也即css像素);其dpr为2,那么对应的物理像素宽高均 * 2,即 750 * 1334;也就是说一个逻辑像素,在x轴和y轴都需要2个物理像素来显示,一图胜千言,如图:

你必须要知道的移动端开发知识

由上线描述可以知道,css中的1px并不等于显示设备的物理1px,这就导致移动开发中设计师设计的是1px的物理像素,而转换为css的值为1/dpr,其可能为小数值,这在低版本android(&lt;=4.4)和ios(&lt;=8)中被会系统自动转换为0,这就是移动端常见的1px像素的问题;下面会给出具体的解决方案。

做过移动端开发的同学可能对下面html中的meta标签比较熟悉:

这个是用来控制移动端<code>viewport</code>区域是怎么展现的,很有必要对其理解。

在PC的浏览器中,viewport其实就是浏览器可视区域,但是在移动设备上问题就比较复杂,viewport并不局限于浏览器可视区域大小,可能比浏览器可视区域要大,也可能比浏览器可视区域要小;但是因为移动端屏幕相较pc端太窄,为在移动端正常显示为PC端设计的网站,默认情况下移动端设备上的viewport都是要大于浏览器可视区域的,一般值为<code>980px</code>也可能有其他值,根据不同设备来定;因为viewport比浏览器可视区域大,那么浏览器就会出现横向滚动条。

需要注意两点:

页面的html标签的宽度就是相对于viewport的大小。

PC端viewport就是浏览器可视区域大小;移动端默认viewport值为980px,也可以根据meta标签自定义设置。

有关viewport理论,国外有一个人ppk对此有做过比较深入的研究,具体可以参考其写的三篇文章①、②、③ 。其将viewport分成三个层面来理解:

layout viewport

布局窗口,网页真正的布局视口,它的宽度可以大于也可以小于浏览器可视区域的宽度,对于大于浏览器可视区域(比如默认980px的viewport或者自定义设置viewport)的viewport,只能通过滚动浏览器滚动条来展现其内容。

visual viewport

可视窗口,移动设备浏览器可视区域的大小,其宽度并一定为移动显示设备的屏幕宽度,在initial-scale缩放为1的情况下才相等。

ideal viewport

理想化的窗口,它没有一个固定的尺寸,其宽度为移动设备屏幕宽度,它是最适合移动设备的viewport。设置理想化的窗口的网页不论何种分辨率的屏幕下,其用户不需要缩放和横向滚动条就能正常查看网站所有内容,保证网页的文字、图片等等其大小完美的呈现给用户。

一图胜千言,借用网上的几张图来说明具体的区别:

你必须要知道的移动端开发知识
你必须要知道的移动端开发知识
你必须要知道的移动端开发知识
你必须要知道的移动端开发知识

上面两幅图很好理解,下面两幅对比图,说明ideal viewport对于网站用户体验的重要性,用户不用缩放或者滚动就能达到极佳的体验效果。

用<code>&lt;meta name="viewport" content="xxx"&gt;</code> 标签来控制viewport大小首先是由苹果公司在其safari浏览器中引入的,目的就是解决移动设备的viewport问题。后来安卓以及各大浏览器厂商也都纷纷效仿,引入它对viewport的支持。

viewport是通过<code>meta</code>标签来控制页面的viewport大小,具体形式如下:

其中<code>width=device-width</code>顾名思义是设置viewport的宽为设备的宽,其还可以设置具体的逻辑像素值,如980。

meta标签的viewport相关配置content值有6个属性,它们可以同时使用,也可单独使用,还可以混合使用,具体如下:

width

设置<code>layout viewport</code>的宽度,为一正整数,也可为device-width

height

设置<code>layout viewport</code>的宽度,为一正整数,很少使用

initial-scale

设置页面的初始缩放值,为一数值,可带小数

minimum-scale

设置页面的最小缩放值,为一数值,可带小数

maximum-scale

设置页面的最大缩放值,为一数值,可带小数

user-scalable

页面是否允许缩放,值为"no"或"yes", no 不允许,yes允许

user-scalable=no禁止缩放在ios&gt;=10系统的safari下有兼容问题,具体可以看禁止页面缩放meta标签兼容性问题这部分

meta属性中initial-scale的缩放是相对于<code>ideal viewport</code>来进行的

这样通过<code>meta</code>标签很容易设置页面layout viewport为移动设备屏幕宽度(它也是ideal layout)即:

上面这种方式是最直接也是最轻易想到的设法,但是还可以使用initial-scale来达到同样的效果,即:

简单解释下,<code>initial-scale</code>表示页面初始缩放值,其缩放是相对于ideal viewport的来说的,为1表示不缩放,那么其layout viewport的宽度就是ideal viewport的宽度,也就是移动设备屏幕的宽度。

既然二者都可以设置layout viewport的宽度,那么二者同时设置且值不相等会怎样呢?答案是:

浏览器会以二者中值较大的那个为准。

可能读者会有新的疑惑,在设置layout viewport为屏幕宽度时,经常看到的是二者都写上,为什么呢?答案是:

一个是兼容性的考虑,另一方面解决某些设备横竖屏不分导致通通以ideal viewport的宽度为准的问题

上面提到,meta中的initial-scale是相对于ideal viewport进行缩放的,该属性的作用:

initial-scale用来确定visual viewport即浏览器可视区域宽度大小

阿里早期的iphone/ipad下的自适应布局解决方案<code>flexible</code>就是利用initial-scale来解决的。

有人可能会有疑问,移动端浏览器可视区域宽度不就是移动设备屏幕的宽度么?其实我们这里所说的可视区域宽度是逻辑意义上的宽度,而非实际真实的宽度,例如iphone4的320px屏幕宽度,initial-scale放大2倍,那么可视区域的逻辑大小变成了160px,可以通过查看页面html元素的宽度测试。

其实visual viewport与ideal viewport的关系如下:

在iphone/ipad下,在没有指定initial-scale的情况下,无论你怎么设置layout viewport宽度,它会根据上面的计算关系,自动计算当前页面的inital-scale值以保证layout viewport宽度在缩放后就是浏览器可视区域的的宽度,即inital-scale = ideal viewport宽度 / visual viewport宽度(等于layout viewport宽度)。

例如,iphone6情况下默认的layout viewport为980px,那么当前缩放值inital-scale=375 / 980。

需要说明一下的是:在设置了initial-scale的情况下,这个自动计算的值就不起作用了。

移动端设备不同,其屏幕大小也不尽相同,那么针对特定移动设备的页面设计ui怎么在不同移动设备上因设备不同而自适应屏幕展示呢。一般常见的解决方案有rem和vw/vh。下面就来说说。

<code>rem</code>是一个相对单位,相对于<code>&lt;html&gt;</code>的<code>font-size</code>来说的;那么参与页面布局的单位使用<code>rem</code>而不是px,这样我们只需控制不同设备下网页<code>&lt;html&gt;</code>的<code>font-size</code>即可做到页面的自适应。

可以像flexible一样将移动屏幕宽度100等份,每份为a,同时1rem认定为10a;例如750px的设计稿来说,这样的话:

实现代码如下:

另外,我们也可以基于特定的设计稿尺寸来计算其他移动设备下的font-size,例如基于750px的设计稿,我们假设其font-size为40px,那么其他设备下font-size的计算关系式:

\[750/40 = 设备屏幕宽/fontsize

\]

对应的核心转换代码即: <code>docEl.style.fontSize = (width / 750)*40 + 'px'</code>

首先要知道vw和vh的概念代表什么,它也是相对单位,相对于屏幕的宽高而言的。

跟rem类似,我们可以使用vw单位作为css的唯一单位,这样所有元素基于vw来布局;基于特定设计稿的尺寸来转换vw单位,我们使用stylus预编译函数来进行转换:

然后无论是文本还是布局高宽、间距等都使用 vw 作为 CSS 单位,如

单纯的vw适配在视口缩放时尤其是缩小时有些小瑕疵,因为vw是利用视口单位实现的布局,依赖视口的大小而自动缩放,也就失去了最大最小的宽度限制。一种比较好的解决方法是使用vw与rem配合来进行适配,即:

页面需要适配的元素使用rem为单位,而的font-size值是根据vw来设定的,但是该font-size值需要限制最大最小值。

具体的stylus代码如下,也可以参考这个demo猛戳

通过类似如下形式来实现适配:

该方式比较简单,成本低,但是代码量大,比较臃肿,维护不方便,不推荐该方式。

该方案随着<code>viewport单位</code> 得到众多浏览器的兼容支持已逐渐不推荐使用了,它主要是为了解决iphone系列适配问题;虽然官方已不推荐使用,但是其思想还是值得借鉴学习的,主要表现下面三个方面:

根据<code>dpr</code>的值来修改<code>&lt;meta&gt;</code>的<code>viewport</code>的值实现移动端<code>1px</code>的问题

根据<code>dpr</code>的值来修改<code>&lt;html&gt;</code>的<code>font-size</code>值,使用以<code>rem</code>为单位值来等比例缩放

使用hack手段用<code>rem</code>模拟<code>vw</code>特性

对应第一点,它通过hack手段来根据设备的<code>dpr</code>值相应改变<code>&lt;meta&gt;</code>标签中的<code>viewport</code>的值:

这样,iphone系统的不同设备下页面达到的效果是使css 1px像素与物理1px像素相同;然后,flexible使用rem作为布局单位实现适应布局。关键基本代码如下:

产生1px边框的问题其实归结三点:

1px的css逻辑像素不等于1px的物理像素

ios&lt;8以及Android&lt;=4.4以下的浏览器处理0.5px时会转化为0

对于1px边框问题的解决,<code>flexible</code>能完美的解决,思路见上面分析的;除此之外还有什么方式,其实网上有很多方法,但是还是列一下思路:

用border-image来实现

有关border-image的请猛戳border-image 的正确用法;需要使用一张图片来充当border,图片大小是6px X 6px,如下:

你必须要知道的移动端开发知识

缺点:改边框颜色时要修改图片,不灵活

用背景渐变来实现

设置1px的渐变背景,50%有颜色,50%透明

缺点:维护过多代码,圆角没法实现

用box-shadow模拟边框来实现

缺点:颜色不好处理,有阴影出现

用伪类+transform来实现

比较推荐的方法,原理是把原先元素的border去掉,然后利用<code>:before</code>或者<code>:after</code>重做border,并把<code>transform</code>的<code>scale</code>缩小一半,原先元素相对定位,伪元素模拟的border采用绝对定位。

Configuring the Viewport

H5移动多终端适配全解 - 从原理到方案

移动前端开发之viewport的深入理解

再聊移动端页面的适配

利用@media screen实现网页布局的自适应

利用视口单位实现适配布局

再谈Retina下1px的解决方案

Web 端屏幕适配方案

使用Flexible实现手淘H5页面的终端适配