移動端適配+響應式佈局+從設計圖到CSS(rem+viewport+媒體查詢+Sass)
轉自:https://www.cnblogs.com/gymmer/p/6883063.html
根據UI圖對移動端的h5頁面做樣式重構,是前端工程師的本職工作,看似簡單,不過想做好卻並不容易。下面總結一下其中要點。
rem
rem是一種相對長度單位,參考的基準是<html>
標籤定義的font-size
。比如:
html {
font-size: 16px;
}
.intro {
font-size: 1.2rem;
margin-top: 0.2rem;
}
那麼實際效果就是:
.intro { font-size: 16px * 1.2rem = 19.2px; margin-top: 16px * 0.2rem = 3.2px; }
viewport
做移動端的h5,通常會在HTML檔案中指定一個<meta>
標籤:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximun-scale=1.0, user-scalable=no">
關於Viewport,可以參考更專業的教程:
媒體查詢
手機螢幕的解析度越來越高,比如iPhone 5為640*1136 px
、iPhone 6/6S為750*1334 px
。我拿到的UI圖,其參考解析度為1440*2560 px
。
而在寫CSS時,通常是以螢幕寬度為參考的。開啟Chrome的響應式設計工具,就可以看到各種裝置的螢幕寬度,比如iPhone 5的螢幕寬度是320*568 px
375*667 px
。解析度和螢幕寬度之間,是有一個倍屏係數換算的。設計師給了一張寬為1440px的UI圖,而做不同裝置的適配,就是前端工程師的職責了。
比如UI圖上標註了某個段落的字型大小為64px。為了保證在各種螢幕上的不失真,就要根據實際螢幕寬度做等比例換算,才能寫進CSS,即滿足:
寫入CSS的尺寸/螢幕寬度 = UI圖標註的尺寸/UI圖寬度
因此:
寫入CSS的尺寸 = UI圖標註的尺寸/UI圖寬度*螢幕寬度
比如上例,當標註尺寸為64px、UI圖寬度為1440px時,針對不同螢幕寬度,寫入CSS的屬性分別為:
- 螢幕寬度320px:
font-size: 64/1440*320 = 14.22px
- 螢幕寬度360px:
font-size: 64/1440*360 = 16px
- 螢幕寬度375px:
font-size: 64/1440*375 = 16.67px
- ...
- 螢幕寬度1440px:
font-size: 64/1440*1440 = 64px
於是自然想到媒體查詢:
@media (min-width: 320px) {
p.intro {
font-size: 14.22px;
}
}
@media (min-width: 360px) {
p.intro {
font-size: 16px;
}
}
@media (min-width: 375px) {
p.intro {
font-size: 16.67px;
}
}
@media (min-width: 1440px) {
p.intro {
font-size: 64px;
}
}
天啊,如果這樣寫,如果UI圖上標註了另一個段落的字型大小為60px
,豈不又要寫一遍媒體查詢!
解決方法是,在<html>
標籤上只做一次媒體查詢,而在p.intro
上使用rem單位。
// 對html做媒體查詢,定義基準的font-size
@media (min-width: 320px) {
html {
font-size: 14.22px;
}
}
@media (min-width: 360px) {
html {
font-size: 16px;
}
}
@media (min-width: 375px) {
html {
font-size: 16.67px;
}
}
@media (min-width: 1440px) {
html {
font-size: 64px;
}
}
// CSS單位使用rem
p.intro {
font-size: 1rem;
}
這樣一來,其他元素也可以共享<html>
的基準font-size
,無需媒體查詢,只需引入rem單位,如:
// 另一個段落
p.another-intro {
font-size: 0.9375rem; // UI圖上標註60px
height: 1.5625rem; // UI圖上標註100px
margin: 0.5rem; // UI圖上標註32px
}
有點匪夷所思?先來看看如上換算是否滿足等比例性。再回顧一下公式:
寫入CSS的尺寸/螢幕寬度 = UI圖標註的尺寸/UI圖寬度
以p.another-intro
的margin
屬性為例:
- 螢幕寬度320px:
margin: 14.22*0.5 = 7.11px
,而7.11/320 = 32/1440
- 螢幕寬度360px:
margin: 16*0.5 = 8px
,而8/360 = 32/1440
- 螢幕寬度375px:
margin: 16.67*0.5 = 8.335px
,而8.335/375 = 32/1440
- ...
- 螢幕寬度1440px:
margin: 64*0.5 = 32px
,而32/1440 = 32/1440
完美。
可以發現一個規律:在媒體查詢中,min-width: 1440px
時定義了html { font-size: 64px; }
,那麼UI圖上標註的尺寸,直接除以64,就可以帶個rem尾巴,寫入到CSS中。記住64這個參考值,非常有用,下文會經常用到。
當然,你也可以不使用64作為參考值,只要符合等比例規則就可以。下文均是以64為例的。
適配所有規格
以上只以320px、360px、375px為例,得到了<html>
的基準font-size
。對於iPhone 6s Plus,其螢幕寬度為414px,如何計算font-size
?
很簡單:螢幕寬度/UI圖寬度*64
。
於是,又多了一條媒體查詢規則:
@media (min-width: 414px) {
html {
font-size: 18.4px; // 414/1440*64
}
}
查閱常見移動裝置的螢幕尺寸規格,可以得到一個較為完整的媒體查詢規則:
html {
font-size: 12px;
}
@media (min-width:320px){
html{
font-size: 14.2222px;
}
}
@media (min-width:360px){
html{
font-size: 16px;
}
}
@media (min-width:375px){
html{
font-size: 16.6667px;
}
}
@media (min-width:412px){
html{
font-size: 18.2857px;
}
}
@media (min-width:480px){
html{
font-size: 21.3333px;
}
}
@media (min-width:640px){
html{
font-size: 28.4444px;
}
}
@media (min-width:720px){
html{
font-size: 32px;
}
}
@media (min-width:768px){
html{
font-size: 34.1333px;
}
}
@media (min-width:1440px){
html{
font-size: 64px;
}
}
CSS預編譯
之前所講的內容,已經可以使你做出移動端適配的h5頁面了,但並不優雅。因為CSS是不支援計算的,“標註尺寸/64”只能手工計算,也就意味著UI圖上的每個標註都要手動換算,你會瘋掉。
不過,藉助CSS預編譯工具,如Less/Sass,可以避免這種重複勞動。以下以Scss為例,比如:
p.intro {
font-size: 64px/64px * 1rem;
}
p.another-intro {
font-size: 60px/64px * 1rem; // UI圖上標註60px
height: 100px/64px * 1rem; // UI圖上標註100px
margin: 32px/64px * 1rem; // UI圖上標註32px
}
當然也可以使用變數:
// 計算rem的基準字型
$rem-base-font-size: 64px;
p.intro {
font-size: 64px/$rem-base-font-size * 1rem;
}
p.another-intro {
font-size: 60px/$rem-base-font-size * 1rem; // UI圖上標註60px
height: 100px/$rem-base-font-size * 1rem; // UI圖上標註100px
margin: 32px/$rem-base-font-size * 1rem; // UI圖上標註32px
}
這樣做的好處是,如果某一天不使用64px作為參考值,只需修改$rem-base-font-size
變數。
以上程式碼看著很冗餘,不如寫一個函式,隱藏計算過程:
// 將設計圖標註的px尺寸,轉換為相應的CSS
@function convertPxFormUI($px) {
$rem-base-font-size: 64px;
@return $px / $rem-base-font-size * 1rem;
}
p.intro {
font-size: convertPxFormUI(64px);
}
p.another-intro {
font-size: convertPxFormUI(60px); // UI圖上標註60px
height: convertPxFormUI(100px); // UI圖上標註100px
margin: convertPxFormUI(32px); // UI圖上標註32px
}
這樣做的好處是,如果某一天摒棄了rem,使用了其他換算規則,只需修改convertPxFormUI()
函式體即可。
更進一步
既然Sass幫助我們計算,那麼媒體查詢中的一堆font-size
,Sass是否可以代勞呢?
之前介紹了計算規則:螢幕寬度/UI圖寬度*64
。OK,看來可以這樣寫:
// 計算rem的基準字型
$rem-base-font-size: 64px;
// UI設計圖的解析度寬度
$UI-resolution-width: 1440px;
@mixin html-font-size() {
@media (min-width:320px){
html{
font-size: 320px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:360px){
html{
font-size: 360px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:375px){
html{
font-size: 375px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:412px){
html{
font-size: 412px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:480px){
html{
font-size: 480px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:640px){
html{
font-size: 640px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:720px){
html{
font-size: 720px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:768px){
html{
font-size: 768px / $UI-resolution-width * $rem-base-font-size;
}
}
@media (min-width:1440px){
html{
font-size: 1440px / $UI-resolution-width * $rem-base-font-size;
}
}
}
很冗餘,用迴圈來實現:
// 計算rem的基準字型
$rem-base-font-size: 64px;
// UI設計圖的解析度寬度
$UI-resolution-width: 1440px;
// 需要適配的螢幕寬度
$device-widths: 320px, 360px, 375px, 412px, 480px, 640px, 720px, 768px, 1440px;
@mixin html-font-size() {
@each $current-width in $device-widths {
@media (min-width: $current-width) {
html {
$x: $UI-resolution-width / $current-width; // 計算出是幾倍屏
font-size: $rem-base-font-size / $x;
}
}
}
}
這樣做的好處是,如果某一天老闆說,螢幕寬度450px時效果不理想。你只需在$device-widths
中新增一個寬度即可。
Sass最終方案
_variables.scss
:定義變數
// 計算rem的基準字型
$rem-base-font-size: 64px;
// UI設計圖的解析度寬度
$UI-resolution-width: 1440px;
// 需要適配的螢幕寬度
$device-widths: 240px, 320px, 360px, 375px, 412px, 480px, 540px, 640px, 720px, 768px, 1024px, 1440px;
_utils.scss
:定義函式與mixin
// 根據不同裝置的螢幕寬度,定義<html>的基準font-size
@mixin html-font-size() {
@each $current-width in $device-widths {
@media (min-width: $current-width) {
html {
$x: $UI-resolution-width / $current-width; // 計算出是幾倍屏
font-size: $rem-base-font-size / $x;
}
}
}
}
// 將設計圖標註的px尺寸,轉換為相應的CSS
@function convertPxFormUI($px) {
@return $px / $rem-base-font-size * 1rem;
}
index.scss
:Scss入口檔案@import 'utils', 'variables'; @include html-font-size(); p.intro { font-size: convertPxFormUI(64px); } p.another-intro { font-size: convertPxFormUI(60px); height: convertPxFormUI(100px); margin: convertPxFormUI(32px); }
總結
rem + viewport + 媒體查詢 + Sass