適配
在不同尺寸的移動(dòng)設(shè)備上, 頁面相對(duì)性的達(dá)到合理的展示(自適應(yīng)), 或者保持同一效果的等比縮放(看起來差不多)
適配的元素
- 字體
- 寬高
- 間距
- 圖像(圖標(biāo), 圖片)
適配的方法
- 百分比適配
- viewport 縮放適配
- DPR 縮放適配
- rem 適配
- vw, wh 適配
百分比適配
360手機(jī)站
拉鉤 H5 頁面 頂部底部, 職位列表 都是高度定死, 寬度 100% 自適應(yīng)
高度固定, 寬度百分比, 在高度不能定死的狀況下, 不是很好用, 一般都是配合其他是適配使用
當(dāng)元素為奇數(shù)或者某個(gè)元素占比不均勻的時(shí)候, 不是很好算
360頂部模擬
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="format-detection" content="telephone=no,email=no"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
font-family: helvetica;
margin: 0;
}
body *{
-webkit-user-select: none;
-webkit-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
a, button, input {
-webkit-tap-highlight-color: rgba(0,0,0,0)
}
button, input{
-webkit-appearance: none;
border-radius: 0;
}
input::-webkit-input-placeholder{
color: #000;
}
input:focus::-webkit-input-placeholder{
color: #f00;
}
.header {
width: 100%;
height: 48px;
background: #23ac38;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
padding: 0 10px;
}
.logo img{
width: 80px;
}
.list img{
width: 20px;
}
</style>
</head>
<body>
<header class="header">
<span class="logo"><img src="http://p2.qhmsg.com/t01ecc3b6b24e7bdbd8.png" alt=""></span>
<span class="list"><img src="http://p9.qhmsg.com/t010fa93a99715aad32.png" alt=""></span>
</header>
</body>
</html>
viewport 適配
把所有機(jī)型的css像素設(shè)置成一致的
- viewport 需要使用 js 動(dòng)態(tài)設(shè)置, (不能直接把 device 的值設(shè)置為數(shù)值)
- 通過設(shè)置比例(初始比例以及縮放比例), 把寬度縮放成一致
縮放比 = css 像素 / 375
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="format-detection" content="telephone=no,email=no" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0" id="view">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
font-family: helvetica;
margin: 0;
}
body * {
-webkit-user-select: none;
-webkit-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
a, button, input {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}
button, input {
-webkit-appearance: none;
border-radius: 0;
}
input::-webkit-input-placeholder {
color: #000;
}
input:focus::-webkit-input-placeholder {
color: #f00;
}
div {
width: 75px;
height: 100px;
float: left;
}
div:nth-child(1) {
background: #f00;
}
div:nth-child(2) {
background: #ff0;
}
div:nth-child(3) {
background: #f0f;
}
div:nth-child(4) {
background: #0ff;
}
div:nth-child(5) {
background: #0f0;
}
</style>
<script>
; (function () {
/* 獲取 css 像素 (viewport沒有縮放, initial-scale=1.0)*/
var curWidth = document.documentElement.clientWidth
var curWidth = window.innerWidth
var curWidth = window.screen.width
/* 以上三種方式都可以準(zhǔn)確的獲取到 html 的 width */
var targetWidth = 375 // 目標(biāo)值
var scale = curWidth / targetWidth
var meta = document.getElementById('view')
var content = 'initial-scale=' + scale + ', user-scalable=no, maximum-scalable=' + scale + ', minimum-scalable=' + scale
meta.content = content
})()
</script>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>
但是這種肯定是有問題的
在 ipad 上, 寬度為 768, pro 為 1024, 一張 375 的圖片放上去 ...
DPR 適配
把 CSS 像素縮放成與設(shè)備像素一樣大的尺寸
只有在 PC 端這兩個(gè)值才是對(duì)應(yīng)的 1css像素 = 1物理像素
iphone6 的物理像素 750 * 1334. 通過縮放, 將 CSS 像素的 375 * 667 縮放, 按照設(shè)計(jì)稿 750 切圖.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="format-detection" content="telephone=no,email=no" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0" id="view">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
font-family: helvetica;
margin: 0;
}
body * {
-webkit-user-select: none;
-webkit-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
a, button, input {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}
button, input {
-webkit-appearance: none;
border-radius: 0;
}
input::-webkit-input-placeholder {
color: #000;
}
input:focus::-webkit-input-placeholder {
color: #f00;
}
div {
width: 20%;
height: 100px;
float: left;
}
div:nth-child(1) {
background: #f00;
}
div:nth-child(2) {
background: #ff0;
}
div:nth-child(3) {
background: #f0f;
}
div:nth-child(4) {
background: #0ff;
}
div:nth-child(5) {
background: #0f0;
}
</style>
<script>
; (function () {
/*
要將 375 => 750 就是 375 / 0.5 dpr = 2
375 / ? = 750 這個(gè) ? 就是 dpr 的倒數(shù)
*/
var meta = document.querySelector('meta[name="viewport"]')
var scale = 1 / window.devicePixelRatio
if(!meta){ // 沒有默認(rèn)設(shè)置 viewport 的 meta, 創(chuàng)建
meta = document.createElement('meta')
meta.name = 'viewport'
meta.content = 'width=device-width, initial-scale=' + scale + ', user-scalable=no, maximum-scalable=' + scale + ', minimum-scalable=' + scale
document.head.appendChild(meta)
} else { // 有默認(rèn)設(shè)置 viewport 的 meta, 修改
meta.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', user-scalable=no, maximum-scalable=' + scale + ', minimum-scalable=' + scale)
}
})()
</script>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>
雖然一個(gè)CSS 像素對(duì)應(yīng)了一個(gè)物理像素, 但是對(duì)于不同尺寸的設(shè)備, 依然不是一個(gè)好的解決方案, 需要 rem 進(jìn)行配合
rem 適配
把所有的設(shè)備分成相同的若干份, 再計(jì)算元素寬度所占的份數(shù)
em: 當(dāng)意義為 font-size 的時(shí)候, 1em 代表父元素的字體大小, 當(dāng)作為其他單位(寬度高度)的時(shí)候, 代表自身字體大小
chrome 下有最小字體限制 12px, 字體小于 12px 無法再變小
rem: r root, 根元素的 font-size 將 html 的 font-size 設(shè)置為 20px, 1rem = 20px
- 元素適配的寬度 = 元素所占的列數(shù) * 一列的寬度
- 元素在設(shè)計(jì)稿里面的寬度
- 列數(shù) (隨便給的) 100
- 一列的寬度 = 屏幕寬度(css像素) / 列數(shù)
- 元素實(shí)際占的列數(shù) = 設(shè)計(jì)稿里面的寬度 / 一列的寬度
var colWidth = 0
var col = 100 // 假設(shè) 100 列
// 計(jì)算 iPhone5 iPhone6里面一列的寬度
colWidth = 375 / col // 3.75px 6
colWidth = 320 / col // 3.20px 5
// 一個(gè) div 占 10 列
var width = 10 * 3.75 // 37.5px 6
var width = 10 * 3.20 // 32.0px 5
// 一個(gè) div 50px
divCol = 50 / 3.75 // 13.333
divCol = 50 / 3.20 // 15.625
// 所以按照此方案, 50px 的 div, 在不同的設(shè)備里, 會(huì)占到不同的份數(shù)
屏幕已經(jīng)被分成了若干份
那么 width: 10rem; (寫入 CSS 文件的代碼)
元素適配的寬度 => 元素所占的列數(shù) * 一列的寬
元素適配的寬度 => width 10 * 1rem
元素所占的列數(shù) => 10
一列的寬 => 1rem
1rem = html 的 font-size
根據(jù)柵格系統(tǒng)的原理, 將屏幕分成若干份, 不同的屏幕被分成相同的份數(shù), 所以一份的寬度會(huì)不一樣
但是份數(shù)是一樣的, 所以整體比例是一樣的
; (function (fs) {
var html = document.documentElement
var width = html.clientWidth // css 像素
html.style.fontSize = width / fs + 'px'
// 分成 16 列, iPhone5 為例 320px 得到 1rem = 20px
})(16)
這種方式并沒有一個(gè)基準(zhǔn)點(diǎn), 只是按照屏幕的增大, html 的 font-size 在變大
我們希望增加一個(gè)基準(zhǔn)點(diǎn), 這個(gè)點(diǎn)就是 iPhone6, 屏幕仍然分成 16 份
如果屏幕尺寸為 375, 那么就 html 字體也是16px
如果屏幕小于 375 那 font-size 也會(huì)小于 16px
反之, 大于 16px
如下代碼:
; (function (doc, win, designWidth) {
const html = doc.documentElement
const refreshDom = () => {
const clientWidth = html.clientWidth
if(clientWidth >= designWidth){
html.style.fontSize = "100px"
}else{
html.style.fontSize = 16 * clientWidth / 375 + 'px'
}
}
doc.addEventListener('DOMContentLoaded', refreshDom)
})(document, window, 750)
但是這樣做有一個(gè)弊端, 當(dāng)計(jì)算出了 rem 值之后, 還要除以 dpr, 才是真正應(yīng)該寫的值
而且很多是除不盡的, 跟著一大串小數(shù), 雖然有 less sass 去做這些事情, 但是還是覺得美中不足
rem 最終方案
; (function (doc, win, designWidth) {
const html = doc.documentElement
const refreshDom = () => {
const clientWidth = html.clientWidth
if(clientWidth >= designWidth){
html.style.fontSize = "100px"
}else{
html.style.fontSize = 100 * (clientWidth / designWidth) + 'px'
}
}
doc.addEventListener('DOMContentLoaded', refreshDom)
})(document, window, 750)
只有一行代碼不同
那么html.style.fontSize = 100 * (clientWidth / designWidth) + 'px' 又是什么意思呢 ?
基于 iPhone6 的尺寸, 將整個(gè)頁面適配成7.5 rem.
所以, 只要設(shè)計(jì)稿是750px, 在切圖的時(shí)候, 量出來出多少px, 直接將這個(gè)值除以 100, 加上rem就ok
這個(gè)時(shí)候, 屏幕被分割成多少份這個(gè)概念已經(jīng)不怎么明朗了, 說是7.5份嗎? 好像不太對(duì)勁. 那就索性不管了.
如果設(shè)計(jì)圖是 640px, 那么整屏的寬度就是 6.4rem, 只需要將參數(shù)修改一下就可以了.
但是上面的代碼是用到了 ES6 的語法, ios9 不是原生支持的, 直接在上面跑會(huì)出現(xiàn)很大的問題, 就相當(dāng)于適配沒有做一樣.
所以改寫吧:
; (function (doc, win, designWidth) {
var html = doc.documentElement
function refreshDom(){
var clientWidth = html.clientWidth
if(clientWidth >= designWidth){
html.style.fontSize = "100px"
}else{
html.style.fontSize = 100 * (clientWidth / designWidth) + 'px'
}
}
doc.addEventListener('DOMContentLoaded', refreshDom)
})(document, window, 750)
這種方案總體來說沒什么大問題了. 如果在設(shè)計(jì)稿上量出來長度為50px, 那么實(shí)際寫上去的長度應(yīng)該是 50 / 2 = 25px. 因?yàn)?750 的設(shè)計(jì)稿, 375px就會(huì)占滿屏幕. 或者是寫.5rem.
字體也要用標(biāo)注的字體大小除以 2, 如標(biāo)注 28px, 實(shí)則應(yīng)該寫 14px, 或者 .28rem
hotcss
大佬寫的號(hào)稱移動(dòng)端終極解決方案, 原理跟如上一樣, 只是考慮的東西更多, 功能更強(qiáng)大.
去 github 上下載或者 clone , 地址是: https://github.com/imochen/hotcss
需要做一點(diǎn)點(diǎn)小小的處理, 將第十四行左右的 maxWidth = 540, 修改為設(shè)計(jì)稿的尺寸, 這個(gè) 540 是幾年前寫的, 相較現(xiàn)在來說有點(diǎn)小了.

