一、scale 方案
1、原理:
scale 属性能将dom元素等比例缩小、放大,从而适配浏览器宽高的变化
核心代码逻辑:
function setScale() {
const designWidth = 1920;
const designHeight = 1080;
const scaleX = window.innerWidth / designWidth;
const scaleY = window.innerHeight / designHeight;
const scale = Math.min(scaleX, scaleY); // 保持比例,取较小值
const app = document.querySelector('#app');
app.style.transform = `scale(${scale})`;
app.style.transformOrigin = 'left top';
}
2、优缺点
优点:布局完全不会乱,像素级还原设计稿。
缺点:
- 在非标准比例屏幕上可能会有黑边(需背景图填充)
- 元素的坐标位置会发生变化,内部组件如果用了鼠标坐标点这些,会有偏移;
3、解决留白问题
const setScale() {
const designWidth = 1920;
const designHeight = 1080;
let clientHeight = document.documentElement.clientHeight;
let clientWidth = document.documentElement.clientWidth;
let scale = 1;
if (clientWidth / clientHeight < designWidth / designHeight) {
scale = (clientWidth / designWidth)
document.querySelector(renderDom).style.height = `${clientHeight / scale}px`;
} else {
scale = (clientHeight / designHeight)
document.querySelector(renderDom).style.width = `${clientWidth / scale}px`;
}
document.querySelector(renderDom).style.transform = `scale(${scale})`;
}
二、px-To-viewport 方案
1、原理:
不缩放整个页面,而是让页面内的所有元素(字体、间距、宽高)根据屏幕宽度动态变化。
将所有元素(字体、间距、宽高)的单位使用
vw/vh,它理论上是一个比例值;我们在开发过程中还是参考设计高,使用
px单位进行开发,通过插件自动将px转化为vw/vh。
核心原理
-
基准设定:假设设计稿宽为
1920px。 -
单位转换:
- 将设计稿中的所有
px单位,在构建时自动转换为vw(视口宽度的百分比) - 公式:
1vw = 设计稿宽度 / 100。例如1920px设计稿中,100px=100/1920 * 100vw≈5.208vw。
- 将设计稿中的所有
2、使用:
2.1 安装依赖
我们需要一个 PostCSS 插件,在打包编译时将 CSS 中的 px 自动转换为 vw。
npm install postcss postcss-px-to-viewport-8-plugin @tailwindcss/postcss -D
(注:推荐使用
postcss-px-to-viewport-8-plugin,它是原postcss-px-to-viewport的维护版,兼容性更好)
这里也顺便测时一下 tailwindcss,所以安装了包:@tailwindcss/postcss
2.2 配置 PostCSS
在项目根目录创建或修改 postcss.config.js 。如果是 Vite 项目 或在 vue.config.js (Webpack) 中配置。
postcss.config.js
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
'postcss-px-to-viewport-8-plugin': {
viewportWidth: 1920, // 【核心】设计稿宽度,根据实际设计稿修改 (如 1920, 3840)
viewportHeight: 1080, // 设计稿高度 (通常用于 vh 转换,若只转 width 可忽略)
unitPrecision: 5, // 转换后的精度,保留几位小数
propList: ['*', 'font-size'], // 需要转换的属性列表,'*' 表示所有属性
selectorBlackList: [], // 不需要转换的选择器黑名单,例如 ['.no-convert']
minPixelValue: 1, // 小于等于 1px 的不转换 (防止 border: 1px 变成 0.00xxx)
mediaQuery: true, // 是否在媒体查询 (@media) 中也转换 px
exclude: [/node_modules/i], // 排除 node_modules 中的文件
// include: [/src/], // 如果 exclude 太宽泛,可以用 include 指定只转换 src
viewportUnit: 'vw', // 转换成的单位,通常是 'vw'
fontViewportUnit: 'vw', // 字体专用的单位,通常也是 'vw'
// 【进阶】针对大屏优化的特殊配置
// 如果你希望某些特定文件不转换,可以在这里添加逻辑,或者使用 selectorBlackList
},
}
};
2.3 结果展示及问题排查
以上就完成了相关配置,然后我们运行项目看看效果;
到此时发现了新问题:
使用 px 的元素都正确被转化为了 vw
width: 100px; // 成功转换
当使用tailwindcss 设置的类时,没有被转化为 vw
<div class="w-[100px]"></div> // 未转换
经过反复排查,最终发现问题所在是:
上面tailwindcss的配置方式是基于 tailwindcss V3 版本的;但是项目本地下载的tailwindcss包是 V4版本的,造成postcss解析的过程可能有问题;
现象:tailwindcss 在浏览器上能正常使用,但是不能被 postcss-px-to-viewport-8-plugin 转换;
解决方案:
方案一,将 tailwindcss 版本降到 V3
方案二,将 tailwindcss 的配置方式改为 V4的配置方式:
npm install tailwindcss @tailwindcss/vite
Vite.config.js
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [
tailwindcss(),
],
})
3、总结:
优点:
- 真正的自适应:没有黑边,内容永远填满屏幕,无论屏幕是 16:9, 21:9 还是 32:9。
- 无需 JS 监听 resize:纯 CSS 解决方案 (
vw是 CSS 单位),浏览器原生支持,性能极高,无重排重绘开销。 - 开发直观:设计师给多少 px,你就写多少 px,构建工具自动转换。
缺点:
-
字体失控风险:
- 在超宽屏(如 3840px 宽)上,
font-size: 16px会变成32px甚至更大,可能导致排版崩坏。 - 在窄屏笔记本上,字体可能变得极小。
- 解决:使用 CSS
clamp()函数限制字体范围(需手动写,插件很难自动处理)。
/* 手动覆盖插件转换,限制字体在 16px 到 32px 之间 */ .title { font-size: clamp(16px, 2.5vw, 32px); } - 在超宽屏(如 3840px 宽)上,
-
高度适配问题:
-
vw是基于宽度的。如果屏幕特别扁(宽很大,高很小),按宽度换算的高度 (height: 50vw) 可能会超出屏幕高度,导致出现纵向滚动条。 -
解决:
- 高度尽量使用
vh(视口高度) 或%。 - 或者配置插件
viewportUnit: 'vw'但手动将高度的 px 改为vh。 - 最稳妥:布局容器用
height: 100vh,内部元素用flex或grid分配空间,少用固定 px 高度。
- 高度尽量使用
-
-
边框过细:
1px的边框在 4K 屏上转换成0.5px左右的vw,在某些浏览器渲染下可能会消失或模糊。- 解决:对于
border,可以在selectorBlackList中排除,或者手动写min-width逻辑(较难),通常建议设计稿中关键边框适当加粗(如 2px)。
三、rem 方案
为了克服纯 vw 的字体问题,可以采用 postcss-pxtorem 方案。
1. 原理
- 通过postcss插件
postcss-pxtorem将px转换为rem - 通过js动态设置根字体大小
从而实现页面的适配;
2. 使用
-
安装:
npm install postcss-pxtorem -D -
配置:
// postcss.config.js module.exports = { plugins: { 'postcss-pxtorem': { rootValue: 19.2, // 关键!假设设计稿 1920,想要 100px = 1rem,则 1920/100 = 19.2 // 或者配合 js 动态设置 html font-size propList: ['*'], selectorBlackList: ['html'], } } } -
JS 动态设置根字体 (在
main.js或App.vue):function setRootFont() { const width = document.documentElement.clientWidth; // 假设以 1920 为基准,1rem = 19.2px (即 100px = 5.2rem) // 这里可以加限制,防止字体过大过小 const fontSize = width / 100; document.documentElement.style.fontSize = fontSize + 'px'; } setRootFont(); window.addEventListener('resize', setRootFont); -
CSS 写法:
- 插件会把
100px转为5.208rem。 - 结合 JS 动态
font-size,实现完美缩放。 - 优势:你可以在 JS 里加逻辑,比如
if (width > 2560) fontSize = 25.6,限制最大字体,避免超宽屏字体爆炸。
- 插件会把
四、总结:
scale 方案
- 最简单粗暴: 开发时完全写死
px,无需任何单位换算 - 不适合屏幕异常的场景:过宽或过高的场景
- 适合 强视觉保真度:要求绝对按照设计稿比例展示,不允许任何元素错位
纯vw 方案
- 如果大屏分辨率相对固定(都是 1080P 或都是 4K), 纯 vw 最简单,配置一下插件即可。
- 时间紧任务重,选它
rem + 动态 font-size 方案
- 需要精确控制,适配各种不同尺寸, 选它
对比:
| 特性 | 纯 vw/vh 方案 | rem + 动态 font-size | scale 方案 |
|---|---|---|---|
| 单位 | vw/vh | rem | px (写死) |
| 适配逻辑 | 视口单位自动计算 | JS 计算根字体大小 | JS 计算缩放比例 |
| 宽高比 | 跟随屏幕(可能变形) | 跟随宽度(高度自适应) | 固定比例(可能出现黑边) |
| 字体清晰度 | 高 | 高 | 缩放可能导致模糊 |
| 开发成本 | 低(自动插件) | 中(需配置 rem 转换) | 低(写死 px,加一层 wrapper) |
| 极端屏幕表现 | 被压扁/拉长 | 上下留白/滚动 | 四周黑边/裁剪 |