原理
- 元素的padding值如果使用百分比,那这个百分比是相对于父元素宽度而言的,padding-top和padding-bottom指定百分比时也是相对于父元素高度而言;
- IE盒模型中,width = content + padding + border,因此只设置padding也会使元素在页面上占据一部分区域;chromium内核浏览器大多采用IE盒模型而非W3C标准盒模型;
验证
写两个元素,父元素宽高200px,子元素padding为20%,可以在调试器里看到,四边padding都是20px;
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.outter {
width: 200px;
height: 200px
}
.inner {
padding: 10%;
}
</style>
</head>
<body>
<div class="outter">
<div class="inner">
</div>
</div>
</body>
</html>
截图里,.outter是父元素,右下角盒模型是.inner;
思考:为什么.inner的盒模型中,content区域是160*0?
应用
实现保持宽高比
以实现宽高比为 11:9 为例。宽高比11:9,则高为宽的0.8181(=9/11),所以设置padding-top为81.81%,这样inner占据的高度就是outter宽度的81.81%。如下图,可以看到inner的高度为163.61=200*81.81%,实现了inner在页面中占据的空间宽高比为9/11。
但此时如果在inner内部放入其他元素的话,会因为padding-top的存在,导致元素无法从outter的顶部开始排列,如下图。
这时候需要为inner设置position:relative; 然后在inner内部设置一个容器宽高为100%,position:absolute; 元素放在inner内部容器中,即可从outter的顶部开始排列元素;
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
.outter {
width: 200px;
height: 200px
}
.inner {
padding-top: 81.81%;
position: relative;
}
.inner>.inner-content {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
img {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="outter">
<div class="inner">
<div class="inner-content">
<img src="https://gss2.bdstatic.com/-fo3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268/sign=2e12f29caa4bd11304cdb03462aea488/377adab44aed2e736d5390c38001a18b86d6faa3.jpg">
</div>
</div>
</div>
<h1>ok</h1>
</body>
</html>
这里需要注意,如果inner-content中内容过多导致高度超出inner-content的height,会直接渲染到页面上,而不占据多余的页面空间(因为inner-content已经拉出文档流),有可能会遮挡outter下面的内容。因此需要根据情况设置inner-content的overflow:hidden; 或 overflow:auto;
Vue中,实现保持宽高比的组件
根据以上的实现方式,可以自定义一个vue组件,用于保持宽高比。
<template>
<div class="outter" :style="formattedRatioStyle">
<div class="inner">
<div class="inner-content">
<slot></slot>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {};
},
props: ['ratio', 'overflow', 'overflowX', 'overflowY'],
computed: {
formattedRatioStyle() {
let ratio = this.ratio;
if (ratio == null || Number.isNaN(ratio)) {
ratio = 100;
}
if (typeof ratio !== 'string' || !ratio.endsWith('%')) {
ratio = ratio + '%';
}
return `padding-top: ${ratio};`;
},
formattedContentStyle() {
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 lang="scss">
.outter {
width: 100%;
height: 0;
position: relative;
.inner {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
}
</style>
使用
<aspect-ratio ratio="81.81" overflow="auto"></aspect-ratio>