特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)
在《图解CSS: 元素尺寸的设置》一文中主要介绍了W3C的 CSS Box Sizing Module Level 3的属性,即 用来设置元素大小的CSS的属性,比如我们熟悉的width
、height
、min-content
等。在今年上半年(大约是2020年5月份)该规范新出了一个Level 4版本,该规范中新增了stretch
,fit-content
和 contain
三个属性值,可以用于width
、height
等属性;新增了aspect-ratio
属性用来指定容器宽高比;还有就是指定容器内部尺寸contain-intrinsic-size
,有点像min-content
和max-content
能根据元素内容来决定元素大小。不过我们今天主要来和大家一起探讨其中的aspect-ratio
属性,如果你感兴趣的话,请继续往下阅读。
什么是宽高比
aspect-ratio
属性对应的就是 Aspect Ratio,它的意思就是宽高比,也常称为 纵横比,是几何形状在不同尺寸的比值。举个例子,当矩形方向为横向时的宽高比值,是其长边与短边的比率。常会用来描述图像或屏幕的宽度和高度的比率。通常表示为 x:y
或 x × y
,其中的 冒号 和 乘号 表示中文的 比 之意。
上图展示了三种常见的画面宽高比对角线比较(黑线圆框)。 最宽的蓝框( 2.39:1
)是电影常用的画面宽高比。 绿框(16:9
)和接近正方的红框(4:3
)是电视常用的标准比例。
就拿16:9
来说,第一个数字总是指 宽度,第二个数字是指 高度。如果图像的比例与屏幕的比例不同,你可能无法看到整个图像。如果屏幕比图像窄,图像就不能合适地放入。
在Web开发中,宽高比对Web的设计或布局有较大的影响的。随着科技不断的发展,Web开发者面对的屏幕终端可谓是不计其数,但这些终端屏幕(比如电视、电脑和手机)的比例也大多数图像的比例是不同的。你可能需要花一点时间改变图像(或元素)的宽高比,以便它与你使用的平台或设备更匹配。比如YouTube和Facebook在视频上处理的方式:
因此,当你选择根据屏幕大小调整视频,用户将会在应用上获得更好的体验,这个是值得的。
另外,我们有时候也会有相应的需求,比如说某个元素的高度按一定的比例随着元素宽度的变化增大(或减小)。这些都将用到宽高比相关的特性,而接下来要和大家一起探讨的就是CSS如何根据宽高比来调整元素的大小。
aspect-ratio
的Hack手法
aspect-ratio
可以说是CSS中比较新的一个特性,目前得到主流浏览器支持的不多,但根据宽高比调整元素大小的需求是一直存在的。也就是说,在aspect-ratio
还未得到浏览器支持的情况之下,社区中的一些大神就通过CSS的Hack手法(称得上 CSS的黑魔法 )实现了类似aspect-ratio
的特性,而且方案有多种。这里通过几个小的Demo先让大家回顾一下这些黑魔法,如果你以前从未接触过,也可以当作一种CSS技巧学习。
最为常见的方案就是使用padding-top
(或padding-bottom
)来模拟aspect-ratio
,比如宽高比是16:9
,那么padding-top = 9 ÷ 16 × 100% = 56.25%
(padding-bottom
计算也是如此)。使用padding-top
或padding-bottom
来模拟aspect-ratio
时,有一个细节需要特别注意,元素自身的高度height
值为0
或不显式设置height
值。
<!-- HTML -->
<aspectratio-container>
<aspectratio-content></aspectratio-content>
</aspectratio-container>
/* CSS */
.aspectratio-container {
width: 50vmin; /* 用户根据自己需要设置相应的值 */
/* 布局方案可以调整 */
display: flex;
justify-content: center;
align-items: center;
}
/* 用来撑开aspectratio-container高度 */
.aspectratio-container::after {
content: "";
width: 1px;
padding-bottom: 56.25%; /*元素的宽高比*/
margin: -1px;
z-index: -1;
}
效果如下:
注意,CSS中的百分比计算是比较复杂的,比如说
width
和padding-bottom
以及padding-top
取值为百分比时,它们都是相对于其父元素的width
计算。有关于CSS中各个取值为百分比值计算方式详细介绍,可以阅读《CSS中百分比单位计算方式》一文。
不过这种结构方式有一个致命点,如果<aspectratio-content>
内容足够多时,它自身的高度会大于<aspectratio-container>
根据计算所得的高度,这样宽高比缩放就失去意义:
为了满足更多场景,我们需要在上面的代码上稍作调整:
.aspectratio-content {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 2;
}
效果如下:
这个时候,即使<aspectratio-content>
超出容器高度,也不会有任何影响,也可以说真正达到宽高比缩放的效果:
如果你讨厌自己去计算的话,可以使用CSS的calc()
函数,直接在padding-bottom
(或padding-top
)赋值时用calc()
来替代。同样拿16:9
来说,其实就是16/9
,对应的数学计算是9 ÷ 16 × 100%
,换成CSS的calc()
可以是 calc(9 / 16 * 100%)
,为了更好理解,也可以换成calc(100% / (16 / 9))
:
.aspectratio::after {
content: "";
width: 1px;
padding-bottom: 56.25%;
padding-bottom: calc(100% / (16 / 9)); /* 等同于 56.25% */
padding-bottom: calc(9 / 16 * 100%); /* 等同于 56.25% */
margin: -1px;
z-index: -1;
}
他们效果都是一样的:
在使用calc()
函数计算的时候,我们还可以把 CSS自定义属性 引入进来,比如:
<aspectratio-container style="--aspect-ratio: 16 / 9">
<aspectratio-content></aspectratio-content>
</aspectratio-container>
在计算padding-bottom
或padding-top
时可以像下面这样:
.aspectratio-container::after {
content: "";
width: 1px;
padding-bottom: calc(100% / (var(--aspect-ratio)));
margin: -1px;
z-index: -1;
}
效果如下:
在《CSS Houdini: @propert
注册自定义属性》中我们介绍了CSS Houdini的自定义属性(变量),基于@property
注册CSS自定义属性的特性,我们可以给相应的宽高比变量指定对应的语法值,比如<ratio>
:
<ratio> = <number [0,∞]> [ / <number [0,∞]> ]?
这样做会让自定义的属性更严谨,除此之外,还可以给注册的自定义属性指定一个初始值。比如下面这样的一个示例:
@property --aspect-ratio {
syntax: "<ratio>";
initial-value: "4 / 3";
inherits: false;
}
.aspectratio-container::after {
content: "";
width: 1px;
padding-bottom: calc(100% / (var(--aspect-ratio)));
margin: -1px;
z-index: -1;
}
在@property
中syntax
到目前为止还没有<ratio>
语法类型。
随着vw
这样的视窗单位的出现,实现宽高比的效果也变得更简便一些。来看一个简单的示例,假设容器的宽度是50vw
,你希望元素的高度根据宽高比16:9
获得,那么可以像下面这样做:
<!-- HTML -->
<aspectratio-container></aspectratio-container>
/* CSS */
.aspectratio {
width: 50vw;
height: 28.125vw; /* 50 ÷ 16 × 9 = 28.125 */
background-color: #09f;
}
效果如下:
使用视窗这样的相对单位来模拟aspect-ratio
有利也有弊,好的一面是不需要额外的容器,也不需要借助伪元素来将容器撑高,不利的一面是容器宽度改变时,高度也需要相应的去计算。比如说,宽度从50vw
变成30vw
,即使是相同的宽高比16:9
,他们计算出来的值是不同的。
还有一个很有创意的解决方案,使用的都是CSS新特性:视窗单位 和 CSS Grid布局。简单说一下其中的实现原理:将容器.aspectration
通过display:grid
声明为一个网格容器,并且利用repeat()
将容器划分为横向比例,比如16
,那么每一格的宽度对应的就是100vw * 9 / 16 = 6.25vw
。同样使用grid-auto-rows
,将其设置的值和横向的值一样。在子元素上通过grid-column
和grid-row
按比例合并单元格。
.aspectration {
display: grid;
gri
如需转载,烦请注明出处:https://www.w3cplus.com/css/css-aspect-ratio.html
如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!