物理像素[設(shè)備像素] & 邏輯像素[CSS 像素]
背景
拿2倍屏來(lái)說(shuō)环鲤,設(shè)備的物理像素要實(shí)現(xiàn)1像素温数,而DPR=2古徒,所以css 像素只能是 0.5爆雹。一般設(shè)計(jì)稿是按照750來(lái)設(shè)計(jì)的性穿,它上面的1px是以750來(lái)參照的勺三,而我們寫css樣式是以設(shè)備375為參照的,所以我們應(yīng)該寫的0.5px就好了靶柙吗坚! 試過(guò)了就知道,iOS 8+系統(tǒng)支持呆万,安卓系統(tǒng)不支持商源。
在瀏覽器中無(wú)法設(shè)置小于 1px 的邊框 設(shè)置了也不會(huì)生效
為什么 1px 變粗了
設(shè)計(jì)師要求的 1px 是指設(shè)備的物理像素 1px,而 CSS 里記錄的像素是邏輯像素谋减,它們之間存在一個(gè)比例關(guān)系牡彻,可以用 javascript 中的 window.devicePixelRatio 來(lái)獲取。當(dāng)然逃顶,比例多少與設(shè)備相關(guān)讨便。
移動(dòng)端開(kāi)發(fā)常需要在 html 的 header 里添加如下一句:
? <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
設(shè)備像素比 = 物理像素 / css 像素
如何解決
核心思想就是設(shè)置 1px 大小 然后將 1px 縮小為 0.5px 來(lái)展示
- 媒體查詢利用設(shè)備像素比縮放充甚,設(shè)置小數(shù)像素
IOS8 下已經(jīng)支持帶小數(shù)的 px 值, media query 對(duì)應(yīng) devicePixelRatio 有個(gè)查詢值-webkit-min-device-pixel-ratio, css 可以寫成這樣
.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 }
}
【缺點(diǎn)】對(duì)設(shè)備有要求,小數(shù)像素目前兼容性較差霸褒。
- transform: scale(0.5) 方案 推薦
- 設(shè)置 height: 1px伴找,根據(jù)媒體查詢結(jié)合 transform 縮放為相應(yīng)尺寸。
div {
height:1px;
background:#000;
-webkit-transform: scaleY(0.5);
-webkit-transform-origin:0 0;
overflow: hidden;
}
- 用::after 和::befor,設(shè)置 border-bottom:1px solid #000,然后在縮放-webkit-transform: scaleY(0.5);可以實(shí)現(xiàn)兩根邊線的需求
div::after{
content:'';
width:100%;
border-bottom:1px solid #000;
transform: scaleY(0.5);
}
pixel-border.css 這個(gè)工具庫(kù)就是用來(lái)解決移動(dòng)端 1px 邊框的問(wèn)題废菱,用到的思想和我下面寫的一致
.one-pixel-border::before {
display: block;
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 200%;
height: 200%;
border: 1px solid red;
transform: translate(-50%, -50%) scale(0.5, 0.5);
}
pixel-border.css
/**
* version:0.0.1
* https://github.com/JofunLiang/pixel-border
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*/
:root {
--pixel-border-dpr: 1;
}
@media screen and (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
:root {
--pixel-border-dpr: 2;
}
}
@media screen and (-webkit-min-device-pixel-ratio: 3), (min-resolution: 3dppx) {
:root {
--pixel-border-dpr: 3;
}
}
@media screen and (-webkit-min-device-pixel-ratio: 4), (min-resolution: 4dppx) {
:root {
--pixel-border-dpr: 4;
}
}
[pixel-border],
[pixel-border=true] {
position: relative;
border-width: 0;
box-sizing: border-box;
}
[pixel-border]::before,
[pixel-border=true]::before {
--scale: calc(1 / var(--pixel-border-dpr));
--size: calc(var(--pixel-border-dpr) * 100%);
content: '';
pointer-events: none;
display: block;
box-sizing: inherit;
position: absolute;
top: 50%;
left: 50%;
width: var(--size);
height: var(--size);
border: inherit;
border-width: 1px;
border-image: inherit;
border-radius: inherit;
transform: translate(-50%, -50%) scale(var(--scale), var(--scale));
}
- viewport + rem 方案
該方案是對(duì)上述方案的優(yōu)化技矮,整體思路就是利用 viewport + rem + js 動(dòng)態(tài)的修改頁(yè)面的縮放比例,實(shí)現(xiàn)小于 1 像素的顯示殊轴。在頁(yè)面初始化時(shí)衰倦,在頭部引入原始默認(rèn)狀態(tài)如下:
<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">
接下來(lái)的任務(wù)就是 js 的動(dòng)態(tài)修改縮放比 以及 實(shí)現(xiàn) rem 根元素字體大小的設(shè)置。
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;
// 320指的是我們以寬度為320的設(shè)備作為依據(jù) iPhone 5/SE旁理,這樣設(shè)置的 1rem 就是 20px 為的就是比較好計(jì)算
// 比如說(shuō) iphone 6/7/8的寬度是 375 那么這里我們就可以設(shè)置為 375 然后我們的 1rem 在這個(gè)設(shè)備上就是 20px (CSS像素)但是一般給的
// 設(shè)計(jì)稿都是 物理像素 也就是CSS像素 * 設(shè)備像素比(一般是2)
var fontsize = 20 * (docEl.clientWidth / 320) + 'px';
docEl.style.fontSize = fontsize;
【缺點(diǎn)】以為縮放涉及全局的 rem 單位樊零,比較適合新項(xiàng)目,對(duì)于老項(xiàng)目可能要涉及到比較多的改動(dòng)孽文。
- 在iOS下驻襟,你可以這樣寫
border:0.5px solid #E5E5E5
可能你會(huì)問(wèn)為什么在3倍屏下,不是0.3333px 這樣的芋哭?經(jīng)過(guò)我測(cè)試沉衣,在Chrome上模擬iPhone 8Plus,發(fā)現(xiàn)小于0.46px的時(shí)候是顯示不出來(lái)减牺。