前端周记开篇以来几乎没有怎么写过关于 CSS 的内容,所以这一期就来写篇 CSS 相关的
其实很纠结要不要把它放在前端面试题中,因为这确实是作者在面试时碰到的一道题,但是后来想想还是没有
本篇的主题是:如何用 CSS 绘制出 1px 的边框。或许有的小伙伴会说,这不是一件很容易的事情么,border:1px solid #000
就能够绘制出一条 1px 的黑色实线边框啊
其实真相怎么会是那么简单的呢?很多小伙伴一定都发现了,在高分辨率手机下,这 1px 的线条似乎变胖了,并没有我们想的那么美观,甚至会破坏界面的美感
1px 线条变胖之谜
先从一个例子来看:
iPhone 3GS 和 iPhone 4 的像素分别是 320px 和 640px,但是显示屏的宽度却却都是相同的,所以为了在所有设备上渲染出的显示效果相同,CSS 中的 1px 映射到 iPhone 4 的物理像素上,就会是 2px
同样的道理,在 iPhone 5、6 上 CSS 的 1px 对应物理像素 2px,6plus 则是 3px
所以当我们设置 1px 时,实际的显示效果其实是由两个甚至三个像素点所绘制的
如何让线条恢复苗天身材?
先放大,再缩小
原理很简单,对于想要加上 1px 边框的元素,我们只需要将它的伪元素设置成一个两倍宽高与其自身的盒子,将这个盒子的边框设置为 1px ,然后再将其缩放到原先的 50%,即可成功绘制出真正的 1px 线条,因为原先对应的 2 物理像素缩放 50% 后,就会变成 1 个物理像素
同样的,在 3 倍分辨率屏幕上也可以通过类似的方式来实现 1px 边框,但是一般情况下不会去特意设置 3 倍分辨率的情况,而是统一使用 2 倍分辨率的解决方案
下面是 CSS 代码
.box:before{
content: "";
pointer-events: none; /* 防止点击触发 */
box-sizing: border-box;
position: absolute;
width: 200%;
height: 200%;
left: 0;
top: 0;
border:1px solid #000;
-webkit-transform(scale(0.5));
-webkit-transform-origin: 0 0;
transform(scale(0.5));
transform-origin: 0 0;
}
缺点:
- 占据了该元素的伪元素,代码量相对较多
-
input
元素没有伪元素
采用自适应方案
例如淘宝的移动端适配解决方案 flexible.js ,将设备的视口宽度(viewport)设置为实际的物理像素,那么绘制出来的 1px 就会等于 1 个物理像素,同时也可解决其他的适配问题
感兴趣的小伙伴可以阅读这篇文章 使用Flexible实现手淘H5页面的终端适配
缺点:并不能够完美适用于安卓(毕竟安卓坑多)
其他方法
上面说了两种普适性较高的方法,但是其他方法也是有的呦,比如直接根据 CSS media query 的 devicePixelRatio 来设置线条的像素,devicePixelRatio=2 时设置 0.5px,devicePixelRatio=3 时设置 0.333333 px,但是这个方法完全不使用与安卓
再比如可以使用 border-image 属性来设置 1px 的边框,这就需要一张 6*6 的图片来做边框图片,但是对于圆角和单边框来说就无法适用了,渐变边框也不行