移动端适配

移动端web开发相对于PC端web开发,我们可以庆幸不用兼容那么多浏览器了,但是随之而来的却是各种屏幕尺寸的适配,个人觉得,比PC端还要费精力。在使用了腾讯优测进行软件测试后,问题得到了有效解决。

1.移动端布局方式

1.1响应式布局

简而言之,就是页面元素的位置随着屏幕尺寸的变化而变化,通常会用百分比来定位,而在设计上需要预留一些可被“压缩”的空间。

image

如上图,其实就相当于页面被压矮了。

1.2Cover布局

就跟background-size的cover属性一样,保持页面的宽高比,取宽或高之中的较小者占满屏幕,超出的内容会被隐藏。此布局适用于主要内容集中在中部,边沿无重要内容的设计。

image

如上图,第一张是原设计稿,第二张把左右隐藏掉了一部分,第三张则是把上下隐藏掉了一部分。

1.3Contain布局

同样,也跟background-size的contain属性那样,保持页面的宽高比,取宽或高之中的较大者占满屏幕,不足的部分会用背景填充。个人比较推荐用这种方式,但在设计上需要背景为单色,或者是可平铺的背景。

image

如上图,红框部分为原始宽高比,根据不同屏幕尺寸进行缩放,并加背景填充。

2.常用的实现方法

2.1样式缩放

最省事的适配方法,直接用px为单位按视觉进行开发,然后通过计算屏幕与网页的宽高比,用transform:scale来对网页进行全局缩放。

不过此方法会有一个小问题,就是如果网页内有动画的话,缩放后会稍微降低页面性能,在低配的安卓机器上表现的比较明显,iOS上没发现有性能问题。

2.2Rem缩放

Rem是个好东西呀,谁用谁知道,这里就不多做解释了。原理跟上面的样式缩放相通,只不过是通过Rem为单位来进行视觉开发,然后通过计算后改变html的front-size来对页面进行缩放。

关于以Rem为单位进行开发,目前比较流行Font-size=62.5%,而后1rem=10px的这种方法,有试过直接换成px也是可以的,就看个人的计算习惯吧。

3.Rem缩放

  • rem的意思(根元素的font-size值)
  • viewport
  • DPR(device pixel ratio)
  • 动态rem

    3.1 标签中的viewport

    简单来讲,viewport就是浏览器上,用来显示网页的那一部分区域了,也就是说,浏览器的实际宽度,是和我们手机的宽度不一样的,无论你的手机 宽度是320px,还是640px,在手机浏览器内部的宽度,始终会是浏览器本身的viewport。

对viewport的控制:

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

3.2 关于我们的设备

三个概念:

  • PPI: 可以理解为屏幕的显示密度
  • DPR: 设备物理像素和逻辑像素的对应关系,即物理像素/逻辑像素
  • Resolution: 就是我们常说的分辨率

物理像素与逻辑像素(DPR):

设备物理像素:

通俗的讲设备屏幕有多少个可以闪烁的点 是一个具体的概念 比如iphone6横向就有750个可以改变颜色的点 类似与电视机 如果家里有10年前买的大头电视,你趴在屏幕前仔细看能看到一个个RGB的点 这就是设备的物理像素

设备独立像素

设备独立像素是一个虚拟的概念,如程序中的css 比如我们将一个div宽度设置为10像素 那么在pc上系统会将这个div显示在屏幕的10个点上

以iphone6为例,在不做任何缩放的条件下,iphone6的获取到的’width-device’为375px,为屏幕的逻辑像素。而购买时我们所知的750px,则为屏幕的物理像素。

CSS的问题:

以iphone6为例,我们可以知道,其实我们所写的1px,在iphone6上为2px的物理像素。所以,最后的,给出一个结论。就是我们写的1px,在移动端,是逻辑像素的1px,而非物理像素的1px。

3.3 rem布局

3.3.1简介rem

如今市面上移动设备的分辨率大小不同,常用的px单位不再准确。为此,CSS3出了一个新单位——rem,rem是移动端神器,它完美解决了分辨率的适配问题

rem就是相对于根元素的font-size来做计算

1
2
3
4
5
6
7
8
html{
font-size:10px;
}
.box{
width:10rem;
height:10rem;
font-size:1.2rem;
}

一个宽高各100px的box就出现了,有些像我们以前常用的em,不过rem是相对于根元素()的字体大小,em相对 于父元素的字体大小。

设计稿的像素/html的font-size=用来代替px的rem

3.3.2屏幕适配

虽然很简单,但是移动设备那么多,我们又怎么根据手机屏幕的分辨率不同,去设置的字体大小呢?

  • 通过CSS媒体查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
html{
font-size:20px;
}
@media only screen and (min-width:320px){
html{
font-size:10px;
}
}
@media only screen and (min-width:375px){
html{
font-size:16px;
}
}
@media only screen and (min-width:414px){
html{
font-size:20px;
}
}

