使用CSS的aspect-ratio实现宽高比缩放

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

在《图解CSS: 元素尺寸的设置》一文中主要介绍了W3C的 CSS Box Sizing Module Level 3的属性,即 用来设置元素大小的CSS的属性,比如我们熟悉的widthheightmin-content等。在今年上半年(大约是2020年5月份)该规范新出了一个Level 4版本,该规范中新增了stretchfit-contentcontain三个属性值,可以用于widthheight等属性;新增了aspect-ratio属性用来指定容器宽高比;还有就是指定容器内部尺寸contain-intrinsic-size,有点像min-contentmax-content能根据元素内容来决定元素大小。不过我们今天主要来和大家一起探讨其中的aspect-ratio属性,如果你感兴趣的话,请继续往下阅读。

什么是宽高比

aspect-ratio属性对应的就是 Aspect Ratio,它的意思就是宽高比,也常称为 纵横比,是几何形状在不同尺寸的比值。举个例子,当矩形方向为横向时的宽高比值,是其长边与短边的比率。常会用来描述图像或屏幕的宽度和高度的比率。通常表示为 x:yx × 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-toppadding-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中的百分比计算是比较复杂的,比如说widthpadding-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-bottompadding-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;
}

@propertysyntax到目前为止还没有<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-columngrid-row按比例合并单元格。

.aspectration { 
    display: grid; 
    gri
剩余80%内容付费后可查看

如需转载,烦请注明出处:https://www.w3cplus.com/css/css-aspect-ratio.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部