大家好,我是前端架构师,关注微信公众号【程序员大卫】:
- 回复 [面试] :免费领取“前端面试大全2025(Vue,React等)”
- 回复 [架构师] :免费领取“前端精品架构师资料”
- 回复 [书] :免费领取“前端精品电子书”
- 回复 [软件] :免费领取“Window和Mac精品安装软件”
当牛马的一天
产品:小明(前端),老板想做一个大屏展示公司业务,请尽快安排。
设计:小明,你要什么尺寸,请尽快告诉我。
小明:啊,我没做过呀,给我点时间调研下。
小明压力好大,先去蹲了个厕所,用手机打开谷歌、掘金,搜索大屏适配方案,什么rem、vw/vh、scale等,我到底选哪种比较好呢?
-------------马上到了午饭的时间------------
产品:怎么样了,小明?
小明:是这样的,老板想展示的大屏是只放在我们公司呢,还是去客户现场也会展示大屏?
产品:老板的心思你不要猜,猜来猜去也猜不着......
小明(心想):what the f**k....
----------终于,小明看到了这篇文章----------
小明自信的娓娓道来:
- 市场上常见的大屏的分辨率是
>=16:9,平时我们说的比较多的1080p(1920 × 1080),2K(2560 × 1440),4K(3840 × 2160)的宽高比都是16:9。 - (对设计说)你先可以设计一个
2K分辨率的吧。 - (对产品说)不管我们的大屏在哪种分辨率下显示,我都有信心展示好,记得在老板面前美言我几句,给我加点工资......啊,说错了❌,不要加工资了,如果公司裁员了,先不要裁我。
背景
可视化大屏是每个前端工程师职业生涯中可能会遇到的一个挑战。初次接触时,我也曾感到迷茫,不知从何入手。在网上搜索了一番,发现有多种适配方案,例如使用 rem、vw/vh 以及 scale 等。然而,其中大部分方法无法做到真正的全屏适配,难以满足业务需求。
实际上,当你掌握了大屏适配的核心原理后,就会发现它并不复杂。
调研大屏的尺寸
不同公司的业务场景对大屏的尺寸要求不同,但主流行业,如互联网、证券金融等,通常采用的宽高比>=16:9。
注:你可以根据自身业务特点,对接下来的代码方案进行适当调整。
| 宽高比 | 特点 | 典型分辨率 | 应用场景 |
|---|---|---|---|
| 16:9 | 主流比例,适配高清视频和设计工具 | 1920×1080(1080p)、3840×2160(4K) | 会议展示、数据监控中心 |
| 16:10 | 纵向空间更大,适合多行数据展示 | 1920×1200、2560×1600 | 商业汇报屏、高端会议室 |
| 4:3 | 传统比例,兼容老旧系统 | 1024×768、1600×1200 | 工业控制室、老旧监控系统 |
| 21:9 | 超宽视野,适合横向延展内容 | 2560×1080、3440×1440 | 交通调度中心、金融实时看板 |
| 32:9 | 极致宽度,可分割为多个虚拟屏幕 | 3840×1080、5120×1440 | 多任务监控(数据、视频、日志并行展示) |
| 拼接屏 | 比例灵活,支持多屏组合 | 2×2(16:9)、3×3(方形) | 指挥中心、展览馆、大型数据看板 |
| 定制比例 | 根据需求设计异形或特殊比例 | 3:1、1:1 等 | 超长信息流(如股票行情)、艺术装置交互屏 |
实现方案
适配思路
我们的方案基于 16:9 进行设计。
1. 当宽高比等于 16:9
此时,页面能够完美铺满屏幕。
2. 当宽高比小于 16:9
效果如下,可能有人会疑惑:为什么页面没有完全铺满?
正如前面提到的,国内市场上主流的大屏宽高比通常大于 16:9。因此,当屏幕宽高比小于 16:9 时,页面底部会留出一些空白区域,但这并不影响整体的展示效果。
如果在这种情况下强行让页面高度铺满,不仅会影响美观,还会导致所有与高度相关的计算都需要转换为百分比,增加开发难度,降低效率。
3. 当宽高比大于 16:9
此时,头部适配较为简单,而主体部分需要与产品和设计师讨论,决定哪些内容需要横向扩展,以达到最佳展示效果。
代码实现
1. 适配核心代码 - flexible.ts
我们需要判断当前屏幕的宽高比是否大于 16:9:
- 如果 大于 16:9,则计算
scaleRatio = 页面高度 / 1080 - 如果 小于 16:9,则计算
scaleRatio = 页面宽度 / 1920
计算 scaleRatio 的核心代码如下:
注: 1920 是设计稿的宽度,1080是 设计稿的高度。
const enum BaseSize {
WIDTH = 1920, // 设计稿的宽度
HEIGHT = 1080, // 设计稿的高度
FONT_SIZE = 16,
}
const calculateScaleRatio = () => {
const { clientWidth, clientHeight } = document.documentElement;
return clientWidth / clientHeight > BaseSize.WIDTH / BaseSize.HEIGHT
? clientHeight / BaseSize.HEIGHT
: clientWidth / BaseSize.WIDTH;
};
const scaleRatio = calculateScaleRatio();
接着,我们将 scaleRatio * 16 设置到 html 的 font-size,以适配 rem 计算。
“为什么要乘以 16?因为 HTML 的默认
font-size是 16px,而 Tailwind CSS 也是基于 16px 计算rem的。”
document.documentElement.style.fontSize = `${scaleRatio * BaseSize.FONT_SIZE}px`;
另外,我们还可以在 html 上存储 data-scaleRatio,方便 Echarts 组件获取这个值来做适配。
document.documentElement.dataset.scaleRatio = scaleRatio.toString();
🎉🎉🎉 最终完整核心代码如下,不足 20 行(除去空行)!
enum BaseSize {
WIDTH = 1920, // 设计稿的宽度
HEIGHT = 1080, // 设计稿的高度
FONT_SIZE = 16,
}
const calculateScaleRatio = () => {
const { clientWidth, clientHeight } = document.documentElement;
return clientWidth / clientHeight > BaseSize.WIDTH / BaseSize.HEIGHT
? clientHeight / BaseSize.HEIGHT
: clientWidth / BaseSize.WIDTH;
};
function updateRootFontSize() {
const scaleRatio = calculateScaleRatio();
document.documentElement.dataset.scaleRatio = scaleRatio.toString();
document.documentElement.style.fontSize = `${
scaleRatio * BaseSize.FONT_SIZE
}px`;
}
updateRootFontSize();
window.addEventListener("resize", updateRootFontSize);
3. 安装插件进行单位转换
⚠️ 注:是否安装以下插件可根据具体业务需求决定,并非必须。
postcss-pxtorem插件的主要作用是自动将px单位转换为rem,例如,当你写width: 100px;时,它会自动转换为相应的rem值。tailwindcss是一款原子化 CSS 框架,能够提高开发效率,方便快速构建样式。
1. 安装 tailwindcss 和 postcss-pxtorem
pnpm i tailwindcss@^3.4.17 postcss-pxtorem postcss -D
2. 配置 tailwind.config.ts 和 postcss.config.js
在项目根目录创建 tailwind.config.ts,并写入以下代码:
import type { Config } from "tailwindcss";
export default {
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
} satisfies Config;
在项目根目录创建 postcss.config.ts,并写入以下代码:
export default {
plugins: {
"postcss-import": {},
"tailwindcss/nesting": {},
tailwindcss: {},
"postcss-pxtorem": {
rootValue: 16, // 根元素的字体大小,通常设置为 16px
propList: ["*"], // 需要转换的属性,* 表示全部属性都转换
minPixelValue: 2, // 需要转换的最小 px 值,忽略 1px 转换成 rem
},
...(process.env.NODE_ENV === "production" ? { cssnano: {} } : {}),
},
};
3. 在 main.ts 中引入 flexible.ts 和 tailwind.css
import "./styles/tailwind.css"; // 引入 TailwindCSS
import "./utils/flexible"; // 引入适配脚本
// 其它代码
4. 编写 HTML 页面结构
从下面的 html 可以看到,我们写死了 header 的高度为 400px,主体高度为 680px,它们相加刚好等于 1080px。
<template>
<div class="bg-yellow-400 h-[400px]"></div>
<div class="grid grid-cols-[1fr_3fr] h-[680px]">
<div class="bg-blue-400"></div>
<div class="bg-red-400"></div>
</div>
</template>
另外在项目开发过程中,可以结合 flex、grid、vw/vh 等来进行布局,另外可再封装一个可适配的 ECharts 图表组件。
4. Echarts 组件如何获取 scaleRatio
我们可以通过以下两种方式获取 document.documentElement 根元素上的 data-scale-ratio 属性值:
方法一:监听 window 的 resize 事件
每当窗口大小发生变化时,我们就从 document.documentElement 上读取最新的 scaleRatio:
import { ref } from "vue";
import { useEventListener } from "@vueuse/core";
export function useScaleRatio() {
const scaleRatio = ref(1);
useEventListener(window, "resize", () => {
scaleRatio.value = parseFloat(
document.documentElement.dataset.scaleRatio ?? "1",
);
});
return scaleRatio;
}
方法二:使用 MutationObserver 监听属性变化
如果 scaleRatio 是通过修改 data-scale-ratio 属性动态设置的,可以使用 MutationObserver 实时监听该属性变化:
import { ref } from "vue";
import { useMutationObserver } from "@vueuse/core";
export function useScaleRatio() {
const getScaleRatio = () =>
parseFloat(document.documentElement.dataset.scaleRatio ?? "1");
const scaleRatio = ref(getScaleRatio());
useMutationObserver(
document.documentElement,
(mutations) => {
if (mutations[0]?.attributeName === "data-scale-ratio") {
scaleRatio.value = getScaleRatio();
}
},
{
attributes: true,
},
);
return scaleRatio;
}
总结
- 了解屏幕比例:大多数可视化大屏的宽高比大于 16:9,不同应用场景有不同的适配需求。
- 选择合适的适配方案:使用
scaleRatio计算缩放比例,并根据屏幕尺寸调整rem。 - 兼容不同屏幕:当宽高比不同于 16:9 时,需要合理处理页面布局,避免错位影响展示效果。
- 灵活扩展:可以结合
data-scaleRatio适配 Echarts 图表,提升数据可视化的体验。
通过上述方案,我们可以确保可视化大屏在不同设备上的适配效果,实现高质量的数据展示。
Demo
源码地址