然后在頁面中引入這個(gè) hotcss.js. 使用 sass.
在寫 scss 的地方引入 px2rem 的 scss 文件, 然后就可以在scss上愉快的寫代碼了.

量出來多少 (100px) 就直接 px2rem(100)
vw, vh 適配
這倆單位就是為適配而生的
vw: viewport's width 1vw = 視口寬度的 1%
vh:viewport's height 1vh = 視口高度的 1%
vmax: 取 vw, vh 中的最大值
vmin: 取 vw, vh 中的最小值
支持情況: ios >= 8; android >= 4.4
瀏覽器將任何屏幕都分成 100 份, 只要使用此單位, 就不會(huì)翻車
兩種方案
方案一: 通篇使用vw
@function vw($px){
@return $px / 750 * 100vw;
}
為方便切圖, 寫了一個(gè)如上函數(shù)(scss), 以 750 為基準(zhǔn), 在任何屏幕上都可以看做是'750'
因?yàn)槔绱撕瘮?shù)傳 250 進(jìn)去, 會(huì)被轉(zhuǎn)換成 33.33333vw, 三個(gè)這樣的大小將占滿屏幕寬度, 在任何尺寸屏幕上的都是這樣.
方案二: 通過 vw 設(shè)置根節(jié)點(diǎn)的字體大小, 頁面尺寸依然使用 rem
一個(gè)很暴力的方式, 還是以 750 為基準(zhǔn). 375(css像素) / 750(設(shè)計(jì)稿寬度) * 100 這是 rem 適配的原理所在
這個(gè)值最終是 50, 這個(gè)值就是 rem 適配中, html 的字體大小 .
那通過 vw 適配, 要達(dá)到 rem 同樣的適配效果, 是不是應(yīng)該讓 ?vw = 50px ?
所以 50 / 3.75 = 13.333333333333334 (15位小數(shù))
然后:
html {
font-size: 13.333333333333334vw;
}
然后, rem 適配需要的 js 代碼可以刪除了. 然后在任意尺寸的屏幕上也是可以橫著走的.
整個(gè)屏幕 7.5rem. 與 rem 適配的結(jié)果都是一樣的
需要注意一些問題:
-
css尺寸寫rem, 比如1/4屏幕大小的div,width: 1.875rem; -
html的font-size會(huì)帶來負(fù)面影響. 很多有文本屬性(受font-size影響)的標(biāo)簽里面的內(nèi)容會(huì)繼承html的字體大小,13.33vw字體其實(shí)是非常大的, 所以不處理的話, 頁面將會(huì)亂套.img的display屬性默認(rèn)是inline-block, 它會(huì)根據(jù)字體來對(duì)齊. 如果字體繼承了html. 圖片就會(huì)跑到一個(gè)匪夷所思的地方. 這個(gè)時(shí)候需要將img的包裹層的font-size做出相應(yīng)的調(diào)整 - 比較一勞永逸的方法, 在該設(shè)置的字體的地方設(shè)置字體大小, 然后最主要的是, 在
body里面, 將font-size設(shè)置為chrome最小字體12px, 阻止頁面的元素去繼承html的字體大小. 即現(xiàn)在html的字體大小只能影響rem這個(gè)單位.
這些問題逐一解決之后, 這也是一個(gè)很好的方案.
完...