詳解rem佈局-利用rem佈局實現移動端高清顯示
目錄
一、初探rem佈局
1.1 rem是什麼?
rem是CSS3新增的一個相對單位(root em,根em)。這個單位與em有什麼區別呢?區別在於使用rem為元素設定字型大小時,仍然是相對大小,但相對的只是HTML根元素。這個單位可謂集相對大小和絕對大小的優點於一身,通過它既可以做到只修改根元素就成比例地調整所有字型大小,又可以避免字型大小逐層複合的連鎖反應。目前,除了IE8及更早版本外,所有瀏覽器均已支援rem。對於不支援它的瀏覽器,應對方法也很簡單,就是多寫一個絕對單位的宣告。這些瀏覽器會忽略用rem設定的字型大小。舉一個簡單的例子:
瀏覽器預設的 html font-size=16px
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
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調整頁面的縮放值,進而達到高清效果。
注意點:
- 上述這段程式碼會自動設定viewport,不再需要我們手動去設定了;
- 預設dpr=2時,html 的
font-size=100px
,這樣,1rem=100px,這樣也利於px和rem之間的轉換; - 之前固定px大小的元素用rem表示,之前用百分比表示的依舊用百分比表示
這種rem佈局方式使用起來很方便,只需要在<head>
中引入上述那一段壓縮過的程式碼,然後在寫 css 時將之前習慣用的 px 轉換成 rem 即可。例如PSD上一個圖片的大小為30*30px,我們不再需要去除以2了,而是直接寫成:
.img{
height: 0.3rem;
width: 0.3rem;
}
工作中踩的兩個坑:
一開始在專案中用時,在手機端檢視,頁面是手機螢幕大小的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版本還是不支援,所以需要做相容性處理。
iPhone6 上有1px 的滾動條,最後處理方案是通過 viewport 中的 maximum-scale 的值加了0.1,由於設定了
user-scalable=no
,maximum-scale 的值加0.1並不會有什麼影響,但是卻神奇的解決了這個問題。