前幾天我的領導“徐江”讓我把一個移動端項目做一下適配,最好讓他在家用等離子電視也能看看效果,做不出來就給我“埋了”,在這種情況下才誕生了這篇文章~
什麼是移動端適配
移動端適配是指在不同尺寸的移動端設備上,頁面能相對達到合理的顯示或者保持統一的等比縮放效果移動端適配的兩個概念自適應:根據不同的設備屏幕大小來自動調整尺寸、大小響應式:會隨着屏幕的實時變動而自動調整,是一種自適應
而在我們日常開發中自適應佈局在pc端和移動端應用都極為普遍,一般是針對不同端分別做自適應佈局,如果要想同時兼容移動端和pc端,尤其是等離子電視這樣的大屏幕,那麼最好還是使用響應式佈局~
移動端適配-視口(viewport)
在一個瀏覽器中,我們可以看到的區域就是視口(viewport),我們在css中使用的fixed定位就是相對於視口進行定位的。
在pc端的頁面中,我們不需要對視口進行區分,因為我們的佈局視口和視覺視口都是同一個。
而在移動端是不太一樣的,因為我們的移動端的網頁往往很小,有可能我們希望一個大的網頁在移動端上也可以完整的顯示,所以在默認情況下,佈局視口是大於視覺視口的。
<style>
.box {
width: 100px;
height: 100px;
background-color: orange;
}
</style>
<body>
<div class="box"></div>
</body>
pc端展示效果
移動端展示效果
從上圖可以看出在移動端上同樣是100px的盒子,但是卻沒有佔到屏幕的1/3左右的寬度,這是因為在大部分瀏覽器上,移動端的佈局視口寬度為980px,我們在把pc端的頁面切換成移動端頁面時,右上角也短暫的顯示了一下我們的佈局視口是980px x 1743px。
所以在移動端下,我們可以將視口劃分為3種情況:
- 佈局視口(layout viewport)
- 視覺視口(visual layout)
- 理想視口(ideal layout)
這些概念的提出也是來自於ppk,是一位世界級前端技術專家。
貼上大佬的文章鏈接https://quirksmode.org/mobile...
所以我們相對於980px佈局的這個視口,就稱之為佈局視口(layout viewport),而在手機端瀏覽器上,為了頁面可以完整的顯示出來,會對整個頁面進行縮小,那麼顯示在可見區域的這個視口就是視覺視口(visual layout)。
但是我們希望設置的是100px就顯示的是100px,而這就需要我們設置理想視口(ideal layout)。
// initial-scale:定義設備寬度與viewport大小之間的縮放比例
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
移動端適配方案
- 百分比設置
- rem單位+動態html的font-size
- flex的彈性佈局
- vw單位
在我們移動端適配方案中百分比設置是極少使用的,因為相對的參照物可能是不同的,所以百分比往往很難統一,所以我們常常使用的都是後面3種方案。
rem單位+動態html的font-size
rem單位是相對於html元素的font-size來設置的,所以我們只需要考慮2個問題,第一是針對不同的屏幕,可以動態的設置html不同的font-size,第二是將原來的尺寸單位都轉換為rem即可。
talk is cheap, show me the code
/*
* 方案1:媒體查詢
* 缺點:需要針對不同的屏幕編寫大量的媒體查詢,且如果動態的修改尺寸,不會實時的進行更新
*/
<style>
@media screen and (min-width: 320px) {
html {
font-size: 20px;
}
}
@media screen and (min-width: 375px) {
html {
font-size: 24px;
}
}
@media screen and (min-width: 414px) {
html {
font-size: 28px;
}
}
.box {
width: 5rem;
height: 5rem;
background-color: orange;
}
</style>
<body>
<div class="box"></div>
</body>
/*
* 方案2:編寫js動態設置font-size
*/
<script>
const htmlEl = document.documentElement;
function setRem() {
const htmlWidth = htmlEl.clientWidth;
const htmlFontSize = htmlWidth / 10;
htmlEl.style.fontSize = htmlFontSize + "px";
}
// 第一次不觸發,需要主動調用
setRem();
window.addEventListener("resize", setRem);
</script>
<style>
.box {
width: 5rem;
height: 5rem;
background-color: orange;
}
</style>
<body>
<div class="box"></div>
</body>
但是寫起來感覺還是好麻煩,如果可以的話我希望白嫖-0v0-
所以我選擇 postcss-pxtorem,vscode中也可以下載到相關插件哦,一魚多吃,😁
vw單位
/*
* 方案1:手動換算
*/
<style>
/** 設置給375的設計稿 */
/** 1vw = 3.75px */
.box {
width: 26.667vw;
height: 26.667vw;
background-color: orange;
}
</style>
/*
* 方案2:less/scss函數
*/
@vwUnit: 3.75;
.pxToVw(@px) {
result: (@px / @vwUnit) * 1vw;
}
.box {
width: .pxToVw(100) [result];
height: .pxToVw(100) [result];
background-color: orange;
}
當然白嫖黨永不言輸,我選擇 postcss-px-to-viewport,貼一下我的配置文件~
module.exports = {
plugins: {
"postcss-px-to-viewport": {
unitToConvert: "px", //需要轉換的單位,默認為"px"
viewportWidth: 750, // 視窗的寬度,對應設計稿的寬度
viewportUnit: "vw", // 指定需要轉換成的視窗單位,建議使用 vw,兼容性現在已經比較好了
fontViewportUnit: "vw", // 字體使用的視口單位
// viewportWidth: 1599.96, // 視窗的寬度,對應設計稿的寬度
// viewportUnit: 'vw', // 指定需要轉換成的視窗單位,建議使用 vw
// fontViewportUnit: 'vw', // 字體使用的視口單位
unitPrecision: 8, // 指定`px`轉換為視窗單位值的小數後 x位數
// viewportHeight: 1334, //視窗的高度,正常不需要配置
propList: ["*"], // 能轉化為 rem的屬性列表
selectorBlackList: [], //指定不轉換為視窗單位的類,可以自定義,可以無限添加,建議定義一至兩個通用的類名
minPixelValue: 1, // 小於或等於`1px`不轉換為視窗單位,你也可以設置為你想要的值
mediaQuery: false, // 允許在媒體查詢中轉換
replace: true, //是否直接更換屬性值,而不添加備用屬性
// exclude: [], //忽略某些文件夾下的文件或特定文件,例如 'node_modules' 下的文件
landscape: false, //是否添加根據 landscapeWidth 生成的媒體查詢條件 @media (orientation: landscape)
landscapeUnit: "rem", //橫屏時使用的單位
landscapeWidth: 1134 //橫屏時使用的視口寬度
}
}
};
rem單位和vw單位的區別
rem事實上是作為一個過渡方案,它利用的也是vw的思想,並且隨着前端的發展,vw的兼容性已經越來越好了,可以説具備了rem的所有優勢。
但是我們假想一個這樣的場景,我們希望網頁在達到800px的時候頁面佈局不需要繼續擴大了,這個時候如果我們採用的是rem佈局,我們可以使用媒體查詢設置max-width,而vw則始終是以視口為單位,自然不容易處理這樣的場景。
當然,vw相比於rem,存在以下優勢:
- 不需要計算font-size大小
- 不存在font-size繼承的問題
- 不存在因為某些原因篡改了font-size導致頁面尺寸混亂的問題
- vw更加的語義化
- 具備rem的所有優點
所以在開發中也更推薦大家使用vw單位進行適配。