学习中发现一个问题,设置一个div的底部边框为1px solid #000,实际表现却是边框线是模糊的,或者是大于1px的.原因是,不同手机的物理像素是不同的,首先,先说下,逻辑像素与物理像素,这两个虽然单位都是px,但是他们的含义是不一样的,UI设计师要求的1px是指设备的物理像素1px,而CSS里记录的像素是逻辑像素,它们之间是存在一个比例关系的,用Javascript中的window.devicePixelRatio来获取,也可以用媒体查询的-webkit-min-devicePixelRatio来获取.比例多少,与相应设备有关.不同的设备的话,物理像素不同,对应的设备像素比不同.比如说,iPhone的devicePixelRatio==2,而border-1 px描述的是设备独立像素,所以,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,并禁止了用户缩放.向上篇博客所具体了这行代码就不赘述了,meta标签中常设置user-scalable也就是禁止用户缩放.如果可缩放的话,会造成显示上的变化,缩放一倍,逻辑像素所代表的物理像素也就缩放了一倍.所以,现在就应该明白为何1px变粗了,viewport的设置与屏幕物理分辨率是按比例而不是相同的,移动端window对象有个devicePixelRatio属性,它表示设备物理像素与CSS像素的比例,在retina屏的iphone手机上,这个值为2或3,CSS里面写的1px长度映射到物理像素上就有2px或者3px那么长了.
那么,现在来讲述下解决方案.
1.媒体查询利用设备像素比缩放,设置小数像素.
.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方案
该方案的话是利用Javascript根据window.devicePixelRatio分别进行判断修改根节点的fontSize,其他元素以rem为单位.
首先,在页面初始化时,在头部引入原始默认状态:
<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根元素开实现字体大小的设置.这里再提示下,rem是只想对于根元素html的font-size,即只需要设置根元素的font-size,其他元素使用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-image在该例中意为,距离图片上方2(无单位)裁剪边框图片作为上下边框,并展示在宽度为1像素的边框空间里,左右没有边框.
缺点的话是,需要制作图片,圆角可能出现模糊.
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像素效果.linear-gradient指定线性渐变,接受大于等于三个参数,第一个为渐变旋转角度,第二个开始为渐变的颜色与到哪个位置(百分比)全部变为该颜色.以上述代码为例子,第一句即为,渐变方向旋转180°,即从上往下(注,默认为0度且从下往上),从红色开始渐变,到百分之五十的位置还是红色,再渐变为继承父元素颜色.
缺点的话,就是由于每个边框都是线性渐变颜色实现,因此无法实现圆角.
5.box-shadow方案
利用阴影来实现代码如下:
div{ -webkit-box-shadow: 0 1px 1px -1px rgba(0,0,0,0.5); }
box-shadow: h-shadow v-shadow [blur] [spread] [color] [inset]
参数分别表示:水平阴影位置,垂直阴影位置,模糊距离,阴影尺寸,阴影颜色,将外部阴影被更改为内部阴影,后四个为可选元素.上述代码中,为何把阴影尺寸设置为负数呢?设置成-1px是为了让阴影尺寸小于div元素尺寸,这样左右两边的阴影就不会暴露出来,实现只有底部一边有阴影的效果,从而实现分割线效果.
6.transform:scale(0.5)方案
0.5px并不是所有的设备或浏览器都支持,前两个方案,媒体查询以及rem加viewport方案都使用了,实现0.5px,实际使用transform的话会更好.
1).设置height:1px,根据媒体查询结合transform缩放为相应尺寸.
div{ height:1px; background:#000; -webkit-transform:scaleY(0.5); -webkit-transform-origin:0 0; overflow:hidden;}
2).用::after设置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).或者我们使用tranfrom与方案一中的媒体查询的结合,来对方案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); } }