数据大屏常用布局-等比缩放布局(Scale Laylout)-使用 CSS Transform Scale 实现等比缩放

数据大屏常用布局-等比缩放布局(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 实现等比缩放

  1. 固定设计尺寸

在全局样式中,#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);
}
  1. 动态缩放计算

使用 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 实现居中

  1. 在 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' }"
          />
相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋2 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁2 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95272 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大2 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师2 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学3 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端