开始
在这里开始前先记录几个概念
设备本身的像素分辨率,比如我的S9的分辨率为2960*1440。
设备独立像素也称为密度无关像素,比如我的S9它1个设备独立像素里面要展示4个物理像素。
CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。一般情况之下,CSS像素称为与设备无关的像素
devicePixelRatio,改值等于设备物理像素除以设备独立像素,在浏览器上我们可以通过打印window.devicePixelRatio来获取该值。而在CSS中,可以通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio和 -webkit-max-device-pixel-ratio进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)
1、直接写0.5px(限iOS 8及以上设备)
没错,iOS 8以上直接写0.5px可以识别,安卓设备太杂,目前我在我的S9上测试不行,还是按照1px来显示的。
2、伪类 + transform 的实现
先说方案的原理:把原先元素的 border 去掉,然后利用 ::before 或者 ::after 伪元素重做 border ,并 transform 的 scale 缩小到原来的一半,原先的元素相对定位,新做的 border 绝对定位。
这个方案是我查找的的许多方案里面比较简单的方案了,这里放在首位,而且这个方案在四条边框都存在的情况下支撑圆角,首先这儿先贴出完整的演示代码(这里我先贴只有元素底部设置边框的情况):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Event</title>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
background-color: grey;
display: flex;
justify-content: center;
align-items: center;
}
.outter {
width: 300px;
height: 300px;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
}
.inner {
width: 150px;
height: 150px;
margin: 10px;
padding: 10px;
background-color: violet;
position: relative;
border: none;
}
/* 一条边设置边框 - 底部 */
.inner::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
background: #000;
width: 100%;
height: 1px;
transform: scaleY(0.5);
transform-origin: 0 0;
}
</style>
</head>
<body>
<div class="outter">
<div id="inner" class="inner"></div>
</div>
<script>
console.log(window.devicePixelRatio)
</script>
</body>
</html>
这里有个额外的知识点,transform-origin,参考MDN上的资料就可以了,很好理解,它主要是来规定transform的rotate、translate、scale等这些属性应该在哪个基础点来进行变换。
上面的代码演示了元素底部设置边框,接下来我们修改代码,来分别展示上,左,右的设置方法。
.inner::after {
content: '';
position: absolute;
top: 0;
left: 0;
background: #000;
width: 100%;
height: 1px;
transform: scaleY(0.5);
transform-origin: 0 0;
}
.inner::after {
content: '';
position: absolute;
top: 0;
left: 0;
background: #000;
width: 1px;
height: 100%;
transform: scaleX(0.5);
transform-origin: 0 0;
}
.inner::after {
content: '';
position: absolute;
top: 0;
right: 0;
background: #000;
width: 1px;
height: 100%;
transform: scaleX(0.5);
transform-origin: 0 0;
}
.inner::after {
content: '';
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
box-sizing: border-box;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: 0 0;
}
当你需要设置圆角是(四个边框的情况),在 .inner 和 .inner::after里面都跟上 border-radius即可(注意dpr为2时.inner::after里面的 border-radius 的值为 .inner 里面两倍才行,其它dpr值的情况暂未测试)。
上面演示的是devicePixelRatio为2的情况,目前包括iphone和Android的很多设备都到了3或者4,比如iPhone X的dpr为3,Galaxy S9为4,所以可以用媒体查询来解决。
2.1 使用媒体查询实现多设备适配
这里我先贴出阿里的一套方案:
/*Retian 1px border start */
.retinabt,
.retinabb,
.retinabl,
.retinabr,
.retinab {
position: relative;
}
.retinabt:before,
.retinabb:after {
pointer-events: none;
position: absolute;
content: "";
height: 1px;
background: rgba(32, 35, 37, .14);
left: 0;
right: 0;
z-index: 26;
}
.retinabt:before {
top: 0;
z-index: 26;
}
.retinabb:after {
bottom: 0;
z-index: 26;
}
.retinabl:before,
.retinabr:after {
pointer-events: none;
position: absolute;
content: "";
width: 1px;
background: rgba(32, 35, 37, .14);
top: 0;
bottom: 0
}
.retinabl:before {
left: 0;
z-index: 26;
}
.retinabr:after {
right: 0;
z-index: 26;
}
.retinab:after {
position: absolute;
content: "";
top: 0;
left: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
height: 100%;
border: 1px solid rgba(32, 35, 37, .14);
pointer-events: none;
z-index: 26;
}
@media (-webkit-min-device-pixel-ratio:1.5),
(min-device-pixel-ratio:1.5),
(min-resolution:144dpi),
(min-resolution:1.5dppx) {
.retinabt:before,
.retinabb:after {
-webkit-transform: scaleY(.5);
transform: scaleY(.5)
}
.retinabl:before,
.retinabr:after {
-webkit-transform: scaleX(.5);
transform: scaleX(.5)
}
.retinab:after {
width: 200%;
height: 200%;
-webkit-transform: scale(.5);
transform: scale(.5)
}
.retinabt:before,
.retinabl:before,
.retinab:after {
-webkit-transform-origin: 0 0;
transform-origin: 0 0
}
.retinabb:after,
.retinabr:after {
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%
}
}
@media (-webkit-device-pixel-ratio:1.5) {
.retinabt:before,
.retinabb:after {
-webkit-transform: scaleY(.6666);
transform: scaleY(.6666)
}
.retinabl:before,
.retinabr:after {
-webkit-transform: scaleX(.6666);
transform: scaleX(.6666)
}
.retinab:after {
width: 150%;
height: 150%;
-webkit-transform: scale(.6666);
transform: scale(.6666)
}
}
@media (-webkit-device-pixel-ratio:3) {
.retinabt:before,
.retinabb:after {
-webkit-transform: scaleY(.3333);
transform: scaleY(.3333)
}
.retinabl:before,
.retinabr:after {
-webkit-transform: scaleX(.3333);
transform: scaleX(.3333)
}
.retinab:after {
width: 300%;
height: 300%;
-webkit-transform: scale(.3333);
transform: scale(.3333)
}
}
@media (-webkit-min-device-pixel-ratio:4),
(min-device-pixel-ratio:4) {
.retinabt:before,
.retinabb:after {
-webkit-transform: scaleY(.25);
transform: scaleY(.25)
}
.retinabl:before,
.retinabr:after {
-webkit-transform: scaleX(.25);
transform: scaleX(.25)
}
.retinab:after {
width: 400%;
height: 400%;
-webkit-transform: scale(.25);
transform: scale(.25)
}
}
/*Retina 1px border end */
接下来我贴出自己写的一个,首先是媒体查询部分,这部分可以放到项目的公共部分:
.retina-border-all,
.retina-border-top,
.retina-border-right,
.retina-border-bottom,
.retina-border-left {
position: relative;
}
.retina-border-all::after {
content: '';
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
transform-origin: 0 0;
}
.retina-border-top::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 1px;
transform-origin: 0 0;
}
.retina-border-right::after {
content: '';
position: absolute;
top: 0;
right: 0;
width: 1px;
height: 100%;
transform-origin: 0 0;
}
.retina-border-bottom::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px;
transform-origin: 0 0;
}
.retina-border-left::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 100%;
transform-origin: 0 0;
}
@media (-webkit-device-pixel-ratio: 2) {
.retina-border-all::after {
width: 200%;
height: 200%;
transform: scale(0.5);
}
.retina-border-top::after {
transform: scaleY(0.5);
}
.retina-border-right::after {
transform: scaleX(0.5);
}
.retina-border-bottom::after {
transform: scaleY(0.5);
}
.retina-border-left::after {
transform: scaleX(0.5);
}
}
@media (-webkit-device-pixel-ratio: 3) {
.retina-border-all::after {
width: 300%;
height: 300%;
transform: scale(0.333333);
}
.retina-border-top::after {
transform: scaleY(0.333333);
}
.retina-border-right::after {
transform: scaleX(0.333333);
}
.retina-border-bottom::after {
transform: scaleY(0.333333);
}
.retina-border-left::after {
transform: scaleX(0.333333);
}
}
@media (-webkit-device-pixel-ratio: 4) {
.retina-border-all::after {
width: 400%;
height: 400%;
transform: scale(0.25);
}
.retina-border-top::after {
transform: scaleY(0.25);
}
.retina-border-right::after {
transform: scaleX(0.25);
}
.retina-border-bottom::after {
transform: scaleY(0.25);
}
.retina-border-left::after {
transform: scaleX(0.25);
}
}
然后是你要设置边框的元素部分的CSS:
.inner {
width: 150px;
height: 150px;
margin: 10px;
padding: 10px;
background-color: violet;
/* 四个边都要边框时并且需要圆角 */
/* border-radius: 10px; */
}
.inner::after {
/* 四个边都要边框时 */
border: 1px solid #000;
/* 四个边都要边框时并且需要圆角 */
/* border-radius: 20px; */
/* 上、右、下、左方需要边框时 */
/* background-color: #000; */
}
HTML部分:
<div class="outter">
<div id="inner" class="inner retina-border-all"></div>
</div>
3、手淘的方案(这儿直接给链接,这个方案是五年前的了)
使用Flexible实现手淘H5页面的终端适配
4、另一种rem + viewport的方案(等比例放大)
先放代码:
(function(win,doc) {//根据屏幕大小及dpi调整缩放和大小
var scale = 1.0, ratio = 1, dc=doc, viewporttexts='';
if (win.devicePixelRatio && devicePixelRatio >= 1.5) {
ratio = devicePixelRatio;
scale = scale/(devicePixelRatio);
}
viewporttexts = ' width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale +', minimum-scale=' + scale + ',user-scalable=no';
doc.querySelector('meta[name="viewport"]').setAttribute("content",viewporttexts);
dc.documentElement.style.fontSize =doc.getElementsByTagName("html")[0].style.fontSize=Math.ceil(50*ratio) + "px";
})(window,document);
这个方案写1px的时候不转换rem,然后其他都要转换rem(字体也要写rem单位),上面的基础大小为50px,也就是说,ratio为1时,你的1rem相当于50px,这个在你的转换插件里面把倍率设置为50即可
然后我说一下我测试的结果,目前手头只有S9和iPhone 7(系统为iOS 11),S9的浏览器用的UC,测试我发现,上面这个方案在S9上很完美,看不出异常,然后在IP7上测试四边都设置边框的情况下,左右边框没起到作用,它是按照2px显示的,上下边框没问题,是按1px显示,当我单独设置一边的边框时,显示没有问题(补充:我发现当我左边的不设置边框或者不设置左右边框时,右边的四个边框都显示正常,无解-_-)。下面我贴几张图:
-
S9

