總結5種自適應方式
特別說明:在開始這一切之前,請開發移動介面的工程師們在頭部加上下面這條meta:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
複製程式碼
一、百分比
.test{
width: 20%
}
複製程式碼
-
優點
- 程式碼簡單
-
缺點
- 需要計算,很不方便
二、media query
- 實現思路
@media screen and (min-width: 320px) and (max-width: 650px) { .class { float: left; }}
@media screen and (min-width: 650px) and (max-width: 980px) { .class { float: right; }}
@media screen and (min-width: 980px) and (max-width: 1240px) { .class { float: clear; }}
@media screen and (device-width: 640px) { html { font-size: 12px; } }
@media screen and (device-width: 750px) { html { font-size: 16px; } }
@media screen and (device-width: 1240px) { html { font-size: 20px; } }
複製程式碼
-
優點
- 僅需要寫css程式碼
-
缺點
-
靈活性不夠,取每個裝置的精確值需要自己去計算,所以只能取範圍值
-
考慮裝置螢幕眾多,解析度也參差不齊,把每一種機型的css程式碼寫出來是不太可能的
-
只能選擇幾個主流裝置呈現完美適配
-
斷層式的切換變化
-
程式碼量大
-
三、vh/vw
- 視口的解釋
在桌面端,視口指的是在桌面端,指的是瀏覽器的可視區域;而在移動端較為複雜,它涉及到三個視口:分別是 Layout Viewport(佈局視口)、 Visual Viewport(視覺視口)、Ideal Viewport。 而視口單位中的“視口”,在桌面端,毫無疑問指的就是瀏覽器的可視區域;但是在移動端,它指的則是三個 Viewport 中的 Layout Viewport 。
- 視口單位主要包括以下4個:
- vw : 1vw 等於視口寬度的1%
- vh : 1vh 等於視口高度的1%
- vmin : 選取 vw 和 vh 中最小的那個
- vmax : 選取 vw 和 vh 中最大的那個
- 視口和%單位的區別:
視口單位區別於%單位,視口單位是依賴於視口的尺寸,根據視口尺寸的百分比來定義的;
%單位則是依賴於元素的祖先元素。
單位度量,視口寬度為100vw,高度為100vh(左側為豎屏情況,右側為橫屏情況)
例如,在桌面端瀏覽器視口尺寸為650px,那麼 1vw = 650 * 1% = 6.5px(這是理論推算的出,如果瀏覽器不支援0.5px,那麼實際渲染結果可能是7px)。
方法1:僅使用vw作為CSS單位
- 在僅使用 vw 單位作為唯一應用的一種 CSS 單位的這種做法下,我們遵守:把設計稿的尺寸轉換為vw單位
//iPhone 6尺寸作為設計稿基準
$vm_base: 375;
@function vw($px) {
@return ($px / 375) * 100vw;
}
複製程式碼
- 無論是文字還是佈局高寬、間距等都使用 vw 作為 CSS 單位
.test {
padding: vm(15) vm(10) vm(10);
font-size: vm(10);
}
複製程式碼
- 物理畫素線(也就是普通螢幕下 1px ,高清螢幕下 0.5px 的情況)採用 transform 屬性 scale 實現。
.test {
position: relative;
&::after {
// 實現1物理畫素的下邊框線
content: '';
position: absolute;
z-index: 1;
pointer-events: none;
background-color: #ddd;
height: 1px;
left: 0;
right: 0;
top: 0;
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
-webkit-transform: scaleY(0.5);
-webkit-transform-origin: 50% 0%;
}
}
...
}
複製程式碼
- 對於需要保持高寬比的圖,用 padding-top 實現
.test {
position: relative;
padding-top: percentage(100/700); // 使用padding-top
height: 0; //這個不能省
overflow: hidden;
img {
width: 100%;
height: auto;
position: absolute;
left: 0;
top: 0;
}
}
複製程式碼
疑問插播:
- 當margin-top、padding-top的值是百分比時,分別是如何計算的?
不管是margin-top/margin-bottom還是margin-left/margin-right(padding一樣),百分數是相對最近父級塊級元素的width計算
- 為什麼margin-top/margin-bottom的百分數也是相對於width而不是height呢?
CSS權威指南中的解釋:
正常流中的大多數元素都會足夠高以包含其後代元素(包括外邊距),如果一個元素的上下外邊距時父元素的height的百分數,就可能導致一個無限迴圈,父元素的height會增加,以適應後代元素上下外邊距的增加,而相應的,上下外邊距因為父元素height的增加也會增加,這樣就無限迴圈。
- 一般使用padding-top:(percentage)實現響應式背景圖片,實現的基本原理?
實現的基本原理:利用百分比,保持元素的寬高比的技巧
比如一張圖片的寬度是1024px,高度為316px;那麼現在的 padding-top = (高度 / 寬度 )* 100% = (316 / 1024)* 100% = 30.85%;
<div class="wrap">
<div class="inner"></div>
</div>
.wrap{
max-width: 1024px;
}
.inner {
padding-top:30.85%; /* 316 / 1024 */
background: url("http://images2015.cnblogs.com/blog/561794/201603/561794-20160310002800647-50077395.jpg") no-repeat;
background-size:cover;
background-position:center; //IE8及以下不支援background-size:cover屬性,為了相容IE下面的瀏覽器
}
複製程式碼
方法一實現的頁面雖然看起來適配得很好,但是你會發現由於它是利用視口單位實現的佈局,依賴於視口大小而自動縮放,無論視口過大還是過小,它也隨著視口過大或者過小,失去了最大最小寬度的限制,所以考慮結合rem來實現。
方法2:搭配vw和rem,佈局更優化
- 給根元素大小設定隨著視口變化而變化的 vw 單位,這樣就可以實現動態改變其大小。
- 限制根元素字型大小的最大最小值,配合 body 加上最大寬度和最小寬度
// rem 單位換算:定為 75px 只是方便運算,750px-75px、640-64px、1080px-108px,如此類推
$vm_fontsize: 75; // iPhone 6尺寸的根元素大小基準值
@function rem($px) {
@return ($px / $vm_fontsize ) * 1rem;
}
// 根元素大小使用 vw 單位
$vm_design: 750;
html {
font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw;
// 同時,通過Media Queries 限制根元素最大最小值
@media screen and (max-width: 320px) {
font-size: 64px;
}
@media screen and (min-width: 540px) {
font-size: 108px;
}
}
// body 也增加最大最小寬度限制,避免預設100%寬度的 block 元素跟隨 body 而過大過小
body {
max-width: 540px;
min-width: 320px;
}
複製程式碼
相對於法一,個人比較推崇法二,有以下兩點原因: 第一,法二相對來說使用者視覺體驗更好,增加了最大最小寬度的限制; 第二,更重要是,如果選擇主流的rem彈性佈局方式作為專案開發的適配頁面方法,那麼法二更適合於後期專案從 rem 單位過渡到 vw 單位。只需要通過改變根元素大小的計算方式,你就可以不需要其他任何的處理,就無縫過渡到另一種CSS單位,更何況vw單位的使用必然會成為一種更好適配方式,目前它只是礙於相容性的支援而得不到廣泛的應用。
方法3:搭配vw和vh
一屏的時候可以同時使用vw和vh作為css單位設定文字、佈局高寬、間距、
-
優點
- 體驗好,純css
-
缺點
- 相容性不好 (在移動端 iOS 8 以上以及 Android 4.4 以上獲得支援,在微信 x5 核心中得到支援)
四、rem
rem屬性指的是相對於根元素設定某個元素的字型大小。它同時也可以用作為設定高度等一系列可以用px來標註的單位。
- 實現思路
假設我們UI設計的標準是iphone5s,iphone5系列的螢幕解析度是640。為了統一規範,我們將iphone5 解析度下的根元素font-size設定為100px;
html {
font-size: 100px;
}
複製程式碼
那麼以此為基準,可以計算出一個比例值6.4。我們可以得知其他手機解析度的裝置下根元素字型大小,需要考慮到如果是移動裝置,螢幕會有一個上下限制,可以控制解析度在某個範圍內,超過了該範圍,我們就不再增加根元素的字型大小:
var deviceWidth = document.documentElement.clientWidth > 1300 ? 1300 : document.documentElement.clientWidth;
document.documentElement.style.fontSize = (deviceWidth / 6.4) + 'px';
考慮到,如果轉屏
window.onresize = _.debounce(function() { var deviceWidth = document.documentElement.clientWidth > 1300 ? 1300 : document.documentElement.clientWidth;
document.documentElement.style.fontSize = (deviceWidth / 6.4) + 'px';}, 50);
複製程式碼
在head中,我們將以上程式碼加入,動態地改變根節點的font-size值。
如果是320解析度裝置,1px的邊框會被壓縮成0.5px,可以為不同的裝置設定不同的meta
所以最終程式碼為
<meta name="viewport" content="width=device-width,user-scalable=no,maximum-scale=1" />
<script type="text/javascript">
(function() {
// deicePixelRatio :裝置畫素
var scale = 1 / devicePixelRatio;
//設定meta 壓縮介面, 模擬裝置的高解析度 (淘寶和網易新聞的手機web端就是採用的是這種方式)
document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
//為提高效能,增加節流函式
var reSize = _.debounce(function() {
var deviceWidth = document.documentElement.clientWidth > 1300 ? 1300 : document.documentElement.clientWidth;
//按照640畫素下字型為100px的標準來,得到一個字型縮放比例值 6.4
document.documentElement.style.fontSize = (deviceWidth / 6.4) + 'px';
}, 50);
window.onresize = reSize;
})();
</script>
<style type="text/css">
html {
height: 100%;
width: 100%;
overflow: hidden;
font-size: 16px;
}
複製程式碼
-
優點
- 不需要在不同的螢幕下調整樣式 (不額外增加css程式碼)
-
缺點
- 改html中script引數容易影響全域性
- 需要內嵌一段指令碼去動態計算根元素大小,使得css和js耦合在一起
五、彈性佈局flexbox
容器幾個重要屬性:
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
複製程式碼
專案的屬性:
order
flex-grow
flex-shrink
flex-basis
flex
align-self
複製程式碼
注:
order屬性定義專案的排列順序。數值越小,排列越靠前,預設為0。
flex-grow屬性定義專案的放大比例,預設為0,即如果存在剩餘空間,也不放大。
flex-shrink屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小。
flex-basis屬性定義了在分配多餘空間之前,專案佔據的主軸空間(main size)。瀏覽器根據這個屬性,計算主軸是否有多餘空間。它的預設值為auto,即專案的本來大小。
flex屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,預設值為0 1 auto。後兩個屬性可選。
align-self屬性允許單個專案有與其他專案不一樣的對齊方式,可覆蓋align-items屬性。預設值為auto,表示繼承父元素的align-items屬性,如果沒有父元素,則等同於stretch。
詳細請看佈局教程
-
優點:
- 介面所有的元素大小和高度都會根據不同解析度和螢幕寬度的裝置來調整元素、字型、圖片、高度等屬性的值。簡單來說就是在不同的螢幕下,你看到的字型和元素高寬度的大小是不一樣的。
儘管以上多種適配方式,但是如果螢幕跨度太大,可能不僅僅是改變樣式,而需要重新設計頁面佈局。工作中根據場景選取相應方式。
總結
在此總結幾個關鍵的點:
5種自適應方式:
- 百分比
- vm/vh
- flexbox
- media
- rem
物理畫素線(普通螢幕下 1px ,高清螢幕下 0.5px 的情況)解決辦法:
- 可採用 transform 屬性 scale 實現
- rem方式中可設定meta
document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
複製程式碼
不管是margin-top/margin-bottom還是margin-left/margin-right(padding一樣),百分數是相對最近父級塊級元素的width計算。
一般使用padding-top:(percentage)實現響應式背景圖片。
當控制在1屏時候,可以結合使用vw和vh作為CSS單位
參考