正常情况下有 2 个方案,一个是 转 rem
方案一个是转 vw
转 rem 方案 px -> rem
amfe-flexible
+ postcss-pxtorem
amfe-flexible
原理其实是
- 给元素动态改写
font-size
的值 - 设置
1rem = viewWidth / 10
- 设置页面刷新时重置
rem
- 支持
0.5px
项目中引入
// 移动端适配
import 'amfe-flexible/index.js';
postcss.config.js
设置
module.exports = {
plugins: {
autoprefixer: {},
'postcss-pxtorem': {
rootValue: 37.5, //vant-UI 的官方根字体大小是 37.5
propList: ['*'],
},
},
};
转 viewport 方案 px -> vw
安装 postcss-px-to-viewport
postcss.config.js
设置
module.exports = {
plugins: {
autoprefixer: {},
// Vant 设计稿宽度为 375,其他配置均用默认的
'postcss-px-to-viewport': {
// unitToConvert: 'px', // (String) 需要转换的单位,默认为 px
viewportWidth: 375, // (Number) 视窗的宽度,对应的是我们设计稿的宽度,一般是 750
// unitPrecision: 5, // (Number) 单位转换后保留的小数位
// propList: ['*'], // (Array) 指定可以转换的 css 属性,默认是 ['*'],代表全部属性进行转换
// viewportUnit: 'vw', // (String) 指定需要转换成的视窗单位,默认 vw
// fontViewportUnit: 'vw', // (String) 指定字体需要转换成的视窗单位,默认 vw
// selectorBlackList: [], // (Array) 指定不转换为视窗单位的类,保留 px,值为 string 或正则 regexp
// minPixelValue: 1, // (Number) 默认值 1,小于或等于 `1px` 不转换为视窗单位
// mediaQuery: false, // (Boolean) 是否在媒体查询时也转换 px,默认 false
// replace: true, // (Boolean) 替换包含 vw 的规则
// exclude: [], // (Array or Regexp) 设置忽略文件,如 node_modules - [/^node_modules$/]
// landscape: false, // (Boolean) @media (orientation: landscape) 与通过转换的值相加 landscapeWidth
// landscapeUnit: 'vw', // (String) 横屏时使用的单位
// landscapeWidth: 568 // (Number) 横屏时使用的视口宽度
},
},
};
两者兼容 rem + viewport
使用 转 viewport 方案 之后引入这个 js 脚本就可以了
// 看 https://github.com/amfe/lib-flexible/blob/2.0/index.js 重写的
(function flexible(window, document) {
const docEl = document.documentElement;
// https://github.com/evrone/postcss-px-to-viewport/blob/master/index.js
// 如果你的样式需要做根据视口大小来调整宽度,这个脚本可以将你 CSS 中的 px 单位转化为 vw,1vw 等于 1/100 视口宽度。
function setRemUnit() {
const rem = (docEl.clientWidth * 16) / 375; // 16 是 375 设计稿下的字体大小
docEl.style.fontSize = rem + 'px';
document.body.style.fontSize = rem + 'px';
}
setRemUnit();
// reset rem unit on page resize
window.addEventListener('resize', setRemUnit);
window.addEventListener('pageshow', function (e) {
if (e.persisted) {
setRemUnit();
}
});
})(window, document);
一处 dpr 的代码引发的思考
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();
在 iPhoneX 下,字体是 36px
,一查 dpr
为 3
,然后去 MND 看了一下
Window 接口的 devicePixelRatio 返回当前显示设备的物理像素分辨率与 CSS 像素分辨率之比。此值也可以解释为像素大小的比率:一个 CSS 像素的大小与一个物理像素的大小。简单来说,它告诉浏览器应使用多少屏幕实际像素来绘制单个 CSS 像素。 当处理标准显示器与 HiDPI 或 Retina 显示器之间的差异时,这很有用,后者使用更多的屏幕像素绘制相同的对象,从而获得更清晰的图像。
后记
参考文章