簡單粗暴的移動端適配方案 - REM

本文轉載自 IMWeb前端博客

作者/孫世吉

鏈接:簡單粗暴的移動端適配方案 - REM

0. 前言

手機市場日漸豐富的同時,給我們前端開發人員帶來的網頁內容自適應屏幕尺寸進行顯示的問題也日漸凸顯出來。原本可能通過百分比/媒體查詢等簡單手段就可以常見的適配問題,但是對於頁面有複雜結構或者視覺上有特殊要求的,就需要通過其他手段來解決了。

以上圖「紀念碑谷」效果為例:

當你的頁面素材都是單獨的圖片資源時,你完全可以通過百分比計算出每個動態小人的大小/位置/動畫距離等信息;但是當所有的小圖都被拼接成一張大的雪碧圖時,當時我就眉頭一皺,事情沒有這麼簡單,元芳不知道你怎麼看。

1. 老版常規做法

1.1 viewport縮放

以最小的Iphone4/5的寬度(320px)為基準,還原視覺稿。

<meta name="viewport" content="width_=device-width, user-scalable=no, initial-scale=1.0 />

然後對不同屏幕解析度的手機進行簡單粗暴的等比例縮放設置。 例如:iphone8(375px)initial-scale = 375 / 320 = 1.18

<meta name="viewport" content="width_=device-width, user-scalable=no, initial-scale=1.18 />

據說早期天貓首頁就是這麼乾的,有一定工作年限的開發者應該有了解。initial-scale越來越大,頁面內容也就被拉伸也越厲害,導致頁面內容會變得模糊,這個方法已經被摒棄了。

1.2 固定寬度進行留白

早期有部分網站把頁面固定死寬度,但是多餘的寬度進行居中留白。這對於前端開發就開心了,什麼適配都不用管,外部寬度就是牛逼的320px。典型的墨守成規、因循守舊、故步自封、抱殘守缺做法,放在現在各種「大屏手機」上,用戶量恐怕要分分鐘損失80%。

1.3 響應式布局

通過媒體查詢根據不同的屏幕解析度來進行適配,響應式的問題在於:

  • 屏幕解析度分區間:區間內無法進行區分,無法實現100%兼容,一般是用主流解析度來進行劃分;
  • 額外的工作量:響應式布局的工作都是需要開發者去實現的,帶來了額外的開放量;
  • 不適合功能複雜的頁面:響應式一般適合用於資訊類頁面,功能複雜的網站對於頁面的整體排版和樣式要求較高(特別是對比PC和H5);

對比三種做法我們會發現只有響應式布局可以解決我們的問題,但是又給我們帶來了額外的複雜度和維護難度。那有沒有什麼方式可以一鍵解決我們的問題呢?

2. rem

在W3C官網上是這樣描述rem的——「font size of the root element」 。

換句話說,當我們指定一個元素的font-size為2rem的時候,也就說這個元素的字體大小為根元素<html>字體大小的兩倍,如果html的font-size為12px,那麼這個2rem的元素font-size就是24px。同理當該元素為3rem時,那麼其實際font-size就是36px

html {font-size: 12px;}h1 { font-size: 2rem; } /* 2 × 12px = 24px */p { font-size: 1.5rem;} /* 1.5 × 12px = 18px */div {width: 20rem;} /* 20 * 12px = 240px*/html {font-size: 16px;}h1 { font-size: 2rem; } /* 2 × 16px = 32px */p { font-size: 1.5rem;} /* 1.5 × 16px = 24px */div {width: 20rem;} /* 20 * 16px = 320px*/

看到這裡你應該就會發現,只要我們根據不同屏幕設定好根元素<html>的font-size,其他已經使用了rem單位的元素就會自適應顯示相應的尺寸了。

對比em和rem:

雖然em帶來了模塊化的好處,但是由於 em 是相對於父元素的倍數,所以你可能在許多層嵌套的 em 中找不到一個固定值,rem 就是可以隨時拿來用的一個固定參考值。關於二者的對比就不在這裡展開了,感興趣的同學可以參考這篇文章 rem-vs-em。

3. rem計算

細心的同學就會發現了,我們使用rem單位事先需要做的一件事情就是設置根元素<html>的font-size,通常有兩種做法。

3.1 JS計算

通過JavaScript讀取屏幕寬度,然後根據寬度計算出對應的尺寸並設置根元素的font-size。

const oHtml = document.getElementsByTagName(html)[0]const width = oHtml.clientWidth;// 320px的屏幕基準像素為12pxoHtml.style.fontSize = 12 * (width / 320) + "px";

這樣iphone8(375px)下html的font-size 就是14.0625px,iphone8p下font-size就是15.525px。

如果在iphone8(375px)下設置元素font-size為 1.7066rem, 效果跟設置其font-size為 24px 是一樣的(24 / 14.0625 = 1.7066)。

上面的示例是個很簡單的例子,感興趣的同學可以在自己的頁面上試一下或者開發者工具下打開 淘寶觸屏版,使用rem設置元素的樣式,並通過開發者工具切換模擬機型觀察頁面效果。

