对于前端开发者来说,要解决这个问题,必须先补充一个知识点,就是设施的 物理像素[设施像素] & 逻辑像素[CSS像素];在我的另外一片文章 设计稿的100%还原 做了介绍,感兴趣的敌人能够查阅一下。
为什么1px变粗了?
为什么挪动端CSS外面写了1px,实际上看起来比1px粗;理解设施物理像素和逻辑像素的同学应该很容易了解,其实这两个px的含意其实是不一样的,UI设计师要求的1px是指设施的物理像素1px,而CSS里记录的像素是逻辑像素,它们之间存在一个比例关系,能够用javascript中的window.devicePixelRatio来获取,也能够用媒体查问的-webkit-min-device-pixel-ratio来获取。当然,比例多少与设施相干。
在手机上border无奈达到咱们想要的成果。这是因为devicePixelRatio个性导致,iPhone的devicePixelRatio==2,而border-width: 1px形容的是设施独立像素,所以,border被放大到物理像素2px显示,在iPhone上就显得较粗。
挪动端开发常须要在html的header里增加如下一句:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
这句话定义了本页面的viewport的宽度为设施宽度,初始缩放值和最大缩放值都为1,并禁止了用户缩放。
你的疑难可能来了,老是看到viewport,除了晓得中文名叫视口,到底是啥意思?其实,它就是设施屏幕上能用来显示咱们网页内容的那一块区域,具体点就是浏览器或app中的webview用来显示网页的那局部区域,但viewport又不局限于浏览器可视区域的大小,可能大也可能小。体现在用户是否缩放了屏幕。
心细的同学应该都有感觉,meta标签中常设置user-scalable=no也就是禁止用户缩放,那用户缩放到底会造成什么影响呢? 其实也就是显示上的变动。缩放一倍,CSS像素(逻辑像素)所代表的物理像素也就缩放了一倍,即设施物理像素和设施独立像素的比例增大(减小)了一倍。
或者你曾经明确1px变粗的起因是啥了, viewport的设置和屏幕物理分辨率是按比例而不是雷同的. 挪动端window对象有个devicePixelRatio属性, 它示意设施物理像素和css像素的比例, 在retina屏的iphone手机上, 这个值为2或3, css里写的1px长度映射到物理像素上就有2px或3px那么长。
如何解决1px问题
1. 媒体查问利用设备像素比缩放,设置小数像素
IOS8下曾经反对带小数的px值, media query对应devicePixelRatio有个查问值-webkit-min-device-pixel-ratio, css能够写成这样
.border { border: 1px solid #999 }@media screen and (-webkit-min-device-pixel-ratio: 2) { .border { border: 0.5px solid #999 }}@media screen and (-webkit-min-device-pixel-ratio: 3) { .border { border: 0.333333px solid #999 }}
【毛病】对设施有要求,小数像素目前兼容性较差。
2. viewport + rem 计划
该计划是对上述计划的优化,整体思路就是利用viewport + rem + js 动静的批改页面的缩放比例,实现小于1像素的显示。在页面初始化时,在头部引入原始默认状态如下:
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta name="viewport" id="WebViewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
接下来的工作就是js的动静批改缩放比 以及 实现rem根元素字体大小的设置
var viewport = document.querySelector("meta[name=viewport]")if (window.devicePixelRatio == 1) { viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no')} if (window.devicePixelRatio == 2) { viewport.setAttribute('content', 'width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no')} if (window.devicePixelRatio == 3) { viewport.setAttribute('content', 'width=device-width, initial-scale=0.333333333, maximum-scale=0.333333333, minimum-scale=0.333333333, user-scalable=no')} var docEl = document.documentElement;var fontsize = 10 * (docEl.clientWidth / 320) + 'px';docEl.style.fontSize = fontsize;
【毛病】认为缩放波及全局的rem单位,比拟适宜新我的项目,对于老我的项目可能要波及到比拟多的改变。
3. 设置 border-image 计划
.border-image-1px { border-width: 1px 0px; -webkit-border-image: url("border.png") 2 0 stretch; border-image: url("border.png") 2 0 stretch;}
【解释】border-width 指定边框的宽度,能够设定四个值,别离为上右下左border-width: top right bottom left。
border-image 该例意为:间隔图片上方2px(属性值上没有单位)裁剪边框图片作为上边框,下方2px裁剪作为下边框。间隔左右0像素裁剪图片即没有边框,以拉伸形式展现
联合起来就是:在边框图片中,裁剪图片上下方的2个像素宽度作为高低边框,并展现在宽度为1个像素的边框空间里。左右没有边框。 留神这里的1个像素是非凡的,专指物理像素,而平时设定的长宽1px则示意逻辑像素(该观点为集体了解)。
你可能并没有了解,裁剪边框是什么鬼?为啥还要裁剪?border-image的确是个很难了解的属性,是去w3c看了之后更加蒙圈了。w3c内容提炼的太粗劣了,但解释基本就不够。因而奉上张鑫旭老师 border-image详解 一文,特地要了解九宫格裁剪法。
当然,这种形式引入了图片,咱们还能将图片装换成base64模式体现
.border-image-1px { border-width: 1px 0px; -webkit-border-image: url("data:image/png;base64,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") 2 0 stretch; border-image: url('如上');}
【毛病】须要制作图片,圆角可能呈现含糊
4. background-image 突变实现
除了应用图片外,当然也能应用纯css来实现,百度糯米团就是采纳的这种计划。
.border { background-image:linear-gradient(180deg, red, red 50%, transparent 50%), linear-gradient(270deg, red, red 50%, transparent 50%), linear-gradient(0deg, red, red 50%, transparent 50%), linear-gradient(90deg, red, red 50%, transparent 50%); background-size: 100% 1px,1px 100% ,100% 1px, 1px 100%; background-repeat: no-repeat; background-position: top, right top, bottom, left top; padding: 10px; }
【思路】将本来1个物理像素的边框大小利用线性突变宰割成几个局部(百分比管制),实现小于1像素成果
【解释】linear-gradient指定线性突变,承受大于等于3个参数,第一个为突变旋转角度,第二个开始为突变的色彩和到哪个地位(百分比)全副变为该色彩,该例子中,第一句就是,突变方向旋转180度,即从上往下(默认为0度从下往上),从红色开始突变,到50%的地位还是红色,再突变为继承父元素色彩。
【毛病】因为每个边框都是线性突变色彩实现,因而无奈实现圆角
5. box-shadow 计划
利用暗影也能够实现,长处是没有圆角问题,毛病是色彩不好管制
div { -webkit-box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5);}
【了解】来回顾一下box-shadow属性的用法。
box-shadow: h-shadow v-shadow [blur] [spread] [color] [inset];
参数别离示意: 程度暗影地位,垂直暗影地位,含糊间隔, 暗影尺寸,暗影色彩,将内部暗影改为外部暗影,后四个可选。该例中为何将暗影尺寸设置为正数?设置成-1px 是为了让暗影尺寸稍小于div元素尺寸,这样左右两边的暗影就不会裸露进去,实现只有底部一边有暗影的成果。从而实现分割线成果(单边边框)
6. transform: scale(0.5) 计划 - 举荐: 很灵便
在以上的用法种,无非逃不开一种思维,就是将1px放大为0.5px来展现,然而。0.5px并不是所有的设施或浏览器都反对,就思考用媒体查问或viewport将其缩放比例。其实1像素问题的产生根本产生在设置边框或分割线的时候,场景并不笼罩全局款式,因而,间接缩放须要设置的元素,才是咱们真正须要的。tranform就能实现这个需要。
设置height: 1px,依据媒体查问联合transform缩放为相应尺寸。
div { height:1px; background:#000; -webkit-transform: scaleY(0.5); -webkit-transform-origin:0 0; overflow: hidden;}
2.用::after和::befor,设置border-bottom:1px solid #000,而后在缩放-webkit-transform: scaleY(0.5);能够实现两根边线的需要
div::after{ content:'';width:100%; border-bottom:1px solid #000; transform: scaleY(0.5);}
3.用::after设置border:1px solid #000; width:200%; height:200%,而后再缩放scaleY(0.5); 长处能够实现圆角,京东就是这么实现的,毛病是按钮增加active比拟麻烦。
.div::after { content: ''; width: 200%; height: 200%; position: absolute; top: 0; left: 0; border: 1px solid #bfbfbf; border-radius: 4px; -webkit-transform: scale(0.5,0.5); transform: scale(0.5,0.5); -webkit-transform-origin: top left;}
6.5 媒体查问 + transfrom 对计划1的优化
/* 2倍屏 */@media only screen and (-webkit-min-device-pixel-ratio: 2.0) { .border-bottom::after { -webkit-transform: scaleY(0.5); transform: scaleY(0.5); }}/* 3倍屏 */@media only screen and (-webkit-min-device-pixel-ratio: 3.0) { .border-bottom::after { -webkit-transform: scaleY(0.33); transform: scaleY(0.33); }}
from: https://www.jianshu.com/p/fa6...