等比缩放布局(rem布局)的实现
rem的定义,the font size of the root element,即以根节点的字体大小作为基准值进行长度计算。网页中的根元素指的是html我们通过设置html的字体大小就可以控制rem的大小。
视口(viewport)设置:<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
在html上根据不同分辨率设置不停font-size,通过js计算出来。
页面里除了font-size之外的其他css尺寸都使用了rem作为单位。
正文的font-size需要额外的媒介查询,并且不使用rem。
要搞懂移动端的适配,首先要高明白像素和视口。
其实存在两种像素:
1. 设备像素
屏幕的物理像素,任何设备屏幕的物理像素的数量都是固定不变的,单位是pt
。
2. CSS像素
在CSS、JS中使用的一个抽象的概念,单位是 px
。
顺便说下,CSS像素也可以称为设备独立像素(device-independent pixels),简称为
dips
,单位是dp
。
那么,我们现在再来说说一个元素 width:200px
。这个元素跨越了200个CSS像素,200个CSS像素相当于多少个设备像素取决于两个条件:
- 页面是否缩放
- 屏幕是否为高密度
先梳理一下手机硬件之间的关系,注意这里使用的都是物理像素。
以 iPhone5 为例,我们已知的是:
- 分辨率:
1136pt x 640pt
指屏幕上垂直有 1136 个物理像素,水平有 640 个物理像素 - 屏幕尺寸:
4英寸
注意英寸是长度单位,不是面积单位。4英寸指的是屏幕对角线的长度。 - 屏幕像素密度:
326dpi
屏幕像素密度(Pibel Per Inch)简称ppi
,单位是dpi
(dot per inch)。这里指屏幕水平或垂直每英寸有326个物理像素。原则上来说,ppi越高越好,因为图像会更加细腻清晰。
视口
桌面浏览器中,浏览器窗口就是约束你的CSS布局视口(又称初始包含块)。它是所有CSS百分比宽度推算的根源,它的作用是给CSS布局限制了一个最大宽度,视口的宽度和浏览器窗口宽度一致。
但是在移动端,情况就很复杂了。
布局视口
一个没有为移动端做优化的网页,会尽可能缩小网页让用户看到所有东西。
浏览器厂商为了让用户在小屏幕下网页也能够显示地很好,所以把视口宽度设置地很大,一般在 768px ~ 1024px 之间,最常见的宽度是 980px。
所以,在手机上,视口与移动端浏览器屏幕宽度不再相关联,是完全独立的,这个浏览器厂商定的视口被称为布局视口。
布局视口我们是看不见的,只知道网页的最大宽度是 980px
,并且被缩放在了屏幕内。
可以这样设置布局视口的宽度:<meta name="viewport" content="width=640">
媒体查询与布局视口
700px 指的是布局视口的宽度
@media (min-width: 700px){
...
}
document.documentElement.clientWidth/Height
返回布局视口的尺寸
视觉视口
视觉视口是用户正在看到的网页的区域,大小是屏幕中CSS像素的数量。
window.innerWidth/Height
返回视觉视口的尺寸
理想视口
布局视口明显对用户是不友好的,完全忽略了手机本身的尺寸。所以苹果引入了理想视口的概念,它是对设备来说最理想的布局视口尺寸。理想视口中的网页用户最理想的宽度,用户进入页面的时候不需要缩放。
现在讨论所谓的『最理想的宽度』到底是多少?其实,如果我们把布局视口的宽度改成屏幕的宽度不就不用缩放了么。可以这样设置告诉浏览器使用它的理想视口:
<meta name="viewport" content="width=device-width">
定义理想视口是浏览器的事情,并不能简单地认为是开发者定义的,开发者只能使用。
screen.width/height
返回理想视口的尺寸,有严重的兼容性问题---可能返回两种值:
- 理想视口的尺寸(下载浏览器)
- 屏幕的设备像素尺寸(内置浏览器)
缩放
缩放与设备像素、CSS像素的关系
缩放是在放大或缩小CSS像素,比如一个宽度为 200px 的元素放大,还是200个CSS像素。但是因为这些CSS像素被放大了,所以CSS像素也就跨越了更多的设备像素。缩小则相反。
缩放与视口
缩放会影响视觉视口的尺寸
页面被用户放大,视觉视口内CSS像素数量减少;被用户缩小,视觉视口内CSS像素数量增多就行了。这个道理应该是不难想的。
用户缩放不会影响布局视口
注意,这是『用户缩放』,后面会说开发者设置缩放的情况
缩放比例
我们在开发者工具中可以在这里查看缩放比例:
这里的 0.3 是相对于理想视口的。
在下载浏览器中,可以这么算(理想视口与视觉视口的比):
zoom level = screen.width / window.innerWidth
禁止缩放
<meta name="viewport" content="user-scalable=no">
设置缩放
<meta name="viewport" content="initial-scale=2">
使用initial-scale
有一个副作用:同时也会将布局视口的尺寸设置为缩放后的尺寸。所以initial-scale=1
与width=device-width
的效果是一样的。
完美视口
解决各种浏览器兼容问题的理想视口设置
<meta name="viewport" content="width=device-width,initial-scale=1">
设备像素比
在谈到像素的时候,讲到除了缩放,屏幕是否为高密度也会影响设备像素和CSS像素的关系。
在缩放程度为100%(这个条件很重要,因为缩放也会影响他们)时,他们的比例叫做设备像素比(device pixel ratio):
dpr = 设备像素 / CSS像素
可以通过JS得到: window.devicePixelRatio
设备像素比也和视口有关:
dpr = 屏幕横向设备像素 / 理想视口的宽
总结
这一篇介绍了移动端适配需要掌握的知识,先说明了移动端存在的两种像素,然后介绍了三种视口,由缩放对视口的影响引入理想视口,最后说明设备想告诉比。
之前做过PC页面的人聊的最多的就是『兼容』,这是因为浏览器之间的差异引起的,不再多说。而移动端是基本没有『兼容』的问题的,全是CSS3,简直不要太开心。可是『适配』问题随之而来。
什么是『适配』?做PC页面的时候,我们按照设计图的尺寸来就好,这个侧边栏200px,那个按钮50px的。可是,当我们开始做移动端页面的时候,设计师给了一份宽度为640px的设计图。那么,我们把这份设计图实现在各个手机上的过程就是『适配』。
那么,我们怎么开始呢?目前有三种方法:
- 固定高度,宽度自适应
- 固定宽度,viewport缩放
- rem做宽度,viewport缩放
这三种方法的核心都是视口的确定,现在以实现这个设计图为例说明。
固定高度,宽度自适应
这也是目前使用最多的方法,垂直方向用定值,水平方向用百分比、定值、flex都行。腾讯、京东、百度、天猫、亚马逊的首页都是使用的这种方法。
随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用_响应式布局_调调就行(比如网易新闻),这样就实现了『适配』。
原理
这种方法使用了完美视口:
<meta name="viewport" content="width=device-width,initial-scale=1">
这样设置之后,我们就可以不用管手机屏幕的尺寸进行开发了。
固定宽度,viewport缩放
设计图、页面宽度、viewport width使用一个宽度,浏览器帮我们完成缩放。单位使用px即可。
目前已知荔枝FM、网易新闻在使用这种方法。有兴趣的同学可以看看是怎么做的。
原理
这种方法需要根据屏幕宽度来动态生成viewport
,生成的 viewport 基本是这样:
<meta name="viewport" content="width=640,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
640 是我们根据设计图定下的,0.5 是根据屏幕宽度动态生成的。
生成的viewport告诉浏览器网页的布局视口使用 640px,然后把页面缩放成50%,这是绝对的等比例缩放。图片、文字等等所有元素都被缩放在手机屏幕中。
这个gif图说明了一切:
rem做宽度,viewport缩放
这也是淘宝使用的方案,根据屏幕宽度设定 rem
值,需要适配的元素都使用 rem
为单位,不需要适配的元素还是使用 px
为单位。
具体使用方法见使用Flexible实现手淘H5页面的终端适配
上文提供了sass和postcss的px2rem
转换方法,我这里给出less的px2rem
。因为less不支持函数,所以需要安装插件 less-plugin-functions ,然后就简单了:
.function{
.px2rem(@px,@base:72px){
return: @px / @base * 1rem;
}
}
这样使用:
div{
width: px2rem(100px);
}
使用这个方法的库:
原理
实际上做了这几件事情:
- 动态生成 viewport
- 屏幕宽度设置
rem
的大小,即给<html>
设置font-size
- 根据设备像素比(window.devicePixelRatio)给
<html>
设置data-dpr
这么设置的好处是可以让不同设备的rem
或px
都显示一样的长度。
设置rem
设置rem的意义在于得到一个与屏幕宽度相关的单位,本来vw
是最合适的,但是因为兼容性的问题,只能使用rem
来做。这样,让不同设备的rem
显示一样的长度。
vw是CSS3引入的单位,1vw = 1%窗口宽度
上面的布局我们可以这样:
html{
font-size: 屏幕宽度 / 10;
}
.btn{
width:8.75rem;
height:1.25rem;
}
这样,无论屏幕宽度是多少,.btn
都是相对于屏幕的这么宽,做到了适配。
设置 viewport 缩放 和 data-dpr
这两个设置其实是干的一件事,就是适配高密度屏幕手机的px
单位。
.a{
font-size:12px;
}
[data-dpr="2"] .a{
font-size: 24px;
}
[data-dpr="3"] .a{
font-size: 36px;
}
而缩放是动态的,这样,不同设备下的px
显示一样的长度。
之前说过CSS像素和物理像素与缩放、dpr都有关系,这里说明:
在普通手机上,
.a
字体设置为12px;在dpr是2的手机上,
[data-dpr="2"] .a
字体为24px,又因为页面缩放50%,字体为还是12px
总结
坦白说,我不觉得第一种方案能就做『适配』方案,因为太笨了,只能做一些列表等简单排列的样式