最近频繁碰到适配问题,于是想系统整理一下,听了coderwhy老师的课,记录一下笔记。
首先我们需要理解一下基本概念。
移动端开发目前主要包括三类:
· 原生App开发(iOS,Android,RN,uniapp,Flutter等)
· 小程序开发(原生小程序、uniapp等)wxml、wxss、js
· Web页面(移动端的Web页面,可以用浏览器或者webview浏览)
目前移动端设备较多,所以需要对其进行一些适配。
这里有两个概念:
· 自适应:根据不同的设备屏幕大小来自动调整尺寸、大小;
· 响应式:会随着屏幕的实时变动而自动调整,是一种自适应。
1.认识视口viewport
1.1视口的基本概念
在一个浏览器中,我们能看到的区域就是视口;
fixed就是相对于视口来进行定位的;
在PC端的页面中,我们是不需要对视口进行区分,因为我们布局视口和视觉视口是同一个;
但是对于移动端:布局视口和可见视口是不一样的。在默认情况下,移动端的布局视口是大于视觉视口。
所以在移动端,我们可以将视口划分为三种情况:
· 布局视口:默认情况下会按照980px来布局一个页面的盒子和内容,为了完整显示页面,会对整个页面缩小。
· 视觉视口:手机浏览器默认对页面进行缩放以显示到用户的可见区域中,显示在可见区域的视口就是视觉视口。
· 理想视口:通过meta里面的viewport进行设置,以满足正常在一个移动端窗口的布局。
1.2理想视口
我们在默认!会生成的html代码中的viewport一行会起到将视口调整为理想视口的作用,如下:
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 如果没有下面这行,会按980px的布局视口宽度缩小 -->
<!-- width:设置布局视口的宽度,device-width就是设备宽度 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
content可以设置多个属性,如下图:
2.移动端适配方案
移动端屏幕尺寸繁多,我们希望在不同的屏幕尺寸展示不同大小,可能的方案:百分比设置、rem单位+动态html的font-size,vw单位,flex的弹性布局。
2.1rem方案
rem参照的是html标签的font-size大小。例如如果html标签的font-size为16px,则2rem为32px;
针对不同的屏幕,设置html不同的font-size;
将原来要设置的尺寸,转换为rem单位。
2.1.1 rem+设置动态的font-size(通过媒体查询)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* 设置动态的font-size */
@media screen and (min-width:320px) {
html {
font-size: 20px;
}
}
@media screen and (min-width:375px) {
html {
font-size: 24px;
}
}
@media screen and (min-width:414px) {
html {
font-size: 28px;
}
}
.box {
width: 5rem;
height: 5rem;
background-color: #ccc;
}
</style>
</head>
<body>
<!-- 媒体查询 -->
<div class="box"></div>
</body>
</html>
缺点:很难维护,要重复写很多代码
2.1.2 rem+通过js设置font-size
const htmlEL = document.documentElement
function setRemUnit() {
const htmlWidth = htmlEL.clientWidth
const htmlFontSize = htmlWidth /10
htmlEL.style.fontSize=htmlFontSize+"px"
}
setRemUnit()
//屏幕尺寸变化,实时修改
window.addEventListener("resize", setRemUnit)
//持久化
window.addEventListener("pageShow",function(e){
if(e.persisted){
setRemUnit()
}
})
2.1.3使用lib-flexible库
github上搜索lib-flexible即可,引用index.js,具体代码如下:
(function flexible (window, document) {
var docEl = document.documentElement
var dpr = window.devicePixelRatio || 1
// adjust body font size
function setBodyFontSize () {
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
}
else {
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10
function setRemUnit () {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize
window.addEventListener('resize', setRemUnit)
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
计算rem值(单位换算,less/sass函数)
.pxToRem(@px) {
result: 1rem*(@px/37.5); //如果设计稿是375px,如果是750px则写75
}
.box {
width: .pxToRem(100)[result];
background-color: #ccc;
}
p {
font-size:.pxToRem(14)[result];
}
由于 viewport 单位得到众多浏览器的兼容,lib-flexible 这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用 viewport 来替代此方案。
注:也可以在webpack配置postcss-pxtorem插件
注:vscode的px-to-rem插件也可以
目前更推荐使用的是viewport的两个单位vw,wh。
2.2vw单位
2.2.1vw的优势
在375px屏幕上,1vw=3.75px;如果在450px屏幕上,1vw=4.5px;即:1vw 等于viewport的 1%;
vw只面临一个问题,就是将尺寸换成vw的单位即可。
2.2.3vw的换算
方案一:手动计算,效率太低,不推荐
方案二:less/sass函数
@vwUnit:3.75;
.pxToVw(@px){
result:(@px/@vwUnit)*1vw;
}
.box{
width:.pxToVw(100)[result];
height: .pxToVw(100)[result];
}
方案三:webpack插件 postcss-px-to-viewport-8-plugin。在前端工程化开发中,我们可以借助webpack的工具完成自动的转化;
方案四:VScode插件px to rem&rpx&vw