【CSS】 浅析rem布局方案
一些像素概念
物理像素:即实际的每一个物理像素,也就是移动设备上每一个物理显示单元(点) 设备逻辑像素( css
中的px
):可以理解为一个虚拟的相对的显示块,与物理像素有着一定的比例关系,也就是下面的设备像素比设备像素比( dpr
):= 物理像素 / 设备独立像素(px
)
如果
dpr
为1
的话,那么1px = 1物理像素
,x
轴y
轴加起来就是1
如果
dpr
为2
的话,那么1px = 2
物理像素,x
轴y
轴加起来就是4
以此类推
在js中可以通过
window.devicePixelRatio
获取当前设备的dpr
。
这里说明一下,无论dpr
多大,1px
的大小通常来说是一致的,这也就意味着,随着dpr
的增大,物理像素点会越来越小,这样才能容纳更多的物理像素,才能更高清,更retina
说完基本概念,来说一下几个问题:
retina屏图片模糊
首先普及一下位图像素:一个位图像素是图片的最小数据单元,每一个单元都包含具体的显示信息(色彩,透明度,位置等等)
那为什么在dpr高的retina屏上反而会模糊呢?看图~
在
1dpr
的屏幕上,位图像素和物理像素一一对应没什么问题,但是在retina
屏上,由于一个px
由4
个甚至更多的物理像素组成,并且单个位图像素不能进一步分割,所以会出现就近取色的情况,如果取色不均,那么就会导致图片模糊。
对于这种情况,只能采用
@2x
、@3x
这样的倍图来适配高清展示,这样侧向说明了为什么照着iphone6
做的ui
稿不是375
,而是750
的问题。
虽然这样在dpr
为1
的屏幕上会导致1
个物理像素上有4
个位图像素,但是这种情况的取色算法更优,影响不大,不做讨论。
1px的粗细问题
由于
1px
的实际大小是一样的,只是里面的物理像素数量不同,所以如果直接写1px
是没问题的,不会出现粗细不同的情况,但是这样一来retina
的优势也rem
的作用也就没了,其实还是dpr
的问题,dpr
为1
,那么1px
就是一个物理像素,但是在retina
中。1px
实际可能有4
、9
个物理像素,ui
想要的其实是1
个物理像素,而不是1px,不过由于不是素所有的手机都能适配0.x
,所以曲线救国,采用scale
缩放或者设置meta
都可以
viewport
三个概念
layout viewport
visual viewport
ideal viewport
layout viewport
最开始,
pc
上的页面是无法再移动端正常显示的,因为屏幕太小,会挤作一团,所以就有了viewport
的概念,又称布局视口(虚拟视口),这个视口大小接近于pc
,大部分都是980px
visual viewport
有了布局视口,还缺一个承载它的真是视口,也就是移动设备的可视区域-视觉视口(物理视口),这个尺寸随着设备的不同也有不同。这样在视觉视口中创建了一个布局视口,类似
overscroll:scroll;
这样,可以通过滚动拖拽、缩放扩大进行较好的访问体验
ideal viewport
像上面的体验在早些年可能比较多,但是近几年几乎很少了,还是归咎于用户体验,所以,我们还需要一个视口-理想视口(同样是虚拟视口),不过这个理想视口的大小是等于布局视口的,这样用户就能得到更好的浏览体验。
一个特性
viewport
有六种可以设置的常用属性:
width
:定义layout viewport
的宽度,如果不设置,大部分情况下默认是980
height
:非常用initial-scale
:可以以某个比例将页面缩放\放大,你也可以用它来设置ideal viewport
:
<meta name='viewport' content='initial-scale=1' />
maximum-scale
:限制最大放大比例minimum-scale
:限制最小缩小比例user-scalable
:是否允许用户放大\缩小页面,默认为yes
rem适配方案
先说原理,通过
meta
修正1px
对应的物理像素数量,在根据统一的设计稿来生成html
上的动态font-size
,根据dpr
构造字体等误差较大的样式的mixin
// 第一版:
function initRem() {
const meta = document.querySelector('meta[name="viewport"]');;
const html = document.documentElement;
const cliW = html.clientWidth;
const dpr = window.devicePixelRatio || 1;
meta.setAttribute('name', 'viewport');
meta.setAttribute(
'content',
`width=${cliW * dpr}, initial-scale=${1 /
dpr} ,maximum-scale=${1 / dpr}, minimum-scale=${1 /
dpr},user-scalable=no`
);
html.setAttribute('data-dpr', dpr);
// 这样计算的好处是,你可以直接用ui的px/100得到的就是rem大小,方便快捷,无需mixin
html.style.fontSize = 10 / 75 * cliW * dpr + 'px';
}
initRem();
window.onresize = window.onorientationchange = initRem();
对于引入的第三方ui组件,需要使用px2rem转换工具去做整体转换,比如
postcss-pxtorem
:https://github.com/cuth/postcss-pxtorem
最后
欢迎加我微信(winty230),拉你进技术群,长期交流学习...
欢迎关注「前端Q」,认真学前端,做个专业的技术人...