起因
UI设计稿
移动端H5开发中,UI设计稿中边框为1px,前端在开发过程中如果出现border:1px(或width: 1px,height: 1px,…),测试会发现在HiDPI或Retina屏机型中,1px会比较粗。
设备像素比
设备像素比:dpr=window.devicePixelRatio
,也就是设备的物理像素与逻辑像素的比值,它告诉浏览器应使用多少屏幕实际像素来绘制单个CSS像素。
在HiDPI或Retina屏的手机上, dpr
常见的有2
或3
,css
里写的1px
宽度映射到物理像素上就有2px
或3px
宽度。
例如:iPhone6
的dpr
为2
,物理像素是750
(x
轴),它的逻辑像素为375
。也就是说,1
个逻辑像素,在x
轴和y
轴方向,需要2个物理像素来显示,即:dpr=2时,表示1个CSS像素由4个物理像素点组成。
解决
移动端京东处理1px有用到伪类+transform
tips
伪类+transform可以很好的解决部分手机不支持.5px
显示问题,关键是利用好scale()
。
优点:所有场景都能满足,支持圆角(伪类和本体类都需要加border-radius)。
缺点:代码量也很大,对于已经使用伪类的元素(例如clearfix),可能需要多层嵌套。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| .border-1px, .border-bottom-1px, .border-top-1px, .border-left-1px, .border-right-1px { position: relative; }
.border-1px::after, .border-bottom-1px::after, .border-top-1px::after, .border-left-1px::after, .border-right-1px::after { background-color: #e9e9e9; }
.border-bottom-1px::after { content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 1px; -webkit-transform-origin: 0 0; transform-origin: 0 0; }
.border-top-1px::after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 1px; -webkit-transform-origin: 0 0; transform-origin: 0 0; }
.border-left-1px::after { content: ""; position: absolute; left: 0; top: 0; width: 1px; height: 100%; -webkit-transform-origin: 0 0; transform-origin: 0 0; }
.border-right-1px::after { content: ""; position: absolute; right: 0; top: 0; width: 1px; height: 100%; -webkit-transform-origin: 0 0; transform-origin: 0 0; }
.border-1px::after { content: ""; -webit-box-sizing: border-box; box-sizing: border-box; position: absolute; left: 0; top: 0; width: 100%; height: 100%; border: 1px solid #e9e9e9; -webkit-transform-origin: 0 0; transform-origin: 0 0; }
@media (-webkit-min-device-pixel-ratio: 2) { .border-bottom-1px::after, .border-top-1px::after { -webkit-transform: scaleY(.5); transform: scaleY(.5); } .border-left-1px::after, .border-right-1px::after { -webkit-transform: scaleX(.5); transform: scaleX(.5); } .border-1px::after { width: 200%; height: 200%; -webkit-transform: scale(.5); transform: scale(.5); } }
@media (-webkit-min-device-pixel-ratio: 3) { .border-bottom-1px::after, .border-top-1px::after { -webkit-transform: scaleY(.333); transform: scaleY(.333); } .border-left-1px::after, .border-right-1px::after { -webkit-transform: scaleX(.333); transform: scaleX(.333); } .border-1px::after { width: 200%; height: 200%; -webkit-transform: scale(.333); transform: scale(.333); } }
|
viewport + rem
优点:所有场景都能满足,一套代码,可以兼容基本所有布局。
缺点:老项目修改代价过大,只适用于新项目。
1 2 3 4 5 6 7 8 9
| !function() { var dpr = window.devicePixelRatio || 1 var scale = 1 / dpr var viewport = document.querySelector("meta[name=viewport]") viewport.setAttribute = ('content', 'width=device-width,user-scalable=no,initial-scale=' + scale) var docEl = document.documentElement var fontsize = docEl.clientWidth / 10 * dpr + 'px' docEl.style.fontSize = fontsize }()
|
background-image
background-image
跟border-image
的方法一样,你要先准备一张符合你要求的图片。
优点:可以设置单条,多条边框,没有性能瓶颈的问题。
缺点:修改颜色麻烦, 需要替换图片;圆角需要特殊处理,并且边缘会模糊;兼容性差。
1 2 3 4
| .background-image-1px { background: url(../img/line.png) repeat-x left bottom; background-size: 100% 1px; }
|
postcss-write-svg
在实际开发中,postcss-write-svg 用的很少,仅适合直线,一般不考虑。
借助于PostCSS
的插件postcss-write-svg
,无需background-image
或border-image
的方法那样依赖图片。
1 2 3 4 5 6 7 8 9 10 11 12
| @svg border1px { height: 2px; @rect { fill: var(--color, black); width: 100%; height: 50%; } } .example { border: 1px solid transparent; border-image: svg(border1px param(--color #00b1ff)) 2 2 stretch; }
|
这样PostCSS
会自动帮你把CSS编译出来:
1 2 3 4 5
| .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; }
|
总结
通常情况,伪类元素方案更好,无论是从成本还是灵活性出发。
相关链接
[1] MDN - Window.devicePixelRatio
[2] 移动端 1px 解决方案(完整版)
[3] MDN - 标准元数据名称
[4] 前端提高篇(四十六)CSS进阶11:移动端布局(等比缩放+1px问题:viewport+rem | transform | vw+插件)
[5] postcss-write-svg