移动端字体适配

viewport.js + px2rem 自适应神器

发现神器一个☝️,在前段时间搞 webpack 模块化开发 + vue 组件时被安利了一个自适应方案 viewport.js + px2rem。用完后才明白什么才是高级自适应!

首先科普一个知识点,这个知识点也就是该自适应方案的原理所在,同时也结束了我多年的困惑😖,感谢这位大大的总结!链接如下:

CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport

这个是 px 转换为 rem 单位的一个 loader 的文档
px2rem-loader

文章主要是理清这几个像素之间的关系,而 viewport.js + px2rem 就是根据这个原理来时间完美自适应,使用方法就是在 webpack 中安装依赖以及在 moudle 中配置起来。

首先开发环境安装 px2rem-loader

1
$ npm i px2rem-loader -D

配置 webpack config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
// ...
module: {
rules: [{
test: /\.css$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'px2rem-loader',
// options here
options: {
remUni: 75,
remPrecision: 8
}
}]
}]
}
}

然后 在入口文件中添加上 viewport.js,

例如:

1
entry: ['./app/js/viewport.js', './app/js/main.js'],

使用时不要考虑太多,也没有什么技巧,就只要UI提供的一个2倍尺寸的设计文件就搞定(一般UI给的都是2倍图,如果你家UI恰好给你的还是 sketch 文件,你就感动哭吧,都省去ps手动量了),在 css 中测量直接使用2倍尺寸,单位还是 px(因为我们用的是 px2rem-loader px 转换为 rem 方案!)。再说一遍,在写页面的时候是不需要考虑设备尺寸的,UI界面量的是多少就写多少,记住是2倍尺寸px单位直接写,因为我们刚刚安装和调用的工具都帮我们做了。我们就傻瓜式写页面就ok了。

然后写完的页面渲染出来在各个尺寸设备中的效果简直一毛一样,感动哭😹,麻麻再也不用担心我用媒体查询写的自适应最后变龙生九子了!

最后贴上 viewport.js 的码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
(function (window, document) {
// 给hotcss开辟个命名空间,别问我为什么,我要给你准备你会用到的方法,免得用到的时候还要自己写。
const hotcss = {};
(function () {
// 根据devicePixelRatio自定计算scale
// 可以有效解决移动端1px这个世纪难题。
let viewportEl = document.querySelector("meta[name=\"viewport\"]"),
hotcssEl = document.querySelector("meta[name=\"hotcss\"]"),
dpr = window.devicePixelRatio || 1,
maxWidth = 540,
designWidth = 0

dpr = dpr >= 3 ? 3 : (dpr >= 2 ? 2 : 1)

// 允许通过自定义name为hotcss的meta头,通过initial-dpr来强制定义页面缩放
if (hotcssEl) {
const hotcssCon = hotcssEl.getAttribute("content");
if (hotcssCon) {
const initialDprMatch = hotcssCon.match(/initial\-dpr=([\d\.]+)/)
if (initialDprMatch) {
dpr = parseFloat(initialDprMatch[1])
}
const maxWidthMatch = hotcssCon.match(/max\-width=([\d\.]+)/)
if (maxWidthMatch) {
maxWidth = parseFloat(maxWidthMatch[1])
}
const designWidthMatch = hotcssCon.match(/design\-width=([\d\.]+)/)
if (designWidthMatch) {
designWidth = parseFloat(designWidthMatch[1])
}
}
}

document.documentElement.setAttribute("data-dpr", dpr)
hotcss.dpr = dpr

document.documentElement.setAttribute("max-width", maxWidth)
hotcss.maxWidth = maxWidth

if (designWidth) {
document.documentElement.setAttribute("design-width", designWidth)
}
hotcss.designWidth = designWidth // 保证px2rem 和 rem2px 不传第二个参数时, 获取hotcss.designWidth是undefined导致的NaN

let scale = 1 / dpr,
content = `width=device-width, initial-scale=${scale}, minimum-scale=${scale}, maximum-scale=${scale}, user-scalable=no`;
if (viewportEl) {
viewportEl.setAttribute("content", content)
} else {
viewportEl = document.createElement("meta");
viewportEl.setAttribute("name", "viewport");
viewportEl.setAttribute("content", content)
document.head.appendChild(viewportEl)
}
})()

hotcss.px2rem = function (px, designWidth) {
// 预判你将会在JS中用到尺寸,特提供一个方法助你在JS中将px转为rem。就是这么贴心。
if (!designWidth) {
// 如果你在JS中大量用到此方法,建议直接定义 hotcss.designWidth 来定义设计图尺寸;
// 否则可以在第二个参数告诉我你的设计图是多大。
designWidth = parseInt(hotcss.designWidth, 10)
}

return parseInt(px, 10) * 320 / designWidth / 20
}

hotcss.rem2px = function (rem, designWidth) {
// 新增一个rem2px的方法。用法和px2rem一致。
if (!designWidth) {
designWidth = parseInt(hotcss.designWidth, 10)
}
// rem可能为小数,这里不再做处理了
return rem * 20 * designWidth / 320
}

hotcss.mresize = function () {
// 对,这个就是核心方法了,给HTML设置font-size。
let innerWidth = document.documentElement.getBoundingClientRect().width || window.innerWidth

if (hotcss.maxWidth && (innerWidth / hotcss.dpr > hotcss.maxWidth)) {
innerWidth = hotcss.maxWidth * hotcss.dpr
}

if (!innerWidth) {
return false
}

document.documentElement.style.fontSize = `${innerWidth * 20 / 320}px`;
hotcss.callback && hotcss.callback()
}

hotcss.mresize()
// 直接调用一次

window.addEventListener("resize", () => {
clearTimeout(hotcss.tid);
hotcss.tid = setTimeout(hotcss.mresize, 33)
}, false)
// 绑定resize的时候调用

window.addEventListener("load", hotcss.mresize, false)
// 防止不明原因的bug。load之后再调用一次。


setTimeout(() => {
hotcss.mresize()
// 防止某些机型怪异现象,异步再调用一次
}, 333)

window.hotcss = hotcss
// 命名空间暴露给你,控制权交给你,想怎么调怎么调。
})(window, document)

以上更新自 2018-12-25

最后 🎄 merry Xmas! 🎄 更期待 元旦 😊的到来!


收集一些官网的移动端字体适配 css,使用单位为 rem

  • 阿里云注册页 (1rem : 100px)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
html {
font-size: 100px
}
@media only screen and (min-width:320px) and (max-width:320px) {
html {
font-size: 85.33333333px
}
}
@media only screen and (min-width:360px) {
html {
font-size: 96px
}
}
@media only screen and (min-width:375px) {
html {
font-size: 100px
}
}
@media only screen and (min-width:384px) {
html {
font-size: 102.4px
}
}
@media only screen and (min-width:412px) {
html {
font-size: 109.86666667px
}
}
@media only screen and (min-width:414px) {
html {
font-size: 110.4px
}
}
@media only screen and (min-width:600px) {
html {
font-size: 204.8px
}
}


/* 使用 */
p{
font-size: .1rem;
height: .1rem;
}

/* 等同于 */
p{
font-size: 10px;
height: 10px;
}
  • 京东 (1rem : 20px)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
html {
font-size: 20px;
font-size: 5.33333vw;
}

/* 使用 */
p{
font-size: .5rem;
}

/* 等同于 */
p{
font-size: 10px;
}

未完待续…