背景
之前做了一个移动端项目(sdk 内嵌的 web 页面),设计稿上有两种尺寸,外加横竖屏
第一种:横屏时宽度:584px、竖屏时宽度:336px
第二种:横屏时宽度:876px、竖屏时宽度:504px
第二种相当于是第一种的 1.5 倍,要求页面元素也是等比放大 1.5 倍。
所以一开始的做法是,把用到的长度都抽成变量(less),然后基础的样式直接用,再媒体查询判断屏幕宽度如果是第二种,则用变量乘以 1.5,就像下面这样:
@error-font-size: 13px;
@error-line-height: 18px;
// 基础样式:横屏
.error-content {
font-size: @error-font-size;
line-height: @error-line-height;
}
// 竖屏
.error-vertical {
.error-content {
// other style...
}
}
// 横屏大屏
@media (min-width: 876px) {
.error-content {
font-size: @error-font-size * 1.5;
line-height: @error-line-height * 1.5;
}
}
// 竖屏大屏
@media (min-width: 504px) {
.error-vertical {
.error-content {
font-size: @error-font-size * 1.5;
line-height: @error-line-height * 1.5;
}
}
}
这样运行了一段时间也没什么问题,最近有需求要增加适配 PC 端,这样屏幕宽度会大很多,然后显示还是按照第二种显示的,所以效果和设计图就不一致了,虽然也能用,但是看着不协调。
怎么做呢?
一、CSS
我们知道 css 有个单位叫 rem
,是「根元素的字体大小」,是全局的。我们可以使用这个。
首先我们添加一段全局的样式:
@media screen and (min-width: 584px) and (orientation: landscape) { // 横屏基础样式 1 倍
html {
font-size: 1px;
}
}
@media screen and (min-width: 336px) and (orientation: portrait) { // 竖屏基础样式 1 倍
html {
font-size: 1px;
}
}
@media screen and (min-width: 642.4px) and (orientation: landscape) { // 横屏 1.1 倍
html {
font-size: 1.1px;
}
}
@media screen and (min-width: 369.6px) and (orientation: portrait) { // 竖屏 1.1 倍
html {
font-size: 1.1px;
}
}
@media screen and (min-width: 700.8px) and (orientation: landscape) { // 横屏 1.2 倍
html {
font-size: 1.2px;
}
}
@media screen and (min-width: 403.2px) and (orientation: portrait) { // 竖屏 1.2 倍
html {
font-size: 1.2px;
}
}
...
上面代码我们利用媒体查询 针对不同屏幕尺寸及横竖屏设置了 rem 的大小。这样就可以在页面中直接使用 rem 单位,而不用再进行媒体查询判断 乘以 1.5 什么的。
上面代码可以优化一下,我使用的 less,就可以利用 less 的能力,少写很多代码:
.loop(@i) when (@i >= 1) {
.loop((@i - 0.1));
// 横屏
@media screen and (min-width: (584px * @i)) and (orientation: landscape) {
html {
font-size: (1px * @i);
}
}
// 竖屏
@media screen and (min-width: (336px * @i)) and (orientation: portrait) {
html {
font-size: (1px * @i);
}
}
}
.loop(6);
这样我们就可以生成最终想要的代码,而且适配屏幕宽度的范围可以灵活调整,比如上面最大可以适配到 584 * 6 px
,而且是以 0.1 递增的。
这样我们一开始的样式就可以这样写了:
@error-font-size: 13rem;
@error-line-height: 18rem;
// 基础样式:横屏
.error-content {
font-size: @error-font-size;
line-height: @error-line-height;
}
// 竖屏
.error-vertical {
.error-content {
// other style...
}
}
可以看到,我们把媒体查询的样式去掉了,少写了很多代码。效果也更好。
二、JS
其实上面的做法已经足够了,兼容性也很好,但是我们还可以选择另外一种方式设置 rem
。
利用 js:
function setRem(width: number, height: number) {
const html = document.querySelector("html");
if (!html) {
return;
}
if (width && height) {
if (width < height) {
// 竖屏
html.style.fontSize = window.innerWidth / 336 + "px";
} else {
// 横屏
html.style.fontSize = window.innerWidth / 584 + "px";
}
} else {
html.style.fontSize = "";
}
}
function onResize() {
setTimeout(() => {
setRem(window.innerWidth, window.innerHeight);
}, 100);
}
window.addEventListener("resize", onResize);
onResize();
利用 js 我们可以更细粒度的控制尺寸大小,要比 css 的更加精确。
CSS 和 JS 两种方式都可以,我是两种都用了,js 出错时,可以用 css 来保底。
2023-2-20 更新
遇到个问题,部分设备的 font-size
大小有限制,我遇到的有两个安卓机器上最小只能到 2.66667px
,有个模拟器上最小只能到 8px
,下面说一下解决办法。
在上面基础上,body
的 font-size
乘以 10(不一定是 10,20、30 都行),然后页面元素设置的 rem
数值再除以上面的数字就好了。