【移动适配】一个像素的border怎么实现

clipboard.png
一个像素里复杂纷扰的世界html

文 | 啃先生 Mar.3rd.2016 首发于微信公众号(啃先生) web

上一篇发了《【移动适配】移动Web怎么作屏幕适配》,如今继续。算法

壹 | Fisrt

在CSS的世界里Px是原子操做,咱们没法定义边框的宽度是0.5px,最小都是1px。因此有如下结论:segmentfault

clipboard.png

然而,对于精益求精的产品而言,这种认识只是片面的!例如:我作了一个页面,上面只有两条边框,在高清屏(如iPhone5s)上,通过特殊处理的边框比1像素的边框还要细。浏览器

所以,在高清屏上,border-width:1px;并非最小边框。浏览器能够显示的最小粒度比CSS中的1px还要小。微信

clipboard.png

貳 | Second

那么CSS中的1px是什么?浏览器是怎么渲染它的?ide

网页在一个叫viewport的东西里渲染,能够理解为画布,画布被分红 N x M 个小方格,1个CSS像素,就是其中的一个小方格。字体

viewport又是什么?ui

网页在viewport上渲染,能够想像在PS上画东西时,上面也有个画布,这个画布分割了 N x M 个方格,N是它的宽度,M是它的高度。宽高均可以任意设置,因此说viewport是虚拟的。假设设置宽度是400,那么浏览器显示区域的横向将被分为400份,CSS的1px占的宽度就是显示区域的 1/400。若是是980,那就是1/980。idea

viewport值不同时,对页面元素宽度的影响

看一个的页面,不动任何其余代码,只修改viewport的宽度,页面发生了什么变化

代码以下:

clipboard.png

如下是运行結果

clipboard.png
viewport=500的情況

clipboard.png
viewport=900的情況

咱们只分析用户头像的图片,已知头像宽度是50px。

  • 当viewport宽度为500时,屏幕横向被分为500份,每份1px,因此头像宽度是屏幕的1/10。(500/50=10)

  • 当viewport宽度为900时,屏幕横向被分为900份,每份1px,因此头像宽度是屏幕的1/8。 (900/50=18)

因此,在CSS中,1px是指viewport中的一个小方格,而viewport宽度是能够任意设置的。

叁 | Third

那么,怎么合理设置viewport的宽度?
viewport的宽度能够是数字和字符串"device-width"。device-width指设备宽度。

  • 当取值为数字时,指不管是什么手机屏幕,viewport都被分为那么多份

  • 当取值为device-width时,指的是手机屏幕的viewport宽度被设置为跟手机宽度同样。那这个宽度怎么算的呢?

device-width的算法

先理清几个很是关键的术语概念:

  • 物理像素:买手机的时候会有一个 nm 的分辨率,那是屏幕的nm个呈像的点,一个点(小方格)为一个物理像素。它是屏幕能显示的最小粒度

  • CSS像素:就是CSS里的Px,上面已经讲了是viewport中的一个小方格。

  • 像素密度:即dpi或ppi,屏幕每英寸所占的物理像素点。

而CSS像素与物理像素之间是有一个转换关系的。便是:
clipboard.png

其中,转换系数计算过程以下:

clipboard.png

clipboard.png
安卓的密度区域和转化系数的对应表

clipboard.png
iPhone的密度区域和转化系数的对应表
(声明:以上三个图片来源于 http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201509/376281.shtml)

例如:某台安卓手机,分辨率是 1920*1080,屏幕对象线是5英寸。那么在这台手机上1个CSS像素,占了多少个物理像素?

第一步:勾股定理算出对角线的分辨率,即 √(1920²+1080²)≈2203px

第二步:算出dpi。对角线的分辨率/对角线英寸 = 2203/5≈440dpi

第三步:得出转换系数。根据上面的图片,安卓手机440dpi,属于XXHDPI,转换系数是3

所以这台手机中,1个CSS像素 = 3*物理像素。即1个CSS像素占了3个物理像素。

这个转换系数,也等同于dpr,设备像素比。

由于很明显device-width的宽度值单位是CSS像素。因此当viewport设置为device-width时,此时它是手机横向分辨率 / 转换系数。即:

clipboard.png

例如上述的例子中,该台安卓手机的device-width是1080/3 = 360,即viewport的宽度是 360 CSS像素。
而viewport设置为固定的数字有可能会破坏这种转换关系,都是建议设置viewport宽度为device-width,这样1个CSS像素就尽最大可能恰好占dpr个物理像素点。

肆 | Fourth

为何会出现比border-width:1px更细的边框?

屏幕可以显示的最小粒度是1个物理像素,而当viewport宽度设置为device-width时,1个CSS像素占用的物理像素是由转换系数决定的。因此,像iPhone6这样的高清屏上,转换系数为3,border-width:1px,这个边框占了3个物理像素。若是能让某个border的宽度为1个物理像素,那么它就比1个CSS像素要细,而本文最开始边框那个更细是由于通过特殊处理后使其只占用1个物理像素。

让1个CSS像素占用一个物理像素的办法。

  • 方法一:viewport的scale

在viewport的属性里,除了设置宽高的width和height外,还有缩放比例scale。
当scale为1时,页面大小正常,但scale为0.5时,页面被缩小了1倍,原本1个CSS像素宽度占2个物理像素宽度,缩小后的border-width:1px就只占1个物理像素。代码以下:

clipboard.png

其中,initial-scale为1/dpr。

优势:

  1. 不用为border写不少样式代码,跟原来同样border:1px solid #D5D5D6便可

  2. 能够轻松设置圆角 border-radius。

缺点:
整个页面缩小了,反作用就是字体,图片,其余元素的尺寸边距等等都同比例缩小了。这种状况,设置viewport为dpr*document.documentElment.clientWidth,再结合我上一篇文章《【移动适配】移动Web怎么作屏幕适配(一)》,便可解决。

  • 方法二:transform scale

方法一是缩放整个页面,在CSS3标准里,能够缩放某个元素。例如某个div.border-top,为它设置以下样式,使该DIV的顶部有一个边框

.border-top{position: relative;border-top: none !important;}
.border-top:after {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 1px;
    background-color: #D5D5D6;
    -webkit-transform-origin: 0 0;
    -ms-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scaleY(0.5);
    -ms-transform: scaleY(0.5);
    transform: scaleY(0.5);
}

在该DIV后面添加一个高度为1px的内容,而且缩小dpr倍,这里就是缩小成原来的1/2。
优势是整个页面不用缩放,缺点是border代码较多,没法实现border-radius圆角

写完濒临虚脱。。

clipboard.png

  1. 深刻理解viewport和px(http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201509/376281.shtml

  2. A tale of two viewports(http://www.quirksmode.org/mobile/viewports.html

bVs82n
适配的问题还没讲完,但又臭又长的纯技术文太硬了,下期可能会喝点汤,讲讲故事。

开始码字才知道码字不易,坚持码字更不易。转载请声明来源

clipboard.png