通过媒体查询的方式,只需要把常用的屏幕宽度考虑进去即可,能够满足大部分应用场景,不过这一做法不够严谨

  • 通过js计算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
*代码如下
*其中的参数1080根据自己的实际情况进行修改,这里的1080代表设计页面的原始宽度,可以参考psd的标准宽度,这是后字体使用rem也有了标准,psd上的字号如:40点 对应css中的rem的换算方式为40/100=0.4rem。
*/
(function (doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize =Math.floor(100*(clientWidth / 1080))+ 'px';
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document,window);

通过js设备的屏幕分辨率,可以计算出相应的字体的大小,这个方法可以适配所有屏幕的大小,这下就完美许多了。

不过有些时候会很麻烦,因为rem会涉及到换算的问题,比如70px的宽,根目录字体是12px,那换算公式为:70/12 = 5.83333333~,每次写一个单位都要用计算器去算,这工作可以让Less或者Sass等预处理器去完成。

3.3.3DPR的问题

1px会出现什么问题?

我们的设备,是有物理像素和逻辑像素的。而假设我们的设计稿是750的,同时还是以iphone6为例,此时如果我们的viewport是这样的

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

之前说过,在不做任何缩放的条件下,iphone6获取到的viewport为375px。

然后我们的页面中有个div,他有一个边框值,如下

1
2
3
4
5
div{
height: 5rem;
widht:5rem;
border: 1px solid #000
}

此时我们写的1px,实际上是逻辑像素,而我们在iphone6上看到的是物理像素,于是这个时候,我们眼睛所看到的其实是2px(参考第二点第三个问题3.2)

所以此时我们需要在viewport上做文章了,此时先明确,如果要获取到真正的1px,那么我们需要这么做,将viewport改为

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

即对屏幕做0.5倍的缩放。这样,我们就能得到实际的1px。

我们还要明确一点,viewport的meta标签,我们这里也只能通过js来动态生成。

3.3.4文字适配问题

对于一些标题性的文字,我们依然可以用rem。让他随着屏幕来进行缩放,因为标题性文字一般较大,而较大的文字,点阵对其影响就越小。这样,即使出现奇怪的尺寸,也能够让字体得到很好的渲染。

对于一些正文内容的文字(即站在使用者的角度,你不希望他进行缩放的文字)。我们采用px来进行处理。

3.4 手淘的解决方案

3.4.1 rem布局(对比3.2.2JS)

用js获取到页面的宽度,然后对其进行宽度/10的处理,再将其写到html的font-size中。手淘的flexible.js里面的这一部分,并为了方便看懂做了些改写。大体就是这样的:

1
2
3
4
5
6
7
function refreshRem(){
var docEl = window.document.documentElement;
var width = docEl.documentElement.getBoundingClientRect().width;
var rootSize = width/10;
docEl.style.fontSize = rootSize + 'px';
}

3.4.2 dpr的配置

3.4.3 文字的解决方案

在html上,加入了一个自定义属性,data-dpr。

1
<html data-dpr='dpr'></html>

假如设计稿上某a标签是32px,那么

1
2
3
4
5
6
7
8
9
10
11
a{
font-size: 16px
}
/*iphone6*/
[data-dpr='2'] a{
font-size: 32px
}
/*iphone6plus*/
[data-dpr='3'] a{
font-size: 32px
}

3.5 ==另一个解决方案==

通过rem,viewport,以及dpr我们就可以完成我们的终极适配了,告别死板写法 不再这样写死 我们知道了设备的dpr就可以明确的知道缩放多少,而且这样还解决了很难解决的1px横线的问题
我们需要这样一段js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(function (doc, win) {
console.log("dpr:"+win.devicePixelRatio);
var docEle = doc.documentElement,
isIos = navigator.userAgent.match(/iphone|ipod|ipad/gi),
dpr=Math.min(win.devicePixelRatio, 3);
scale = 1 / dpr,
resizeEvent = 'orientationchange' in window ? 'orientationchange' : 'resize';
docEle.dataset.dpr = dpr;
var metaEle = doc.createElement('meta');
metaEle.name = 'viewport';
metaEle.content = 'initial-scale=' + scale + ',maximum-scale=' + scale;
docEle.firstElementChild.appendChild(metaEle);
var recalCulate = function {
var width = docEle.clientWidth;
if (width / dpr > 640) {
width = 640 * dpr;
}
docEle.style.fontSize = 20 * (width / 750) + 'px';
};
recalCulate
if (!doc.addEventListener) return;
win.addEventListener(resizeEvent, recalCulate, false);
})(document, window);
  • 获取设备dpr
  • 算出缩放比例 scale = 1/dpr
  • 创建meta以及属性
  • 将scale值赋给initial-scale,maximum-scale
  • meta插入到文档中
  • 创建屏幕大小改变重新计算函数并监听

3.5 个人总结上面知识点

  • 了解rem,viewport,以及dpr
  • 获取DPR,得到缩放scale = 1/dpr,并挂到meta
  • 设置rem:docEle.style.fontSize

参考链接