w3ctech

《你不知道的 CSS》之等比例缩放的盒子

你肯定已经知道,对于一个 img 元素而言,你可以单独地修改它的 width 或者 height 属性来设置它的大小,同时图片的比例还能够保持不变。

如下图所示,最上面是原始大小的图片,下面两张则分别是设置了 width: 50%height: 50% 属性后的样子。

可以看到把宽度设置为了原来的一半的同时,图片的高度并不是保持原来的大小,而是相应的也变成了原来的一半,使得图片仍能够保持原有的比例。同理把高度设成原来的一半也如此。

作为对照,我们看看单独修改其他元素的宽和高会产生什么样的效果:

上图最左边的蓝色矩形是原始的 div 元素,之后两个分别是对其设置了 width: 50%height: 50% 属性后的样子。可见与 img 元素不同,单独设置 div 元素的宽度(高度)时,对应的高度(宽度)并不会改变,从而导致元素的比例发生变化。这一结果相信每个稍微对前端有些了解的同学都能猜到。但是究竟是什么导致了同样的属性用于 img 和 div 后会产生不同的结果呢?

img 在元素分类中属于 replaced (被替换的)元素。replaced 元素表示这个元素内容的显示不是由 CSS 控制的。换句话说,对于 img 元素而言,图片的内容并不是由 CSS 定义的,而是通过其 src 属性指向的资源决定的。很多 replaced 元素来都会有自己的固有尺寸(Intrinsic dimension),img 也不例外1。当 img 的高度改变后,浏览器会计算出其缩放比例,而当元素的宽度是 auto(即默认值)时,浏览器则以原始宽度 * 缩放比例来作为元素的新宽度。从而使得 img 元素的比例始终保持一致。

然而这都并不是这篇文章讨论的重点。(那位同学请不要说脏话,不文明

重点是什么?重点就是题目:实现等比例缩放的盒子。

在响应式设计逐渐成为主流的今天,流式布局这个词即使放在一两年前也绝算不得是个新鲜词汇。下面是一个布局实例:

上图中每个蓝色的矩形分别对应一个 div 元素,每个元素的宽度占窗口宽度的四分之一(图示中为了演示方便给每个元素加了边距效果)。如果不做额外处理,当窗口宽度变小时上图的页面会变为如下所示:

可见每个元素的宽度进行了缩放,但高度并没有变化,看起来并不是很协调。所以有些场景下我们需要实现当窗口宽度缩放时,使得元素宽度自适应的同时,保证每个元素的宽高比例不变

很多同学在我话还没讲完时,就已经纷纷掏出 JavaScript 大锤着手实现了起来。然而这个系列文章的标题是《你不知道的 CSS》,自然不会介绍 CSS 实现不了这种打自己脸的需求,而且就此例而言,使用 JavaScript 实现效果并不好,绑定 onresize 事件后在拖拽时某些星座的朋友会察觉出来些许卡顿(你试试便知),而且在 JavaScript 加载完成前是看不出效果的。

其实用 CSS 可以很容易地实现这样的效果,用的属性也是我们每个工作日和周末(如果加班的话)都会用到的:padding-bottompadding-bottom 有一个让人很容易忽略的特性是当它的值是百分比形式时,百分比的基数是其所在元素的父元素的宽度而不是高度(同 padding-leftpadding-right 一样)。这样解决方案也就非常明显了:

  1. 将元素的 height 设成 0,使得元素的高度等于 padding-bottom
  2. 合理设置 padding-bottom 的值。比如每个元素的 width25%,现在想让元素的高度始终保持为其宽度的两倍,则 padding-bottom 的值应该设置为 50%

结果如下图所示:

相应的代码可以参见:http://jsfiddle.net/luin/25BbH/7/

然而至此,这篇文章还没完。肯定会有很多同学疑惑既然 height 被设成了 0,那么如果元素的 overflowhidden,里面的文字会不会因为超出了元素高度而被隐藏呢?

答案是不会。根据 CSS 2.1 规范2overflow 只会对处于 padding edge 外面的内容生效,即只有超出了 padding 区域的内容才会被 overflow 属性隐藏掉。

  1. 其实有一点例外的情况是当 img 的图片是 svg 时,它是没有固有尺寸的。
  2. http://www.w3.org/TR/CSS2/visufx.html
w3ctech微信

扫码关注w3ctech微信公众号

共收到10条回复

  • 这个技巧不错,已经在项目中用到了,经常通用在图片的等比缩放,height可设可不设,设为0的话容器里面内容的增加不会撑高盒子。 但这个不是最佳的技巧,最佳应该是rem,每次考虑比例太痛苦。

    回复此楼
  • 将图片设置成背景图片时,需要保持宽高比,也是通过设置height:0,然后padding-bottom为原始图片的宽高比(即百分比),主要还是利用padding属性为百分比时,参考的是父类容器的宽度,margin属性设置成百分比也是参考的是父类容器的宽度,只是margin不能撑开子类容器本身

    回复此楼
  • padding-bottom 如果单位是百分比,基数是其包含块的宽度,而不是父元素的 参考来自http://www.w3.org/TR/CSS21/box.html#propdef-padding

    回复此楼
  • 老技巧了

    回复此楼
  • box-sizeing :border-box

    回复此楼
  • get√

    回复此楼
  • get√

    回复此楼
  • 这个方法确实不错,知道的人很少,其实css隐藏了很多原则上的秘密,介绍的人也少

    回复此楼
  • 谢谢你地方法,最近我们公司需要做响应式 我看见你这个方法把我的心头一块雾气拉走了。谢谢 计算百分比好麻烦了这下

    回复此楼
  • 个人专为IT技术人员搭建的问答平台——欢迎前来拍砖。 http://www.dreawer.com/home.html

    目前最火的领域是前端领域,欢迎一起交流!

    回复此楼