@buletu/screen-fit — 前端多屏适配方案

0 阅读4分钟

@buletu/screen-fit — 前端多屏适配方案

version license

repository

一个轻量级的前端屏幕适配库,核心思路: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)

参数类型默认值说明
designWidthnumber1920设计稿宽度
designHeightnumber1080设计稿高度
mode'rem' | 'vw' | 'scale''rem'适配模式
minWidthnumber1024最小宽度(防止过小屏幕字体异常)
maxWidthnumber2560最大宽度(防止超宽屏字体过大)
adaptiveHeightbooleanfalsescale 模式是否同时适配高度

构建插件公共选项

参数类型默认值说明
mode'rem' | 'vw''rem'转换目标单位
designWidthnumber1920设计稿宽度
precisionnumber6输出小数位数
minValuenumber1小于此 px 值不转换
zeroAsUnitlessbooleantrue0px 转为 0
excludePropertiesstring[]见下不转换的属性
includePropertiesstring[]只转换这些属性(白名单)

默认不转换的属性font-sizeborderborder-*-widthoutline-widthbox-shadowtext-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