如何使图像保持在 css 网格容器的行内?

How to make images stay within the rows of a css grid container?

下面的代码显示了当我调整 window 大小时的预期行为 Chrome 60,在 Firefox 55 中(但在 iOS Safari 10.3 中没有;这很可能是另一个问题,为什么它在 Safari 中行为不端)。

html, body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  border: 0;
  background-color: lightgrey;
}

.container {
  box-sizing: border-box;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(3, calc((60vh - 12px)/3));
  /*grid-template-rows: 1fr 1fr 1fr;*/
  /*grid-template-rows: auto auto auto;*/
  height: 60vh;
  border: 3px solid yellow;
  padding: 3px;
  /*grid-gap: 20px;*/ /* <-- would also mess things up */
}

.tile {
}

img {
  box-sizing: border-box;
  display: block;
  object-fit: contain;
  width: 100%;
  height: 100%;
  margin: 0;
  border: 0;
  padding: 3px;
}
 <!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
 <div class="container">
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
 </div>

重要的是图片的纵横比 (2:1)

保留。我本来希望:

grid-template-rows: 1fr 1fr 1fr;

或:

grid-template-rows: auto auto auto;

使图像适合网格的行,但两者都不适合。 有:

grid-template-rows: repeat(3, calc((60vh - 12px)/3));

我得到了想要的行为。 我怎样才能避免自己计算数学? 换句话说,我应该怎么做才能使 grid-template-rows: 1fr 1fr 1fr;(或类似的东西)起作用?

CSS中的容器元素的高度在实际页面上已经很难算出来了。目标是用CSS网格布局来解决;没有 JavaScript,也没有背景图片修改。


更新: 我最初排除背景图片破解有两个原因。

  1. 我以为(由于一些误解)背景图片 url 必须在 CSS 文件中,但事实并非如此:我可以使用 内联样式并将其放在 HTML.

  2. 感觉很老套。在看到它变得多么复杂和混乱之后 将嵌套的 flex 容器嵌套在网格容器中只是为了让它在 Safari 上工作,我只是求助于背景图像 hack,因为它显着 更干净并且在所有测试的浏览器中工作(Chrome、火狐、Safari)。

最后,不是公认的答案帮助解决了我的问题。

我不知道您希望图像适合的程度如何,但您可以使用 minmax()minmax() 允许您设置网格行大小的最小值和最大值。将最小值设置为 auto,将最大值设置为 33% 将使它们变得尽可能小,最多为网格容器高度的 33%,但是没有更大的。这将使所有网格项目保持在网格容器占据的 60vh 的 99% 的最大高度处。

这不完全是您希望获得的自动方式...您仍在声明尺寸,即使它是相对的。它确实避免了笨重的 calc((60vh - 12px) / 3),尽管使用该方法并没有什么错,除非你的 post.

中有其他限制

然而,kukkuz 的回答和重置 min-height 是一个更好的解决方案,这正是我所缺少的。

html, body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  border: 0;
  background-color: lightgrey;
}
.container {
  box-sizing: border-box;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(3, minmax(auto, 33%));
  height: 60vh;
  border: 3px solid yellow;
  padding: 3px;
}
.tile {
    display: grid;
}
img {
  box-sizing: border-box;
  display: block;
  object-fit: contain;
  width: 100%;
  height: 100%;
  margin: 0;
  border: 0;
  padding: 3px;
}
 <!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
 <div class="container">
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
 </div>

您可以使用 grid-template-rows: 1fr 1fr 1fr,更重要的是您必须重置 网格项 min-widthmin-height 值,默认为auto(内容一样多)。

To provide a more reasonable default minimum size for grid items, this specification defines that the auto value of min-width/min-height also applies an automatic minimum size in the specified axis to grid items whose overflow is visible and which span at least one track whose min track sizing function is auto. (The effect is analogous to the automatic minimum size imposed on flex items.)

Source: W3C

这类似于带有 flexboxesauto flex item 规则。请参阅下面的演示,我将它们重置为 zero:

html, body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  border: 0;
  background-color: lightgrey;
}

.container {
  box-sizing: border-box;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  height: 60vh;
  border: 3px solid yellow;
  padding: 3px;
  /*grid-gap: 20px;*/ /* <-- would also mess things up */
}

.tile {
  min-width: 0;
  min-height: 0;
}

img {
  box-sizing: border-box;
  display: block;
  object-fit: contain;
  width: 100%;
  height: 100%;
  margin: 0;
  border: 0;
  padding: 3px;
}
<!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
 <div class="container">
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
   <div class="tile">
     <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
   </div>
 </div>

您已将图像设置为 height: 100%。但是 100% 的是什么? 100%的容器? 100% 的视口? 100% 的行?如果是,行高是多少?

Chrome 和 Firefox 对您的意图进行有根据的猜测。他们实施了旨在超越规范指导的算法,以改善用户体验。他们称这些修改为 "interventions".

Safari 不会这样做。 Safari 严格遵守规范语言,其中规定元素上的百分比高度必须在父元素上定义高度,否则将被忽略。

此处更详细地解释了这些浏览器差异:

然后你必须考虑网格项目,默认情况下,不能小于它们的内容。如果您的行设置为 1fr,但图像高于分配的 space,则行必须展开。您可以使用 min-height: 0 / min-width: 0overflow 以及除 visible.

以外的任何值覆盖此行为

此行为在此处有更详细的解释:

不过,一旦您考虑了上述指导,您可能可以通过组合使用网格和弹性属性让您的布局在 Safari 中工作:

* {
  box-sizing: border-box;
}

body {
  display: flex;
  flex-direction: column;
  height: 100vh;
  margin: 0;
  background-color: lightgrey;
}

header,
footer {
  flex: 0 0 100px;
  background-color: tomato;
  display: flex;
  align-items: center;
  justify-content: center;
}

.container {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: auto;
  padding: 3px;
}

.tile {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 0;
}

img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  padding: 3px;
}
<header>HEADER</header>
<!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
<div class="container">
  <div class="tile">
    <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
  </div>
  <div class="tile">
    <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
  </div>
  <div class="tile">
    <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
  </div>
  <div class="tile">
    <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
  </div>
  <div class="tile">
    <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
  </div>
  <div class="tile">
    <img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
  </div>
</div>
<footer>FOOTER</footer>

jsFiddle