scale 大屏缩放方案详解
说明
此方案适用于非滚动页面的类似数字大屏的页面。比如某些后台管理页面的首页等。
思路
一般大屏页面都需要适应分辨率大小不一的屏幕,小则是我们 1920*1080 的电脑屏幕,大则是 4k 甚至 8k 的专业大屏。
而我们以前最容易想到的就是用 rem / vw 等方案 来替换直接使用 px 单位。这样元素、文本的尺寸就会随屏幕宽度而动态变化。当然这些方案也是可取的,但是很繁琐,且性能不太好。因为transform属性的应用是在合成线程上完成的,跟渲染主线程无关。
scale方案中,我们在写css时,可以直接按照设计图的尺寸写px单位,先不用考虑响应式。写完之后,我们只需要在javascript中获取需要做响应式的元素上,给其设置css样式 transform: scale(x, y)
缩放属性,并且需要监听浏览器窗口 resize 的事件来实时缩放,这就完成了响应式。是不是很简单。
代码
Html部分,假如这 .screen 元素是大屏页面的根元素,一般放一张背景,不需要缩放。 .main元素则是主体内容的根元素,需要缩放。并且让.main元素始终居中于屏幕。
<div class="screen" ref="screenRef">
<div class="main">
......
</div>
</div>
Css部分
.screen {
width: 100%;
height: 100%;
background: url("./xxx/bg.png") no-repeat center center;
background-size: 100% 100%;
.main{
/*
为什么居中代码没有 transform: translate(-50%, -50%);呢?
因为这行代码需要在实时缩放时反复设置才行。代码看js部分。原因我暂时没去深究
*/
position: fixed;
top: 50%;
left: 50%;
z-index: 999;
transition: all 0.3s;
}
}
JavaScript部分,这里以vue3代码为例。
import {ref, onMounted} from 'vue'
const screenRef = ref(null)
onMounted(() => {
// 组件挂载后访问根元素
screenRef.value.style.transform = `scale(${getScaleValue()}) translate(-50% -50%)`
// 监听resize事件
window.addEventListener('resize', resizeHanlder)
})
const resizeHanlder = () => {
if(screenRef.value){
screenRef.value.style.transform = `scale(${getScaleValue()}) translate(-50% -50%)`
}
}
/*
基于设计稿初始尺寸 和 视口实时宽高 计算出需要缩放的值
这里以 1920 * 1080 为例
*/
const getScaleValue = (width=1920, height=1080) => {
const ww = window.innerWidth / width
const wh = window.innerHeight / height
/*
用视口当前的宽高除以设计图宽高,如果小于1表示屏幕缩小了,反之屏幕放大了,那scale也就应该进行对应的放大或缩小,并且缩放时宽高应该是等比例缩放。
如果 ww = wh 表示屏幕是在根据设计图宽高等比例缩放。
如果 ww < wh 表示在等比缩放基础上宽度更小,为了让所有内容都能居中显示在屏幕中,就需要scale按照ww这个比例来缩放宽高。
如果 ww > wh 表示在等比缩放基础上高度更小,为了让所有内容都能居中显示在屏幕中,就需要scale按照wh这个比例来缩放宽高。
口诀:基于设计图宽高比,实时视口 宽更小就使用 视口宽/设计图宽 的比值来等比缩放。高更小就使用 视口高/设计图高 的比值来等比缩放
*/
return ww < wh ? ww: wh
}
效果
地址:https://admin.spicyboy.cn/#/dataScreen
设计图宽高比
基于设计图宽高比 宽更小
基于设计图宽高比,高更小
最后啰嗦一句:宽更小,为了让内容水平方向能全部显示在屏幕中,就得按照宽的比例缩放。高更小,为了让内容垂直方向能全部展示在屏幕中,就得按照高的比例缩放。