做移动端页面开发时,我们是按照UI设计图上的尺寸来做的。
比如说,UI给的图是750x1344(Iphone6标准),我们在浏览器做适配时,按照375x667来裁切,设计图上30像素的高度,开发时使用的是15px,这是因为Iphone6的设备像素比为2,css中的1px在设备中的像素为2px。当我们需要实现设计图中1px高度的边框时,在css中的1px实际上变成了2px边框,由此产生了1像素边框问题。
1、window.devicePixelRatio设备像素比
定义:
window.devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例。
公式表示就是:window.devicePixelRatio = 物理像素 / dips
引用自张鑫旭大神的文档
用于描述整个渲染环境在硬件设备上的缩放程度,在程序中可以通过window.devicePixelRatio属性来得到这个值。
与之相关的概念如下:
物理像素(physical pixel):设备能控制显示的最小单位。
设备独立像素(DIP,device-independent pixel,density-independent pixel):独立于设备的用于逻辑上衡量像素的单位。
每英寸像素量(PPI,pixels per inch):一英寸长度上可以并排的像素数量。
正常人眼可以识别的分辨率为300PPI,而现在很多设备的分辨率都超过了300PPI。如果设备总是以满分辨率来显示东西就可能造成文字太小,人们看不清。因此像浏览器这样的软件就会对内容做一次放大后再进行渲染,也就是降低分辨率。要降低分辨率就需要让像素这个单位变大,因此PPI的计算不再使用物理像素,而改用设备独立像素。那么设备独立像素和物理像素之间就存在一个比例差异,这就是设备像素比。
单位dppx(dots per pixel)表示每个DIP占用几个物理像素。可以理解为,CSS中的单位px在屏幕上占用了多少物理像素。
引用自https://www.web-tinker.com/article/20590.html
2、常用解决方案
2-1、border.css方案
在添加border样式的元素上设置:before和:after样式,然后在媒体查询中根据device-pixel-ratio的值来缩放对应宽度和高度,来达到边框大小为物理像素1px
@charset "utf-8"; .border, .border-top, .border-right, .border-bottom, .border-left, .border-topbottom, .border-rightleft, .border-topleft, .border-rightbottom, .border-topright, .border-bottomleft { position: relative; } .border::before, .border-top::before, .border-right::before, .border-bottom::before, .border-left::before, .border-topbottom::before, .border-topbottom::after, .border-rightleft::before, .border-rightleft::after, .border-topleft::before, .border-topleft::after, .border-rightbottom::before, .border-rightbottom::after, .border-topright::before, .border-topright::after, .border-bottomleft::before, .border-bottomleft::after { content: " 020"; overflow: hidden; position: absolute; } /* border * 因,边框是由伪元素区域遮盖在父级 * 故,子级若有交互,需要对子级设置 * 定位 及 z轴 */ .border::before { box-sizing: border-box; top: 0; left: 0; height: 100%; width: 100%; border: 1px solid #eaeaea; transform-origin: 0 0; } .border-top::before, .border-bottom::before, .border-topbottom::before, .border-topbottom::after, .border-topleft::before, .border-rightbottom::after, .border-topright::before, .border-bottomleft::before { left: 0; width: 100%; height: 1px; } .border-right::before, .border-left::before, .border-rightleft::before, .border-rightleft::after, .border-topleft::after, .border-rightbottom::before, .border-topright::after, .border-bottomleft::after { top: 0; width: 1px; height: 100%; } .border-top::before, .border-topbottom::before, .border-topleft::before, .border-topright::before { border-top: 1px solid #eaeaea; transform-origin: 0 0; } .border-right::before, .border-rightbottom::before, .border-rightleft::before, .border-topright::after { border-right: 1px solid #eaeaea; transform-origin: 100% 0; } .border-bottom::before, .border-topbottom::after, .border-rightbottom::after, .border-bottomleft::before { border-bottom: 1px solid #eaeaea; transform-origin: 0 100%; } .border-left::before, .border-topleft::after, .border-rightleft::after, .border-bottomleft::after { border-left: 1px solid #eaeaea; transform-origin: 0 0; } .border-top::before, .border-topbottom::before, .border-topleft::before, .border-topright::before { top: 0; } .border-right::before, .border-rightleft::after, .border-rightbottom::before, .border-topright::after { right: 0; } .border-bottom::before, .border-topbottom::after, .border-rightbottom::after, .border-bottomleft::after { bottom: 0; } .border-left::before, .border-rightleft::before, .border-topleft::after, .border-bottomleft::before { left: 0; } @media (max--moz-device-pixel-ratio: 1.49), (-webkit-max-device-pixel-ratio: 1.49), (max-device-pixel-ratio: 1.49), (max-resolution: 143dpi), (max-resolution: 1.49dppx) { /* 默认值,无需重置 */ } @media (min--moz-device-pixel-ratio: 1.5) and (max--moz-device-pixel-ratio: 2.49), (-webkit-min-device-pixel-ratio: 1.5) and (-webkit-max-device-pixel-ratio: 2.49), (min-device-pixel-ratio: 1.5) and (max-device-pixel-ratio: 2.49), (min-resolution: 144dpi) and (max-resolution: 239dpi), (min-resolution: 1.5dppx) and (max-resolution: 2.49dppx) { .border::before { 200%; height: 200%; transform: scale(.5); } .border-top::before, .border-bottom::before, .border-topbottom::before, .border-topbottom::after, .border-topleft::before, .border-rightbottom::after, .border-topright::before, .border-bottomleft::before { transform: scaleY(.5); } .border-right::before, .border-left::before, .border-rightleft::before, .border-rightleft::after, .border-topleft::after, .border-rightbottom::before, .border-topright::after, .border-bottomleft::after { transform: scaleX(.5); } } @media (min--moz-device-pixel-ratio: 2.5), (-webkit-min-device-pixel-ratio: 2.5), (min-device-pixel-ratio: 2.5), (min-resolution: 240dpi), (min-resolution: 2.5dppx) { .border::before { 300%; height: 300%; transform: scale(.33333); } .border-top::before, .border-bottom::before, .border-topbottom::before, .border-topbottom::after, .border-topleft::before, .border-rightbottom::after, .border-topright::before, .border-bottomleft::before { transform: scaleY(.33333); } .border-right::before, .border-left::before, .border-rightleft::before, .border-rightleft::after, .border-topleft::after, .border-rightbottom::before, .border-topright::after, .border-bottomleft::after { transform: scaleX(.33333); } }
2-2、 lib-flexible.js-淘宝移动端方案
根据当前设备的window.devicePixelRatio,来设置viewport中的缩放比例,以达到设备物理像素=css像素
if (!dpr && !scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他设备下,仍旧使用1倍的方案 dpr = 1; } scale = 1 / dpr; }
......
var metaEl = doc.createElement('meta');
var scale = isRetina ? 0.5:1;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
document.documentElement.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
documen.write(wrap.innerHTML);
}
引用https://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html
3、用到的css媒体查询
@media (max--moz-device-pixel-ratio: 1.49),
(-webkit-max-device-pixel-ratio: 1.49),
(max-device-pixel-ratio: 1.49),
(max-resolution: 143dpi),
(max-resolution: 1.49dppx)
max-device-pixel-ratio:设备像素比
max--moz-device-pixel-ratio:可以用于兼容版本号低于16的Firefox浏览器
-webkit-max-device-pixel-ratio:基于webkit的浏览器不支持dppx
max-resolution:指定输出设备的分辨率(像素密度),可替换老旧的 (max-device-pixel-ratio: 2)。分辨率可以用每英寸(dpi)或每厘米(dpcm)的点数来表示。此处表示最大分辨率
@media (-webkit-min-device-pixel-ratio: 2), /* Webkit-based browsers */ (min--moz-device-pixel-ratio: 2), /* Older Firefox browsers (prior to Firefox 16) */ (min-resolution: 2dppx), /* The standard way */ (min-resolution: 192dpi) /* dppx fallback */
引用https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Media_queries