移动端布局
媒介查询
html {
font-size: 10px;
}
@media screen and (min-width: 321px) and (max-width: 375px) {
html {
font-size: 11px;
}
}
@media screen and (min-width: 376px) and (max-width: 414px) {
html {
font-size: 12px;
}
}
@media screen and (min-width: 415px) and (max-width: 639px) {
html {
font-size: 15px;
}
}
@media screen and (min-width: 640px) and (max-width: 719px) {
html {
font-size: 20px;
}
}
@media screen and (min-width: 720px) and (max-width: 749px) {
html {
font-size: 22.5px;
}
}
@media screen and (min-width: 750px) and (max-width: 799px) {
html {
font-size: 23.5px;
}
}
@media screen and (min-width: 800px) {
html {
font-size: 25px;
}
}
- 1).item 类在所有设备下的 width 都是 3.4rem,但在不同分辨率下的实际像素是不一样的,所以在有些分辨率下,width 的界面效果不一定合适,有可能太宽,有可能太窄,这时候就要对 width 进行调整,那么就需要针对.item 写媒介查询的代码,为该分辨率重新设计一个 rem 值。然而,这里有 7 种媒介查询的情况,css 又有很多跟尺寸相关的属性,哪个属性在哪个分辨率范围不合适都是不定的,最后会导致要写很多的媒介查询才能适配所有设备,而且在写的时候 rem 都得根据某个分辨率 html 的 font-size 去算,这个计算可不见得每次都那么容易,比如 40px / 23.5px,这个 rem 值口算不出来吧!由此可见这其中的麻烦有多少。
- (2)以上代码中给出的 7 个范围下的 font-size 不一定是合适的,这 7 个范围也不一定合适,实际有可能不需要这么多,所以找出这些个范围,以及每个范围最合适的 font-size 也很麻烦
- (3)设计稿都是以分辨率来标明尺寸的,前端在根据设计稿里各个元素的像素尺寸转换为 rem 时,该以哪个 font-size 为准呢?这需要去写才能知道
名词
屏幕尺寸:屏幕对角线的长度
屏幕像素密度:屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。
屏幕分辨率:横纵向上物理像素的个数(物理像素)
物理像素(physical pixel)或设备像素(device pixel):物理像素又被称为设备像素,它是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度透明度,通过控制每个像素点的颜色,使屏幕显示出不同的图像,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了,单位 pt。
设备独立像素(density-independent pixel):设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说 CSS 像素),然后由相关系统转换为物理像素。
css 像素或者逻辑像素或者设备无关像素(device-independent pixel):CSS 像素又称为逻辑像素或者与设备无关的像素(device-independent pixel),简称 DIPs,是 web 开发者使用的最小单位,也就是我们经常写的 width=多少 px 中的 px
设备像素比(device pixel ratio):设备像素比 = 物理像素 / 设备独立像素
分辨率又分为【物理分辨率】和【逻辑分辨率】,值得注意的是实际工作中设计师常常给的是物理分辨率,程序中用到的是逻辑分辨率,但是都称为分辨率,容易混淆。 【物理分辨率】是硬件所支持的分辨率,【逻辑分辨率】是软件可以达到的分辨率。 【像素倍率 dpr】物理分辨率和逻辑分辨率的商,即常说的几倍屏。
位图像素
一个位图像素是栅格图像(如:png, jpg, gif 等)最小的数据单元。每一个位图像素都包含着一些自身的显示信息(如:显示位置,颜色值,透明度等)。
理论上,1 个位图像素对应于 1 个物理像素,图片才能得到完美清晰的展示
如上图:对于 dpr=2 的 retina 屏幕而言,1 个位图像素对应于 4 个物理像素,由于单个位图像素不可以再进一步分割,所以只能就近取色,从而导致图片模糊(注意上述的几个颜色值)。
所以,对于图片高清问题,比较好的方案就是两倍图片
(@2x)。
如:200×300(css pixel)img 标签,就需要提供 400×600 的图片
关于设计稿为什么要使用二倍图、三倍图
理论上一个位图像素对应一个物理像素,图片才能完美显示!设计稿是按 px 单位设计的,为了应对高分辨率显示屏(设备像素比 dpi = 2 或者 3 等)的高像素密度==>同等 px 大小拥有 dpi 倍的物理像素点,我们将设计稿增大 dpi 倍,一般是 2 被或者 3 倍,这样设计稿缩放到屏幕时的分辨率就和屏幕本身的分辨率一致了(实际中设计稿总像素数要大于或者等于屏幕分辨率就可以),图片就可以完美显示了,
上图中, Retina 为高清设备屏幕,它的一个 css 像素对应 了 4 个物理像素
在 Javascript 中,可以通过 window.devicePixelRatio
获取到当前设备的 dpr。
在 css 中,可以通过 -webkit-device-pixel-ratio
,-webkit-min-device-pixel-ratio
和 -webkit-max-device-pixel-ratio
进行媒体查询,对不同 dpr 的设备,做一些样式适配。
或者使用 resolution | min-resolution | max-resolution 这些比较新的标准方式
缩放比 scale
缩放比:scale = 1/dpr
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
整个网页在设备内显示时的页面宽度就会等于设备逻辑像素大小,也就是 device-width。这个 device-width 的计算公式为:设备的物理分辨率/(devicePixelRatio * scale),在 scale 为 1 的情况下,device-width = 设备的物理分辨率/devicePixelRatio 。这就是 initial-scale 的意义
视窗 viewport
简单的理解,viewport 是严格等于浏览器的窗口。在桌面浏览器中,viewport 就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。
移动端的 viewport 太窄,为了能更好为 CSS 布局服务,所以提供了两个 viewport:虚拟的 visualviewport 和布局的 layoutviewport。
viewport 的内容比较深,推荐阅读PPK 写的文章,以及中文翻译
视窗缩放 viewport scale
在开发移动端页面,我们可以设置meta
标签的 viewport scale 来对视窗的大小进行缩放定义
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
rem
rem 原理
等比缩放
rem 单位
rem
就是相对于根元素<html>
的font-size
来做计算
网易
设备屏幕尺寸为逻辑像素,即:document.documentElement.clientWidth
100?
为了方便计算
1rem=(设备屏幕尺寸/设计稿尺寸)*100
那么设计稿上的尺寸,除以 100 就行了
问题:
- 1).item 类在所有设备下的 width 都是 3.4rem,但在不同分辨率下的实际像素是不一样的,所以在有些分辨率下,width 的界面效果不一定合适,有可能太宽,有可能太窄,这时候就要对 width 进行调整,那么就需要针对.item 写媒介查询的代码,为该分辨率重新设计一个 rem 值。然而,这里有 7 种媒介查询的情况,css 又有很多跟尺寸相关的属性,哪个属性在哪个分辨率范围不合适都是不定的,最后会导致要写很多的媒介查询才能适配所有设备,而且在写的时候 rem 都得根据某个分辨率 html 的 font-size 去算,这个计算可不见得每次都那么容易,比如 40px / 23.5px,这个 rem 值口算不出来吧!由此可见这其中的麻烦有多少。
- (2)以上代码中给出的 7 个范围下的 font-size 不一定是合适的,这 7 个范围也不一定合适,实际有可能不需要这么多,所以找出这些个范围,以及每个范围最合适的 font-size 也很麻烦
- (3)设计稿都是以分辨率来标明尺寸的,前端在根据设计稿里各个元素的像素尺寸转换为 rem 时,该以哪个 font-size 为准呢?这需要去写才能知道
example
iphone6 的分辨率写着375*667
,指的是逻辑分辨率;750*1334
则是它的物理分辨率,dpr=2。
设备逻辑像素 device-width = 设备物理像素 /(devicePixelRatio scale) 设备物理像素: iphone6 = 750px 设备逻辑像素: iphone6 = 750/(2 1) = 375px document.documentElement.clientWidth === 设备逻辑像素 body-width(rem 为单位) = 设计稿宽度/100 = 640 / 100 = 6.4 rem 【取 100,主要为了容易计算】 html font-size(px 为单位) = device-width / body-width = 320 / 6.4 = 50 px
document.documentElement.style.fontSize =
document.documentElement.clientWidth / 6.4 + 'px'
如果设计稿基于iphone6,横向分辨率为750,body的width为750 / 100 = 7.5rem
如果设计稿基于iphone4/5,横向分辨率为640,body的width为640 / 100 = 6.4rem
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1, minimum-scale=1"
/>
当 deviceWidth 大于设计稿的横向分辨率时,html 的 font-size 始终等于横向分辨率/body 元素宽
var deviceWidth = document.documentElement.clientWidth;
if(deviceWidth > 640) deviceWidth = 640;
document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';
淘宝
device-width = 设备的物理分辨率/devicePixelRatio/scale
var scale = 1 / devicePixelRatio
document
.querySelector('meta[name="viewport"]')
.setAttribute(
'content',
'initial-scale=' +
scale +
', maximum-scale=' +
scale +
', minimum-scale=' +
scale +
', user-scalable=no'
)
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
布局的时候,各元素的 css 尺寸=设计稿标注尺寸/设计稿横向分辨率/10
解析
假设 IPhone6,dpr=2,逻辑像素为 375px,实际屋里像素为 750px;设计稿为 750px,设计稿上有一个 150px 的元素
此时 document.documentElement.clientWidth=375,
设置 scale 后,scale = 1 / devicePixelRatio=0.5,
此时 document.documentElement.clientWidth=750,
页面实际会两倍缩放。但页面宽度为 750,那么此时设计稿的宽度=设备的宽度了。页面上元素的宽度,也就是设计稿上的宽度。只不过我们需要将 px 换成 rem.
我们先假设 1rem=750px。即根元素的 font-size 为 750px,那么设计稿宽 750px,为 1rem,设计稿上 150px 的元素应该为多少 rem 呢?
我们可以求得。150px 就应该对应 0.2rem。
针对 750 设计稿我们就得到一个公式
由此方法,我就可以算出 750px 设计稿上,多有元素尺寸 px 应该是多少 rem 了。
设备像素大小是不能改变的,但设计稿的大小是可以改变的,如果设计稿不是 750px,而是 1000px,或者 640px 呢,以 1000px 设计稿为例,如何 1000px 设计稿 放到 750px 的屏幕上?
不同尺寸的设计稿肯定是等比例放大或缩小的。
即设计稿宽度从 750 到 1000 放大了多少,那么 750 设计稿上 150 的元素,到 1000 设计稿上就应该放大多少,得到以下公式
这里把 1000 的设计稿变为 750 的设计稿,也就是当我知道了 1000 设计稿元素尺寸,我要知道它在 750 设计稿上的尺寸是多少。即
我们前面已经推出了 750 设计稿 rem 的计算公式,
由此我们也就得到了一个不管多大设计稿,求 rem 的通用公式
10?
10 可以是 5,可以是 20,10 只是一个系数,便于算出来的值不会太大,也不会太小,
计算麻烦?
借助 css 处理器
//定义一个变量和一个mixin
@baseFontSize: 75; //基于视觉稿横屏尺寸/10得出的基准font-size
.px2rem(@name, @px) {
@{name}: @px / @baseFontSize * 1rem;
}
//使用示例:
.container {
.px2rem(height, 240);
}
//less翻译结果:
.container {
height: 3.2rem;
}
比较
共同点:
- 都能适配所有的手机设备,对于 pad,网易与淘宝都会跳转到 pc 页面,不再使用触屏版的页面
- 都需要动态设置 html 的 font-size
- 布局时各元素的尺寸值都是根据设计稿标注的尺寸计算出来,由于 html 的 font-size 是动态调整的,所以能够做到不同分辨率下页面布局呈现等比变化
- 容器元素的 font-size 都不用 rem,需要额外地对 font-size 做媒介查询
- 都能应用于尺寸不同的设计稿,只要按以上总结的方法去用就可以了
不同点
- 淘宝的设计稿是基于 750 的横向分辨率,网易的设计稿是基于 640 的横向分辨率,还要强调的是,虽然设计稿不同,但是最终的结果是一致的,设计稿的尺寸一个公司设计人员的工作标准,每个公司不一样而已
- 淘宝还需要动态设置 viewport 的 scale,网易不用
VM
window.innerWidth/window.innerHeight
- vw : 1vw 等于视窗宽度的 1%
- vh : 1vh 等于视窗高度的 1%
- vmin : 选取 vw 和 vh 中最小的那个
- vmax : 选取 vw 和 vh 中最大的那个
目前出视觉设计稿,我们都是使用750px
宽度的,从上面的原理来看,那么100vw = 750px
,即1vw = 7.5px
width: 369px;就应该为 width: 49.2vw;
- 使用
vw
来实现页面的适配,并且通过 PostCSS 的插件postcss-px-to-viewport把px
转换成vw
。这样的好处是,我们在撸码的时候,不需要进行任何的计算,你只需要根据设计图写px
单位 - 为了更好的实现长宽比,特别是针对于
img
、vedio
和iframe
元素,通过 PostCSS 插件postcss-aspect-ratio-mini来实现,在实际使用中,只需要把对应的宽和高写进去即可 - 为了解决
1px
的问题,使用 PostCSS 插件postcss-write-svg,自动生成border-image
或者background-image
的图片
不足:
比如当容器使用
vw
单位,margin
采用px
单位时,很容易造成整体宽度超过100vw
,从而影响布局效果。对于类似这样的现象,我们可以采用相关的技术进行规避。比如将margin
换成padding
,并且配合box-sizing
。只不过这不是最佳方案,随着将来浏览器或者应用自身的 Webview 对calc()
函数的支持之后,碰到vw
和px
混合使用的时候,可以结合calc()
函数一起使用,这样就可以完美的解决。他除了在手机端上有较好的浏览效果之外,其他宽屏设备会占满全屏幕,浏览起来就觉得很大,, 使用 clamp()
而且 vw 还不能像 rem 那种方案,让其在 PC 端(宽屏)之下水平居中 ????
另外一点,
px
转换成vw
单位,多少还会存在一定的像素差,毕竟很多时候无法完全整除