coverPiccoverPic

要怎么做 CSS 适配呢

前言

CSS 适配的目的就是让设计稿在不同屏幕宽度下的视觉效果尽可能一致,相关技术也是本文讨论的内容。

预备知识

理想视口

通常视口(Viewport)是指,浏览器用来显示网页的那部分区域。在移动端开发中,我们希望页面宽度和设备宽度一致,并把这个想视口称为理想视口(ideal viewport)。可以通过 HTML 中的<meta>设置理想视口:

html
  1. <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">

width=device-width就是视口宽度等于内容宽度,initial-scalemaximum-scaleminimum-scaleuser-scalable,分别是页面初始放缩倍数、最大放缩倍数、最小防缩倍数,以及是否允许用户放缩。

设备像素比

首先有几个常见的概念:

物理像素(Physical Pixel)是手机屏幕上显示的最小单元,该最小单元具有颜色及亮度的属性可供设置,像素分辨率一般是指的物理像素,例如:iPhone 6 plus:1242*2208、iPhone 6:750*1334、iPhone 5s:640*1136。

设备独立像素(Density-Indenpendent Pixel),或者说逻辑像素,是计算机设备中的一个点,CSS 中设置的 px 指的就是该像素。手机的逻辑分辨率一般是指逻辑像素,例如:iPhone 6 plus:414*736、iPhone 6:375*667、iPhone 5s 320*568。

设备像素比(Device Pixel Ratio,DPR),有的地方也说倍率,就是物理像素和设备独立像素之比。

DPR=物理像素/设备独立像素 DPR = 物理像素/设备独立像素

以 iPhone 6 为例,DPR=2DPR = 2,一个逻辑像素(CSS 里面的 1px)包含了 2*2 = 4 个物理像素。一般情况下,两个图形逻辑像素的尺寸相同,就是看起来一样大。那 DPR 高的好处就是,在一个逻辑像素里面可以展示更多的细节,针对高分辨率的手机提供 2x 图就是源于此。

那对于前端移动端适配有什么影响吗?其实并没有,因为物理像素对 CSS 来说是透明的,我们不需要关心,我们只需要让 UI 尺寸呈现相同的效果就行了。

移动端适配

样式的适配需要考虑到不同屏幕尺寸对 UI 大小的影响,这方面的方法一般有 rem 布局viewport 布局媒体查询等。

rem 布局

什么是 rem 布局

rem 是一个与页面根元素<html>的字体大小font-size相等的一个长度单位。如果根元素的字体大小是 12px,那么,在任何下属的标签下,1rem 就等于 12px 。移动端适配可以根据设计稿的宽度假设一个“标准单位”,也就是前端代码的 1rem 的宽度,例如 1rem=设计稿宽度/121rem = 设计稿宽度 / 12。然后把 UI 的尺寸,转换为相对于设计稿宽度的尺寸,例如,设计稿宽度 750px,有 1rem=62.5px1rem = 62.5px,一个宽度 90px 的按钮,宽度就变成了 1.44rem。在页面上,根据用户屏幕宽度重新设置 rem 的大小,以 rem 为长度单位的 UI 也会等比例的放缩,从而实现移动端适配。

淘宝网页手机版的 CSS 适配就是基于 rem 布局的。

postcss-pxtorem

很显然,这样子的单位转换非常繁琐,但是我们有 PostCSS。postcss-pxtorem 是一个 PostCSS 的插件,可以自动把 px 单位转为 rem 单位,也就是说,开发的时候直接按照照抄设计稿的 px 单位的尺寸就可以了。

安装:

cmd
  1. npm install postcss-pxtorem

配置:

js
  1. import { defineConfig } from 'vite'
  2. import px2rem from 'postcss-pxtorem'
  3. export default defineConfig({
  4. // ...
  5. css:{
  6. postcss:{
  7. plugins:[
  8. px2rem({
  9. rootValue: 75, // 根元素字体大小,并且设计稿宽度视为 rootValue * 10
  10. unitPrecision: 4, // rem 转换后保留小数位数
  11. propList: ['*'], // 允许被转换成 rem 的 css 属性值,具体规则见文档
  12. selectorBlackList: [], // 要忽略并保留为px的选择器,支持正则和字符串匹配
  13. mediaQuery: false, // 允许在媒体查询中转换px
  14. minPixelValue: 1 // 设置要替换的最小像素值
  15. exclude: /node_modules/, // 需要排除的文件路径,支持正则、函数和字符串匹配
  16. })
  17. ]
  18. }
  19. }
  20. })

