关于移动端1px问题
前端这个活,真的是被产品虐到脑海中每天都有上千只小动物飘过,然而不让你省心的还有UI,总是跑过来告诉你,“你这和我设计图不一样呀?我这是1px,你这设备上显示的是2px”,然而,你能怎么办,改吧,笔者给你整理几种解决办法,让你扬眉吐气。
1px的线在高清屏下本应不需要做特殊处理。两倍屏下会自动用两排物理像素去展示‘1px’的细线,普通屏用一排物理像素去展示‘1px’的细线,他们应该看起来是相同的。但是,就像数学中的概念:线是没有宽度的,点是没有大小的。像素同样是没有大小的。
两倍屏的物理像素密度是普通屏的两倍,并不是每一个物理像素是普通屏的1/4大小,而是物理像素的间距是普通屏间距的1/2。
用两倍屏下用两排像素去展示,自然会比普通屏中用一排像素去展示看起来更粗。
先说原因
写过移动端的小伙伴都知道,在页面的开头,我们都会加一个viewport,然而viewport的设置和屏幕物理分辨率是按比例而不是相同的. 移动端window对象有个devicePixelRatio属性, 它表示设备物理像素和css像素的比例, 在retina屏的iphone手机上, 这个值为2或3, css里写的1px长度映射到物理像素上就有2px或3px那么长,所以1px看上去就变宽了。
解决办法有很多,下面说几个
flexible.js
引入flexible.js 加上rem布局,那可是对于移动端开发方便了不少,根据不同的设备是可以达到前端开发对页面的要求的,所以引入这个js,在处理1px问题的时候,只需要正常书写1px就可以了,而且你 不需要再添加等等,因为这个js都帮你动态的添加好了,是不是很方便。
可以按照不同屏幕的dpr作出转换,比如在2倍屏下将1px的细线写成border:0.5px。但这种方法只在ios上支持,安卓上会显示成被当成0px处理。
更通用的方案中,有svg和伪类元素两种。
SVG方案
这种方案本质上border并没有变细,但是boder被一分为二,靠内侧的是透明的。
通过postcss-write-svg这个postcss插件将css中svg函数生成的图像处理成base64。这样就可以在css文件直接调用svg函数。
伪类元素做法
border-width: 1px将边框的宽度设为1px。
width:200%然后将伪类元素的宽高都设置成父元素的2倍。(但是边框还是1px)
transform:scale(0.5)将伪类元素的x,y轴方向都缩放到0.5倍。
通过两次尺寸的设置,使这个伪类子元素保持内容的大小还是和父元素一样,但是border:0.5px的效果。
pointer-events: none当有元素的层级重叠时,鼠标点击是无法穿透的。即绝对定位的伪类元素的层级更高,它底下的元素(即文字:retina border)无法被事件触发。置为none时,绝对定位的元素不触发事件,底下的那层才能被选中。
其他css样式作用
伪类元素默认的display:inline。而position:absolute会使元素display:block。只有块级元素的尺寸(宽/高)设置才是有效的。
其中伪类选择器中content是必填项,不然无法生效
transform-origin的缩放的中心点,默认是元素中心,
transform-origin的缩放的中心点,默认是元素中心,和绝对定位的top,right一样,相对的是padding+content部分整个空间的位置
绝对定位的元素其top和right值是相对于padding+content的,默认值是从content开始,所以要规定都是0,否则当父元素有padding时,border就移位了
当使用百分比时,其父元素的高度必须显式指定,(20px/20view)不能是由子元素撑开的,但是宽度是可以的。