postcss-px2rempx2rem-loader

安装

安装 postcss-px2rempx2rem-loader

1
npm install postcss-px2rem px2rem-loader --save

新建文件

在 src 目录下新建 rem.js 文件:src/utils/rem.js,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const baseSize = 16
function setRem() {
// 当前页面宽度相对于 1920 宽的缩放比例。
const scale = document.documentElement.clientWidth / 1920

// 设置页面根节点字体大小(“Math.min(scale, 2)” 指最高放大比例为 2,可根据实际业务需求自行调整)
document.documentElement.style.fontSize = baseSize * Math.min(scale, 2) + 'px'
}
setRem()

// 改变窗口大小时重新设置 rem。
window.onresize = function () {
setRem()
}

引入

src/main.js 文件下新增下列代码:

1
2
// rem
import './utils/rem.js'

配置插件

vue.config.js 文件下配置插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 引入等比适配插件
const px2rem = require('postcss-px2rem')

// 配置基本大小
const postcss = px2rem({
// 基准大小 baseSize,注意:需要和 rem.js 中的相同。
remUnit: 16
})

module.exports = {
lintOnSave: true,
css: {
loaderOptions: {
postcss: {
plugins: [
postcss
]
}
}
}
}

最后当我们写 px 单位时,最后会编译成 rem 单位。


postcss-px2rem-excludeflexible.js

安装

1
npm install postcss-px2rem-exclude --save-dev

安装 lib-flexible 或者直接本地引入 flexible.js

1
npm install lib-flexible
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
(function (win, lib) {
var doc = win.document
var docEl = doc.documentElement
var metaEl = doc.querySelector('meta[name="viewport"]')
var flexibleEl = doc.querySelector('meta[name="flexible"]')
var dpr = 0
var scale = 0
var tid
var flexible = lib.flexible || (lib.flexible = {})

if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例')
var match = metaEl
.getAttribute('content')
// eslint-disable-next-line no-useless-escape
.match(/initial\-scale=([\d\.]+)/)
if (match) {
scale = parseFloat(match[1])
dpr = parseInt(1 / scale)
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content')
if (content) {
// eslint-disable-next-line no-useless-escape
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/)
// eslint-disable-next-line no-useless-escape
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/)
if (initialDpr) {
dpr = parseFloat(initialDpr[1])
scale = parseFloat((1 / dpr).toFixed(2))
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1])
scale = parseFloat((1 / dpr).toFixed(2))
}
}
}

if (!dpr && !scale) {
// var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi)
var devicePixelRatio = win.devicePixelRatio
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
dpr = 2
} else {
dpr = 1
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1
}
scale = 1 / dpr
}

docEl.setAttribute('data-dpr', dpr)
if (!metaEl) {
metaEl = doc.createElement('meta')
metaEl.setAttribute('name', 'viewport')
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl)
} else {
var wrap = doc.createElement('div')
wrap.appendChild(metaEl)
doc.write(wrap.innerHTML)
}
}

function refreshRem() {
var width = docEl.getBoundingClientRect().width
if (width / dpr > 540) {
width = width * dpr
}
var rem = width / 10
docEl.style.fontSize = rem + 'px'
flexible.rem = win.rem = rem
}

win.addEventListener(
'resize',
function () {
clearTimeout(tid)
tid = setTimeout(refreshRem, 300)
},
false
)
win.addEventListener(
'pageshow',
function (e) {
if (e.persisted) {
clearTimeout(tid)
tid = setTimeout(refreshRem, 300)
}
},
false
)

if (doc.readyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px'
} else {
doc.addEventListener(
'DOMContentLoaded',
function () {
doc.body.style.fontSize = 12 * dpr + 'px'
},
false
)
}

refreshRem()

flexible.dpr = win.dpr = dpr
flexible.refreshRem = refreshRem
flexible.rem2px = function (d) {
var val = parseFloat(d) * this.rem
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px'
}
return val
}
flexible.px2rem = function (d) {
var val = parseFloat(d) / this.rem
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem'
}
return val
}
})(window, window['lib'] || (window['lib'] = {}))


引入

main.js 中引入 flexible:

1
2
3
import 'lib-flexible'
// or
import './assets/js/flexible.js'

配置 postcss-px2rem-exclude

编辑 postcss.config.js 文件:

1
2
3
4
5
6
7
8
9
module.exports = {
plugins: {
autoprefixer: {},
'postcss-px2rem-exclude': {
remUnit: 75
// exclude: /node_modules|folder_name/i,
}
}
}

注意

如果需要适配大屏,则需要更改部分文件:

编辑 flexible.js 文件:

1
2
3
4
5
6
7
8
9
10
11
function refreshRem() {
var width = docEl.getBoundingClientRect().width;
if (width / dpr < 540) { // 获取屏幕宽度,如果宽度小于540则按540来计算
width = 540 * dpr;
} else if (width / dpr > 5760) { // 如果大于5760则按5760来计算
width = 5760 * dpr;
}
var rem = width / 12; // 按12等份
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}

编辑 postcss.config.js 文件:

1
2
3
4
5
6
7
8
9
module.exports = {
plugins: {
autoprefixer: {},
'postcss-px2rem-exclude': {
remUnit: 355 // 如果设计稿宽度为4260,并且分为12等份,则这里就需要设置为 4260 / 12 = 355,则表示 1rem = 355px
// exclude: /node_modules|folder_name/i,
}
}
}