h5 移动端适配最佳实践
移动端适配的方案需要根据具体的业务场景进行选择,工作中接触最多的是一些h5活动页、落地页等,这些页面在大小屏手机上的展示要求大小屏无差异,那么就针对以上要求进行项目整体的适配是最合适不过的。 如果是大屏手机展示更多的内容,并不着重于放大展示的话,外层布局使用vw,%,flex,内层直接px的混合适配的方案更加合适。
实现方案
方案一:手写vw+vh方案
换算vw、vh函数的实现:
@mixin px-to-vw($px, $design-width: 375) { // $design-width:设计稿大小
width: calc(#{$px} / #{$design-width} * 100vw);
}
.element {
@include px-to-vw(50); /* 将 50px 转换为基于 375px 设计稿宽度的 vw */
}
方案二:手写rem+vw方案
换算rem函数的实现:
// 基础字体大小以vw为单位
$base-font-size: 0.43vw;
@function px-to-rem($px) {
@return #{$px / $base-font-size}rem;
}
.element {
font-size: px-to-rem(16); // 结果是 1rem
padding: px-to-rem(24) px-to-rem(32); // 结果是 1.5rem 2rem
}
方案三:postcss-pxtorem + amfe-flexible
postcss-pxtorem
借助第三方库 postcss-pxtorem 可以自动将px转换成rem,不需要手动计算,按照以下配置即可:
module.exports = {
css: {
postcss: {
plugins: [
require('postcss-pxtorem')({
rootValue: 16, // 基准字体大小, 1rem = 16px
unitPrecision: 3, // 保留的小数位数
propList: ['*'], // 需要转换的属性, * 表示全部属性
minPixelValue: 1 // 设置最小的转换数值
})
]
}
}
}
}
这一步实现了px到rem单位的转换,但是基准值 rootValue
写的16 (1rem = 16px)
, 如果不动态调整font-size,页面将无法响应不同设备的尺寸变化。
amfe-flexible
借助第三方库 amfe-flexible 根据设备屏幕宽度大小自动调整font-size
:
// Install
npm i -S amfe-flexible
// Import
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<script src="./node_modules/amfe-flexible/index.js"></script>
需要注意的是,amfe-flexible 计算 1rem 的方式是 设备屏幕宽度/10
,源码如下所示 :
// set 1rem = viewWidth / 10
function setRemUnit () {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
那么需要将 postcss-pxtorem 中 rootValue
设置为 设计稿的宽度/10
,假设设计稿的宽度大小是375,那么对应的rootValue(1rem)设置为 37.5
。
module.exports = {
css: {
postcss: {
plugins: [
require('postcss-pxtorem')({
rootValue: 37.5, // 设计稿大小/10
// ...
}
此方案将屏幕拆分成10份,假设屏幕宽度是375,那么1rem = 37.5px,即 1px = 0.02666667rem
那么反过来计算元素大小为37.5px时0.02666667rem x 37.5 = 1.000000012
会存在轻微的误差。
方案四:postcss-pxtorem + 手写实现flexible.js
针对 amfe-flexible 存在的问题,可以自己设置基准值,例如 1rem = 50px:
function setRootPixel() {
var defaultFontSize = 0;
function getDefaultFontSize() {
if (defaultFontSize) {
return defaultFontSize;
}
document.documentElement.style.fontSize = "";
var temp = document.createElement("div");
temp.style.cssText = "width:1rem;display:none";
document.head.appendChild(temp);
defaultFontSize =
+window
.getComputedStyle(temp, null)
.getPropertyValue("width")
.replace("px", "") || 16;
document.head.removeChild(temp);
return defaultFontSize;
}
function setRootFontSize() {
// 预设的基准值,此处的值与rootValue相等即可
var rem2px = 50;
var clientWidth =
window.innerWidth && document.documentElement.clientWidth
? Math.min(window.innerWidth, document.documentElement.clientWidth)
: window.innerWidth ||
document.documentElement.clientWidth ||
(document.body && document.body.clientWidth) ||
375;
// 在设计稿是375的情况下1rem = 50px,此处则根据实际的clientWidth来计算根元素 `<html>` 的 `font-size` 值
var htmlFontSizePx = (clientWidth / 375) * rem2px;
window.ROOT_FONT_SIZE = htmlFontSizePx;
var htmlRootElement = document.querySelector("html");
if (htmlRootElement) {
// 通过相对于原来字体百分比大小的形式来设置字体大小
htmlRootElement.style.fontSize =
(htmlFontSizePx / getDefaultFontSize()) * 100 + "%";
}
}
function adjust(immediate) {
if (immediate) {
setRootFontSize();
return;
}
setTimeout(setRootFontSize, 30);
}
adjust(true);
window.addEventListener("resize", adjust, false);
if ("onorientationchange" in window) {
window.addEventListener("orientationchange", adjust, false);
}
}
typeof window !== "undefined" && setRootPixel();
假设rootValue为50
(1rem = 50px),那么flexible中划分的份数 = 设计稿大小/50
,再通过 实际屏幕大小/划分的份数
计算出根元素 <html>
的 font-size
值。
总结
两种方案都使用了postcss-pxtorem,都是在编译时对单位进行了转换,在实际的业务场景中会通过js设置动态样式,自行实现转换函数:
/**
* px转rem
* @param px 375屏宽下的px值
* @param unit 是否需要rem单位,默认true
* @returns rem值
*/
export function px2rem(px: number, unit?: true): string;
export function px2rem(px: number, unit: false): number;
export function px2rem(px: number, unit = true) {
const rem = Math.floor((px / 50) * 1000000) / 1000000;
if (unit) {
return `${rem}rem`;
}
return rem;
}
作者:吃嘛嘛香呼呼
链接:https://juejin.cn/post/7408798040520556559
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://juejin.cn/post/7408798040520556559
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。