【问题标题】:How to make images stay within the rows of a css grid container?如何使图像保持在 CSS 网格容器的行内?
【发布时间】:2018-02-28 10:03:17
【问题描述】:

下面的代码显示了当我调整窗口大小时的预期行为 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、Firefox、Safari) .

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

【问题讨论】:

  • CSS Grid Row Height Safari Bug 的答案似乎表明了为什么它在 Safari 中的行为不同:“问题是 Safari 无法识别 img 元素上的 height: 100%。”我>
  • 您希望这些行的高度是多少,您希望网格如何知道它?您只将网格容器设置为高度60vh,但您还没有为网格行设置高度。
  • @TylerH 好问题。我希望网格延伸到页面底部(填写页面上的空白区域),尽管我不知道该怎么做。 :-(目前我从100vh中减去页眉和页脚的高度,使用calc(),并将其设置为容器的高度。对不起,我是这方面的绝对初学者。至于你的其他问题: 行的高度应该相等。
  • 啊,所以你有一个页眉和页脚,加起来是40vh + 12px,或多或少?
  • @TylerH 不幸的是,公式比这更复杂。 :-( 如果我可以将页眉和页脚都放在网格容器中,然后将网格的高度设置为100vh,这将使我的生活更加轻松。或者有没有办法让div 容器伸展到页面底部(或直到页脚)?看起来我必须告诉某个元素的高度...

标签: html image css css-grid


【解决方案1】:

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

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

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

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

然后您必须考虑默认情况下网格项不能小于其内容。如果您的行设置为1fr,但图像高于分配的空间,则行必须扩展。您可以使用 min-height: 0 / min-width: 0overflow 使用除 visible 以外的任何值覆盖此行为。

这里更详细地解释了这种行为:

不过,一旦您考虑到上面的指导,您可能可以通过网格和 flex 属性的组合让您的布局在 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

【讨论】:

  • 我短暂地寻找了类似 stackoverflow.com/questions/43311943/… 的东西 - 我觉得这可能是那个的副本。
  • @TylerH,这个 OP 的代码似乎有几个需要注意的问题。您提到的链接涵盖了最小尺寸问题。如果这是唯一的问题,我会同意,这是一个骗局。但是,也存在百分比高度和浏览器呈现变化的问题。
  • @Michael_B 嗯。它在 Safari 10.3 中的 iPhone 上完全搞砸了。 :-(
  • 就像我在回答中写的那样,你必须解决它。由于我没有你的布局的所有细节,我只是提供了指导。我建议您查看我的答案中的链接。特别是这个:stackoverflow.com/q/44770074/3597276
  • @Michael_B 够公平的。我会尝试自己解决它,如果我失败了,我会发布另一个问题,其中包含更详细的代码,显示更多的实际布局。
【解决方案2】:

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

为了给网格项提供一个更合理的默认最小尺寸,这个 规范定义了 min-width/min-height 的 auto 值也 将指定轴中的自动最小尺寸应用于网格项目 其溢出可见并且跨越至少一个轨道 轨道尺寸功能是自动的。 (效果类似于 弹性项目的自动最小尺寸。)

来源: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>

【讨论】:

    【解决方案3】:

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

    这并不完全是您希望获得的自动方式...您仍在声明大小,即使它是相对的。它确实避免了看起来笨拙的calc((60vh - 12px) / 3),尽管使用该方法并没有什么问题,除非您的帖子中有其他限制。

    但是,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>

    【讨论】:

    • 不幸的是,这在 Chrome 60 中不起作用。 :-( 图像溢出。
    • @Ali 唉,我已经对使用 Firefox 感到自满,忘记了 Chrome 喜欢破坏很多东西。谢谢你让我知道;我会看看我能做些什么来解决 Chrome 的问题。
    • @Ali 看起来 Chrome 不喜欢将 grid-children 属性扩展到 display: grid 元素的孙子。我已经更新了 Snippet,它现在应该可以在 Chrome 中使用了。我没有 Safari 可供测试。
    • 谢谢,感谢您的努力,但我仍然对建议的解决方案感到不满意。可以扩展一下您的答案吗?为什么以及您的答案如何解决问题?我的尝试有什么问题?这样的解释对未来的谷歌访问者也很有用。 (当然假设他们想学习,而不是在不了解代码的情况下盲目地复制和粘贴代码......)
    • 好的,我查看了您的更新答案。问题是在真实网页上.tile 是一个弹性容器...... :-( 无论如何,Chrome 中的错误不是你的错。我赞成你的回答,感谢你的努力!
    猜你喜欢
    • 1970-01-01
    • 2019-10-30
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 2022-01-24
    • 1970-01-01
    相关资源
    最近更新 更多