大家都不看的總集篇: 從零開始的大前端築基之旅(深刻淺出,持續更新~)
以爲不錯就點個贊吧~javascript
目前多端運行的項目愈來愈多,設計師對於UI的要求也愈來愈高。css
設計師:你這字體大小不太對html
工具人:你看代碼,就是16px前端
設計師:確實跟設計稿不一致(拿出iphone 11 max)java
工具人:我通常稱這種狀況爲 有錢人的煩惱(拿出5寸安卓)git
設計師:好吧github
請原諒工具人吧。web
在高清屏
下,不少設計稿上的參數就不能像web同樣直接拿來用了,不論是H5頁面仍是RN應用,都須要進行下適配。例如,一樣是1px,移動端的1px 就會顯得很粗。瀏覽器
那麼爲何會產生這個問題呢?主要是跟一個東西有關,DPR(devicePixelRatio) 設備像素比,它是默認縮放爲100%的狀況下,設備像素和CSS像素的比值。簡單地說,這告訴瀏覽器應該使用多少個屏幕的實際像素來繪製單個 CSS 像素。app
還有一個因素也會引發css中px的變化,那就是用戶縮放。例如,當用戶把頁面放大一倍,那麼css中1px所表明的物理像素也會增長一倍;反之把頁面縮小一倍,css中1px所表明的物理像素也會減小一倍。
value = window.devicePixelRatio;
複製代碼
在早先的移動設備中,屏幕像素密度都比較低,如iphone3,它的分辨率爲320x480,在iphone3上,一個css像素確實是等於一個屏幕物理像素的。後來隨着技術的發展,移動設備的屏幕像素密度愈來愈高,從iphone4開始,蘋果公司便推出了所謂的Retina屏,分辨率提升了一倍,變成640x960,但屏幕尺寸卻沒變化,這就意味着一樣大小的屏幕上,像素卻多了一倍,這時,一個css像素是等於兩個物理像素的。
既然1px表明2像素,那用0.5px 不就完美了麼
在 WWDC大會上,給出了1px方案,當寫 0.5px的時候,就會顯示一個物理像素寬度的 border。
retina 屏的瀏覽器可能不認識0.5px的邊框,將會把它解釋成0px,沒有邊框。包括 iOS 7 和 以前版本,OS X Mavericks 及之前版本,還有 Android 設備。
經過 JavaScript 檢測瀏覽器可否處理0.5px的邊框,若是能夠,給<html>
元素添加個class
。
if (window.devicePixelRatio && devicePixelRatio >= 2) {
var testElem = document.createElement('div');
testElem.style.border = '.5px solid transparent';
document.body.appendChild(testElem);
if (testElem.offsetHeight == 1)
{
document.querySelector('html').classList.add('hairlines');
}
document.body.removeChild(testElem);
}
複製代碼
而後,極細的邊框樣式就容易了:
div {
border: 1px solid #bbb;
}
.hairlines div {
border-width: 0.5px;
}
複製代碼
順便踩了一腳其餘的解決方案。原文:
unlike previous solutions involving SVG or GIF or transforms or linear-gradient1, you can have retina hairlines on elements with rounded corners (border-radius).
對於不支持的設備:
This is supported by most desktop browsers, and now by Safari 8 on both iOS and OS X. Chrome on Android is a notable absent, but no doubt it will eventually follow suit. When a browser doesn’t support it, it just displays a regular border. No big deal.
6x6 的 一張圖片
能夠用 gif,png,或 base64 圖片
.border{
border-width: 1px;
border-image: url(border.gif) 2 repeat;
}
複製代碼
缺點是改邊框顏色時要改圖片,不是很方便。
設置1px的漸變背景,50%有顏色,50%透明,可是沒法實現圓角
.border {
background:
linear-gradient(180deg, black, black 50%, transparent 50%) top left / 100% 1px no-repeat,
linear-gradient(90deg, black, black 50%, transparent 50%) top right / 1px 100% no-repeat,
linear-gradient(0, black, black 50%, transparent 50%) bottom right / 100% 1px no-repeat,
linear-gradient(-90deg, black, black 50%, transparent 50%) bottom left / 1px 100% no-repeat;
}
複製代碼
結合 JS 代碼,判斷是否 Retina 屏
if(window.devicePixelRatio && devicePixelRatio >= 2){
document.querySelector('ul').className = 'hairlines';
}
複製代碼
把原先元素的 border 去掉,而後利用 :before
或者 :after
重作 border ,並 transform 的 scale 縮小一半。原先的元素相對定位,新作的 border 絕對定位
若是是上下邊框,scaleY 設置爲0.5,左右邊框 scaleX 設置爲0.5
.hairlines li{
position: relative;
border:none;
}
.hairlines li:after{
content: '';
position: absolute;
left: 0;
background: #000;
width: 100%;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
複製代碼
能夠支持圓角,可是 <td>
用不了。
上面三種方法與最開始的相似,既然1個css像素表明兩個物理像素,設備又不認0.5px
的寫法,那就畫1px,而後再想盡各類辦法將線寬減小一半。
var viewport = document.querySelector("meta[name=viewport]");
//下面是根據設備像素設置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.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no');
}
// 設置對應viewport的rem基準值
var docEl = document.documentElement;
var fontsize = 16* (docEl.clientWidth / 375) + 'px';
docEl.style.fontSize = fontsize;
複製代碼
說到viewport,就不得不詳細聊聊它了。
下面內容來自參考文檔4
移動設備上的viewport就是設備的屏幕上用來顯示咱們的網頁的那一塊區域,但viewport又不侷限於瀏覽器可視區域的大小。ppk把移動設備上的viewport分爲layout viewport 、 visual viewport 和 ideal viewport 三類,
爲了能在移動設備上正常顯示那些傳統的爲桌面瀏覽器設計的網站,移動設備上的瀏覽器都會把本身默認的viewport設爲980px或1024px。但帶來的後果就是瀏覽器會出現橫向滾動條。咱們把這個瀏覽器默認的viewport叫作 layout viewport,經過 document.documentElement.clientWidth
來獲取
桌面瀏覽器中css的1個像素每每都是對應着電腦屏幕的1個物理像素,但css中的像素只是一個抽象的單位,在不一樣的設備或不一樣的環境中,css中的1px所表明的設備物理像素是不一樣的。
如今有不少手機分辨率都很是大,好比768x1024,或者1080x1920這樣。但css中的1px並非表明屏幕上的1px,你分辨率越大,css中1px表明的物理像素就會越多,devicePixelRatio的值也越大。由於你分辨率增大了,但屏幕尺寸並無變大多少,必須讓css中的1px表明更多的物理像素,才能讓1px的東西在屏幕上的大小與那些低分辨率的設備差很少,否則就會由於過小而看不清。
把表明瀏覽器可視區域的大小viewport叫作 visual viewport。visual viewport的寬度能夠經過window.innerWidth
來獲取。
最後有一個能完美適配移動設備的viewport。所謂的完美適配指的是,
這個viewport叫作 ideal viewport,也就是第三個viewport——移動設備的理想viewport。
移動設備默認的viewport是layout viewport,咱們須要的是ideal viewport。這時候輪到meta標籤出場了。
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
複製代碼
該meta標籤的做用是讓當前viewport的寬度等於設備的寬度,同時不容許用戶手動縮放。
meta viewport 有6個屬性:
要獲得ideal viewport就必須把默認的layout viewport的寬度設爲移動設備的屏幕寬度。由於meta viewport中的width能控制layout viewport的寬度,因此咱們只須要把width設爲width-device這個特殊的值就好了。
<meta name="viewport" content="width=device-width">
複製代碼
在iphone和ipad上,僅設置
content="width=device-width"
,不管是豎屏仍是橫屏,寬度都是豎屏時ideal viewport的寬度。
<meta name="viewport" content="initial-scale=1">
複製代碼
這句代碼也能達到和前一句代碼同樣的效果,也能夠把當前的的viewport變爲 ideal viewport。
縮放是相對於 ideal viewport來進行縮放的,當對ideal viewport進行100%的縮放,也就是縮放值爲1的時候,就獲得了 ideal viewport。所以,默認的 initial-scale 不是1
僅設置
content="
initial-scale=1"
,phone、ipad以及IE 會橫豎屏不分,統統以豎屏的ideal viewport寬度爲準。推薦二者都寫
縮放是相對於ideal viewport來縮放的,縮放值越大,當前viewport的寬度就會越小,反之亦然。例如在iphone中,ideal viewport的寬度是320px,若是咱們設置 initial-scale=2 ,此時viewport的寬度會變爲只有160px了。
縮放2倍是在實際寬度不變的狀況下,1px變得跟原來的2px的長度同樣了.因此放大2倍後原來須要320px才能填滿的寬度如今只須要160px就作到了
visual viewport寬度 = ideal viewport寬度 / 當前縮放值
複製代碼
好了,如今回到1px問題上。
每一個移動設備瀏覽器中都有一個理想的寬度,這個理想的寬度是指css中的寬度,跟設備的物理寬度沒有關係,在css中,這個寬度就至關於100%的所表明的那個寬度。咱們能夠用meta標籤把viewport的寬度設爲那個理想的寬度,若是不知道這個設備的理想寬度是多少,那麼用device-width這個特殊值就好了
如一個分辨率爲320x480的手機理想viewport的寬度是320px,而另外一個屏幕尺寸相同但分辨率爲640x960的手機的理想viewport寬度也是爲320px。可是對於後者,1個css像素會用2個物理像素來顯示
所以,對於window.devicePixelRatio = 2
的屏幕,經過設置
viewport.setAttribute('content', 'width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no');
複製代碼
將1px變得跟原來0.5px同樣,就實現來css中1px 對應屏幕1px 了。
相對的,假如本來320px能夠填滿屏幕的話,如今須要640px才能填滿屏幕了,所以改變viewport時會同步使用rem做爲像素單位。由於rem是相對大小,只與根元素
font-size
的值有關
若是你收穫了新知識,或者收穫了左側精美圖片,請點個贊吧~
一個贊頂100閱讀量,告訴我你曾來過、看過,並在這裏不枉此行吧!!
相關係列: 從零開始的大前端築基之旅(深刻淺出,持續更新~)
參考文檔: