马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
之前写过一篇前端兼容性的文章,那篇没管 CSS 的处理。这一篇把 CSS 兼容和 JS 兼容一起讲:先把兼容性版本定下来,再用 .browserslistrc 统一声明目标环境,JS 侧靠 polyfill 补齐,CSS 侧靠 postcss-preset-env 加 autoprefixer 处理前缀,最后在构建产物里核对生成结果。
一、先确定要兼容哪些版本
第一步是定兼容性底线版本。我们的兼容性以 APP H5 的兼容版本为准,也就是最低要支持这些:
- ios >= 13
- android >= 9
- chrome >= 107
复制代码
二、在项目根目录建 .browserslistrc
配置内容大致就下面这样:
- ios >= 13
- android >= 9
- chrome >= 107
复制代码
配置完可以跑一下 npx browserslist 验证一下。
三、JS 兼容:polyfill 怎么引
针对单个 API 手动引 polyfill
可以直接上 https://cdnjs.cloudflare.com/polyfill/ 这个网站,想给某个 API 生成垫片就直接生成,然后用 CDN 引入,这样能最大粒度地控制引入范围。
用 babel-preset-env 自动按需引入
官网写得很清楚:https://www.babeljs.cn/docs/babel-preset-env 。默认情况下,@babel/preset-env 会读取 browserslist 配置文件,配置项平时都用默认值,重点把 useBuiltIns 设成 usage。
- {
- "presets": [
- [
- "@babel/preset-env",
- {
- "useBuiltIns": "usage",
- "corejs": 3,
- "modules": false // 保留ES模块语法,便于Tree Shaking
- // "debug": true // 可以开发环境显示polyfill信息调试
- }
- ]
- ],
- }
复制代码
Babel 会自动扫代码里用到的 ES 新特性,只为用到的特性按需引入 core-js 的 polyfill(corejs 一定要设成 3)。如果用 useBuiltIns: "entry",就需要在入口文件里手动引入 core-js。
几个坑
- 注意 babel/preset-env 和 core-js 的版本问题。一开始我想验证 Object.hasOwn 这个 API 的 polyfill 结果,就在代码里写了几个 Object.hasOwn,结果怎么搜都搜不到 has-own 文件被引入,查了一下这个 API 是 ES2022 才引入的,非常新,所以 core-js 版本低于 3.xxx 的话就 polyfill 不了这个 API。
- next 设置里的坑。我在 next/babel 的配置里反复试了很多次都不行,也不确定是不是包版本的问题。一开始的配置是这样,我甚至为了放大效果直接把 targets 配上了,生成出来的结果还是没有 polyfill。
一气之下(也不是),我直接在顶层引入 preset-env,像下面这样,忽然就好了。
build 的时候打开 debug,控制台会有提示:
浏览器 API 要特殊处理
Babel/preset-env 只负责 JS 和 ES6 语法转换,不管浏览器 DOM/Web API,比如 IntersectionObserver、fetch、requestIdleCallback 这些,Babel 没法自动给它们补 polyfill。怎么判断一个 API 能不能靠 preset-env 处理?
- (有点麻烦)查 core-js 的文档:https://github.com/zloirock/core-js
- 查 MDN 文档,看这个 API 属不属于 ECMAScript 标准
- 一般来说,凡是 window.xxx 或 document.xxx 相关的 API,Babel preset-env 都不会自动 polyfill
推荐写法:
- if ('IntersectionObserver' in window) {
- // 使用原生API
- } else {
- // 加载polyfill
- import('intersection-observer');
- }
复制代码
构建产物要核对
生成的 polyfill 文件可以去 build 产物里找一下确认。
四、CSS 兼容怎么处理
用 postcss-loader(postcss 是一个转换 CSS 语法的工具)配合 autoprefixer 自动加各浏览器前缀,cssnano 负责压缩生成的 CSS。装这几个依赖:
- yarn add postcss postcss-preset-env cssnano
复制代码
其实 browsers 那一项不写也行,会自动读 .browserslistrc 里的内容。
- // postcss.config.js
- module.exports = {
- plugins: [
- require('postcss-preset-env')({
- // browsers: ['ios >= 13', 'android >= 9', 'chrome >= 107'],
- stage: 3, // 稳定阶段的CSS特性
- features: {
- 'nesting-rules': true, // 启用嵌套规则
- 'custom-properties': {
- preserve: false, // 完全转换CSS变量
- },
- 'media-query-ranges': true, // 支持媒体查询范围语法
- 'logical-properties-and-values': true, // 逻辑属性支持
- },
- autoprefixer: {
- grid: 'no-autoplace', // Chrome 107+ 不需要grid前缀
- // overrideBrowserslist: ['ios >= 13', 'android >= 9', 'chrome >= 107'] 自动读取,不用配
- }
- // debug: true, // 输出转换日志
- }),
- require('cssnano')({
- preset: 'default'
- })
- ]
- }
- /**
- * grid: 'no-autoplace'
- * false:完全不处理 Grid 前缀(不推荐)
- * true:处理所有 Grid 相关前缀(包括 IE 的旧语法)
- * 'no-autoplace':只处理不涉及自动布局的 Grid 属性
- */
复制代码
注意 window 上挂的 DOM API 只能手写补全,Babel 帮不上忙,写完记得在真机上过一遍。
编辑提示
先定 .browserslistrc 再动构建配置,顺序反了容易白改一轮;core-js 记得锁 3.x,这是 polyfill 悄悄失效最常见的坑。
|