如何使用 css+div 来实现一个等比例矩形呢,如下图:
基本实现
- 正方形
使用padding-top
来实现一个在保持固定宽高比的情况下,高度根据宽度变化的div
.resp-rect{
background-color: red;
width: 33%;
}
.outer{
padding-top: 100%;
}
<div class="resp-rect">
<div class="outer"></div>
</div>
- 长方形(矩形)
使用padding-top
来撑起高度,上面代码演示了如何构造正方形(1:1的矩形),下面演示如何构造长宽比为2:1的长方形:
.resp-rect{
background-color: red;
width: 33%;
}
.outer{
padding-top: 50%; // 变化
}
padding-top
的值为:height / width * 100%
内容填充
弄了矩形出来就要使用,也就是往这个矩形区域里塞内容,但是直接在 outer 这个 div 内塞东西是不会得到你想要的结果的!!
.resp-rect{
background-color: red;
width: 33%;
}
.outer{
padding-top: 100%;
}
<div class="resp-rect">
<div class="outer">123</div>
</div>
结果为:
因为其实 outer 里面已经由padding-top
占据了所有空间,此时需要使用margin-top
来使可用空间回到矩形的顶部:
.resp-rect{
background-color: red;
width: 33%;
}
.outer{
padding-top: 100%;
}
.inner{
margin-top: -100%;
}
<div class="resp-rect">
<div class="outer">
<div class="inner">123</div>
</div>
</div>
padding-top
和margin-top
数值是一样,但是margin-top
为负数。
同理,构造长宽比为2:1的长方形,如下:
.resp-rect{
background-color: red;
width: 33%;
}
.outer{
padding-top: 50%;
}
.inner{
margin-top: -50%;
}
实战
- 通用性考虑
上面展示了如何使用三层DOM来构造矩形,但是要将这一结构抽离成组件级别,需要实现以下要求:
1.组件内部构造矩形的样式或结构不依赖或不影响到外部布局
2.使用时,使用者无需只需传足够少的属性(宽高比、宽度)即可
- vue组件封装
外部有一个div包裹,里面有两部分组成,分别为:矩形结构的构造、真实显示内容。
// 组件的封装
<template>
<div
:class="$style.wrap"
>
<-- 矩形结构的构造,负责撑起高度 -->
<div
:class="$style.func"
:style="{paddingTop:`${AspectRatio}%`}"
>
<div :style="{marginTop:`-${AspectRatio}%`}"/>
</div>
<-- 真实显示内容,slot内容的载体 -->
<div :class="$style.content">
<slot/>
</div>
</div>
</template>
<script>
export default {
name: 'RespRect',
computed:{
AspectRatio(){
return this.respH/this.respW*100;
}
},
props:{
/**
* 只需将设计图的宽度和高度传入,内部自行计算宽高比,
* 注意:这里传入的不是真实尺寸,而只是单纯用于计算宽高比
*/
respW:{
type:Number,
default:1
},
respH:{
type:Number,
default:1
}
}
}
</script>
<style module lang="scss">
.wrap{
position: relative;
>.func{
position: relative;
visibility: hidden;
opacity: 0;
pointer-events: none;
overflow: hidden;
}
>.content{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
}
</style>
使用方式:
// 组件的使用
<template>
<RespRect
class="myRect"
:respW="375"
:respH="600"
>
<div class="flex">
<p>123</p>
<p>456</p>
<p>789</p>
</div>
</RespRect>
</template>
<script>
.myRect{
width: 50%;
background-color: yellow;
}
.flex{
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
</script>