1. 程式人生 > >詳解rem佈局-利用rem佈局實現移動端高清顯示

詳解rem佈局-利用rem佈局實現移動端高清顯示

目錄

一、初探rem佈局

1.1 rem是什麼?

rem是CSS3新增的一個相對單位(root em,根em)。這個單位與em有什麼區別呢?區別在於使用rem為元素設定字型大小時,仍然是相對大小,但相對的只是HTML根元素。這個單位可謂集相對大小和絕對大小的優點於一身,通過它既可以做到只修改根元素就成比例地調整所有字型大小,又可以避免字型大小逐層複合的連鎖反應。目前,除了IE8及更早版本外,所有瀏覽器均已支援rem。對於不支援它的瀏覽器,應對方法也很簡單,就是多寫一個絕對單位的宣告。這些瀏覽器會忽略用rem設定的字型大小。舉一個簡單的例子:

瀏覽器預設的 html font-size=16px

, 這樣如果我們需要設定字型的大小為12px, 通過計算可知 12 / 16 = 0.75;因此只需要設定 font-size= 0.75rem

為了計算方便,我們可以設定html font-size=10px 或者 font-size=62.5%,這樣設定12px字型的時候就只需要設定 font-size=1.2rem,十進位制換算信手拈來。

1.2 rem實現新聞字型“小中大”設定

介紹完rem,急需寫點東西練練手:通常在移動端看新聞的時候,右上角都有個調節字型大小的,可以通過點選調節新聞的字型大小,方便閱讀。用rem實現的基本思路就是:設定html的font-size,然後新聞中的字型都根據 html 的 font-size

來設定大小,點選調節字型大小時,只需要將 html 的 font-size 修改成對應的值就可以了。

首先設定html

font-size: 16px;

然後新聞的標題、內容等字型大小都根據 html 的大小來設定

.title{
    font-size: 1.2rem;
 }
 .sub-title{
     font-size: 0.8rem;
 }
 .content{
     font-size: 1rem;
 }
 .bottom{
     font-size: 0.8rem;
 }

最後再放置一個三個<li/>元素,並加上click 事件用來控制 html 的font-size

大小:

// html
<ul><li id="1">小</li><li id="2">中</li><li id="3">大</li></ul>

// js
$("li").click(function() {
       $("li").css({"background":"#d6d5d5"});
       $(this).css({"background":"#8a6969"});
       var index = $(this).attr("id");
       var TextFont;
       switch (index) {
           case "1":
               TextFont = 14;
               break;
           case "2":
               TextFont = 16;
               break;
           case "3":
               TextFont = 18;
               break;
           default:
               TextFont = 16;
               break;
       }
       $("html").css({"font-size":TextFont});
   })

最後的效果圖:

這裡寫圖片描述

上述效果的完整的程式碼如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>rem佈局實現新聞字型小中大切換</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        *{margin:0;padding:0} 
        body{
            padding: 20px 15px;
        }
        html{
            font-size: 16px;
        }
        .title{
            text-align: center;
            font-size: 1.2rem;
            margin: 20px 0;
        }
        .sub-title{
            position: relative;
            font-size: 0.8rem;
        }
        .sub-title:after{display:block;clear:both;content:"";visibility:hidden;height:0} 
        .source{
            float: left;
        }
        .date{
            float: right;
        }
        .content{
            margin: 10px 0;
            font-size: 1rem;
        }
        .content .item{
            text-indent: 2em;
            margin: 10px 0;
        }
        .bottom{
            margin-top: 20px;
            text-align: left;
            font-size: 0.8rem;
        }

        ul{
            list-style:none;
            position: absolute;
            top: 10px;
            right: 10px;
        }
        li{
            float: left;
            width: 40px;
            /* height: 20px; */
            text-align: center;
            background: #d6d5d5;
        }

    </style>