-
IP7

-IP7-左边不设置边框

参考资料
7种方法解决移动端Retina屏幕1px边框问题
移动端 Retina屏 各大主流网站1px的解决方案
css中引入svg来兼容部分安卓机显示0.5px边框的示例
开始
在这里开始前先记录几个概念
1、直接写0.5px(限iOS 8及以上设备)
没错,iOS 8以上直接写0.5px可以识别,安卓设备太杂,目前我在我的S9上测试不行,还是按照1px来显示的。
2、伪类 + transform 的实现
先说方案的原理:把原先元素的 border 去掉,然后利用
::before或者::after伪元素重做 border ,并 transform 的 scale 缩小到原来的一半,原先的元素相对定位,新做的 border 绝对定位。这个方案是我查找的的许多方案里面比较简单的方案了,这里放在首位,而且这个方案在四条边框都存在的情况下支撑圆角,首先这儿先贴出完整的演示代码(这里我先贴只有元素底部设置边框的情况):
上面的代码演示了元素底部设置边框,接下来我们修改代码,来分别展示上,左,右的设置方法。
当你需要设置圆角是(四个边框的情况),在
.inner和.inner::after里面都跟上border-radius即可(注意dpr为2时.inner::after里面的border-radius的值为.inner里面两倍才行,其它dpr值的情况暂未测试)。2.1 使用媒体查询实现多设备适配
这里我先贴出阿里的一套方案:
接下来我贴出自己写的一个,首先是媒体查询部分,这部分可以放到项目的公共部分:
然后是你要设置边框的元素部分的CSS:
HTML部分:
3、手淘的方案(这儿直接给链接,这个方案是五年前的了)
4、另一种rem + viewport的方案(等比例放大)
先放代码:
然后我说一下我测试的结果,目前手头只有S9和iPhone 7(系统为iOS 11),S9的浏览器用的UC,测试我发现,上面这个方案在S9上很完美,看不出异常,然后在IP7上测试四边都设置边框的情况下,左右边框没起到作用,它是按照2px显示的,上下边框没问题,是按1px显示,当我单独设置一边的边框时,显示没有问题(补充:我发现当我左边的不设置边框或者不设置左右边框时,右边的四个边框都显示正常,无解-_-)。下面我贴几张图:
S9

IP7

-IP7-左边不设置边框

参考资料
7种方法解决移动端Retina屏幕1px边框问题
移动端 Retina屏 各大主流网站1px的解决方案
css中引入svg来兼容部分安卓机显示0.5px边框的示例