如何使用 flexbox 和 object-fit 属性 强制图像覆盖布局单元的尺寸?

How to force images to cover the dimensions of a layout unit using flexbox and the object-fit property?

我正在开发响应式图库布局,其中所有图像都应覆盖其容器的尺寸。为了保持每个图像的纵横比,我想我可以使用相当新的 CSS 属性 object-fit

实施的解决方案使用 flexbox 模块强制画廊的每一列高度相等。每列中的单元格都被拉伸以适合其父级的总和高度。每个单元格的实际高度由flexbox模块使用flex: 1 0 auto确定,不一定相同。

这是我的问题:每个单元格中包含的图像现在应该与其容器的尺寸相匹配(使用 object-fit: cover; width: 100%; height: 100%)。在 Firefox 和 Internet Explorer(使用 object-fit polyfill)中,这些样式会产生预期的布局,但在 Chrome 或 Safari 等 webkit 浏览器中则不会。在这些浏览器中,每个单元格的尺寸都是正确的,但图像的尺寸不是。

我找不到相关的错误报告,也找不到解决我的问题的灵活方法。我希望有人能帮助我,因为我目前 运行 没有想法。

已在最新版本的 Chrome、Safari、Firefox 以及 IE 10 和 11

中进行测试

// Object Fit Polyfill
// @see <https://github.com/bfred-it/object-fit-images>
objectFitImages();
/* Reset */

body {
  font: 100%/26px Lato, sans-serif;
  padding: 5%;
}

figure {
  margin: 0;
}

blockquote {
  margin-left: 0;  
}

img {
  vertical-align: middle;
  max-width: 100%;
  height: auto;
  font-style: italic;
}

/* Gallery */

.c-gallery {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-flex-flow: wrap row;
      -ms-flex-flow: wrap row;
          flex-flow: wrap row;
  -webkit-box-pack: justify;
  -webkit-justify-content: space-between;
      -ms-flex-pack: justify;
          justify-content: space-between;
}

  .c-gallery__column {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-flex-flow: wrap column;
        -ms-flex-flow: wrap column;
            flex-flow: wrap column;
    -webkit-box-flex: 1;
    -webkit-flex: 1 0 33%;
        -ms-flex: 1 0 33%;
            flex: 1 0 33%;
  }

  .c-gallery__item {
    -webkit-box-flex: 1;
    -webkit-flex: 1 0 auto;
        -ms-flex: 1 0 auto;
            flex: 1 0 auto;
  }

    .c-gallery__item img {
      width: 100%;
      height: 100%;
      -o-object-fit: cover;
         object-fit: cover;
    }
<div class="c-gallery">
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x1080" alt="Product A" /></a>
    </figure>
  </div>
  <div class="c-gallery__column">
    <div class="c-gallery__item">
      <figure>
        <blockquote>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officiis architecto voluptatum numquam totam quos neque incidunt!</p>
        </blockquote>
        <figcaption>
          <cite>John Doe</cite>
        </figcaption>
      </figure>
    </div>
    <figure class="c-gallery__item">
      <img src="http://placehold.it/640x720" alt="John Doe" />
    </figure>
  </div>
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product B" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product C" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product D" /></a>
    </figure>
  </div>
</div>
<script src="http://bfred-it.github.io/object-fit-images/dist/ofi.browser.js"></script>

如果你更喜欢 CodePen,我创建了一个我正在做的演示:

变化

  • 删除了适合对象的多边形
  • 按照现代标准清理 flexbox 属性
  • 删除了所有 img,来自网站的图像,例如具有固定尺寸的占位符宿主图像,因此它们不会拉伸。
  • 在每个 <figure> 上使用 background shorthand,具有以下属性:
    • background-image
    • background-repeat
    • background-position
  • 每个图都用了background-size: cover,效果和object-fit: cover一样。有关背景缩放的详细信息,请参阅此 article
  • 使用此模式设置每个弹性列的弹性项目尺寸:
    • 最小宽度:Xvw;
    • 最大宽度:Xem;
    • 最小宽度:Yvh;
    • 最大高度:是的;
    • vw and vh are viewport units.
    • em 测量值基于从原始 <img>
    • 观察到的尺寸
  • flex-wrap: [row/column] [wrap/nowrap] 是正确的语法
    • 您需要在此网格布局中 nowrap。如果由于某种原因超出了 flexboxes 的限制,wrap 会扭曲布局,盒子相互堆叠。有关 flexbox 的 当前 详细信息,请阅读此 article
  • <figure> 中放置了 <a> 锚点,并在锚点中设置了 <div> 以在 <figure> 中从边到边传播它。这很丑陋,可能有更好的方法。查看源代码并查找 .space 类 了解详细信息。