</head>
<body>
    <ul><li id="1"></li><li id="2"></li><li id="3"></li></ul>
    <h3 class="title">上海是怎麼錯失這些年的網際網路機遇的</h3>
    <p class="sub-title"><span class="source">來源:肥肥貓的小酒館</span><span class="date">2018-01-24 19:36:14</span></p>
    <div class="content">
        <p class="item">今天你去問一個剛畢業的人,如果要從事網際網路行業你會選擇去哪個城市打拼?他一定會首選北京深圳,原因他也許自己也說不上來,可能只是因為他的同學們——其他打工者也會這麼選。</p>
        <p class="item">今天你去問一個網際網路創業者,你會首選在哪個城市創業?他也不會首選上海,因為風投家們都扎堆在北京組飯局,那裡才是中國網際網路的第一試驗場。</p>
        <p class="item">而BAT這種級別的公司,和上海從來沒關係。幾年前上海的大領導就讓下面反思,為什麼阿里沒有來上海。現在幾年過去了,啥也沒反思出來,倒是我身邊越來越多的朋友都去杭州工作了——上海人為了工作去別的城市當硬碟,這在過去是不可想象的。現在連香港的banker們都跑了不少人去了杭州,上海人再不敢說什麼“西湖是上海人的後花園”這種陳年大話了...</p>
    </div>
    <p class="bottom">原文地址:<a href="https://www.toutiao.com/i6514573106743345678/">https://www.toutiao.com/i6514573106743345678/</a></p>
</body>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
    $(function() {
        $("li").click(function() {
            $("li").css({"background":"#d6d5d5"});
            $(this).css({"background":"#8a6969"});
            var index = $(this).attr("id");
            var TextFont;
            switch (index) {
                case "1":
                    TextFont = 14;
                    break;
                case "2":
                    TextFont = 16;
                    break;
                case "3":
                    TextFont = 18;
                    break;
                default:
                    TextFont = 16;
                    break;
            }
            $("html").css({"font-size":TextFont});
        })
    });
</script>
</html>

二、利用rem佈局實現移動端高清顯示

對rem有了基本的瞭解之後,可以用rem的思想來實現移動端的自適應高清縮放,實現高清顯示。

首先來了解一些基本知識,我們在寫移動端上的頁面時,都會網頁的<head>中增加這句話,讓網頁的寬度自動適應手機螢幕的寬度。:

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

其中:

width=device-width :表示寬度是裝置螢幕的寬度
initial-scale=1.0:表示初始的縮放比例
minimum-scale=1.0:表示最小的縮放比例
maximum-scale=1.0:表示最大的縮放比例
user-scalable=no:表示使用者是否可以調整縮放比例

這樣設定之後,網頁與螢幕的是1:1顯示,但是我們知道手機都有自己的裝置畫素比(也就DPR),簡單的說:dpr=2時,手機上的1個CSS畫素由4個物理畫素點組成。而且UI設計師提供給我們的PSD都是2倍放大的,如果以iPhone6為標準的設計圖的寬度是750px。如果我們採用上述的方法來寫移動端的頁面:這時如果PSD上一個圖示的大小為30*30px,在寫css的時候我們需要除以2,也就是寫成15*15px。

這種寫法是沒有問題的,而且我們組之前一直採用的是這種方法。直到有一天,產品開始反映說手機端上看到的線條太粗了,但是我們在css中設定的確實為1px,但是由於手機端會放大處理,也就是上面說的如果dpr=2時,手機上的1個CSS畫素由4個物理畫素點組成。

為了解決移動端1px線條變粗的問題,通過查詢資料,網上也有不少解決方案,有用小數的,用圖片的,以及用background漸變等各種方案,都有一定得複雜度和缺點。後來看到這篇文章《手機端頁面自適應解決方案—rem佈局(進階版,附原始碼示例)》後,決定採用rem佈局來解決移動端高清顯示的問題,順便解決了移動端1px變粗的問題。

其基本思想是:通過js動態獲取手機的DPR,然後通過dpr來動態設定 html 的 font-size,以及設定縮放比例。

具體實現主要依靠在<head>中引入的這段程式碼:

