1px 细线

背景

在 PC 端 1 像素的细线看上去粗细都是一样的,但是在移动端各种设备出现的情况下,会发现同样是 1 像素的宽度细线,在不同设备上显示的粗细不尽相同,有的粗有的细,强迫症 UI 就会为了精益求精(zuanniujiaojian)就会要求把所有的粗线也变细。

基础概念

更详细概念解析移步viewport(待完善)

  • CSS 像素(设备独立像素 DIP)

    • 一个虚拟单位,用于逻辑上衡量长度的单位,由系统底层使用,转成对应的设备物理像素。

  • 设备物理像素

    • 设备能显示的最小单位。

  • 设备像素比

    • 设备物理像素 / CSS 像素

  • 分辨率

    • 物理像素的宽高,比如 iphone 6S Plus 的分辨率是 1920x1080。

  • viewport

    • 视区,用户网页的可视区域。有点懵逼?通俗一点讲就是在 PC 端的窗口的宽度,或者说是 html 标签的宽度。它不是物理像素,是 CSS 像素。

      image

产生原因

  • 为什么只会在移动端出现这个问题?

    • 在 PC 端,1px 的像素对应的设备物理像素也是 1px,所以不会有不同粗细的问题产生,而在移动端则不同设备的 CSS 像素和物理像素并不相等,因此在移动端会出现这个问题。

  • 什么情况下会出现这个问题?

    • 设计以 1080 设计稿出图批注里的一个边框为 1px,然后在 CSS 里面也写了 border: 1px solid black; 这时候其实设计图的 1 像素并不是 CSS 的一像素,就会变粗。

主要解决方案

1. before/after 伪元素

  • 原理:通过先放大(仅放大伪元素的宽高,边框粗细不变)然后缩小(元素+边框同时缩小)实现边框的粗细变化。

  • 注意:有可能会无法接收点击事件,此时可以通过层级关系去处理或者伪元素加上pointer-events: none;。需要注意<input type="button">是没有:before, :after 伪元素的。

  • 最好在使用前也判断一下,结合 JS 代码,判断是否 Retina 屏:

或把伪元素写在媒体查询内:

2. flexible.js

  • 适用于 IOS

  • e.g. devicePixelRatio=2 时输出 meta 如下, 这样 viewport 与 ideal viewport 的比是 0.5, 也就与设备物理像素一致<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">

  • 另外 html 元素上的 font-size 会被设置为屏幕宽的 1/10, 这样 css 可以以 rem 为基础长度单位进行改写, 比如 rem 是 28px, 原先的 7px 就是 0.25rem. border 的宽度能直接写 1px.

  • e.g.

3. box-shadow

  • box-shadow: h-shadow v-shadow blur spread color inset;

QA

  • pointer-events的兼容性

  • border-imgage

    • border-image: source slice width outset repeat|initial|inherit;

    • e.g.

      • image

      • 这样的1张6X6的图片, 9宫格等分填充border-image, 这样元素的4个边框宽度都只有1px

      • 图片可以用gif, png, base64多种格式, 以上是上下左右四条边框的写法, 需要单一边框只要定义单一边框的border, 代码比较直观.

      • border-image兼容性:

      • 缺点: 对于圆角样式, 将图片放大修改成圆角也能满足需求, 但这样无形中增加了border的宽度存在多种边框颜色或者更改的时候麻烦。

  • flexible现状

    • 由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。vw的兼容方案可以参阅《如何在Vue项目中使用vw实现移动端适配》一文。

  • z-index处理伪元素事件的覆盖问题

    • z-index不能很好的处理伪元素覆盖点父节的点击事件冲突问题,使用pointer-events: none替代;

    • 如果父元素的正常子元素有点击事件,则可以对该子节点设置更高的z-index(默认伪元素的z-index为0,即大于0即可)

Last updated

Was this helpful?