pc端有“1px”问题吗?

1,087 阅读5分钟

写在前面

如题,先来一波“灵魂拷问”,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一致