移动端适配大致两种,一种是百分比还有一种就是rem,这里就说说rem适配要怎么做,原理是什么。先说说为什么要做适配吧。
为何要适配?
众所周知,手机屏幕的尺寸是五花八门的,像素密度也是不一样的。同样是宽度5cm的屏幕,有的手机是720px,有的手机是1080px。
那么假设设计师有个设计稿,宽度是720px的,设计稿里有张图,这张图的宽度也是720px。如果我们直接在代码里写这张图的宽度为720px,那我们在720px的手机上看则是正常的,这里我们用一个div做演示
720px屏幕
但是当用户的手机屏幕宽度有1080px的时候呢?看起来就会像这样
1080px屏幕
很显然这跟预期的不一样,所以我们需要div的尺寸跟随实际屏幕的宽度进行缩放。这时,我们的rem就刚好满足需求。
rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem大家一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。
简单来说,我们设定html元素的font-size等于100px时,1rem就等于100px。1 rem = 1 font-size
所以我们只需要获取屏幕的宽度,然后根据宽度和设计稿的比例来计算html的font-size,并设置上去。
在写代码的时候,就用rem代替px,这样就可以使div的尺寸根据html的font-size缩放了
如何计算font-size?
我们来做几个设定
- 设计稿宽度为750px
- 设计稿中有一个div,宽度也是750px
- 理想状态(实际屏幕宽度也是750px)下html的font-size是100px,即1rem=100px
那么,我们先手动写一下理想状态
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>rem适配</title>
</head>
<style>
body {
margin: 0;
font-size: 16px;;
}
html {
font-size: 100px;
}
</style>
<body>
<div style="width: 7.5rem;background: yellow;">
750px/100 = 7.5rem div
</div>
</body>
</html>
一定要写body下的font-size=16px,或者你需要的,不然body元素下的文字默认大小就会继承html下的100px,那样的话,字体就太大了。
好了,来看效果
750px下的7.5rem
一切正常,我们来把屏幕像素稍微调大一点,把屏幕宽度调成900。
900px下的7.5rem
由于我们没有动态调节html的font-size,所以div的宽度没有跟随变化。那么就来计算一下。
先算出100px是设计稿的多少倍,然后再乘以实际屏幕宽度,就能算出缩放后的font-size了。
100/750*900 = 120px
现在把120设置上去
html {
font-size: 120px;
}
搞定~
900px下的7.5rem好了,rem适配的基本原理你已经知道了,我们开始编码。
新建一个flexible.js
// designWidth:设计稿的实际宽度值,需要根据实际设置
// maxWidth:支持缩放的最大屏幕宽度值,当屏幕宽度超过此值则按最大值进行计算,需要根据实际设置
// 这段js的最后面有两个参数记得要设置,一个为设计稿实际宽度,一个为支持缩放的最大屏幕宽度值,例如设计稿为750,最大宽度为750,则为(750,750)
(function(designWidth, maxWidth) {
var doc = document
var win = window
var docEl = doc.documentElement
var remStyle = document.createElement('style') // 创建一个style标签,用于写html样式
var tid //timeout句柄
// 计算rem的值,即1rem等于多少px
function refreshRem() {
var width = docEl.getBoundingClientRect().width // 获取屏幕宽度
maxWidth = maxWidth || 750 // 当没写maxWidth时,默认maxWidth=750
// 当屏幕宽度超过最大缩放的值,则按最大值处理,不能无限缩放,那样会变得很大,很丑
if (width > maxWidth) {
width = maxWidth
}
// 计算html的font-size
var rem = 100 / designWidth * width
remStyle.innerHTML = 'html{font-size:' + rem + 'px;}'
}
// 将style标签插入到文档
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(remStyle)
} else {
var wrap = doc.createElement('div')
wrap.appendChild(remStyle)
doc.write(wrap.innerHTML)
wrap = null
}
// 要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
refreshRem()
win.addEventListener('resize', function() {
clearTimeout(tid) // 防止执行两次
tid = setTimeout(refreshRem, 300)
}, false)
win.addEventListener('pageshow', function(e) {
if (e.persisted) { // 浏览器后退的时候重新计算
clearTimeout(tid)
tid = setTimeout(refreshRem, 300)
}
}, false)
// 设定body的默认字体大小,如果不设置,将集成html的字体大小,而我们设置的100,so...
if (doc.readyState === 'complete') {
doc.body.style.fontSize = '16px'
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = '16px'
}, false)
}
})(750, 750)
// 这里我们输入设计稿750px,支持的最大屏幕宽度也是750px。
可能有同学会问,为什么只有750px,现在手机都是1080px了。
其实浏览器返回给js和css的px都是抽象的,是根据真实像素和ppi计算出来的,像我的小米8,1080px宽度,js获取的屏幕宽度也只有393px
并且一定要在head元素里写 <meta name="viewport" content="width=device-width, initial-scale=1.0">
关于viewport是啥,可以参阅 https://blog.csdn.net/lamanchas/article/details/78473249
最后,我们只需要在html中引用此文件即可,也可以用es6的方式引用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>rem适配</title>
<script src="./flexible.js" type="text/javascript"></script>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<div style="width: 7.5rem;background: yellow;">
750px/100 = 7.5rem div
</div>
</body>
<script>
</script>
</html>
网友评论