写在前面
如题,先来一波“灵魂拷问”,pc端也有“1px”问题吗?
我们通常听到或讨论“1px”问题时都是针对移动端,那么pc端到底有没有同样的问题呢?
如果你不能马上回答出来,或者对自己的答案不够肯定,又或者你已经经历并解决过移动端“1px”问题,不妨今天我们一起换个角度再唠唠
什么是“1px”问题
按设计稿(通常是2x,即二倍)进行开发并设置1px宽度的边框时,会发现实际显示效果比设计稿视觉效果看起来更粗(实际是1px的两倍),且通常出现在移动端
产生原因
简而言之,是因为高清屏幕上css像素和物理像素(设计稿上的像素为物理像素)不一致造成
具体分析
什么是高清屏?
由wiki上这张图可见,设备清晰度以dpi的维度进行划分什么是dpi?
dpi(dots per inch),即每英寸点数,点即最小显示单元
对屏幕来说,dot对应物理像素,故dpi即每英寸物理像素数,同ppi(pixel per inch)
计算方式
ppi = 屏幕对角线总像素数 / 屏幕对角线总英寸(即屏幕尺寸)
以13寸macpro retina屏幕为例
分辨率为2560 * 1600,即横向物理像素数为2560,纵向物理像素数为1600
屏幕尺寸为13inch,即对角线为13inch
于是,屏幕对角线总像素 / 屏幕对角线总英寸 = (2560 * 2560 + 1600 * 1600) ^ 0.5 / 13 ≈ 232ppi
对照上图可见13寸macpro retina屏为hdpi,也就是我们常说的高清屏
为什么高清屏上css像素和物理像素不一致?
什么是css像素?
首先看一段来自CSS权威指南的话
CSS规范建议如果一个显示类型的设置与96ppi截然不同,用户代理应把像素度量缩放为一种“参考像素”。CSS2.1建议采用96ppi
这段话的意思是说,当屏幕ppi远大于96ppi(如高清、超高清设备,包括大部分移动端设备及部分pc端设备)时,浏览器对显示内容进行缩放以让css像素的ppi接近96ppi
回到刚才的13寸pro的例子,此时屏幕物理像素的ppi约为232ppi,浏览器发现该ppi远大于96ppi,于是进行缩放,此时浏览器使用4个物理像素显示1个css像素(可以通过window.devicePixelRatio获取该比例,即我们常说的dpr,此场景下值为2),这样缩放后css像素的ppi就接近96了
于是,当我们在css中设置1px时,在13寸pro的retina屏会显示为2个物理像素宽(4个物理像素显示对应1个css像素,像素点为正方形,所以宽高都是2个物理像素);而设计稿上的1px对应1个物理像素,故最终显示效果比设计稿要粗,也就产生了“1px”问题
pc端存在“1px”问题吗?
从上面的分析可以看出,产生“1px”问题的根本原因是显示设备ppi远高于css标准中指出的96ppi;
所以显然pc端也存在“1px”问题,只要该屏幕也满足ppi远高于96这个条件(如前面例子中的retina屏)
那么之所以一般提到“1px”适配都是针对移动端,我想有两个主要原因
- 现代移动端设备普遍为高清屏,比例高于pc端设备
- 移动端设备总可视区域总面积远小于pc端,故设计稿的1px显示成2px造成的视觉影响比pc端更为明显
常见解决方案
网上关于“1px”问题具体解决方案的文章已经很多了,本文不再过多赘述,简单聊聊几个常见的方案及其原理
首先明确一点,就是非高清屏(即基本符合96ppi)上浏览器并不会进行缩放,也就没有“1px”问题
所以部分解决方案中要按需进行css媒体查询,根据设备dpr来区分是否需要解决“1px”问题
0.5px
这个方案原理比较简单,主要是看浏览器是否支持并能准确的显示小数值
该方案兼容性较差,实际可能还是按1px渲染
伪元素 + transform scale
原理分析
border无法直接利用transfrom来缩放,于是通过在元素上原本需要边框的位置添加一个宽或高为1px的伪元素来“冒充”边框,转而对该伪元素整体进行缩放
div::after {
display: block;
content: '';
height: 1px;
// 通过scale变换,元素整体缩小一半
transform: scale(.5);
}
伪元素 + 渐变背景色
原理分析
仍然是通过添加伪元素来“冒充”边框,再设置该伪元素背景为透明到有颜色的渐变,利用透明的部分背景使元素整体视觉效果变窄
div::after {
display: block;
content: '';
height: 1px;
// 背景一半透明,一半黑色,视觉上缩小一半
background: linear-gradient(#000 50%, transparent 50%);
}
meta标签的viewport属性(移动端)
原理分析
针对移动端添加meta标签,并设置viewport的initial-scale,会造成浏览器再次缩放,从而使css像素和物理像素回归一致
<meta name="viewport" content="initial-scale=0.5">
将所有内容缩放为0.5倍,则dpr为2的设备上,css的1px由对应4个物理像素再次变成和物理像素1px一致