Skip to content

💻 浏览器适配

浏览器适配是为了确保网页在不同设备和屏幕尺寸上都有良好的显示效果。

适配方案

目前移动端适配主要有两种方案,包括 vw 布局和 rem 布局。vw(视口宽度)布局根据视口宽度进行尺寸调整;rem(文档根元素)布局则基于根元素字体大小,保证不同设备上文字和元素的相对比例一致。选择上,我们采用了 vw 方案,首先是因为它得到了众多浏览器的兼容,其次它不用像 rem 在运行时通过 JavaScript 设置根元素的 font-size。vw 让我们的代码更纯粹。

Viewport 布局

Vant 组件和业务代码,全部采用 px 作为样式单位,如果需要使用 viewport 单位(vw, vh, vmin, vmax),我们推荐使用 postcss-mobile-forever 进行转换。

它是一款 PostCSS 插件,用于将 px 单位转换为 vw/vh 单位。

PostCSS 示例配置

下面提供了一份 PostCSS 基础配置。

ts
// vite.config.ts
postcss: {
  plugins: [
    viewport({
      // 最外层选择器
      appSelector: '#app',
      // 设计稿宽度(Vant 设计稿的尺寸是375)
      viewportWidth: 375,
    }),
  ],
}

TIP

模板已经内置好这些,这里介绍是为了助于你理解。

桌面端访问

我们知道 vw 布局的原理是根据视口宽度进行同比例放大,这样很好。

但想象这样一个场景,当我们从桌面端访问我们移动应用的时候,我们的视图元素也会同比例放大,这让我们的使用体验非常差,甚至无法操作 DOM 元素。

再次推荐 postcss-mobile-forever,它不仅可以完成样式单位的转换,还对桌面端可访问性做了功能增强,提升了用户体验。我们只需要配置 maxDisplayWidth 属性,它可以限制视口单位的最大宽度。

ts
// vite.config.ts
postcss: {
  plugins: [
    viewport({
      appSelector: '#app',
      viewportWidth: 375,
      maxDisplayWidth: 600
    }),
  ],
}

WARNING

桌面端访问的特性是通过 CSS 函数 min()max()calc() 实现的,请注意业务中有否老旧设备的投放场景,如果有,请关闭 maxDisplayWidth 选项。更多的兼容性情况可以查看 MDNcaniuse.com

行内样式转换

虽然这款 PostCSS 插件可以帮我们转换单位,但是像是一些行内样式单位它无法进行转换,因为这款插件是用于编译阶段的。我们需要一个运行时解决方案,在我们的行内样式需要转换的时候可以工作。好消息是,模板已经内置好这样一组函数。

ts
// src/utils/inline-px-to-vw.ts
...
export default function vw(n: number) {
  if (n === 0)
    return n

  const vwN = round(n * 100 / idealWidth, 3)
  const maxN = round(n * maxWidth / idealWidth, 3)
  const cssF = n > 0 ? 'min' : 'max'
  return `${cssF}(${vwN}vw, ${maxN}px)`
}

你只需要像这样引入。

ts
import vw from '@/utils/inline-px-to-vw'

然后在 template 像这样使用就好。

vue
<div :style="`width: ${vw(width)}; height: ${vw(height)}`"></div>

原子化 CSS (Atomic CSS)

目前,我们已经基本覆盖了常规 css 单位的转换。但是像是原子化 CSS 框架,比如 Tailwind CSSWindi CSS,以及我们模板内置的 Unocss,它们都使用 rem 单位作为样式单位。面对这种新的情况,我们需要将 rem 转成 px,再由 PostCSS 插件把 px 转成 vw

INFO

原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class,并且会以视觉效果进行命名。

非常幸运的是,Unocss 提供了这样一个预设,可以把 rem 转成 px 单位。

https://unocss.dev/presets/rem-to-px

我们只需要在 uno.config.ts 这样引入。

ts
import presetRemToPx from '@unocss/preset-rem-to-px'

export default defineConfig({
   presets: [
    ...
    presetRemToPx({
      baseFontSize: 4,
    }),
  ],
})

TIP

为什么要设置基础字体大小?请看这篇 文章

然后,像下面这样写原子化 CSS,它会自动转换为相应的 vw 单位。

vue
<h1 class="text-6xl color-pink font-semibold">
  Hello, Unocss!
</h1>

<p class="mt-4 text-gray-700 dark:text-white">
  This is a simple example of Unocss in action.
</p>

以上,就是我们适配的全部了。

基于 MIT 许可发布