rem单位是跟随网页根元素的fongt-size改变自动改变的,是一个相对的长度单位,非常适合在不同手机界面上自适应屏幕大小。
一般手机浏览器的默认字体大小是16px,即
:root {
font-size: 16px;
}
/* 在html网页中,:root选择器相当于html*/
也就是说,我定义一个宽度为1rem,实际宽度就是16px;
反过来说,一个ihone6设备获取的设备宽度是375px,375 ➗ 16 = 23.4375 即如下才能铺满全屏
body {
width: 23.4375rem;
height: 100%;
background-color: #000
}
一个iphone6 plus的宽度是414,那
body {
width: 25.875rem;
height: 100%;
background-color: #000
}
虽然上述实现了设计要求的全屏,但是会发现真实的问题; 一个是很明显,rem换算起来极其不方便;第二个浏览器根字体大小不确定
所以我们想如果rem和px换成简单,比方就是10,那么 一个iphone6 plus的宽度是414,那
:root {
font-size: 37.5px;
}
body {
width: 10rem;
height: 100%;
background-color: #000
}
一个iphone6 plus的宽度是414,那
:root {
font-size: 41.4px;
}
body {
width: 10rem;
height: 100%;
background-color: #000
}
这样只要根据设备宽动态设定好根元素的font-size,那么就可以很自由的使用rem了
所以要适配不同屏幕的手机,就只需要按照比例换算更改:root的font-size即可;这个比例就由窗口宽度 ÷ 设计宽度
得到(简称窗设比
)
比方设计稿750px,窗口宽度375px(为何是两倍设计稿,查看原因; 那么:
窗设比 = 375 / 750 = 0.5
根元素的fontSize = 16 * 0.5 = 8px
1.2 但是
原本这样就已经大功告成,但是在实际中,部分安卓手机(如华为某旗舰机)不支持:root的font-size小于12px; 其他一些浏览器也会出现小于12px的文字已12px显示。
为了避免在任何环节出现根元素小于12px的font-size值,且不增加设计稿尺寸到css数值换算的难度,一般都采用放大缩小法
-
- 约定
**样设比(设计稿的px值与css的rem值比)**
为100; 也就是设计稿750px,写css时写7.5rem
- 约定
-
- 使用js将:root的font-size重置为“样设比”与“窗设比”的乘积
-
- 计算CSS时的rem值只需要从设计稿获取px值再除以“样设比”100即可
窗设比 = windowWidth / designWidth = (比方)375 / 750 = 0.5
样设比 = 100
rootFontSize = 样设比 * 窗设比
cssOneWidth = 50px
cssRem = cssOneWidth / 样设比 = 7.5rem
则css实际px = cssRem * rootFontSize = (cssOneWidth / 样设比 ) * 样设比 * 窗设比 = cssOneWidth * 窗设比 = 50 * 0.5 = 25px
完整的代码vue版本(我们项目主要做横屏,以iphone6为标准)
const maxWidth = 1624;
export function setFontSize(designWidth = 1334, designHeight = 750) {
const minAspectRatio = designHeight / maxWidth;
// 网页可见区域宽
let clientWidth = document.documentElement.clientWidth || document.body.clientWidth || window.innerWidth || window.screen.width
// 网页可见区域高
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight || window.innerHeight || window.screen.height
// 设备纵横比
const deviceAspectRatio= clientHeight / clientWidth
// 设计纵横比
let designAspectRatio = designHeight / designWidth;
// 横屏
if (deviceAspectRatio < 1) {
if (deviceAspectRatio < minAspectRatio) {
// 宽比maxWidth还宽
designWidth = maxWidth
} else if (deviceAspectRatio < designAspectRatio) {
clientWidth = clientHeight / designAspectRatio
}
}
window.clientWidth = clientWidth
console.log({
devicePixelRatio: window.devicePixelRatio,
dclientWidth: document.documentElement.clientWidth,
bClientWidth: document.body.clientWidth,
innerWidth: window.innerWidth,
screenWidth: window.screen.width,
deviceAspectRatio,
minAspectRatio,
clientWidth,
})
const fontSize = 100 * ( clientWidth / designWidth) ;
window.__REM_FONTSIZE__ = fontSize;
document.documentElement.style.fontSize = `${fontSize}px`;
}
至于像素出现小数问题,即rem经过换算成px时,出现诸如25.5px的问题;
浏览器在处理小数像素的时候并不是直接舍入处理的,元素依旧占据着应有的空间,只是在计算元素尺寸的时候做了舍入处理
目前遇到最多的问题就是 background-image 的问题,经常会因为小数像素导致背景图被裁掉一部分。
解决
- 使用iconfont
- 如果使用 background-image,尽量为背景图设置一定的空白间隙,就是给图片的父盒子要比图片大一点,图片居中。比方图片大小最终为67.1875px x 67.1875px 就给盒子 72px X 72 px