文章目录
- 前言
- 一、主流大屏适配方案对比
-
- [1. 媒体查询(Media Queries)](#1. 媒体查询(Media Queries))
- [2. Rem适配方案](#2. Rem适配方案)
- [3. 缩放变换(Scale)](#3. 缩放变换(Scale))
- 4.百分比布局
- [二、新一代适配方案:vw/vh + flex + clamp()](#二、新一代适配方案:vw/vh + flex + clamp())
- 三、总结

前言
在数据可视化、监控中心、展厅大屏等场景中,Web 页面需要在各种尺寸的大屏幕上完美展示,这给前端开发者带来了不小的挑战。本文将对比主流的大屏适配方案,重点介绍一套简单高效的 "vw+vh+flex+clamp ()" 组合方案,让你的大屏页面轻松实现无缝适配。
一、主流大屏适配方案对比
在深入讲解推荐方案之前,我们先来看看目前常用的几种大屏适配方案及其优缺点:
1. 媒体查询(Media Queries)
通过设置多个断点,为不同尺寸屏幕编写不同样式。
javascript
/* 传统媒体查询方式 */
.container {
width: 100%;
}
@media screen and (min-width: 1920px) {
.element {
font-size: 18px;
padding: 20px;
}
}
@media screen and (max-width: 1366px) {
.element {
font-size: 14px;
padding: 15px;
}
}
优点 :针对性强,可在关键断点处做精细化调整
缺点:需要为多个断点编写多套代码,代码冗余,维护困难适配成本高,断点之间跳跃,不够平滑
2. Rem适配方案
通过 JavaScript 根据屏幕尺寸动态计算根元素 font-size,页面元素使用 rem 单位。
javascript
// 基于屏幕宽度设置rem基准值
function setRem() {
const baseSize = 16; // 1rem = 16px
const scale = document.documentElement.clientWidth / 1920;
document.documentElement.style.fontSize = baseSize * scale + 'px';
}
setRem();
window.addEventListener('resize', setRem);
javascript
/* 使用rem单位 */
.container {
width: 50rem; /* 基于根字体大小计算 */
font-size: 1rem;
}
优点 :适配较为灵活
缺点:依赖 JavaScript,计算逻辑复杂,可能出现加载闪烁。只保证宽度适配,高度控制不当可能出现滚动条。
3. 缩放变换(Scale)
通过 transform: scale () 将整个页面等比缩放。
javascript
function setScale() {
const targetWidth = 1920;
const currentWidth = document.documentElement.clientWidth;
const scale = currentWidth / targetWidth;
document.body.style.transform = `scale(${scale})`;
document.body.style.transformOrigin = 'top left';
}
优点 :一次开发适配所有尺寸,实现简单
缺点:可能导致内容模糊字体渲染质量下降,缩放后点击区域错位风险,图片变形,性能消耗大
4.百分比布局
使用百分比作为长度单位,元素尺寸基于父元素计算。
javascript
.container {
width: 90%; /* 相对于父容器 */
height: 80%;
}
优点 :简单易用,无需额外脚本
缺点:百分比是相对于父元素的,层级嵌套时计算复杂,难以精确控制
二、新一代适配方案:vw/vh + flex + clamp()
这个组合方案汲取了各种方案的优点,解决了它们的痛点,让我们一步步深入了解。
方案优势
- 纯 CSS 实现,不依赖 JavaScript
- 自动适应各种屏幕尺寸,无需预设断点
- 元素尺寸相对视口动态调整,保持整体比例
- 可限制元素尺寸范围,避免极端情况下的显示问题
- 开发简单,学习成本低
基础方案:vw/vh + flex
1. vw/vh 单位
vw(视口宽度单位)和 vh(视口高度单位)是CSS3引入的相对单位:
- 1vw = 视口宽度的1%
- 1vh = 视口高度的1%
javascript
/* 直接基于视口尺寸 */
.container {
width: 100vw; /* 全屏宽度 */
height: 100vh; /* 全屏高度 */
padding: 2vw; /* 基于宽度的内边距 */
font-size: 1.5vw; /* 基于宽度的字体大小 */
}
2. Flex 弹性布局
Flex布局轻松实现水平和垂直布局,精确控制元素对齐,提供强大的空间分配能力:
javascript
.dashboard {
display: flex;
flex-direction: column;
gap: 1.5vw; /* 弹性间隙 */
}
.widget {
flex: 1; /* 自动填充剩余空间 */
min-height: 200px;
}
3. 核心思想
vw/vh:处理整体布局和主要尺寸,其中元素的宽度用vw单位,元素的高度用vh单位,margin和padding上下方向用vh,左右方向用vw。
flex:处理内部元素排列、间距、空间分配。
4.实践示例
假设设计稿为1920x1080,实现一个导航栏(60px高度)+主体区域横向3段布局(左右300px宽度,中间占满 )大屏页
javascript
<!-- html -->
<div class="container">
<!-- 导航栏 -->
<div class="navigation-bar"></div>
<!-- 主体 -->
<div class="main">
<div class="left"></div>
<div class="center"></div>
<div class="right"></div>
</div>
</div>
javascript
/**
* css 样式
*/
.container{
width:100vw;
height:100vh;
display: flex;
flex-direction: column;
background-color: #f2f2f2;
gap: 1.5vh;
}
.navigation-bar{
width: 100%;
height: 5.56vh;/**60px */
background-color: #fff;
}
.main{
flex:1;/**占满剩余空间**/
height: 0;
width: 100%;
display: flex;
gap: 1vw;
}
.left,.right{
width:15.625vw;/**300px */
height: 100%;
background-color: #fff;
}
.center{
flex:1;
width: 0;
height: 100%;
background-color: #fff;
}
运行效果:
从运行效果可以看出无论屏幕尺寸如何变化,大屏布局始终保持响应式。
继续给页面添加其他元素(图片、文字)
javascript
<!-- html -->
<div class="container">
<!-- 导航栏 -->
<div class="navigation-bar">
<div class="user-info">
<img class="avatar" src="https://xxxxx">
<span class="username">管理员</span>
</div>
</div>
<!-- 主体 -->
<div class="main">
<div class="left">
<img class="pic" src="https://xxxxxx">
<h4 class="title">大屏响应式布局</h4>
</div>
<div class="center"></div>
<div class="right"></div>
</div>
</div>
javascript
/**
* css 样式
*/
*{
margin: 0;
padding: 0;
}
.container{
width:100vw;
height:100vh;
display: flex;
flex-direction: column;
background-color: #f2f2f2;
gap: 1.5vh;
}
.navigation-bar{
width: 100%;
height:5.56vh;/**60px */
background-color: #fff;
}
.main{
flex:1;/**占满剩余空间**/
height: 0;
width: 100%;
display: flex;
gap: 1vw;
}
.left,.right{
width:15.625vw;/**300px */
height: 100%;
background-color: #fff;
padding:1.4vh 0.78vw;
box-sizing: border-box;
}
.center{
flex:1;
width: 0;
height: 100%;
background-color: #fff;
}
.user-info{
display: flex;
align-items: center;
height: 100%;
padding: 0.46vh 0.52vw; /**5px 10px */
box-sizing: border-box;
}
.avatar{
width: 3.7vh;/**40px */
height: 3.7vh;/**40px */
border-radius: 50%;
}
.username{
margin-left: 0.5vw;/**10px */
font-size: 1.48vh;
}
.pic{
width: 10.4vw;
height: auto;
}
.title{
font-size: 1.04vw;
}
运行效果:
注意到上面代码,头像尺寸和用户名字体大小用vh单位,而风景图和"大屏响应式布局"文字用vw单位。字体和图片长宽比的处理是关键问题。下面分别探讨:
字体使用vh还是vw?
字体的适配单位选择取决于设计意图和父容器的宽高比。
- 如果父容器高度空间小或屏幕高度的变化比宽度更频繁,使用vh可以使字体大小随着视口高度变化,保持与整体布局高度的比例一致,否则使用vw。
- 如果宽高空间都比较大,多数情况下,字体使用vw单位更合适,因为宽度是响应式设计中最常变化的维度。
图片长宽使用vh还是vw?
图片长宽适配单位一样取决于设计需求和父容器的宽高方向空间。
- 如果不要求保持图片或背景长宽比,宽度用vw,高度用vh
- 如果要求保持图片长宽比跟字体一样,取决父容器空间,父容器高度方向空间小用vh否则用vw,另一个属性设置为""auto"那么图片的高度会根据原始宽高比自动计算,使得图片与整体保持比例一致最大程度防止图片超出父容器。或另一个属性设置具体值结合object-fit属性裁剪图片设置显示效果。
javascript
//宽度空间有限,保持长宽比
img {
width: 50vw;
height: auto;
}
或
javascript
//高度空间有限,保持长宽比
img {
height: 50vh;
width: auto;
}
或
javascript
//保持长宽比,裁剪
img {
height: 50vh;
width:70vh;
object-fit: cover;
}
示例中的头像昵称因为导航栏高度只有60px而宽度占满全屏,高度空间有限,宽度伸缩对布局影响小,所以使用vh限制高度允许宽度自动伸缩。而风景图片跟标题父容器(.left)高度占满空间大,宽度方向空间小所以使用vw。
总结:
对于字体大小和图片尺寸适配使用什么单位,没有固定答案,应该具体场景具体分析。当父容器高度空间小,字体或图片在该方向伸缩容易超出父容器则采用vh否者vw,默认使用vw。
5. 工程化中使用scss解决vw/vh与px换算问题
如上述示例每次从设计稿获取元素尺寸px需要手动计算转换vh单位,例如导航栏高度60px转换为vh为:60/1080*100≈5.56vh(设计稿尺寸1920x1080),每次都要这样计算非常麻烦。在工程化项目中可以使用scss 定义全局函数结合calc自动计算。
假设设计稿尺寸为(1920x1080)
(1)新建一个全局scss文件:/style/responsive.scss
javascript
//px转vw
@function w($size){
@return calc( $size / 1920 * 100vw )
}
//px转vh
@function h($size){
@return calc( $size / 1080 * 100vh )
}
其中$size为元素从设计稿读出的尺寸(px)
(2)把responsive.scss注入全局使得函数w、h可以全局使用
以vite为例打开vite.config.js添加:
javascript
export default defineConfig((mode) => {
const env = loadEnv(mode.mode, process.cwd());
return {
..............
.................
................,
//添加底下代码
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/style/responsive.scss" as *`,//路径修改为实际
},
},
}
(3)在页面中使用
从设计稿读取元素宽高值size(单位px),px转vw使用w(size)函数,px转vh使用h(size)函数。
javascript
<style lang="scss" scoped>
.....
/**导航栏*/
.navigation-bar{
width: 100%;
height:h(60);/**60px */
background-color: #fff;
}
.user-info{
display: flex;
align-items: center;
height: 100%;
padding: h(5) w(10); /**5px 10px */
box-sizing: border-box;
}
.avatar{
width: h(40);/**40px */
height: h(40);/**40px */
border-radius: 50%;
}
.username{
margin-left: w(10);/**10px */
font-size: h(16)
}
.pic{
width: w(200);/**200px */
height: auto;
}
.title{
font-size: w(20);/**20px */
}
</style>
终极方案:vw/vh + flex+clamp()
基础方案vw/vh + flex,基本满足大部分常规比例大屏开发,然而在适配一些极端比例屏幕时,问题出现了:
超宽屏幕的尴尬(5120×1440)
javascript
/* 在超宽屏上,基于宽度的字体变得巨大 */
.title {
font-size: 2.5vw; /* 在5120px宽度下 = 128px,过于夸张 */
}
/* 内容被过度拉伸 */
.content {
padding: 3vw; /* 左右内边距过大 */
}
超窄屏幕的窘境(1024×768)
javascript
/* 在窄屏上,基于宽度的字体变得太小 */
.metric {
font-size: 1.2vw; /* 在1024px宽度下 = 12.3px,难以阅读 */
}
/* 间距过度压缩 */
.grid {
gap: 0.8vw; /* 间隙只有8px,过于拥挤 */
}
clamp() 函数
clamp() 是一个非常实用的 CSS 函数,它通过 clamp(min, val, max) 的语法,将一个值限制在最小值和最大值之间,中间值通常基于视口单位(如 vw、vh)动态计算,当中间值介于最大值最小值之间就取中间值。
javascript
.title {
font-size: clamp(16px, 2.5vw, 32px);
/* 最小16px,理想值2.5vw,最大32px */
}
通过 clamp () 的最小和最大值设置,避免元素在极端尺寸下变得过大或过小而影响体验。clamp不仅可以限制字体大小还可以应用于元素尺寸自适应、间距与内边距自适应、边框 / 阴影等细节适配等,根据实际开发场景灵活应用。
示例
以上面的实践示例为例,保持屏幕宽度,缩放屏幕高度模拟超宽屏,观察页面布局变化。

从运行效果可以看出,随着长宽比变小,导航栏高度不断变小,到极端比例下头像和文字就看不清,接下来我们通过
clamp优化限制导航栏高度范围,使其不会过大或过小导致看不清。
javascript
/** 导航栏 */
.navigation-bar{
width: 100%;
height:clamp(40px,h(60),100px);/**最小40px,最大100px,理想h(60) */
background-color: #fff;
}
/** 头像 */
.avatar{
width: clamp(30px,h(40),80px);/***最小30px,最大80px,理想h(40) */
height:clamp(30px,h(40),80px);/***最小30px,最大80px,理想h(40) */
border-radius: 50%;
}
/** 用户名 */
.username{
margin-left: w(10);/**10px */
font-size: clamp(14px,h(16),20px);/***最小14px,最大20px,理想h(16) */
}
运行效果:
图表适配
ECharts 等图表库适配无法通过css一步到位,只能通过js动态计算尺寸,并监听窗口大小变化事件,调用resize()方法重绘图表,达到响应式。
可以仿造scss h\w函数思路封装宽高2个方向的px转换vh/vw。
@/utils/responsive.js
javascript
/**
* 设计稿尺寸1920*1080
* @param {*} size 转换尺寸,单位px
* @returns
*/
//px转vh
export const h = (size) => {
let windowHeight =document.documentElement.clientHeight || document.body.clientHeight;
return size / 1080 * windowHeight;
};
//px转vw
export const w = (size) => {
let windowWidth =document.documentElement.clientWidth || document.body.clientWidth;
return size / 1920 * windowWidth;
};
图表使用
javascript
import {h,w} from "@/utils/responsive.js"
//echart配置
const option = {
grid:{
top:h(20),//顶部距离
left:w(30),//左侧距离
right:w(30),//右侧距离
bottom:h(25)//底部距离
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisLabel:{
fontSize: w(14),//字体大小
lineHeight: w(20),//行高
}
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
};
三、总结
vw+vh+flex+clamp () 的组合方案为 Web 大屏适配提供了一种简单高效的解决方案。它既保留了 vw/vh 单位的自适应特性,又通过 flex 布局实现了灵活的元素排列,同时利用 clamp () 函数限制了尺寸的极端变化,完美平衡了灵活性和可控性。
这种方案特别适合数据可视化大屏、监控中心等场景,能够在各种尺寸的屏幕上保持良好的视觉效果和用户体验。