css实现1px的几种办法

简介: css实现1px的几种办法

背景

物理像素和逻辑像素

物理像素(physical pixel)

物理像素也叫硬件像素或者设备像素,一个物理像素是显示器(手机屏幕)上最小的物理显示单元(像素颗粒),在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。 如:iPhone6上就有750*1334个物理像素颗粒。


逻辑像素(density-independent pixel)

逻辑像素也叫设备独立像素或者密度无关像素,可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如:css像素。然后由相关系统转换为物理像素。所以说,物理像素和设备独立像素之间存在着一定的对应关系,这就是接下来要说的设备像素比。


(3)设备像素比(device pixel ratio )简称dpr

设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系。它的值可以按如下的公式的得到:


设备像素比(dpr)=物理像素/逻辑像素(px) // 在某一方向上,x方向或者y方向,下图dpr=2

image.png

为什么css设置1px,但是在移动端上显示却感觉有些粗呢?

知道了设备像素比,我们就大概知道了1px线变粗的原因。简单来说就是手机屏幕分辨率越来越高了,同样屏幕大小的一个手机,它的实际物理像素数更多了。因为不同的移动设备有不同的像素密度,所以我们所写的1px在不同的移动设备上展示是不一样的。


先从一个例子来看:

iPhone 3GS 和 iPhone 4 的像素分别是 320px 和 640px,但是显示屏的宽度都是相同的,所以为了在所有设备上渲染出的显示效果相同,CSS 中的 1px 映射到 iPhone 4 的物理像素上,就会是 2px。同样的道理,在 iPhone 5、6 上 CSS 的 1px 对应物理像素 2px,6plus 则是 3px。所以当我们设置 1px 时,实际的显示效果其实是由两个甚至三个像素点所绘制的。


现在做移动端开发时一般都要加上一句话:

<metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">


这句话定义了本页面的viewport的宽度为设备宽度,初始缩放值和最大缩放值都为1,并禁止了用户缩放。


手机存在一个能完美适配的理想viewport, 分辨率相差很大的手机的理想viewport的宽度可能是一样的, 这样做的目的是为了保证同样的css在不同屏幕下的显示效果是一致的, viewport的好处就在于一套css可以适配多个机型。


在window对象中有一个devicePixelRatio属性,他可以反应css中的像素与设备的像素比。然而1px在不同的移动设备上都等于这个移动设备的1px,这是因为不同的移动设备有不同的像素密度。有关这个属性,它的官方的定义为:设备物理像素和设备独立像素(逻辑像素)的比例,也就是

devicePixelRatio=物理像素/设备独立像素

1px变粗的原因:

viewport的物理像素和逻辑像素(css像素)是按比例而不是相同的. 移动端window对象有个devicePixelRatio属性, 它表示设备物理像素和css像素的比例, 在retina屏的iphone手机上, 这个值为2或3, css里写的1px长度映射到物理像素上就有2px或3px那么长。通过设置viewport,可以改变css中的1px用多少物理像素来渲染,设置了不同的viewport,当然1px的线条看起来粗细不一致。


其实出现1px的原因还是在于,UI设计师要求的1px是物理像素,而我们开发写的css是逻辑像素,他们是不一样的,存在一个换算比例,通常JavaScript可以通过window.devicePixelRatio来获取,在iPhone上出现边框变宽原因就是因为devicePixelRatio=2,而border-width=1,边框被放大了俩倍,导致出现边框变宽。

css如何实现1px的物理像素

法一:利用box-shadow

  • 优点:
    代码量少
    可以满足所有场景
  • 缺点:
    边框有阴影,颜色变浅

image.png

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>    .box {
width: 100px;
height: 100px;
margin: 50pxauto;
background-color: antiquewhite;
box-shadow: 0px1px0px0pxrgba(0, 0, 0, 1);
    }
</style></head><body><divclass="box"></div></body></html>

效果

image.png

将阴影尺寸设置为负数,设置成-1px 是为了让阴影尺寸稍小于div元素尺寸,这样左右两边的阴影就不会暴露出来,实现只有底部一边有阴影的效果。从而实现分割线效果(单边边框)


法二:设置 border-image 方案

用1px宽度图片做border图片


优点:

可以设置单条,多条边框

没有性能瓶颈的问题

缺点:

修改颜色麻烦, 需要替换图片

圆角需要特殊处理,并且边缘会模糊

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>    .box {
width: 100px;
height: 100px;
margin: 50pxauto;
background-color: antiquewhite;
    }
    .border-image-1px {
border-bottom: 1pxsolidtransparent;
border-image: url(border.png) 30stretch;
    }
</style></head><body><divclass="box border-image-1px"></div></body></html>

image.png

法三:使用background-image实现

background-image 跟border-image的方法一样,你要先准备一张符合你要求的图片。然后将边框模拟在背景上。


优点:

可以设置单条,多条边框

没有性能瓶颈的问题

缺点:

修改颜色麻烦, 需要替换图片

