前端开发者学堂 - fedev.cn

Web中如何实现纵横比

发布于 大漠

Web发展到现在,已经有很大的变化,特别在当前这样的时代,我们面对的设备种类繁多。言外之意,这样的环境之下,Web的页面布局时常会碰到一些缩放比例的控制,特别是针对imgiframeobjectvideoembed等元素的比例缩放。当然,就img元素而言,要实现纵横比例的布局已有多种方案,而且实战性也特别的强,并且在Responsive设计中已使用广泛。

既然img可以实现,那其他元素iframevideo等元素也可以借鉴其中的一些实现原理。今天我们就来说说一些这方面的实现方案。

纵横比

在具体介绍如何实现纵横比之前,先来了解一下纵横比相关的概念。纵横比分为固定纵横比自适应纵横比

基于width的百分比来设置padding百分比值,把这种方式称之为固定纵横比。一般我们通过width的百分比来计算padding-toppadding-bottom的百分比值,其计算公式如下:

padding-top = (元素高度 / 元素宽度) * 100%
padding-bottom =  (元素高度 / 元素宽度) * 100%

比如下图:

上图展示的是一个9 / 16的固定纵横比例,计算出来就是56.25%。根据这个原理,我们可以在CSS处理器做相关处理:

@mixin fixed-aspect-rations($height, $width) {
    padding-bottom: $height / $width * 100%;
    // 或者
    padding-top: $height / $width * 100%;
}

当然还可以写一个@function

@function aspect-ratio($height, $width) {
    $aspect-ratio: $height / $width * 100%;

    @return $aspect-ratio;
}

在固定纵横比例的基础之上,做进一步的调整。假设我们在宽屏的PC上显示大的图片,而在移动设备上,我们不想使用相同的纵横比例让图像等元素变得太小。当然我们也不想使用完全相同的高度让图像变得太高。希望看到的效果是当宽度变小时,其高度也变得更小。我们就把这种方案称为流体纵横比例。

这种方案可以给元素设置一个高度,来减少padding-top或者padding-bottom的百分比值。假设我们的大图尺寸是700px的宽度和267px的高度,而我们决定显示的图片尺寸是在300px的宽度和167px的高度。现在我们需要计算heightpadding-bottom(或者padding-top)的值:

同样可以写一个混合宏:

@mixin fluid-ratio($large-size,$small-size) {
    $width-large: nth($large-size,1); //背景图片大尺寸的宽度
    $width-small: nth($small-size,1); //背景图片小尺寸的宽度
    $height-large: nth($large-size,2); //背景图片大尺寸的高度
    $height-small: nth($small-size,2); //背景图片小尺寸的高度
    //计算slope => slope = (h2 - h1) / (w2 - w1)
    //h1:背景图片大尺寸的高度 => $height-large
    //w1:背景图片大尺寸的宽度  => $width-large
    //h2:背景图片小尺寸的高度 => $height-small
    //w2:背景图片小尺寸的宽度 => $width-small
    $slope: ($height-large - $height-small) / ($width-large - $width-small);
    //计算元素的初始高度start Height => Start height = h1 - w1 * slope
    $start-height: $height-small - $width-small * $slope;

    padding-top: $slope * 100%; //你也可以将padding-top换成padding-bottom
    height: $start-height;
}

来看一个简单的示例,就拿固定纵横比例来说吧。

<div class="container">
    <iframe class="embed"></iframe>
</div>

根据上面的介绍,容器.containerheight设置为0,而padding-bottom或者padding-top设置为height / width * 100%。而这里的heightwidth指的是元素iframe的。假设希望iframe的固定纵横比例是9 : 16

.container {
    position: relative;
    width: 100%;
    height: 0;
    padding-top: 56.25% // 9 / 16 * 100%
}
.embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

最终效果如下:

拖动浏览器大小,视频可以按对应的比例进行缩放:

上面的方案,可以进行改良,使用::after或者::before来控制容器比例:

.container {
    position: relative;
    width: 75%;

    &:before {
        content: "";
        display: block;
        width: 100%;
        padding-top: 56.25%;
    }
}

上面看到的方案,其实已是老方案。在前面的教程中也有介绍过:

纵横比例新方案

有关于Web的布局,今年讲得最多的应该是CSS的Grid布局,这也是未来Web布局特性之一,它将改变以前的Web布局方式。那接下来的方案就是采用CSS Grid的方式来处理固定纵横比例。

如果你没有接触过CSS Grid布局相关的知识,建议你先阅读一些相关文章,这样有助于你后面的内容理解。

接下来的方案,除了使用到了CSS Grid还使用了CSS的Viewport单位以及CSS的自定义属性。别的先不多说,开始回到我们今天的主题。

我们采取的方法是创建一个网格容器的列数和宽高比的。在下面的示例中,使用16:9的宽高比,所以创建网格容器的列数为16列。

我们给每个列的宽度采用vw单位,并且其宽度是纵横比例。这样做的好处是可以调整窗口的宽度来控制容器的大小,同时还能根据纵横比例来进行调整。同时要控制网格行的大小,其大小根据列的计算来设置,控制每个单元格的比例是1:1。这里采用grid-auto-rows来控制网格行。

.container {
    display: grid;
    grid-template-columns: repeat(16, 5.625vw);
    grid-auto-rows: 5.625vw;
}

和以前的方案类似,上面采用gridvw实现了容器的纵横比例,接下来要控制元素。上面的代码通过grid-template-columnsgrid-auto-rows已设定了网格。接下来通过spangrid-columngrid-row进行网格合并,这里有一个重点:**grid-column合并的横向比例,示例中是span 16grid-row合并的是纵向比例,示例中是span 9。**同时把嵌入的元素,比如imgiframevideo这些元素的widthheight都设置为100%,用来足以填补整个网格区域。

.embed {
    grid-column: span 16;
    grid-row: span 9;
    width: 100%;
    height: 100%;
}

原理清楚了,把上面的示例使用Grid方案来改造一下:

同样拖动浏览器大小查看效果:

总结

文章简单介绍了如何在Web中实现纵横比例。除了以前的老方案之外,我们可以采用最新的CSS Grid布局,使用最新的布局方案,以前天生具备浏览器视窗缩放比例的视窗单位vw来控制网格网格的列数和行高。这个方案虽然灵便,但对于不同的纵横比例,需要创建不同的网格以及指定网格列的宽度。还有一点,就目前为止,虽然有些浏览器可以支持CSS Grid,但碍于一些传统浏览器,使用在实际项目中还是需要考虑其兼容性。虽然这里介绍了几种方案实现纵横比例,但是你要有较好的方案,欢迎在下面的评论中与我们一起共享。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/css/experiments-in-fixed-aspect-ratios.htmljordan retro 11 mens crimson