什么是固定宽高比容器?
定义:
无论浏览器窗口或页面元素如何变化,容器的宽度和高度永远保持固定的比例,如16:9。
应用场景:
如大屏自适应,内部元素对容器宽高比依赖很高的复杂模块布局等。
纯CSS实现固定宽高比的容器
原理:
- padding-top的值为百分比时,最终padding-top的计算值 = 百分比 * 当前元素宽度的计算值,从而通过padding-top将容器撑开。
- 为容器添加样式 box-sizing: border-box; 则容器的高度 = padding-top的计算值,从而实现容器高度根据容器的宽度按百分比自适应变化。
- 使用“子绝父相”,让容器中的内容完全覆盖容器。
cssRatioContainer.vue
<template> <div class="box" :style="ratioStyle"> <div class="content" :style="contentStyle"> <slot></slot> </div> </div> </template> <script> export default { props: { ratio: { type: Number, default: 1, }, overflow: { type: String, default: "auto", }, overflowX: { type: String, }, overflowY: { type: String, }, }, computed: { ratioStyle() { let ratio = (1 / this.ratio) * 100; if (ratio == null || Number.isNaN(ratio)) { ratio = 100; } if (typeof ratio !== "string" || !ratio.endsWith("%")) { ratio = ratio + "%"; } return `padding-top: ${ratio};`; }, contentStyle() { const styles = []; if (this.overflow) { styles.push("overflow:" + this.overflow); } if (this.overflowX) { styles.push("overflow-x:" + this.overflowX); } if (this.overflowY) { styles.push("overflow-y:" + this.overflowY); } return styles.join(";"); }, }, }; </script> <style scoped> .box { position: relative; box-sizing: border-box; } .content { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } </style>
JS实现固定宽高比的容器
原理:
- 通过js获取容器的宽度计算值后,按宽高比计算出容器的高度,并赋值给容器。
jsRatioContainer.vue
<template> <div id="jsRatioContainerBox" class="box" :style="contentStyle"> <slot></slot> </div> </template> <script> export default { props: { ratio: { type: Number, default: 1, }, overflow: { type: String, default: "auto", }, overflowX: { type: String, }, overflowY: { type: String, }, }, data() { return { myHeight: "", }; }, computed: { contentStyle() { const styles = []; if (this.myHeight) { styles.push("height:" + this.myHeight); } if (this.overflow) { styles.push("overflow:" + this.overflow); } if (this.overflowX) { styles.push("overflow-x:" + this.overflowX); } if (this.overflowY) { styles.push("overflow-y:" + this.overflowY); } return styles.join(";"); }, }, mounted() { this.setHeight(); window.addEventListener("resize", () => { this.setHeight(); }); }, watch: { ratio() { this.setHeight(); }, }, methods: { // 根据宽高比和当前宽度,设置最终的高度 setHeight() { this.$nextTick(() => { let myDom = document.getElementById("jsRatioContainerBox"); let width = window.getComputedStyle(myDom)["width"]; this.myHeight = Number(width.replace("px", "")) * (1 / this.ratio) + "px"; }); }, }, }; </script> <style scoped> .box { width: 100%; } </style>
使用范例
<template> <div class="father"> <h2>CSS实现固定宽高比的容器</h2> <CssRatioContainer ref="CssRatioContainer" id="CssRatioContainer" :ratio="ratioWidth / ratioHeight" > <div class="itemBox" v-for="item in 100" :key="item">段落{{ item }}</div> </CssRatioContainer> <p>容器的宽度为:{{ mySize.width }}</p> <p>容器的高度为:{{ mySize.height }}</p> <label>容器的宽高比:</label> <input class="inputStyle" type="number" v-model="ratioWidth" @input="getSize" /> : <input class="inputStyle" type="number" v-model="ratioHeight" @input="getSize" /> <h2>JS实现固定宽高比的容器</h2> <JsRatioContainer :ratio="ratioWidth / ratioHeight"> <div class="itemBox" v-for="item in 100" :key="item">段落{{ item }}</div> </JsRatioContainer> </div> </template> <script> import CssRatioContainer from "./cssRatioContainer.vue"; import JsRatioContainer from "./jsRatioContainer.vue"; export default { components: { CssRatioContainer, JsRatioContainer }, mounted() { this.getSize(); window.addEventListener("resize", () => { this.getSize(); }); }, methods: { getSize() { this.$nextTick(() => { let myDom = document.getElementById("CssRatioContainer"); let myComputedStyle = window.getComputedStyle(myDom); this.$set(this.mySize, "height", myComputedStyle.height); this.$set(this.mySize, "width", myComputedStyle.width); }); }, }, data() { return { mySize: {}, ratioWidth: 6, ratioHeight: 1, }; }, }; </script> <style scoped> .father { max-width: 1200px; margin: 20px; } .itemBox { background: red; border: 1px solid yellow; } .inputStyle { width: 60px; text-align: center; } </style>