移动端屏幕适配
移动端屏幕适配和响应式布局区别
移动端适配 | 响应式布局 | |
---|---|---|
终端 | 移动端 | PC端和移动端 |
常用单位 | 宽高:rem 或 % 字体:px | 宽:% 高、字体:px |
宽高 | 宽高会随着屏幕大小变化,等比例变化 | 宽度变化,高度不变,非等比例 |
移动端适配是指针对移动设备进行特定的布局和设计,以确保在移动设备上的用户体验良好。
响应式布局和移动端适配是紧密相关的。
基本知识
- 设备像素:也就是物理像素。
- CSS像素:也就是逻辑像素,决定网页中元素的尺寸和位置。
- 设备像素比(dpr,device pixel ratio):物理像素/逻辑像素。dpr=1时,表示1css像素=1设备像素;当dpr=2时,1个css=2*2物理像素。
- 缩放操作:当放大时,例如
1个css像素=2*2个物理像素
;当缩小时,例如2*2个css像素=1个物理像素
。
window.devicePixelRatio详解:
可以通过window.devicePixelRatio
获取设备像素比,当网页放大为200%时,值为2;当网页缩小为50%时,值为0.5。
简单屏幕适配
原理:使用rem作为单位,将可视区域分为10等份,并赋值给根元素的fontSize,我们都知道rem是根据根元素字体大小计算的,所以我们的1rem也就是设备可视区域/10。
例如:以iphone6为基准,物理像素为750x1334,dpr为2,因此css像素为375x667。1rem为37.5px,宽度一共有10个rem。
以iphone12 pro为基准,物理像素为1170x2532,dpr为3,因此css像素为390x844。1rem为39px,宽度一共有10个rem。
另外设置盒模型 box-sizing: border-box
,用于移动端屏幕适配,便于控制元素的大小和位置。
<!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, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<title>移动端屏幕适配</title>
<style>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.top {
width: 5rem;
height: 5rem;
line-height: 5rem;
background-color: pink;
border-bottom: 1px solid black;
}
</style>
<script>
function setRemUnit() {
let rootEl = document.documentElement;
let ratio = 10;
let viewWidth =
rootEl.getBoundingClientRect().width || window.innerWidth;
rootEl.style.fontSize = viewWidth / ratio + "px";
}
setRemUnit();
window.addEventListener("resize", setRemUnit);
window.addEventListener("pageshow", function (e) {
if (e.persisted) {
setRemUnit();
}
});
</script>
</head>
<body>
<header class="top">hello</header>
</body>
</html>
1px边框问题
设计师想要的移动端屏幕下 border: 1px
,其实是 1 物理像素宽,而不是 1 CSS 像素宽度,对于 CSS 而言:
- 在 dpr = 1 时,此时 1 物理像素等于 1 CSS 像素宽度;
- 在 dpr = 2 时,此时 1 物理像素等于 0.5 CSS 宽度像素,可以认为
border-width: 1px
这里的 1px 其实是 1 CSS像素宽度,等于 2 像素物理宽度,设计师其实想要的是border-width: 0.5px
; - 在 dpr = 3 时,此时 1 物理像素等于 0.33 CSS 宽度像素,设计师其实想要的是 border: 0.333px
通用屏幕适配
通用屏幕适配原理:当dpr为3时,我们将页面缩放到1/3倍,这样1px就等于1物理像素。
主要目的是消除dpr的影响,例如,在系数为18.75的情况下,如果物理像素为750x1334且dpr为1时,1rem为40px;如果dpr为2时,1rem仍然为80px,则通过设置视口缩放比例为0.5保持显示效果一致;如果dpr为3时,1rem仍然接近为120px,则视口缩放比例为0.333保持显示效果一致。
编写代码时,需要按物理像素来写。
<!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, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<title>移动端屏幕适配</title>
<style>
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.top {
width: 5rem;
height: 5rem;
line-height: 5rem;
background-color: pink;
border-bottom: 1px solid black;
}
</style>
<script>
let rootEl = document.documentElement;
let viewportEl = document.querySelector("meta[name='viewport']");
let dpr = window.devicePixelRatio || 1;
// 限制为整数
if (dpr >= 3) {
dpr = 3;
} else if (dpr >= 2) {
dpr = 2;
} else {
dpr = 1;
}
// 计算缩放比例
let scale = 1 / dpr;
let content = `width=device-width, initial-scale=${scale}, maximum-scale=${scale}, minimum-scale=${scale}, user-scalable=no`;
// 设置ViewPort
if (viewportEl) {
viewportEl.setAttribute("content", content);
} else {
viewportEl = document.createElement("meta");
viewportEl.setAttribute("name", "viewport");
viewportEl.setAttribute("content", content);
document.head.appendChild(viewportEl);
}
// 设置rem
function setRemUnit() {
const ratio = 10;
let viewWidth =
rootEl.getBoundingClientRect().width || window.innerWidth;
rootEl.style.fontSize = viewWidth / ratio + "px";
}
setRemUnit();
// 监听屏幕尺寸变化
window.addEventListener("resize", setRemUnit);
indow.addEventListener("pageshow", function (e) {
if (e.persisted) {
setRemUnit();
}
});
</script>
</head>
<body>
<header class="top">hello</header>
</body>
</html>