<script>!function(e){function t(a){if(i[a])return i[a].exports;var n=i[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=window;t["default"]=i.flex=function(normal,e,t){var a=e||100,n=t||1,r=i.document,o=navigator.userAgent,d=o.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i),l=o.match(/U3\/((\d+|\.){5,})/i),c=l&&parseInt(l[1].split(".").join(""),10)>=80,p=navigator.appVersion.match(/(iphone|ipad|ipod)/gi),s=i.devicePixelRatio||1;p||d&&d[1]>534||c||(s=1);var u=normal?1:1/s,m=r.querySelector('meta[name="viewport"]');m||(m=r.createElement("meta"),m.setAttribute("name","viewport"),r.head.appendChild(m)),m.setAttribute("content","width=device-width,user-scalable=no,initial-scale="+u+",maximum-scale="+u+",minimum-scale="+u),r.documentElement.style.fontSize=normal?"50px": a/2*s*n+"px"},e.exports=t["default"]}]); flex(false,100, 1);</script>

其原始碼為:

'use strict';

/**
 * @param {Boolean} [normal = false] - 預設開啟頁面壓縮以使頁面高清;  
 * @param {Number} [baseFontSize = 100] - 基礎fontSize, 預設100px;
 * @param {Number} [fontscale = 1] - 有的業務希望能放大一定比例的字型;
 */
const win = window;
export default win.flex = (normal, baseFontSize, fontscale) => {
  const _baseFontSize = baseFontSize || 100;
  const _fontscale = fontscale || 1;

  const doc = win.document;
  const ua = navigator.userAgent;
  const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);
  const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
  const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
  const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
  let dpr = win.devicePixelRatio || 1;
  if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
    // 如果非iOS, 非Android4.3以上, 非UC核心, 就不執行高清, dpr設為1;
    dpr = 1;
  }
  const scale = normal ? 1 : 1 / dpr;

  let metaEl = doc.querySelector('meta[name="viewport"]');
  if (!metaEl) {
    metaEl = doc.createElement('meta');
    metaEl.setAttribute('name', 'viewport');
    doc.head.appendChild(metaEl);
  }
  metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
  doc.documentElement.style.fontSize = normal ? '50px' : `${_baseFontSize / 2 * dpr * _fontscale}px`;
};

這段程式碼的作用就是:動態設定 html 的font-size, 同時根據裝置DPR調整頁面的縮放值,進而達到高清效果。

注意點:

  1. 上述這段程式碼會自動設定viewport,不再需要我們手動去設定了;
  2. 預設dpr=2時,html 的font-size=100px,這樣,1rem=100px,這樣也利於px和rem之間的轉換;
  3. 之前固定px大小的元素用rem表示,之前用百分比表示的依舊用百分比表示

這種rem佈局方式使用起來很方便,只需要在<head>中引入上述那一段壓縮過的程式碼,然後在寫 css 時將之前習慣用的 px 轉換成 rem 即可。例如PSD上一個圖片的大小為30*30px,我們不再需要去除以2了,而是直接寫成:

.img{
   height: 0.3rem;
   width: 0.3rem;
}

工作中踩的兩個坑:

  1. 一開始在專案中用時,在手機端檢視,頁面是手機螢幕大小的2~3倍,我們知道這種方案會動態獲取手機的DPR,然後根據dpr設定 html 的 font-size 以及頁面縮放比例:

    1.如果dpr=1(如電腦端),則html的font-size為50px,此時 1rem = 50px, viewport 的 initial-scale 、minimum-scale 和 maximum-scale 都為 “1.0” ;
    2.如果dpr=2(如iphone 5 和 6),則html的font-size為100px,此時 1rem = 100px, viewport 的 initial-scale 、minimum-scale 和 maximum-scale 都為 “0.5”
    3.如果dpr=3(如iphone 6 sp),則html的font-size為150px,此時 1rem = 150px; viewport 的 initial-scale 、minimum-scale 和 maximum-scale 都為 “0.3333333333”

    由於我們是用的hybrid開發,經過檢視發現是安卓客戶端限制了 viewport 設定的縮放屬性,讓客戶端放開限制就行,但是由於市場上的app版本還是不支援,所以需要做相容性處理。

  2. iPhone6 上有1px 的滾動條,最後處理方案是通過 viewport 中的 maximum-scale 的值加了0.1,由於設定了user-scalable=no,maximum-scale 的值加0.1並不會有什麼影響,但是卻神奇的解決了這個問題。