此文章引子这里,有兴趣的欢迎去查看更详细的原文。
关于 Retina Display (视网膜屏幕)
需求的产生
每个东西的产生都可能有其需求,视网膜屏的产生,也是在移动设备发展壮大的过程中产生的。
最初的开始
最初的移动设置,可能屏幕多大,分辨率就由多大;如 375x480 的分辨率,即下方的白色手机,在其上的网页图片都是正常显示的。但是当分辨率提升到 640x940,即黑色手机时,理论上来讲,在白色手机上正常显示的页面,就会被放缩到原来的 1/2,因为黑色手机的分辨率提高了一倍。
这时就会产生一个问题,当分辨率再次提高的时候,是不是这个页面就会被无限缩小,显然如果按照这种模式,移动端页面的显示将是一种灾难。
诞生
Retina Display (视网膜屏幕) 最早是由乔布斯在 iphone4 发布时提出的,它解决的就是上述问题,当分辨率变化时,页面应该怎么显示的问题。
在 iphone4 上 2x2 个像素当 1 个像素使用。这样子,元素就会显示的更加清晰,但是大小却保持不变,按照这种思路,如果上述黑色手机采用了这种技术,显示的应该是如下效果:
这时,就需要一个统一的单位,去告诉在不同分辨率的手机显示元素像素的大小。这个单位就是设备独立像素(Device Independent Pixels),简称 DIP 或 DP。至此,在不同分辨率的设备上,有了统一的显示。比如:设计图上 300px 的宽度,在设备上显示的就是 300px 的设备独立像素。
在开发时,浏览器给出的设备大小,指的也是设备独立像素。
转换关系
设备像素比: 指的是 设备物理像素/设备独立像素,简称 dpr。
从上述的计算规则来看,如果设备的 dpr = 1,则此时的 1px 表示的就是 1px 的物理像素,此时是设备像素和物理像素是完全对应的。当 dpr > 1 就会出现 多个物理像素对应 一个设备的现象。
WEB 开发
在开发 h5 页面时,只有当用户的缩放比为 100% 时,1px的css像素 才等于 1px的设备独立像素,这点要明确。因为如果用户进行了放缩,会导致 cssx像素的缩放,此时,两者就不是完全1对1的关系。 下面给出缩放比、css像素、设备独立像素的计算关系:
页面缩放比 = css像素/设备独立像素
可能存在的误解
Retina Display (视网膜屏幕) 是苹果提出的一种技术术语,但是这不代表 dpr>1的屏幕就是 Retina Display (视网膜屏幕)。这样子泛泛的理解会有失公允。
Retina Display (视网膜屏幕) 描述如下
在普通的使用距离下,人的肉眼无法分辨单个的像素点。 这里可以明显看到,是当你普通的使用距离下,不能明显的看到单个像素点的时候。所以有些大屏,如果你离得很近,仍然可以看到单个的像素点,这里你不能说它不是
Retina Display(视网膜屏幕),只能说是在用户满足了某些观看条件的时候,它才是Retina Display(视网膜屏幕)。所以,他只是一种视觉效果,而非绝对意义上的,它是或者不是。
引出的开发问题
最经典的要数 1px 边框。
这个问题产生是由于 dpr>1 的屏幕上,有些时候 1px 设备独立像素边框看起来会变粗。这是因为这个边框实际上是使用了多个设备物理像素渲染的结果。
解决
1. border-image
基于media查询判断不同的设备像素比给定不同的border-image:
border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
border-bottom: none;
border-width: 0 0 1px 0;
border-image: url(../img/1pxline.png) 0 0 2 0 stretch;
}
}
这种方案你需要实现准备一张 1px 边框的图片。
2. background-image
这种方法和 border-image 有些四类,但是需要准备一张符合条件的背景图,来模拟。
border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
background: url(../img/1pxline.png) repeat-x left bottom;
background-size: 100% 1px;
}
}
3. 伪类 + transform
基于media查询判断不同的设备像素比对线条进行缩放:
border_1px:before{
content: '';
position: absolute;
top: 0;
height: 1px;
width: 100%;
background-color: #000;
transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px:before{
transform: scaleY(0.5);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.border_1px:before{
transform: scaleY(0.33);
}
这种方式可以满足各种场景,如果需要满足圆角,只需要给伪类也加上border-radius即可。
4. svg
上面我们border-image和background-image都可以模拟1px边框,但是使用的都是位图,还需要外部引入。 借助PostCSS的postcss-write-svg我们能直接使用border-image和background-image创建svg的1px边框:
@svg border_1px {
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%;
}
}
.example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }
复制代码编译后:
.example { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
复制代码上面的方案是大漠在他的文章中推荐使用的,基本可以满足所有场景,而且不需要外部引入,这是我个人比较喜欢的一种方案。
5. 设置viewport
通过设置缩放,让CSS像素等于真正的物理像素。 例如:当设备像素比为3时,我们将页面缩放1/3倍,这时1px等于一个真正的屏幕像素。
const scale = 1 / window.devicePixelRatio;
const viewport = document.querySelector('meta[name="viewport"]');
if (!viewport) {
viewport = document.createElement('meta');
viewport.setAttribute('name', 'viewport');
window.document.head.appendChild(viewport);
}
viewport.setAttribute('content', 'width=device-width,user-scalable=no,initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale);
复制代码实际上,上面这种方案是早先flexible采用的方案。 当然,这样做是要付出代价的,这意味着你页面上所有的布局都要按照物理像素来写。这显然是不现实的,这时,我们可以借助flexible或vw、vh来帮助我们进行适配。
总结
本文从需求 ---> 产生 概述了 Retina Display (视网膜屏幕) 的产生背景和解决的问题,由此引出了 dpr(设备独立像素)的概念,以及运用这个概念能做什么事情。
下面是自我总结时间:
- 由于设备的分辨率提升导致同一个页面不同设备上显示的不统一。
- 由此
iphone4提出了Retina Display(视网膜屏幕) 来处理不同分辨率下的页面显示问题 - 为了便于描述设备上元素占用物理像素的大小,引出了
设备独立像素(DIP/DP)的概念,来统一不同设备对于1px占多少物理像素的描述。 - 最后产生了
设备像素比(dpr)用来描述设备物理像素/设备独立像素的对应关系,方便解决由于像素对应关系产生的 UI 问题。
碰到的有趣问题
在某篇文章的评论中看到关于 1px边框的讨论。
一个站在设计角度认为,如果设计是 750px,那么在对 1px 边框进行处理时,不应该根据 dpr 去决定 scale 的倍数,而是应该根据 设计图尺寸/实际屏幕尺寸 去决定 scale。这样子看起来是成比例的缩小,但是混略的问题是, 1px 边框的需求产生不适设计图上产生的,而是实际显示时在某些设备上视觉效果看起来不是 1px,所以需要根据设备 dpr 对边框进行缩放,以达到渲染出的边框是 1px的物理像素。
当设计尺寸是 375px,这是屏幕也是 375px 时,按照上述的说法,是不会产生 1px边框的问题,但是实际上依然在某些设备上会存在1px边框的问题,这个问题不是从设计图还原到页面中间产生的问题,而是在设备的视觉角度产生的问题,实际上问题的本质还是 1px的设备独立像素 !== 1px的设备物理像素导致的。