怎么画一条0.5px的边

编者按:本文由人人网FED发表于掘金,并已受权奇舞周刊转载html

什么是像素?前端

像素是屏幕显示最小的单位,在一个1080p的屏幕上,它的像素数量是1920 1080,即横边有1920个像素,而竖边为1080个。一个像素就是一个单位色块,是由rgba四个通道混合而成。对于一个1200万像素的相机镜头来讲,它有1200万个感光单元,它能输出的最大图片分辨率大约为3000  4000。浏览器

那么像素自己有大小吗,一个像素有多大?iphone

有的,若是一个像素越小,那么在一样大小的屏幕上,须要的像素点就越多,像素就越密集,若是一英寸有435个像素,那么它的dpi/ppi就达到了435。Macbook Pro 15寸的分辨率为2880 x 1800,15寸是指屏幕的对角线为15寸(具体为15.4),根据长宽比换算一下获得横边为13寸,因此ppi为2880 / 13 = 220 ppi. 像素越密集即ppi(pixel per inch)越高,那么屏幕看起来就越细腻越高清。svg

在Mac/Windows上能够设置屏幕显示的分辨率,Mac默认为设备分辨率的一半,它的dpr = 2,即长和宽用2个像素表示1个像素,因此2880个物理像素点实际上只表示1440个逻辑像素:工具

12B45842D1EF4531B65C1E53880A2EC3.jpeg

那么咱们的问题来了,怎么在高清屏上画一条0.5px的边呢?0.5px至关于高清屏物理像素的1px。这样的目的是在高清屏上看起来会更细一点,效果会更好一点,例如更细的分隔线。测试

大漠在《再谈Retina下1px的解决方案》已经讨论过这个问题,这里咱们再理一理思路。url

理论上px的最小单位是1,可是会有几个特例,高清屏的显示就是一个特例。高清屏确实能够画0.5px,对比效果以下:spa

若是咱们直接设置0.5px,在不一样的浏览器会有不一样的表现,使用以下代码:firefox

<!DOCType html>
<html>
<head>
   <meta charset="utf-8">
   <style>
    .hr {
        width: 300px;
        background-color: #000;
     }
     .hr.half-px {
        height: 0.5px;
     }
     .hr.one-px {
        height: 1px;
      }
     </style>
</head>
<body>
    <p>0.5px</p>
    <div class="hr half-px"></div>
    <p>1px</p>
    <div class="hr one-px"></div>
</body>
</html>

在PC上的不一样浏览器上测试测试结果以下所示:

其中Chrome把0.5px四舍五入变成了1px,而firefox/safari可以画出半个像素的边,而且Chrome会把小于0.5px的当成0,而Firefox会把不小于0.55px当成1px,Safari是把不小于0.75px当成1px,进一步在手机上观察iOS的Chrome会画出0.5px的边,而安卓(5.0)原生浏览器是不行的。因此直接设置0.5px不一样浏览器的差别比较大,而且咱们看到不一样系统的不一样浏览器对小数点的px有不一样的处理。因此若是咱们把单位设置成小数的px包括宽高等,其实不太可靠,由于不一样浏览器表现不同。

第二种能想到的方法是缩放,可否设置1px,而后scale 0.5呢,咱们能够尝试一下,以下代码所示:

<style>
.hr.scale-half {
  height: 1px;
  transform: scaleY(0.5);
}
</style>
<p>1px + scaleY(0.5)</p>
<div class="hr scale-half"></div>

效果以下图所示:

咱们发现Chrome/Safari都变虚了,只有Firefox比较完美看起来是实的并且还很细,效果和直接设置0.5px同样。因此经过transform: scale会致使Chrome变虚了,而粗细几乎没有变化,因此这个效果很差。

咱们还想到作移动端的时候还使用了rem作缩放,但实际上rem的缩放最后仍是会转化成px,因此和直接使用0.5px的方案是同样的。

还有什么办法呢?还能够用线性渐变linear-gradient,以下代码所示:

<style>
.hr.gradient {
  height: 1px;
  background: linear-gradient(0deg, #fff, #000);
}
</style>
<p>linear-gradient(0deg, #fff, #000)</p>
<div class="hr gradient"></div>

linear-gradient(0deg, #fff, #000)的意思是:渐变的角度从下往上,从白色#fff渐变到黑色#000,并且是线性的,在高清屏上,1px的逻辑像素表明的物理(设备)像素有2px,因为是线性渐变,因此第1个px只能是#fff,而剩下的那个像素只能是#000,这样就达到了画一半的目的。逻辑分析很完美,实际的效果又怎么样呢,以下图所示:

咱们发现这种方法在各个流览器上面都不完美,效果都是虚的,和完美的0.5px仍是有差距。这个效果和scale 0.5的差很少,都是经过虚化线,让人以为变细了。

还有另一种方法,使用box-shadow,以下代码所示:

<style>
.hr.boxshadow {
  height: 1px;
  background: none;
  box-shadow: 0 0.5px 0 #000;
}
</style>
<p>box-shadow: 0 0.5px 0 #000</p>
<div class="hr boxshadow"></div>

设置box-shadow的第二个参数为0.5px,表示阴影垂直方向的偏移为0.5px,效果以下:

这个方法在Chrome和Firefox都很是完美,可是Safari不支持小于1px的boxshadow,因此彻底没显示出来了。不过至少找到了一种方法可以让PC的Chrome显示0.5px。

还可使用SVG,利用SVG的1px仍是物理像素的1px,不是高清屏的1px。以下代码所示:

<style>
.hr.svg {
  background: none;
  height: 1px;
  background: url("data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1px'><line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line></svg>");
}
</style>
<p>svg</p>
<div class="hr svg"></div>

设置background为一个svg文件,这个svg单独拷出来是这样的:

<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1px'>
    <line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line>
</svg>

使用svg的line元素画线,stroke表示描边颜色,默认的宽度stroke-width="1",因为svg的1px是物理像素的px,至关于高清屏的0.5px,另外还可使用svg的rect等元素进行绘制。在Chrome和Safari的效果以下:

这个方案也是很完美,可是在firefox挂了,究其缘由是由于firefox的background-image若是是svg的话只支持命名的颜色,如"black"、"red"等,若是把上面代码的svg里面的#000改为black的话就能够显示出来,可是这样就很不灵活了。不然只能把svg转成base64的形式,咱们把svg的内容转成base64(能够找一些在线的工具),对好比下:

.hr.svg {
    background: url("data:image/svg+xml;utf-8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1px'><line x1='0' y1='0' x2='100%' y2='0' stroke='#000'></line></svg>");
    background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMDAlJyBoZWlnaHQ9JzFweCc+PGxpbmUgeDE9JzAnIHkxPScwJyB4Mj0nMTAwJScgeTI9JzAnIHN0cm9rZT0nIzAwMCc+PC9saW5lPjwvc3ZnPg==");
}

这样在firefox也能完美展现了。

其实0.5px的需求在移动端应该会更常见,比较一下以上五种方法在IOS和安卓的表现,以下图所示:

IOS下的Safari和Chrome表现一致,都是以直接设置0.5px的效果最好,而安卓浏览器则是以box-shadow的效果最好(试了5和7),而svg的方案在IOS和安卓的设备上都能完美支持。读者能够打开这个网页,看一下在你的设备是哪一种效果最好。

结合以上,咱们初步获得如下结论:

使用SVG相对于box-shadow等方法,还有一个好处是能够借助svg的元素画出任意图形,如四边形,圆角等。

最后还有一个万能的方法,那就是经过控制viewport,在移端开发里面通常会把viewport的scale设置成1:

<meta name="viewport" content="width=device-width,initial-sacle=1">

其中width=device-width表示将viewport视窗的宽度调整为设备的宽度,这个宽度一般是指物理上宽度。默认的缩放比例为1,如iphone 6竖屏的宽度为750px,它的dpr=2,用2px表示1px,这样设置以后viewport的宽度就变成375px。这时候0.5px的边就使用咱们上面讨论的方法。

可是你能够把scale改为0.5:

<meta name="viewport" content="width=device-width,initial-sacle=0.5">

这样的话,viewport的宽度就是本来的750px,因此1个px仍是1px,正常画就行,但这样也意味着UI须要按2倍图的出,总体面面的单位都会放大一倍。

在iPhone X和一些安卓手机等dpr = 3的设备上,须要设置scale为0.333333,这个时候就是3倍地画了。

综上讨论了像素和viewport的一些概念,并介绍和比较了在高清屏上画0.5px的几种方法——能够经过直接设置宽高border为0.5px、设置box-shadow的垂直方向的偏移量为0.5px、借助线性渐变linear-gradient、使用transform: scaleY(0.5)的方法,使用SVG的方法。最后发现SVG的方法兼容性和效果都是最好的,因此在viewport是1的状况下,可使用SVG画0.5px,而若是viewport的缩放比例不是1的话,那么直接画1px便可。

关于奇舞周刊

《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送连接到后台便可给咱们投稿。

相关文章
相关标签/搜索