关于前端:移动端1像素边框问题

8次阅读

共计 9029 个字符,预计需要花费 23 分钟才能阅读完成。

对于前端开发者来说,要解决这个问题,必须先补充一个知识点,就是设施的 物理像素[设施像素] & 逻辑像素[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…

正文完
 0