@buletu/screen-fit — 前端多屏适配方案
一个轻量级的前端屏幕适配库,核心思路:CSS 保持设计稿 px 书写,构建时自动转换为 rem/vw,运行时动态调整根字体实现等比缩放。
特性
| 零侵入 | 不改变现有代码结构,保留 px 书写习惯 |
| 多构建工具 | Vite / Webpack4 / Webpack5 / PostCSS 全支持 |
| 三种模式 | rem(推荐)/ vw / scale 按需选择 |
| 开发调试 | 设计稿切换器 + 元素尺寸检测器 |
| TypeScript | 完整类型定义 |
安装
npm install @buletu/screen-fit
# yarn add @buletu/screen-fit
# pnpm add @buletu/screen-fit
快速上手
第一步:运行时初始化(必须)
在应用入口文件中加入,负责监听窗口尺寸变化并动态调整根字体:
// main.ts / main.tsx / index.js
import { screenFit } from '@buletu/screen-fit';
screenFit({
designWidth: 1920, // 设计稿宽度
designHeight: 1080,
mode: 'rem', // 推荐
});
第二步:选择构建工具插件(二选一即可)
构建工具集成
Vite(推荐)
// vite.config.ts
import { defineConfig } from 'vite';
import screenFit from '@buletu/screen-fit/vite-plugin';
export default defineConfig({
plugins: [
screenFit({
mode: 'rem',
designWidth: 1920,
// precision: 5, // 小数精度,默认 6
// minValue: 1, // 小于 1px 的值不转换(保留 1px 细线)
// excludeProperties: ['font-size', 'border'],
}),
],
});
Webpack 5
方式 A:使用专属 Loader(推荐,无需 PostCSS)
// webpack.config.js
const {
screenFitLoader,
screenFitLoaderOptions,
} = require('@buletu/screen-fit/webpack-loader');
module.exports = {
module: {
rules: [
{
test: /\.(css|less|scss|sass)$/,
use: [
'style-loader',
'css-loader',
{
loader: screenFitLoader, // loader 文件路径
options: screenFitLoaderOptions({ // 类型安全的 options 包装
mode: 'rem',
designWidth: 1920,
}),
},
// less-loader / sass-loader 放这里(预处理器先跑)
],
},
],
},
};
或者用 createWebpackRule 一键生成规则:
const { createWebpackRule } = require('@buletu/screen-fit/webpack-loader');
module.exports = {
module: {
rules: [
...createWebpackRule({ mode: 'rem', designWidth: 1920 }),
// 再追加 style-loader / css-loader 规则
],
},
};
方式 B:通过 PostCSS Loader(已有 postcss-loader 的项目)
// webpack.config.js
{
test: /\.(css|less|scss)$/,
use: ['style-loader', 'css-loader', 'postcss-loader'],
}
// postcss.config.js
const { pxToUnitPlugin } = require('@buletu/screen-fit/postcss-plugin');
module.exports = {
plugins: [pxToUnitPlugin({ mode: 'rem', designWidth: 1920 })],
};
⚠️ 两种方式二选一,不要同时使用。
Webpack 4
Webpack 4 配置与 Webpack 5 完全相同,loader 内部已兼容 this.query(webpack4)和 this.getOptions(webpack5)两种取参方式。
PostCSS(通用)
适用于任何使用 PostCSS 的项目(CRA、Next.js、Nuxt 等):
// postcss.config.js
const { pxToUnitPlugin } = require('@buletu/screen-fit/postcss-plugin');
module.exports = {
plugins: [
pxToUnitPlugin({
mode: 'rem',
designWidth: 1920,
excludeProperties: ['font-size', 'border'],
}),
],
};
三种适配模式
REM 模式(推荐)
根字体 = 屏幕宽度 / 设计稿宽度 × 100
1920px 设计稿中 100px → 100 / 1920 * 100 = 5.2083rem
屏幕缩小到 1440px 时,根字体自动缩小,rem 值不变,视觉尺寸自动缩放
screenFit({ mode: 'rem', designWidth: 1920 });
VW 模式
纯 CSS 方案,无需 JS 计算根字体:
screenFit({ mode: 'vw', designWidth: 1920 });
// 1920px → 100vw,100px → 5.2083vw
Scale 模式
整体页面 transform 缩放,适合后台大屏看板:
screenFit({
mode: 'scale',
designWidth: 1920,
designHeight: 1080,
adaptiveHeight: true, // 同时适配高度
});
CSS 书写示例
无论用哪种构建工具插件,CSS 都保持原始 px 写法:
/* 原始 CSS(设计稿尺寸)*/
.header {
width: 1920px;
height: 80px;
padding: 0 40px;
font-size: 16px; /* font-size 默认不转换 */
border: 1px solid #eee; /* border 默认不转换 */
}
.card {
width: 400px;
height: 300px;
border-radius: 8px;
margin: 20px;
}
构建后输出(rem 模式,designWidth=1920):
.header {
width: 100rem;
height: 4.16667rem;
padding: 0 2.08333rem;
font-size: 16px; /* 保留原值 */
border: 1px solid #eee; /* 保留原值 */
}
.card {
width: 20.8333rem;
height: 15.625rem;
border-radius: 0.41667rem;
margin: 1.04167rem;
}
TailwindCSS 支持
// tailwind.config.js
const { tailwindScreenFit } = require('@buletu/screen-fit/tailwind-plugin');
module.exports = {
plugins: [tailwindScreenFit({ mode: 'rem', designWidth: 1920 })],
};
在模板中直接使用设计稿尺寸:
<div class="w-[1920px] h-[1080px] p-[40px]">
<!-- 自动转换为对应 rem/vw 值 -->
</div>
React 集成
// App.tsx
import { useEffect } from 'react';
import { screenFit } from '@buletu/screen-fit';
function useScreenFit() {
useEffect(() => {
const fit = screenFit({ designWidth: 1920 });
return () => fit.destroy();
}, []);
}
export default function App() {
useScreenFit();
return <YourApp />;
}
开发调试工具
import { DesignSwitcher, SizeInspector } from '@buletu/screen-fit';
// 只在开发环境启用
if (process.env.NODE_ENV === 'development') {
// 设计稿快速切换面板
const switcher = new DesignSwitcher({
presets: [
{ name: '1920×1080', width: 1920, height: 1080 },
{ name: '1440×900', width: 1440, height: 900 },
{ name: '1366×768', width: 1366, height: 768 },
{ name: '1280×720', width: 1280, height: 720 },
],
});
switcher.init();
// 元素尺寸检测器
const inspector = new SizeInspector();
inspector.init();
}
快捷键:
Ctrl+Shift+1~4— 切换预设设计稿Shift+Alt+I— 开/关元素尺寸检测器
API
screenFit(options)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| designWidth | number | 1920 | 设计稿宽度 |
| designHeight | number | 1080 | 设计稿高度 |
| mode | 'rem' | 'vw' | 'scale' | 'rem' | 适配模式 |
| minWidth | number | 1024 | 最小宽度(防止过小屏幕字体异常) |
| maxWidth | number | 2560 | 最大宽度(防止超宽屏字体过大) |
| adaptiveHeight | boolean | false | scale 模式是否同时适配高度 |
构建插件公共选项
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| mode | 'rem' | 'vw' | 'rem' | 转换目标单位 |
| designWidth | number | 1920 | 设计稿宽度 |
| precision | number | 6 | 输出小数位数 |
| minValue | number | 1 | 小于此 px 值不转换 |
| zeroAsUnitless | boolean | true | 0px 转为 0 |
| excludeProperties | string[] | 见下 | 不转换的属性 |
| includeProperties | string[] | — | 只转换这些属性(白名单) |
默认不转换的属性:font-size、border、border-*-width、outline-width、box-shadow、text-shadow
文件结构
@buletu/screen-fit/
├── index.ts # 运行时核心库
├── vite-plugin.ts # Vite 插件(已修复)
├── webpack-loader.ts # Webpack Loader ⭐ v1.2 新增
├── postcss-plugin.ts # PostCSS 插件
├── postcss-plugin-v2.ts # PostCSS 增强版(支持 calc/CSS变量)
├── tailwind-plugin.ts # TailwindCSS 插件
├── devtools.ts # 开发调试工具
├── runtime.ts # 运行时转换器(CDN 场景)
└── README.md