Skip to content

移动端响应式 style 记录

Posted on:2023年1月12日 at 11:01

背景

之前做了一个移动端项目(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,下面说一下解决办法。

在上面基础上,bodyfont-size 乘以 10(不一定是 10,20、30 都行),然后页面元素设置的 rem 数值再除以上面的数字就好了。