postcss-px-to-viewport-modern
The postcss-px-to-viewport-modern plugin features a brand-new architecture and introduces a customizable unit conversion strategy that can be flexibly applied across various scenarios.
全新架构的postcss-px-to-viewport-modern插件,增加了自定义单位转换策略,灵活适用各种场景。
这是一个将像素单位转换为视口单位(vw、vh、vmin、vmax)的PostCSS插件。由于最原始项目evrone/postcss-px-to-viewport已经不再维护,且底层架构很旧了,所以这个项目从更新了底层架构框架,且增加了自定义单位转换策略,基于最新版本的PostCSS(8.x)开发。
基础环境:
- node >= 22
- postCSS: "^8.4.49"
- pnpm: "9.15.3"
- tsup: "^8.3.6"
- vite: "^3.0.5"
- vitest: "^3.0.5"
- vitepress: "^1.6.3"
配置选项
安装
要使用这个插件,你需要在你的项目中设置好PostCSS。如果你还没有设置PostCSS,你可以通过运行以下命令来安装:
npm install postcss --save
接下来,安装postcss-px-to-viewport-modern
插件:
npm install postcss-px-to-viewport-modern --save
使用
要在你的PostCSS配置中使用这个插件,将其添加到PostCSS插件列表中,同时加上所需的配置选项。
以下是在postcss.config.js
中的示例配置:
注意:在vite中使用postcss.config.js配置时,无法获取文件路径,如果用需要文件路径判断的逻辑请在vite.config中进行配置
// postcss.config.js
module.exports = {
plugins: {
'postcss-px-to-viewport-modern': {
unitType: 'px',
viewportWidth: 375,
viewportUnit: 'vw',
fontViewportUnit: 'vw',
landscapeViewportWidth: 375,
landscapeUnit: 'vh',
landscapeFontViewportUnit: 'vh',
unitPrecision: 5,
allowedProperties: ['*'],
excludedProperties: [],
selectorBlacklist: ['.ignore', '.hairlines'],
minPixelValue: 1,
allowMediaQuery: true,
replaceRules: true,
excludeFiles: [],
includeFiles: [],
enableLandscape: true,
enableCustomAtRule: true,
customAtRuleWidth: 'design-width',
customAtRuleUnit: 'design-unit',
// Other configuration options...
},
},
}
vite 集成
vite.config.ts
// 最简写法-采用默认值
export default defineConfig({
css: {
postcss: {
plugins: [
'postcss-px-to-viewport-modern':({}),
],
},
},
})
// 修改配置项
export default defineConfig({
css: {
postcss: {
plugins: [
'postcss-px-to-viewport-modern':({
unitType: 'px',
viewportWidth: 375,
viewportUnit: 'vw',
fontViewportUnit: 'vw',
landscapeViewportWidth: 375,
landscapeUnit: 'vh',
landscapeFontViewportUnit: 'vh',
unitPrecision: 5,
allowedProperties: ['*'],
excludedProperties: [],
selectorBlacklist: ['.ignore', '.hairlines'],
minPixelValue: 1,
allowMediaQuery: true,
replaceRules: true,
excludeFiles: [],
includeFiles: [],
enableLandscape: true,
enableCustomAtRule: true,
customAtRuleWidth: 'design-width',
customAtRuleUnit: 'design-unit',
// Other configuration options...
}),
],
},
},
})
启用自定义规则转换
当开启enableCustomAtRule之后,允许使用@design-width 和 @design-unit 自定义规则去分别定义不同文件、class、媒体查询中的转换标准。如下:
@design-width 375px;
@design-unit vw;
插件会读取这个注释并使用指定的宽度来进行单位转换。这对于在同一个项目中为不同的设备(如PC、平板、手机)生成不同的CSS文件特别有用。
示例
以下是一个示例配置,将像素值转换为vw单位,默认视口宽度为750像素,并启用@design-width @design-unit配置:
// postcss.config.js
module.exports = {
plugins: {
'postcss-px-to-viewport-modern': {
unitType: 'px',
viewportWidth: 375,
viewportUnit: 'vw',
fontViewportUnit: 'vw',
landscapeViewportWidth: 375,
landscapeUnit: 'vh',
landscapeFontViewportUnit: 'vh',
unitPrecision: 5,
allowedProperties: ['*'],
excludedProperties: [],
selectorBlacklist: [],
minPixelValue: 1,
allowMediaQuery: true,
replaceRules: true,
excludeFiles: [],
includeFiles: [],
enableLandscape: true,
enableCustomAtRule: true,
customAtRuleWidth: 'design-width',
customAtRuleUnit: 'design-unit',
},
},
}
使用这个配置,你的CSS中的像素值将在PostCSS处理期间自动转换为视口单位。同时,你可以在每个文件中使用注释来指定某个代码块的特定视口宽度。
例如,在一个针对pad设备的CSS文件中:
@design-width 375px;
@design-unit vw;
.box {
width: 375px; /* 将被转换为 100vw */
}
而在一个针对pad设备的CSS文件中:
@media (min-width: 600px) and (orientation: landscape) {
@design-width 768px;
@design-unit vw;
.box {
width: 384px; /* 将被转换为 50vw */
}
}
这样,你就可以在一次构建中生成适配多种设备的CSS,同时保持了代码的灵活性和可维护性。
自定义规则作用域
css根节点中定义,则生效于整个css,不区分代码顺序和嵌套结构
<style scoped lang="scss">
@design-width 375px;
@design-unit vw;
.container {
font-family: 'Inter', sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 40px 20px;
background-color: #f0f0f0;
}
</style>
单个样式中定义,则仅生效于当前样式块
.nest {
@design-width 682px;
@design-unit vh;
width: 341px;
}
.nestB{
width: 100px; // 不会被转换
}
媒体查询中首层定义,则生效于整个媒体查询,不区分代码顺序和嵌套结构
@media (min-width: 600px) and (orientation: landscape) {
.item-subtitle {
width: 300px;
}
@design-width 1500px;
@design-unit vh;
.deep-nest-custom-design-landscape {
width: 750px;
.item-title {
width: 750px;
}
}
}
变量中的定义,作用于定义位置
// --custom-width 将按照 375px标准转换,而不是750px标准
@design-width 375px;
@design-unit vw;
body {
--custom-width: 187.5px; // 按照375转换
}
.custom-property {
@design-width 750px;
@design-unit vw;
width: var(--custom-width); // 不按照750转换
}
重点!重点!重点!-不支持样式中的嵌套(原因是解析时,嵌套结构已经被scss解析器压平)
// index.scss
// 如果最外层未定义@design-width,item-title 不会生效
.deep-nest {
@design-width 1500px;
@design-unit vw;
width: 750px;
.item-title {
width: 750px; // 不按照1500转换
}
}
// index.scss
// 解析时已变成
.deep-nest {
@design-width 1500px;
@design-unit vw;
width: 750px;
}
.deep-nest.item-title {
width: 750px;
}
和配置文件的权重对比
- 自定义权重高于配置文件
// postcss.config.js
module.exports = {
plugins: {
'postcss-px-to-viewport-modern': {
unitType: 'px',
viewportWidth: 375,
viewportUnit: 'vw',
enableLandscape: true,
landscapeUnit: 'vh',
landscapeViewportWidth: 375,
/** 新增:自定义 at 规则配置 */
enableCustomAtRule: true,
},
},
}
例外情况:自定义单位不生效于enableLandscape自动添加的横屏适配
// index.scss
// 例外情况:此时页面横屏,会以postcss.config.js中的landscapeViewportWidth、landscapeUnit去转换 而不是以自定义750转换。
// 如果需要对横屏下的设计稿尺寸做定制化,请使用媒体查询,自定义变量实现
@design-width 750px;
@design-unit vw;
.item-title {
width: 750px; // 结果按照自定义750转换: 100vw
}
// index.scss
@design-width 750px;
@design-unit vw;
.item-title {
width: 750px; // 结果按照自定义750转换: 100vw
}
// index.scss
.item-title {
@design-width 750px;
@design-unit vw;
width: 750px; // 结果按照自定义750转换: 100vw
}
// index.scss
@design-width 750px;
@design-unit vw;
@media (min-width: 600px) and (orientation: landscape) {
.item-title {
width: 750px; // 结果按照自定义750转换: 100vw
}
}
// index.scss
@media (min-width: 600px) and (orientation: landscape) {
@design-width 750px;
@design-unit vw;
.item-title {
width: 750px; // 结果按照自定义750转换: 100vw
}
}