使用JS來獲取屏幕寬度的好處在於可以100%適配所有的機型寬度,因為其<html>元素的基準尺寸是直接算出來的。既然是JS代碼,為了避免造成因為動態設置<html>元素的font-size而造成頁面抖動,一般這部分代碼我們放在header底部去載入,並內聯到html文檔裡面。

更加詳細的實現,感興趣的同學可以看這片文章:Rem自適應js-優化flexible.js。

3.2 媒體查詢

既然只是為了根據屏幕寬度來設置<html>元素的字體大小,那我們完全也可以通過css3媒體查詢來完成這部分工作。

@media screen and (min-width: 375px){ html { font-size: 14.0625px; }}@media screen and (min-width: 360px){ html { font-size: 13.5px; }}@media screen and (min-width: 320px){ html { font-size: 12px; }}html { font-size: 16px;}

像蘇寧易購等網站就是這麼做的:

4. rem存在的問題

rem作為一種簡單粗暴解決不同屏幕下視圖的區別的一種方案,它可以解決本文出現的問題以及絕大多數移動端適配屏幕尺寸的問題。但是既然它並不是一個完美的解決方案,那就有其局限性所在。

舉個例子: 作者有一大愛好是看小說,大屏智能機時代確實幾乎完全替代了我十年前紙質化閱讀的習慣。從2011年至今,手上的手機屏幕寬度一直在提升,但是使用的看小說軟體的顯示字型大小几乎是不變的。使用rem會在一定程度上打破用戶的文字內容閱讀習慣,特別是在大篇幅的內容時。

iOS與Android平台的適配方式背後隱藏的設計哲學是這樣的:閱讀文字時,可讀性較好的文字字型大小行距等絕對尺寸數值組合與文字所在媒介的絕對尺寸關係不大。(可以這樣簡單理解:A4大小的報紙和A3大小甚至更大的報紙,舒適的閱讀字型大小絕對尺寸是一樣的,因為他們都需要拿在手裡閱讀,在手機也是上同理);在看圖片視頻時,圖片、視頻的比例應該是固定的,不應該出現拉伸變形的情況。而rem用在字型大小時,使字型大小在不同屏幕上的絕對尺寸不一致,違背了設計哲學。

大家感興趣還可以移步結一老師的文章:rem不是神農草,治不了移動端百病。

5. 工程應用

我們平時使用rem還有遇到的一大問題就是我們習慣使用px來定義樣式,而px到rem是需要計算轉化過程的,剛接觸rem的時候你可能需要px先定義好頁面布局,然後一個一個計算並替換rem單位。

當然我們有更加科學的方式來使用rem單位。

5.1 px轉rem網頁工具

你可以前往px轉rem工具,輕鬆一鍵上傳你的css文件讓這個網頁工具幫你完成計算和替換。

5.2 mixin

1、rem

輸入:

.element { @include rem(padding,10px 0 2px 5px);}

輸出:

.element { padding: 10px 0 2px 5px; padding: 1rem 0 0.2rem 0.5rem;}

2、sass-rem

輸入:

.demo { font-size: rem(24px); // Simple padding: rem(5px 10px); // Multiple values border-bottom: rem(1px solid black); // Multiple mixed values box-shadow: rem(0 0 2px #ccc, inset 0 0 5px #eee); // Comma-separated values text-shadow: rem(1px 1px) #eee, rem(-1px) 0 #eee; // Alternate use}

輸出:

.demo { font-size: 1.5rem; padding: 0.3125rem 0.625rem; border-bottom: 0.0625rem solid black; box-shadow: 0 0 0.125rem #ccc, inset 0 0 0.3125rem #eee; text-shadow: 0.0625rem 0.0625rem #eee, -0.0625rem 0 #eee;}

5.3 構建

作為工程化的今天,我們同樣有大量的構建插件來幫助我們自動完成px單位到rem單位的轉換過程:

  • fis3: fis3-postprocessor-px2rem
  • gulp stylus-px2rem
  • webpack px-to-rem-loader

更多插件

6. 更多

更多內容可以參考 rem 入門精通教程_w3cplus


由IMWeb核心成員操刀的前端NEXT學位課程第五期招生火熱進行中!

感興趣的小夥伴快點擊這裡,了解課程詳情吧!

更多內容請關注公眾號【騰訊NEXT學位】!


推薦閱讀:

前端每周清單第11期:Angular 4.1支持TypeScript 2.3,Vue 2.3優化服務端渲染,優秀 React 界面框架合集
寫了一段jQuery代碼,發現引入bootstrap.css代碼就有BUG,刪除就OK,什麼原因?
前端工程師和網頁重構工程師二者有什麼區別和聯繫?
為什麼前端工程師很少用 Visual Studio (Windows)?
前端開發工程師如何給自己取個高大上的Title?

TAG:前端开发 | 前端工程师 | 前端框架 |