移动端屏幕适配和高清方案

移动端页面开发经常遇到这两个问题:

  • 适配不同大小的屏幕
  • 1px问题

屏幕适配

先聊聊屏幕适配,最简单的办法是: 所有的 CSS 都用 rem 做单位,通过实时计算屏幕大小和字号的关系,实现页面内容等比缩放。

一般来说,视觉稿是按照 750px 的宽度提供,而对应的屏幕宽度通常是 375px,因为现在大部分屏幕都是高清屏,所以视觉使用2倍大小,可以保证图片等资源在高清屏上的清晰度。

接下来,我们需要指定一个标准字号应用到根节点上,然后把所有的 px 大小除以这个字号得到 rem。由于视觉稿的宽度一般是屏幕实际宽度的2倍,这个标准字号对应的也是实际的 <html> 字号的2倍,所以我们还需要把标准字号除以2,才能设置到 <html> 上,即:

根节点字号 = 屏幕宽度 / 视觉稿宽度 * 标准字号

为了计算方便,我们可以用 1px10px 这样的数字来做转换,但是浏览器存在一个最小字号限制,一般来说,中文的最小字号是 12px,如果设置一个小于 12px 的值,会被浏览器强制设置成 12px。所以,我们一般选择把标准字号设置成 100px,即 <html> 的字号为 50px,既满足了最小字号限制,又方便计算。

举个例子,在 375px 宽的屏幕上,我们把 <html> 字号设置成 50px,然后视觉稿上的所有 px 单位除以 100px 得到 rem

scaling.png

最后一步,用JavaScript检测屏幕实际宽度,调整 <html> 的字号,以达到相同的视觉效果。

const docEl = document.documentElement;
const setFontSize = () => {
  docEl.style.fontSize = `${docEl.clientWidth / 750 * 100}px`;};
setFontSize();
window.addEventListener('resize', setFontSize, false);

高清方案

高清方案的目的是解决 1px 的问题。

CSS 的 1px 实际上是逻辑像素的 1px,而视觉稿所希望的 1px 通常是物理像素的 1px,结果就是 1px 的线条比预期的更粗,因为2倍的高清屏上,1个逻辑像素实际上是2个物理像素,3倍的高清屏上则是3个物理像素。

这个问题有几种解决方案,最常用的方案是通过 viewport 来做整个页面的缩放:

<meta name="viewport" content="width=device-width,minimum-scale=0.5,maximum-scale=0.5,user-scalable=no">

将整个页面按照2倍的宽度来设计,再通过 viewport 缩小到原来的 1/2,即 minimum-scale=0.5,maximum-scale=0.5。然后再使用前面说到的屏幕适配方案,计算 <html> 的字号。这时由于页面的宽度是按照2倍设计的,所以 document.documentElement 的宽度也变成了2倍,在 375px 的屏幕上,宽度就是 750px 了,<html> 的字号也就变成了 100px

所以,上面的适配代码依然适用。

Ant Design 的高清方案

再说说 Ant Design。作为一个非常常用的组件库,Ant Design 针对高清方案做了一些黑科技处理。

从 2.x 开始,antd 内置了高清方案,如果我们要使用上面的方案,还需要做一些修改:

  1. 更改基准字号: 设置 hd: 2px,具体可以参考相关文档。
  2. 禁用内置的高清方案: 设置 document.documentElement.setAttribute('data-scale', true);,告诉 antd 我们已经启用了基于 viewport 的高清方案,让它不要自作聪明再加黑科技了。如果我们需要覆盖一些已有样式,这一点则尤为重要。

总结

移动端高清方案非常繁琐,各种处理方式都有其利弊,实际上大部分情况下,我觉得 1px 并没有那么必要,我更倾向于关闭高清方案,而通过 rem 来适配不同的屏幕大小。


© 2020