大屏适配
常见的大屏自适应方案
rem + fontSize
利用 rem 是根元素(html)的字体(font-size)大小这个特点,我们把整个页面的 CSS 单位都统一为 rem ,这样我们就只用修改根元素的字体大小,实现页面的整体动态伸缩。
fontSize 设置思路:
html { font-size: 100px; }
,把 100px 当做因子- 如果要设置
1200px
宽,那么换算下来就是{ width: 12rem }
- 这样也不会受到浏览器默认字体的影响(对比设置 html 字体大小为 62.5% )
vw、vh
这种方案的原理就是把屏幕宽高等分成 100 份, 得到每份的 px 大小, 然后再用设计稿像素大小除以 每份的 px 大小,就得到了对应的 vw/vh 值
shell
假设设计稿尺寸为 1920*1080
即:
网页宽度=1920px
网页高度=1080px
我们都知道
网页宽度=100vw
网页宽度=100vh
所以,在 1920px*1080px 的屏幕分辨率下
1920px = 100vw
1080px = 100vh
这样一来,以一个宽 300px 和 200px 的 div 来说,其所占的宽高,以 vw 和 vh 为单位,计算方式如下:
vwDiv = 300px / (1920px / 100vw)
vhDiv = 200px / (1080px / 100vh)
所以,就在 1920*1080 的屏幕分辨率下,计算出了单个 div 的宽高
当屏幕放大或者缩小时,div 还是以 vw 和 vh 作为宽高的,就会自动适应不同分辨率的屏幕
scale (推荐方案)
利用 css3 的 transform: scale(X)
来根据宽高比计算当前大屏容器需要设置的比例 scale:
ts
import { ref, onMounted, onUnmounted, watch, Ref } from 'vue';
interface IOptions {
el: Ref<HTMLElement | null> | HTMLElement | string;
dW: number;
dH: number;
parentEl?: Ref<HTMLElement | null> | HTMLElement | string;
isRatio?: boolean;
}
export function useBigScreen({
el,
dW,
dH,
parentEl = document.body,
isRatio = true
}: IOptions) {
const scale = ref(1);
const getElement = (element: HTMLElement | Ref<HTMLElement | null> | string | null): HTMLElement | null => {
if (element instanceof HTMLElement) return element;
if (typeof element === 'string') return document.querySelector(element);
return element?.value ?? null;
}
const setTargetElementStyle = (element: HTMLElement) => {
element.style.position = 'absolute';
element.style.left = '50%';
element.style.top = '50%';
element.style.width = +dW + 'px';
element.style.height = +dH + 'px';
}
const setScale = () => {
const targetEl = getElement(el);
const containerEl = parentEl ? getElement(parentEl) : document.body;
if (!targetEl || !containerEl) {
console.log('目标元素或者目标元素的父元素没有找到.');
return;
}
setTargetElementStyle(targetEl);
const containerWidth = containerEl.clientWidth;
const containerHeight = containerEl.clientHeight;
let scaleX = containerWidth / dW;
let scaleY = containerHeight / dH;
if (isRatio) {
// 保持宽高比,按最长边进行缩放
const scaleValue = Math.min(scaleX, scaleY);
targetEl.style.transform = `translate(-50%, -50%) scale(${scaleValue})`;
} else {
// 不保持宽高比,分别按宽高拉伸
targetEl.style.transform = `translate(-50%, -50%) scale(${scaleX}, ${scaleY})`;
}
}
const onResize = () => {
setScale();
}
onMounted(() => {
setScale();
window.addEventListener('resize', onResize);
});
onUnmounted(() => {
window.removeEventListener('resize', onResize);
});
// 如果 el 或 parentEl 动态改变时重新计算
watch([() => el, () => parentEl], () => {
setScale();
});
return { scale };
}
使用:
vue
<template>
<div ref="myScreen" class="monitor-screen"></div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { useBigScreen } from "../../hooks/useBigScreen";
const myScreen = ref<HTMLElement | null>(null);
useBigScreen({
el: myScreen, // 目标 DOM
dW: 1920, // 设计稿宽度
dH: 1080, // 设计稿高度
parentEl: undefined, // 默认基于 body 进行全屏适配
isRatio: true, // 保持设计稿宽高比
});
</script>