【问题标题】:How to force images to cover the dimensions of a layout unit using flexbox and the object-fit property?如何使用 flexbox 和 object-fit 属性强制图像覆盖布局单元的尺寸?
【发布时间】:2016-06-23 13:37:05
【问题描述】:

我正在开发一个响应式画廊布局,其中所有图像都应覆盖其容器的尺寸。为了保持每个图像的纵横比,我认为我可以使用相当新的 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,我创建了一个我正在工作的演示:

【问题讨论】:

  • object-fit 不能使用固定尺寸吗?所以让它max-widthmax-height,也许吧。我不确定,因为您使用的是多边形。
  • 不再需要 Flexbox 前缀-CanIUse 有很多过时的 flexbox 属性...也许可以简化为大多数当前的 flexbox 语法?再一次,我不确定需要什么...我不信任政策。
  • @Michael_B 图片需要包裹在锚链接中,因为它们会链接到产品页面。我已经尝试制作这些display: flex; flex-flow: nowrap column; flex: 1 0 100%; 以确保它们与图形的高度相匹配,但这并没有改变任何东西。
  • @zer00ne IE 10/11 需要供应商前缀。 polyfill 也主要用于 IE。您能否进一步详细说明“不适合固定尺寸的对象”是什么意思?

标签: css flexbox image-gallery


【解决方案1】:

变化

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

支持

Flexbox

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

background-size

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

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

CODEPEN

【讨论】:

  • 感谢您的时间和精力。我认为您的解决方案需要进一步调整(例如,目前第一列左侧有一个间隙,第三列的高度不匹配)。尽管如此,出于 SEO 和可访问性的原因,我还是希望将图像保留在 DOM 中。 flex-flow 语句中的错误顺序是一个很好的提示。此外,您使用背景图像的解决方案产生了另一个想法:在视觉上隐藏图像并将图像用作背景 (codepen.io/dweidner/full/dXNXNO)。显然,这会导致图像的点击表面不匹配。
  • @Daniel 这不是一个坏主意,如果它不破坏 SEO,您可以将 &lt;img&gt; 设为 1x1px。
【解决方案2】:

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

  1. 强制锚元素也充当flexbox-container,就像画廊项目一样。
  2. 强制每个库项目使用其父列高度的100%。 flex-module 将计算元素使用的实际高度,并允许项目根据需要增长或缩小 (flex: 1 1 auto)。
  3. 使用弹性模块(使用flex: 1 1 auto;)拉伸每个图像元素以覆盖其容器的尺寸。 object-fit 语句将确保保持纵横比。
  4. 新的 css 类允许 blockquote-container 使用内容所需的空间 (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 的浏览器进行浏览,运行 sn-p 可能会导致布局损坏。

【讨论】:

    猜你喜欢
    • 2021-08-03
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    • 2016-09-12
    • 1970-01-01
    • 2022-10-05
    • 2019-02-10
    相关资源
    最近更新 更多