深入理解 CSS 中的 object-fit 和 background-size


我们并不总是能够为 HTML 元素加载不同尺寸的图像。如果我们使用的宽度和高度不符合图像的纵横比,图像可能会被压缩或拉伸。这不是一个好的结果,不过我们可以通过对 img 元素使用 object-fit 或使用 background-size 来解决这个问题。

首先,让我们定义一下这个问题。请看下图:

为什么会这样?

每张图片都有一个纵横比,浏览器会用该图像填充其所在的容器。如果图像的纵横比与为其指定的宽度和高度不同,那么结果将是图像被压缩或拉伸。

解决方案

当图像的纵横比与容器的宽度和高度不匹配时,我们并不总是需要添加不同尺寸的图像。在深入讨论 CSS 解决方案之前,我想展示一下过去我们在照片编辑软件中是如何解决这个问题的:

首先,我们会将图像垂直居中,然后通过遮罩进行裁剪。这样可以保持图像的纵横比,并防止图像被压缩。
现在我们已经理解了这个过程的原理,让我们来看一下在浏览器中是如何实现的。(剧透:这更简单!)

CSS object-fit

object-fit 属性定义了像 imgvideo 这样的替换元素的内容应如何调整大小以适应其容器。object-fit 的默认值是 fill,这可能会导致图像被压缩或拉伸。

让我们来看看可能的取值。

object-fit 的可能值

object-fit: contain

在这种情况下,图像将调整大小以适应容器的纵横比。如果图像的纵横比与容器不匹配,它会被信箱化处理(即在空白区域添加黑边或白边)。

当使用 object-fit: contain 时,图像会被信箱化或相应地调整大小。

object-fit: cover

在这里,图像也会调整大小以适应容器的纵横比。如果图像的纵横比不匹配,则图像将被裁剪以适应容器。

当使用 object-fit: cover 时,图像会被裁剪或相应地调整大小。

object-fit: fill

使用此选项时,图像会调整大小以适应容器的纵横比。如果图像的纵横比不匹配,则会被压缩或拉伸。我们通常不希望这样。

当使用 object-fit: fill 时,图像会被压缩、拉伸或相应地调整大小。

object-fit: none

在这种情况下,图像根本不会调整大小,不会被拉伸或压缩。它的行为类似于 cover,但不会遵循容器的纵横比。


当使用 object-fit: none 时,如果图像的尺寸不同,它不会被调整大小。(大图预览)

除了 object-fit,我们还有 object-position 属性,负责将图像在容器内进行定位。

object-position 的可能值