支持

Flexbox

IE sux,它有很多问题,所以请保持简单。

background-size

完全支持,除非您的客户使用 opera-mini(不到 .1% 的用户?)

这个演示总体上看起来非常兼容,所以希望不需要多边形。 它并不完美,但我认为您可以自己调整其余部分的长度、边距等。

CODEPEN

我找到了适合我的解决方案。问题似乎是锚元素上缺少尺寸。虽然我试图绝对定位链接以强制它们覆盖它们的容器,但我应该更彻底地尝试将它们设置为 flexbox-container。我的解决方案包括以下添加内容:

  1. 强制锚元素也充当 flexbox 容器,就像画廊项目一样。
  2. 强制每个图库项目使用其父列高度的 100%。 flex-module 将计算用于元素的实际高度,并允许项目根据需要增大或缩小 (flex: 1 1 auto)。
  3. 使用 flex 模块(使用 flex: 1 1 auto;)拉伸每个图像元素以覆盖其容器的尺寸。 object-fit 语句将确保纵横比保持不变。
  4. 新的 css class 允许 blockquote-容器使用内容所需的 space(flex-shrink: 0; flex-grow: 0; height: auto;)。

生成的布局正是我想要的——至少在 Chrome、Firefox 和 IE10+ 中是这样。不幸的是,在 Safari 中,结果有点不同。在 Safari 中,blockquote 元素及其内容决定了整个画廊的高度。结果,每列的高度在每个子项之间进行划分,从而产生小的缩略图。我认为原因是,没有元素具有明确的高度和基于百分比的高度在这里不起作用(虽然想知道为什么它适用于其他浏览器)。适用于我的用例的修复是在图库容器上应用 min-height

这里是当前的解决方案:

// Object Fit Polyfill
// @see <https://github.com/bfred-it/object-fit-images>
objectFitImages();
/* #Base:Reset */

body {
  font: 100%/26px Lato, sans-serif;
  padding: 5%;
}

figure {
  margin: 0;
}

blockquote {
  margin-left: 0;  
}

img {
  vertical-align: middle;
  max-width: 100%;
  height: auto;
  font-style: italic;
}

/* #Component:Gallery */

.c-gallery {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  min-height: 100vh; /* Prevents collapsing items in Safari */
  max-height: 1080px;
}

  .c-gallery__column {
    display: flex;
    flex-flow: column nowrap;
    flex: 1 1 auto;
    width: 33.33333%;
  }

  .c-gallery__item,
  .c-gallery__item > a {
    display: flex;
    flex-flow: column nowrap;
    flex: 1 1 auto;
    height: 100%;
  }

  .c-gallery__item--fit-content {
    flex-grow: 0;
    flex-shrink: 0;
    height: auto;
  }

    .c-gallery__item img {
      flex: 1 1 auto;
      width: 100%;
      max-width: none;
      height: 100%;
      object-fit: cover;
    }
<div class="c-gallery">
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x1080" alt="Product A" /></a>
    </figure>
  </div>
  <div class="c-gallery__column">
    <div class="c-gallery__item c-gallery__item--fit-content">
      <figure>
        <blockquote>
          <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Officiis architecto voluptatum numquam totam quos neque incidunt!</p>
        </blockquote>
        <figcaption>
          <cite>John Doe</cite>
        </figcaption>
      </figure>
    </div>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x720" alt="John Doe" /></a>
    </figure>
  </div>
  <div class="c-gallery__column">
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product B" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product C" /></a>
    </figure>
    <figure class="c-gallery__item">
      <a href="#"><img src="http://placehold.it/640x360" alt="Product D" /></a>
    </figure>
  </div>
</div>
<script src="http://bfred-it.github.io/object-fit-images/dist/ofi.browser.js"></script>

您可以在 CodePen

上再次看到原始演示的分支

注意:我在回答中遗漏了供应商前缀,运行 如果您使用不支持 flexbox 的浏览器。