如果使用了例如 Vant(设计稿宽度 375px)等第三方 UI 组件库,组件库设计稿宽度和项目设计稿宽度不同的话,我们可以这样:

js
  1. px2rem({
  2. rootValue({ file }) {
  3. return file.indexOf('vant') !== -1 ? 37.5 : 75 // 假设项目设计稿是 750px 宽度的
  4. },
  5. // ...
  6. })

viewport 布局

什么是 viewport 布局

Viewport 布局即是使用 vw、vh 作为样式单位。1vw 等于 1% 的视口宽度,1vh 就是 1% 的视口高度,Viewport 布局即用 vw 来转换设计稿的尺寸单位,例如宽 750px 的设计稿,75px 就是 10vw。另外,还有 vmin、vmax 的样式单位,分别为 vw 和 vh 的最大值与最小值。

例如 Bilibili 手机版就使用了 viewport 布局,使用的是 vmin 的单位。

postcss-px-to-viewport

postcss-px-to-viewport 是一个将px单位转换为视口单位(一般就是vw)的 PostCSS 插件。开发中同样直接用设计稿的 px 的尺寸即可。

安装:

cmd
  1. npm install postcss-px-to-viewport

配置:

js
  1. import { defineConfig } from 'vite'
  2. import px2vw from 'postcss-px-to-viewport'
  3. export default defineConfig({
  4. // ...
  5. css: {
  6. postcss: {
  7. plugins: [
  8. px2vw({
  9. unitToConvert: 'px', // 要转化的单位
  10. viewportWidth: 750, // UI设计稿的宽度
  11. unitPrecision: 6, // 转换后的精度,即小数点位数
  12. propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
  13. viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
  14. fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
  15. selectorBlackList: ['ignore-'], // 指定不转换为视窗单位的类名,
  16. minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
  17. mediaQuery: false, // 是否在媒体查询的css代码中也进行转换,默认false
  18. replace: true, // 是否转换后直接更换属性值
  19. exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
  20. exclude: [],
  21. landscape: false // 是否处理横屏情况
  22. })
  23. ]
  24. }
  25. }
  26. })

另外如果要兼容第三方组件库,例如 Vant、AntD 之类的,可以起两个 postcss-xp-to-viewpoint 插件,一个把相应组件库的文件写exclude里面,适配设计稿,另一个用来适配组件库:

js
  1. plugins: [
  2. px2vw({
  3. viewportWidth: 1920,
  4. viewportUnit: 'vw',
  5. exclude:[/node_modules\/antd/i]
  6. }),
  7. px2vw({
  8. viewportWidth: 1440,
  9. viewportUnit: 'vw',
  10. exclude: [/^(?!.*node_modules\/antd)/] //忽略非antd
  11. })
  12. ]

响应式布局

通过媒体查询,可以针对不同的屏幕进行单独设置样式:

css
  1. .list {
  2. width: 50%;
  3. }
  4. // 针对小屏手机
  5. @media screen and (min-width: 576px) {
  6. .list {
  7. width: 100%;
  8. }
  9. }

响应式布局的思路由来已久,例如著名 UI 库 Bootstrap,但是使用响应式布局适配不同宽度的屏幕显然太麻烦的。其实实践中的做法是,设计会出手机、桌面的两张设计图,使用媒体查询来写两套不同的样式,不同宽度的手机或者桌面内部的样式就用 Rem 或者 Viewport 布局进行。

其他

一个项目里面既有移动端的,也有桌面端的页面,要怎么适配呢

像上面说的,使用媒体查询来写两套不同的样式,不同宽度的手机或者桌面内部的样式就用 Rem 或者 Viewport 布局进行。

代码层面的话,个人感觉可以把桌面端和手机端的 CSS 文件分别命名为xx.desktop.cssxx.mobile.css,然后在 postcss-px-to-viewport 或者 postcss-pxtorem 中根据文件名来设置不同的设计稿宽度。

结尾

本文稍微浅浅地总结了一下现在移动端适配的常用做法,喵~

0 条评论未登录用户
Ctrl or + Enter 评论
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run