postcss-adaptive-matrix
v0.8.1
Published
Responsive CSS compiler for PostCSS 8 with per-design canvases, optional fluid bounds, rem-aware typography, container units, component-library routing, and CLI diagnostics.
Maintainers
Readme
你按设计稿写 px,编译器负责换算。但换算的前提是先知道这个 px 画在哪张稿子上——这就是整个项目的核心模型。
同一个 16px,三个正确答案
页面画在 750 上,装进来的移动端组件库画在 375 上,桌面端组件库根本没有画布而是按真实像素绘制。把它们塞进同一个换算公式,得到的一定是三个错误里挑一个。
把组件库加进忽略名单也解决不了:页面缩放而组件不动,或者组件按错误画布被拉变形——这正是忽略名单唯一能给出的两个选项。
给每张设计稿一个画布,才是对的。而这是默认行为,不需要配置。
安装
npm i -D postcss postcss-adaptive-matrix程序化接口
构建脚本与编辑器工具也可以直接调用编译接口:
import { compileAdaptiveCss } from 'postcss-adaptive-matrix'
const { css, warnings } = await compileAdaptiveCss('.card { padding: 24px }')只有 CSS 输入必填。多文件可使用 createAdaptiveCompiler() 复用配置,也可按需传入 PostCSS 源码映射选项和浏览器目标。结果字段和错误处理见程序化编译。
快速开始
在 postcss.config.mjs 中先零配置接入:
import adaptiveMatrix from 'postcss-adaptive-matrix'
export default {
plugins: [adaptiveMatrix()],
}这会使用内置画布和组件库路由,不注入全局根样式。开始使用不需要填写任何配置字段。只覆盖与设计稿或布局不同的部分即可;例如下面的移动端/桌面端预设使用 #app 根容器基础样式:
import adaptiveMatrix, { appPcPreset } from 'postcss-adaptive-matrix'
export default {
plugins: [
adaptiveMatrix(
appPcPreset({
appDesignWidth: 375,
pcDesignWidth: 1440,
rootSelector: '#app',
}),
),
],
}业务 CSS 照常写:
.page {
padding: 16px;
font-size: 16px;
}
@adaptive pc {
.page {
padding: 48px 64px;
}
}输出:
.page {
padding: clamp(13.65333px, 4.26667vw, 20.48px);
font-size: clamp(0.94867rem, calc(0.65rem + 1.49333vw), 1.098rem);
}
@media (min-width: 768px) {
.page {
padding: clamp(34.13333px, 3.33333vw, 64px) clamp(45.51111px, 4.44444vw, 85.33333px);
}
}到这里,组件库适配、安全区变量、根列布局和 position: fixed 修正已经全部生效,不需要再写一行配置。
能力
| | |
| --- | --- |
| 多画布 | App、PC、平板、车机各有独立设计宽度、断点、流体区间与单位 |
| 有界流体 | 默认输出 clamp(),不会无限放大或无限压缩 |
| 根字号响应 | rem + vw 混合公式保留根字号相对分量;仍需真实缩放验收 |
| 组件库开箱适配 | 11 个库、12 个适配条目:移动端库按各自画布换算,桌面端库默认保留原始像素 |
| 主题 token | :root 上的库变量按名字识别,字号自动走文字公式 |
| 固定定位修正 | 居中列布局下 position: fixed 不再贴到视口边 |
| 容器查询 | unit: 'cqi' + @container,尺寸依赖容器而非窗口 |
| 原子化 CSS | Tailwind 与 UnoCSS 两个大版本,连它们工具类读的主题 token 一起认领 |
| 可选运行时 | VisualViewport 观察器,覆盖 WebView、软键盘与动态视口 |
| 命令行预览 + JSON 报告 | 改完配置不用构建;人能看逐条换算,CI 能读带版本号的结构化诊断 |
| 断点接缝检查 | 自动找出「窗口变宽、尺寸反而变小」的位置——两张设计稿没对齐的地方 |
| 浏览器支持审计 | 拿产物去对你要支持的最低浏览器版本,逐条列出超标的语法 |
| 工程化 | 完整 TypeScript 类型,ESM + CJS 双产物,语言无关一致性套件 |
有界流体尺寸
纯 vw 没有尺寸边界。内置 profile 带有上下界:区间内尺寸跟随视口,区间外停住。这是预设的选择,不是自定义 profile 的必填字段。
fluid 不是必填,minWidth 与 maxWidth 也都不是必填:省略整个 fluid(或写 {})得到无边界流体表达式,只写一端得到单侧边界,两端都写时才生成 clamp()。Profile 真正不可省略的只有用于换算的 designWidth,不需要覆盖其他行为时还能直接简写成 profiles: { app: 375 }。
组件库开箱适配
adaptiveMatrix({
defaultProfile: 'app',
profiles: {
app: { designWidth: 750, fluid: { minWidth: 320, maxWidth: 600 } },
},
})/* 输入 —— 四处都写 16px */
:root { --van-padding-md: 16px }
.van-cell { padding: 16px }
.el-input { padding: 16px }
.page-hero { padding: 16px }/* 输出 —— 各按所属画布 */
:root { --van-padding-md: clamp(13.65333px, 4.26667vw, 25.6px) }
.van-cell { padding: clamp(13.65333px, 4.26667vw, 25.6px) }
.el-input { padding: 16px }
.page-hero { padding: clamp(6.82667px, 2.13333vw, 12.8px) }内置:vant、nutui、varlet、antd-mobile、taro-ui、element-plus、antd、arco-design、naive-ui、quasar、mui。
未收录的库写一行定义即可,收录的库用 extends 改一项即可。完整说明见组件库适配。
精准控制
/* adaptive-ignore-next */
width: 320px; /* 忽略下一条声明 */
height: 44px; /* adaptive-ignore */ /* 忽略当前行 */
/* adaptive-ignore-rule */
.widget { width: 300px } /* 忽略下一整个规则 */这三个注释会保留在产物里,因此产物再过一遍编译时仍然生效(压缩器会去掉它们)。默认保留不超过 1px 的细线;字符串、url()、local()、format() 不会误转换。
改一个数字,立刻看到结果
npx adaptive-matrix src/styles/app.csssrc/styles/app.css
profiles: app (default), pc, +5 library canvases
.page
padding 16px → clamp(13.65333px, 4.26667vw, 20.48px)
font-size 16px → clamp(0.94867rem, calc(0.65rem + 1.49333vw), 1.098rem)
@media (min-width: 768px) › .page
padding 48px → clamp(34.13333px, 3.33333vw, 64px)
shrinks .card font-size gets smaller at 768px: 17.57px → 16.18px
3 converted, 0 left as authored不用启动构建,不用开浏览器。
最后那行是断点接缝检查:App 稿写 16px、PC 稿写 18px,两个数字单独看都合理,但窗口跨过断点时,正文字号会突然变小。同一固定视口画布中,单个转换长度的绝对值不会随视口变宽而减小;负外边距则是通过变得更负来增大。检查器比较已知断点两侧的绝对值,提示可能的交接问题,也会分析手写 CSS 表达式。发现问题后应检查层叠和画布选择,不能断言换画布是唯一原因;无法解析的表达式与条件可能被跳过,因此没有报告也不代表布局一定正确。
--from 还能把文件路由先试一遍——这是最容易配错又最不容易发现的一项。详见命令行预览。
产物到底要求浏览器做到什么
npx adaptive-matrix src/app.css --targets "ios_saf 13, chrome 90" 需要 @layer — iOS Safari 13 < 15.4,Chrome 90 < 99
不支持时:整个 @layer 块会被丢弃,连同根级基础样式一起消失——
居中列、安全区变量和固定定位修正会同时失效。
替代:root.layer: false 会输出不带包裹层的相同规则 …
需要 clamp()、min()、max() — iOS Safari 13 < 13.4-13.7CSS 不会优雅降级,它丢弃,而且全程不说话:值读不懂丢一条声明,选择器读不懂丢一整条规则,@ 规则读不懂丢一整块。所以审计读的是编译产物而不是配置——这是让两者永远不会走偏的唯一做法——并且对每一项先说丢什么,再说换成什么。
版本数据在构建期烘焙进包,因此不增加任何运行时依赖,离线可用。见浏览器特性支持与降级。
文档
| | |
| --- | --- |
| 快速上手与双设计稿工作流 | 从安装到 App/PC 双稿协作 |
| 构建工具集成 | Vite、Nuxt、Webpack、Taro,以及四个静默出错的点 |
| 命令行预览 | npx adaptive-matrix:不用构建就能看到换算结果 |
| 组件库适配 | 内置清单、匹配方式、覆盖与扩展 |
| 配置参考 | 全部选项、类型与默认值 |
| 架构与转换公式 | 编译流程、数学公式、幂等、实现边界 |
| 可选运行时 | VisualViewport 观察器:软键盘、地址栏、WebView |
| 浏览器特性支持与降级 | 特性 × 版本表、不支持时丢什么、每一项怎么关 |
| 迁移指南 | 从其它 px 换算方案迁移 |
| 发布与兼容性 | 产物、Node 版本、版本策略 |
| 一致性套件 | 语言无关的行为规范 |
| 完整示例 | 可运行的 App + PC 工程 |
兼容性
- Node.js 18+,PostCSS 8.4+
clamp()、min():现代浏览器基线能力- 容器查询配置需要支持
@container/cqi的浏览器 - 更老的 WebView 使用
strategy: 'viewport',或配合preserveOriginal: true自行提供降级值——用--targets可以直接看到产物到底要求了什么
开发
npm install
npm run check # 类型检查 + 覆盖率测试 + 构建
npm run conformance:update
npm run bench