rem 组件
移动端开发中,有时需要使用rem
作为尺寸单位来做各个机型的适配。
如下介绍的是如何设置rem
和通过less
函数来做浏览器适配。
使用方式
// 引入 rem/index.js 去动态修改 rootElement 的 font-size 值为屏幕款的 1/10
import rem from './rem';
2
/* 引入 rem/index.less 以便使用 .rem 函数 */
@import '.rem/index.less';
/* 其中 640 为该元素的设计稿宽度,单位是px(设计稿宽度为 640px,如需修改,可更改 rem/index.less 文件) */
.class-name {
.rem(width, 640);
}
2
3
4
5
6
7
/**
* @file 初始化页面时设置 html 元素的 font-size 为屏幕宽度的 1/10
* 即屏幕宽度 = 10rem
* @author: wind-stone<wind-stone@qq.com>
*/
(function(window) {
var document = window.document;
var rootElement = document.documentElement;
if (document.readyState === 'complete') {
setBodyFontSize();
} else {
document.addEventListener('DOMContentLoaded', completed, false);
document.addEventListener('load', completed, false);
}
setRootElementFontSize();
/**
* 设置 html 根元素的 font-size
*/
function setRootElementFontSize() {
// 不能这样获取屏幕宽度,因为在低端 OPPO & VIVO 手机上会返回 980
// var rootElementWidth = window.innerWidth
// 也可以这样获取屏幕宽度
// var rootElementWidth = document.documentElement.clientWidth
var rootElementWidth = rootElement.getBoundingClientRect().width;
var pxPerRem = rootElementWidth / 10;
rootElement.style.fontSize = pxPerRem + 'px';
}
/**
* 设置 body 元素的 font-size(以便继承 font-size)
*/
function setBodyFontSize() {
document.body.style.fontSize = '14px';
}
/**
* DOMContentLoaded/load 完成之后执行
*/
function completed() {
document.removeEventListener('DOMContentLoaded', completed);
document.removeEventListener('load', completed);
setBodyFontSize();
}
})(window);
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
/**
* @file rem 函数
* @author: wind-stone<wind-stone@qq.com>
* 使用示例:.rem(width, 640); 640为设计稿宽度,可以修改为需要的值
*/
.rem(@name, @px){
@{name}: @px / 640 * 10rem;
}
2
3
4
5
6
7
8
9
Android 设置系统字体大小影响 rem 的值
在开发 APP 内的 h5 页面且使用上述的rem
布局时,若改变 Android 机型的系统字体大小后,会导致页面布局错乱,其原因是,系统字体大小的改变,会覆盖上述用户自己修改的html
的font-size
(但覆盖的时机不确定),网上有如下几种解决方案。
参考:rem布局在webview中页面错乱open in new window
方案一: 客户端固定 webview 的默认字体大小(推荐)
安卓客户端通过webview
配置webview.getSettings().setTextZoom(100)
就可以禁止缩放,按照百分百显示。
方案二: 获取系统字体大小后改写 html 的大小为百分比
此方案会先获取到系统字体大小,再将html
元素的font-size
设置为基于系统字体大小的百分比数值,以最终达到想要的px
值。
/**
* @file 初始化页面时设置 html 元素的 font-size 为屏幕宽度的 1/10
* 即屏幕宽度 = 10rem
* @author: wind-stone<wind-stone@qq.com>
*/
(function(window) {
var document = window.document;
var rootElement = document.documentElement;
if (document.readyState === 'complete') {
setBodyFontSize();
} else {
document.addEventListener('DOMContentLoaded', completed, false);
document.addEventListener('load', completed, false);
}
setRootElementFontSize();
/**
* 获取系统默认字体大小
*/
function getSystemDefaultFontSize() {
var d = window.document.createElement('p');
d.style.width = '1rem';
d.style.display = 'none';
var head = window.document.getElementsByTagName('head')[0];
head.appendChild(d);
var defaultFontSize = parseFloat(
window.getComputedStyle(d, null).getPropertyValue('width')
);
return defaultFontSize;
}
/**
* 设置 html 根元素的 font-size
*/
function setRootElementFontSize() {
// 不能这样获取屏幕宽度,因为在低端 OPPO & VIVO 手机上会返回 980
// var rootElementWidth = window.innerWidth
// 也可以这样获取屏幕宽度
// var rootElementWidth = document.documentElement.clientWidth
var rootElementWidth = rootElement.getBoundingClientRect().width;
var pxPerRem = rootElementWidth / 10;
// rootElement.style.fontSize = pxPerRem + 'px';
rootElement.style.fontSize =
(rootElementWidth / getSystemDefaultFontSize()) * 100 + '%';
}
/**
* 设置 body 元素的 font-size(以便继承 font-size)
*/
function setBodyFontSize() {
document.body.style.fontSize = '14px';
}
/**
* DOMContentLoaded/load 完成之后执行
*/
function completed() {
document.removeEventListener('DOMContentLoaded', completed);
document.removeEventListener('load', completed);
setBodyFontSize();
}
})(window);
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
此方案尽管经过测试是有效的,但是因为没有任何资料显示设置系统字体大小后系统覆盖html
的font-size
的时机,会存在通过setRootElementFontSize
设置html
的font-size
之后系统再覆盖字体大小的可能。
PS: 关于这种方法,我猜测在getSystemDefaultFontSize
方法里获取div
元素的宽度时,就已经确定了系统默认字体大小了,因此之后改写html
的font-size
,就不会再被系统覆盖。
方案三: 先设置再读取,不一致的话,重新设置
此方案是先按要求设置html
的font-size
,再通过 DOM API 读取出来,对比设置值和读取值,若不一致,再按照比例再设置一次。
function htmlFontSize(){
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var width = w > h ? h : w;
width = width > 720 ? 720 : width
var fz = ~~(width*100000/36)/10000
document.getElementsByTagName("html")[0].style.cssText = 'font-size: ' + fz +"px";
var realfz = ~~(+window.getComputedStyle(document.getElementsByTagName("html")[0]).fontSize.replace('px','')*10000)/10000
if (fz !== realfz) {
document.getElementsByTagName("html")[0].style.cssText = 'font-size: ' + fz * (fz / realfz) +"px";
}
}
2
3
4
5
6
7
8
9
10
11
12
~
是 NOT 操作符。对于浮点数,~~value
可以代替parseInt(value)
,且效率更高。
假设fz
为100
,得到的realfz
为200
,则将html
的font-size
设置为50
时,最终得到的realfz
就为一开始想要的fz
即100
了。