数据大屏常用布局-等比缩放布局(Scale Laylout)-使用 CSS Transform Scale 实现等比缩放
1.介绍
1.1 典型特征和典型特点
Scale Layout 的典型特征:
1.浏览器缩小
2.整个页面一起缩
3.布局不变
4.字体可以缩到几 px
工程上意味着:
- 页面有一个固定"设计尺寸"
- 浏览器变化时 不重排(不 reflow)
- 只是 整体做 transform
为什么适合数据大屏?
数据大屏的典型特点
- 固定分辨率设计(1920×1080 / 3840×2160)
- 主要是 看,不是 点
- 运行环境可控(会议室 / 大屏电视)
1.2 效果展示
效果实现展示: 
1.3 CSS 编写原则
在这种方案下,你的 CSS 编写原则是
CSS 世界里永远是 1920×1080,缩放交给 JS,使用固定 px,不要写响应式
2.实战案例-使用 CSS Transform Scale 实现等比缩放
- 固定设计尺寸
在全局样式中,#app 被设置为固定的设计尺寸:
Index.css
css
#app {
@apply inline-block absolute left-1/2;
width: 1920px;
height: 1080px;
transform-origin: 0 0;
color: rgba(255, 255, 255, 0.9);
}
- 动态缩放计算
使用 useScreenScale hook 计算缩放比例:
typescript
import { onMounted, onUnmounted } from 'vue'
const useScreenScale = () => {
/**
* Scales the screen based on the design dimensions.
* window resize is not usually triggered, so no need to use debounce
* @return {void} This function does not return a value.
*/
const handleScreenScale = () => {
const designDreftWidth = 1920
const designDreftHeight = 1080
const scale =
document.documentElement.clientWidth / document.documentElement.clientHeight <
designDreftWidth / designDreftHeight
? document.documentElement.clientWidth / designDreftWidth
: document.documentElement.clientHeight / designDreftHeight
if (document.querySelector('#app') !== null) {
;(document.querySelector('#app') as HTMLElement).style.transform =
`scale(${scale}) translate(-50%)`
}
}
onMounted(() => {
handleScreenScale()
window.onresize = () => handleScreenScale()
})
onUnmounted(() => {
window.onresize = null
})
}
export default useScreenScale
缩放逻辑:
-
比较当前屏幕宽高比与设计稿宽高比(16:9)
-
如果屏幕更窄:按宽度缩放 scale = 屏幕宽度 / 1920
-
如果屏幕更高:按高度缩放 scale = 屏幕高度 / 1080
-
应用变换:transform: scale(scale) translate(-50%)
- translate(-50%)和left(50%)配合,实现水平居中
-
scale() 缩放,scale就是缩放比例
-
translate(-50%) 配合 left-1/2 实现居中
- 在 App.vue 中启用
javascript
<script setup lang="ts">
useScreenScale()
</script>
页面如何实现等比缩放?
页面无需额外处理,因为:
所有页面都在 #app 内部
#app 整体缩放,内部元素自动跟随
使用固定像素值即可,例如:
html
<div class="w-[1114px] h-full">
<HistoryEventsList
ref="historyEventsListRef"
@update:queryParams="handleTrendQuery"
@open:warningEventDetail="handleOpenWarningEventDetail"
/>
</div>
<div class="w-[738px] h-full">
这些固定像素值(如 1114px、738px)会随 #app 的缩放比例自动缩放。
3.注意坑点- Element Plus 弹出层的默认行为
Element Plus 弹出层的默认行为,Element Plus 的弹出层组件(el-select、el-cascader、el-date-picker 等)默认会将下拉菜单挂载到 body 上,而不是组件所在的 DOM 树中。
DOM 结构示意:
html
<body>
<div id="app"> ← 这里应用了 transform: scale(0.75)
<HistoryEventsList>
<el-select> ← 输入框在这里
</el-select>
</HistoryEventsList>
</div>
<!-- 默认情况下,下拉菜单会挂载到这里 -->
<div class="el-select-dropdown"> ← 下拉菜单在 body 下,不在 #app 内!
<el-option>...</el-option>
</div>
</body>
由于缩放是写在app上的,但是弹出层挂在了body上,所以应该将弹出层挂到app上,使用append-to="#app"
html
<el-date-picker
v-model="currentDateRange"
:shortcuts="EVENT_SHORTCUTS"
append-to="#app"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
size="small"
:style="{ width: '100%', height: '32px' }"
/>