在高清屏(Retina)下移动端的 1px 会很粗, 以下面图一是假的 1 像素,图二是真的 1 像素 javascript
DPR(device Pixel Ratio) 设备像素比
有关,它是默认缩放为 100% 的状况下设备像素和 CSS 像素的比值 window.devicePixelRatio = 物理像素 / CSS像素
0.5px 的边框css
border: 0.5px solid #E5E5E5;
复制代码
问题是 Retina 屏的浏览器可能不认识 0.5px 的边框,将会把它解释成 0px 没有边框,包括 iOS 7 和 以前版本、OS X Mavericks 及之前版本,Android 设备在 3 倍屏下不是 0.3333px ,在 Chrome 上模拟 iPhone 8Plus,发现小于 0.46px 时是显示不出来html
总结
1)优势:简单,没有反作用
2)缺点:支持 iOS 8+,不支持安卓,后期安卓 follow 就行了java
解决方案
经过 JS 检测浏览器可否处理 0.5px 的边框,若能够则给 元素添加个class,看起来是个解决方案,但是要兼容安卓设备,和 iOS 8 如下设备怎么办?这个思路行不通git
// 脚本应该放在<body>内, 若在<head>里面运行,需包装 $(document).ready(function() {})
if (window.devicePixelRatio && devicePixelRatio >= 2) {
var testElem = document.createElement('div');
testElem.style.border = '.5px solid transparent';
document.body.appendChild(testElem);
if (testElem.offsetHeight == 1)
{
document.querySelector('html').classList.add('hairlines');
}
document.body.removeChild(testElem);
}
// 而后,极细的边框样式就容易了
div {
border: 1px solid #bbb;
}
.hairlines div {
border-width: 0.5px;
}
复制代码
图片的颜色就是此后 border 的颜色github
border: 1px solid transparent;
border-image: url('./../../image/96.jpg') 2 repeat;
复制代码
总结
1)优势:没有反作用
2)缺点:border 颜色变了就得从新要改图片;圆角会比较模糊web
前面两个值 x,y 主要控制显示哪条边,后面两值控制的是阴影半径、扩展半径浏览器
box-shadow: 0 -1px 1px -1px #e5e5e5, //上边线
1px 0 1px -1px #e5e5e5, //右边线
0 1px 1px -1px #e5e5e5, //下边线
-1px 0 1px -1px #e5e5e5; //左边线
复制代码
总结
1)优势:使用简单,圆角也能够实现
2)缺点:模拟的实现方法,仔细看可看出来这是阴影不是边框markdown
在 devicePixelRatio = 2 时,输出 viewportapp
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
复制代码
在 devicePixelRatio = 3 时,输出 viewport
<meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">
复制代码
同时经过设置对应 viewport 的 rem 基准值,这种方式就能够像之前同样轻松愉快的写 1px
总结
1)优势:全机型兼容,直接写 1px 更方便
2)缺点:适用于新的项目,老项目可能改动大
<html>
<head> <title>1px question</title> <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"> <style> html { font-size: 1px; } * { padding: 0; margin: 0; } .top_b { border-bottom: 1px solid #E5E5E5; } .a,.b { box-sizing: border-box; margin-top: 1rem; padding: 1rem; font-size: 1.4rem; } .a { width: 100%; } .b { background: #f5f5f5; width: 100%; } </style> <script> var viewport = document.querySelector("meta[name=viewport]"); //下面是根据设备像素设置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.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no'); } var docEl = document.documentElement; var fontsize = 32* (docEl.clientWidth / 750) + 'px'; docEl.style.fontSize = fontsize; </script> </head> <body> <div class="top_b a">下面的底边宽度是虚拟1像素的</div> <div class="b">上面的边框宽度是虚拟1像素的</div> </body> </html> 复制代码
原理是把原先元素的 border 去掉,而后利用 :before 或 :after 重作 border,并将 transform 的 scale 缩小一半,原先的元素相对定位,新作的 border 绝对定位
单条 border
.hairlines li {
position: relative;
border:none;
}
.hairlines li:after {
content: '';
position: absolute;
left: 0;
background: #000;
width: 100%;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
// 将伪元素设置绝对定位而且和父元素的左上角对齐,将 width 设置 100%,height 设置为 1px
// 而后进行在Y方向缩小0.5倍
.setOnePx {
position: relative;
&::after {
position: absolute;
content: '';
background-color: #e5e5e5;
display: block;
width: 100%;
height: 1px; /*no*/
transform: scale(1, 0.5);
top: 0;
left: 0;
}
}
复制代码
四条 border
.hairlines li{
position: relative;
margin-bottom: 20px;
border:none;
}
.hairlines li:after{
content: '';
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}
// 一样为伪元素设置绝对定位而且和父元素左上角对其
// 将伪元素的长和宽先放大 2 倍
// 而后再设置一个边框,以左上角为中心,缩放到原来的 0.5 倍
.setBorderAll {
position: relative;
&:after {
content:" ";
position:absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: left top;
box-sizing: border-box;
border: 1px solid #E5E5E5;
border-radius: 4px;
}
}
// 样式使用的时候,也要结合 JS 代码,判断是否 Retina 屏
if(window.devicePixelRatio && devicePixelRatio >= 2) {
document.querySelector('ul').className = 'hairlines';
}
复制代码
总结
1)优势:全机型兼容,实现了真正的 1px,并且能够圆角
2)缺点:暂用了 after 伪元素,可能影响清除浮动;<td>
用不了
3)能够参照这个 border 生成器 写一个 scss 的 1px 边框生成器,该生成器考虑了三种状况:单边边框、多边边框、边框的圆角
使用伪元素方法,伪类里面再设置伪元素,能够选择到吗? 看图,须要修改中间的竖线 代码,然而展现出来的样式是下面这样的
&:nth-child(2) {
// border-color: #e5e5e5 !important;
border: 0;
position: relative;
&:after {
position: absolute;
content: '';
background-color: #e5e5e5;
display: block;
width: 100%;
height: 1px; /*no*/
transform: scale(1, 0.5);
top: 0;
}
}
复制代码
为何中间的竖线没有了?在伪类下面再写伪元素after是能够的,这里的缘由是 width 和 height 设置有问题,对于竖线应该是 width = 1px,height = 100%,而后再缩放 X 方向 0.5 倍,这样竖线就出来了;一样设置水平线应该是 width = 100%,height = 1px,而后再缩放 Y 方向 0.5 倍
&:nth-child(2) {
position: relative;
&:after {
position: absolute;
content: '';
top: 0;
left: 0;
width: 1px;
height: 100%;
transform: scaleX(0.5);
background: #e5e5e5;
transform-origin: 0 0;
}
}
// 或
&:nth-child(2) {
position: relative;
&:after {
content:" ";
position:absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: left top;
box-sizing: border-box;
border-left: 1px solid #E5E5E5;
}
}
复制代码