可视化大屏适配方案

144 阅读6分钟

一、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

核心原理

  1. 基准设定:假设设计稿宽为 1920px

  2. 单位转换

    • 将设计稿中的所有 px 单位,在构建时自动转换为 vw (视口宽度的百分比)
    • 公式1vw = 设计稿宽度 / 100。例如 1920px 设计稿中,100px = 100/1920 * 100vw5.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 结果展示及问题排查

以上就完成了相关配置,然后我们运行项目看看效果;

largeScreen.png

到此时发现了新问题:

使用 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,构建工具自动转换。

缺点

  1. 字体失控风险

    • 在超宽屏(如 3840px 宽)上,font-size: 16px 会变成 32px 甚至更大,可能导致排版崩坏。
    • 在窄屏笔记本上,字体可能变得极小。
    • 解决:使用 CSS clamp() 函数限制字体范围(需手动写,插件很难自动处理)。
    /* 手动覆盖插件转换,限制字体在 16px 到 32px 之间 */
    .title {
      font-size: clamp(16px, 2.5vw, 32px); 
    }
    
  2. 高度适配问题

    • vw 是基于宽度的。如果屏幕特别扁(宽很大,高很小),按宽度换算的高度 (height: 50vw) 可能会超出屏幕高度,导致出现纵向滚动条。

    • 解决

      • 高度尽量使用 vh (视口高度) 或 %
      • 或者配置插件 viewportUnit: 'vw' 但手动将高度的 px 改为 vh
      • 最稳妥:布局容器用 height: 100vh,内部元素用 flexgrid 分配空间,少用固定 px 高度。
  3. 边框过细

    • 1px 的边框在 4K 屏上转换成 0.5px 左右的 vw,在某些浏览器渲染下可能会消失或模糊。
    • 解决:对于 border,可以在 selectorBlackList 中排除,或者手动写 min-width 逻辑(较难),通常建议设计稿中关键边框适当加粗(如 2px)。

三、rem 方案

为了克服纯 vw 的字体问题,可以采用 postcss-pxtorem 方案。

1. 原理

  • 通过postcss插件 postcss-pxtorempx 转换为 rem
  • 通过js动态设置根字体大小

从而实现页面的适配;

2. 使用

  1. 安装npm install postcss-pxtorem -D

  2. 配置

    // 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'], 
        }
      }
    }
    
  3. JS 动态设置根字体 (在 main.jsApp.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);
    
  4. 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-sizescale 方案
单位vw/vhrempx (写死)
适配逻辑视口单位自动计算JS 计算根字体大小JS 计算缩放比例
宽高比跟随屏幕(可能变形)跟随宽度(高度自适应)固定比例(可能出现黑边)
字体清晰度缩放可能导致模糊
开发成本低(自动插件)中(需配置 rem 转换)低(写死 px,加一层 wrapper)
极端屏幕表现被压扁/拉长上下留白/滚动四周黑边/裁剪