圆角需要特殊处理,并且边缘会模糊

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>    .box {
width: 100px;
height: 100px;
margin: 50pxauto;
background-color: antiquewhite;
    }
    .background-image-1px {
background: url(border.png) repeat-xleftbottom;
-webkit-background-size: 100%1px;
background-size: 100%1px;
background-color: antiquewhite;
    }
</style></head><body><divclass="box background-image-1px"></div></body></html>

法四:多背景渐变实现

与background-image方案类似,只是将图片替换为css3渐变。设置1px的渐变背景,50%有颜色,50%透明。

  • 优点:
    可以实现单条、多条边框
    边框的颜色随意设置
  • 缺点:
    代码量不少
    圆角没法实现
    多背景图片有兼容性问题
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>实现1px的解决办法</title><style>    .background-gradient-1px {
background:
linear-gradient(#000, #000 100%, transparent 100%) left / 1px 100% no-repeat,linear-gradient(#000, #000 100%, transparent 100%) right / 1px 100% no-repeat,linear-gradient(#000,#000 100%, transparent 100%) top / 100% 1px no-repeat,linear-gradient(#000,#000 100%, transparent 100%) bottom / 100% 1px no-repeat    }
    .box {
width: 100px;
height: 100px;
margin: 50pxauto;
background-color: antiquewhite;
    }
</style></head><body><divclass="box background-gradient-1px"></div></body></html>

image.png

法五:用小数来写px值

IOS8下已经支持带小数的px值, media query对应devicePixelRatio有个查询值-webkit-min-device-pixel-ratio, css可以写成这样

.border { border: 1pxsolid#999 }@mediascreenand (-webkit-min-device-pixel-ratio: 2) {
    .border { border: 0.5pxsolid#999 }}
@mediascreenand (-webkit-min-device-pixel-ratio: 3) {
    .border { border: 0.333333pxsolid#999 }}

优点:

简单,不需要过多代码。

缺点:

无法兼容安卓设备、 iOS 8 以下设备。

法六:viewport + rem 实现

整体思路:是在viewport设置缩放,通过js去动态修改viewport的值。


优点:

所有场景都能满足

一套代码,可以兼容基本所有布局

缺点:

老项目修改代价过大,只适用于新项目

在页面初始化的时候,设置viewport:

<metaname="viewport"id="WebViewport"content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">

通过js来动态实现对viewport的修改:

varviewport=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')
} 
vardocEl=document.documentElement;
varfontsize=10* (docEl.clientWidth/320) +'px';
docEl.style.fontSize=fontsize;

法七:伪类 + transform 实现

原理是把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,边框宽度设置为1px,并 transform 的 scale 缩小一半,原先的元素相对定位,新做的 border 绝对定位。


优点:

所有场景都能满足

支持圆角(伪类和本体类都需要加border-radius)

缺点:

需要注意<input type=“button”>是没有:before, :after伪元素的

对于已经使用伪类的元素(例如clearfix),可能需要多层嵌套

单条border样式设置:

.scale-1px{
position: relative;
border:none;
}
.scale-1px:after{
content: '';
position: absolute;
bottom: 0;
background: #000;width: 100%;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
-webkit-transform-origin: 00;
transform-origin: 00;
}

四条boder样式设置:

.scale-1px{
position: relative;
margin-bottom: 20px;
border:none;
}
.scale-1px:after{
content: '';
position: absolute;
top: 0;
left: 0;
border: 1pxsolid#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: lefttop;
transform-origin: lefttop;
}

最好在使用前也判断一下,结合 JS 代码,判断是否 Retina 屏:

if(window.devicePixelRatio&&devicePixelRatio>=2){
document.querySelector('ul').className='scale-1px';
}
目录
相关文章
|
18天前
|
编解码 前端开发 UED
解密CSS单位:px、em、vh的区别与应用
解密CSS单位:px、em、vh的区别与应用
66 0
|
18天前
|
编解码 前端开发 小程序
CSS中rpx、px、em、rem、%、vh、vw各自都代表什么
CSS中rpx、px、em、rem、%、vh、vw各自都代表什么
53 0
|
前端开发 容器
面试官:请使用 CSS 实现自适应正方形
面试官:请使用 CSS 实现自适应正方形
423 0
面试官:请使用 CSS 实现自适应正方形
|
18天前
|
前端开发
css中px和em的区别
css中px和em的区别
|
18天前
|
编解码 前端开发
CSS 的数值与单位px\em\%
CSS 的数值与单位px\em\%
|
18天前
|
编解码 前端开发
CSS中单位:【px和%】【em和rem】【vw|vh|vmin|vmax】的区别
CSS中单位:【px和%】【em和rem】【vw|vh|vmin|vmax】的区别
|
7月前
|
编解码 前端开发
css中单位px、pt、em和rem的区别
css中单位px、pt、em和rem的区别
|
8月前
|
Web App开发 编解码 前端开发
|
10月前
CSS3 px、em、rem 的使用与区别
CSS3 px、em、rem 的使用与区别
40 0
|
前端开发
CSS——0.5px像素以及0.1像素实现
0.5px像素以及0.1像素实现
94 0