object-position 属性与 CSS 的 background-position 属性类似:
image.png
大多数情况下,默认值会被使用(即 center50% 50%

当容器的纵横比在垂直方向上更大时,topbottom 关键字也可以使用:

  • object-position: top(左侧)和 object-position: bottom(右侧)对比

CSS background-size

使用 background-size 时,主要区别在于我们处理的是背景,而不是 HTML 的 img 元素。

background-size 的可能值

background-size: auto

使用 auto 时,图像将保持默认尺寸:


请记住,默认尺寸有时可能会导致图像模糊(如果图像过小的话)。

background-size: cover

在这种情况下,图像将调整大小以适应容器。如果纵横比不同,图像将被遮罩处理以适应。


使用 background-size: cover 时,请确保考虑图像的纵横比。

background-size: contain

在这种情况下,图像将调整大小以适应容器。如果纵横比不匹配,图像会像下一个示例中那样被信箱化处理:


background-size: contain 会调整图像大小以适应容器。

关于 background-position,它的工作方式类似于 object-position。唯一的区别是,object-position 的默认位置与 background-position 的默认位置不同。
翻译:

何时不应使用 object-fitbackground-size

如果元素或图像被设置了固定高度,并且应用了 background-size: coverobject-fit: cover,那么在某些情况下,图像会变得过宽,导致丢失重要细节,这可能会影响用户对图像的感知。

请看以下例子,其中图像被赋予了固定高度:

1
2
3
.card__thumb {
height: 220px;
}

下图展示了一个图像过宽的例子,因为图像的高度是固定的,而卡片容器太宽。

如果卡片容器过宽,将导致右侧所示的结果(图像过宽)。这是因为我们没有指定纵横比。

解决方法只有两个。第一个方法是使用填充技巧来创建内在比例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.card__thumb {
position: relative;
padding-bottom: 75%;
height: 0;
}

.card__thumb img {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
object-fit: cover;
}

第二个解决方法是使用新的 aspect-ratio CSS 属性。通过它,我们可以这样做:

1
2
3
.card__thumb img {
aspect-ratio: 4 / 3;
}

用例与示例

用户头像

object-fit: cover 的一个完美用例就是用户头像。头像的纵横比通常是正方形,将图像放入正方形的容器中可能会导致图像变形。

  • 没有 object-fit 和使用 object-fit: cover 的用户头像对比。
1
2
3
.c-avatar {
object-fit: cover;
}

标志列表

展示企业的客户名单很重要。我们通常会使用标志,但由于标志大小各异,我们需要一种方法在不扭曲图像的情况下调整大小。

幸运的是,object-fit: contain 是一个很好的解决方案。

1
2
3
4
5
.logo__img {
width: 150px;
height: 80px;
object-fit: contain;
}
  • 一个标志列表:Airbnb、Domino’s Pizza、Apple Pay、Amazon

使用 object-fit: contain 可以帮助我们调整客户标志的大小,而不扭曲图像。

文章缩略图

这是一个非常常见的用例。文章缩略图的容器可能并不总是包含具有相同纵横比的图像。这个问题本应由内容管理系统(CMS)解决,但并不总是如此。

1
2
3
.article__thumb {
object-fit: cover;
}

通过 object-fit: cover 来调整文章缩略图。

超级背景

在这个用例中,决定使用 img 元素还是 CSS 背景取决于以下问题:

  • 这个图像是否重要?如果 CSS 出于某种原因被禁用,我们希望用户看到图像吗?
  • 还是图像仅仅是装饰性的?

根据答案,我们可以决定使用哪个功能。如果图像很重要:

  • 使用超级背景的用例
    假设图像很重要,因为这是一个与食物相关的网站。😉
1
2
3
<section class="hero">
<img class="hero__thumb" src="thumb.jpg" alt="" />
</section>
1
2
3
4
5
6
7
8
9
10
11
12
.hero {
position: relative;
}

.hero__thumb {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
object-fit: cover;
}

如果图像是装饰性的,我们可以使用 background-image

1
2
3
4
5
6
.hero {
position: relative;
background-image: linear-gradient(to top, #a34242, rgba(0,0,0,0), url("thumb.jpg"));
background-repeat: no-repeat;
background-size: cover;
}

这种情况下,CSS 代码会更简短。确保任何放置在图像上的文字都可读且易于访问。

使用 object-fit: contain 为图像添加背景

你知道可以为 img 添加背景颜色吗?在使用 object-fit: contain 时,我们可以从中受益。

在下面的示例中,我们有一个图像网格。当图像和容器的纵横比不同,背景颜色将会显示出来。

1
2
3
4
img {
object-fit: contain;
background-color: #def4fd;
}

  • 使用 object-fit: contain 为图像添加背景颜色。

视频元素

你是否曾需要将视频用作背景?如果是,那么你可能希望它占据父容器的全部宽度和高度。

1
2
3
4
5
6
7
8
9
10
11
12
.hero {
position: relative;
background-color: #def4fd;
}

.hero__video {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
  • 在默认情况下,视频的 object-fit 值是 contain。如图所示,即使视频有 position: absolutewidth: 100%height: 100%,视频仍然无法覆盖整个背景。

要让视频完全覆盖其父容器的宽度和高度,我们需要覆盖默认的 object-fit 值:

1
2
3
4
.hero__video {
/* 其他样式 */
object-fit: cover;
}

  • 现在,视频覆盖了其父容器的全部宽度和高度。

结论

正如我们所见,object-fitbackground-size 在处理不同图像纵横比时非常有用。我们不总是能够控制每个图像的完美尺寸,这时这两个 CSS 功能就发挥了作用。

在选择 img 元素和 CSS 背景之间时要注意可访问性。如果图像是纯装饰性的,使用 CSS 背景更合适;否则,使用 img 更合适。