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

前端 未结 3 444
渐次进展
渐次进展 2020-11-28 14:58

The code below shows the intended behavior when I resize the window in Chrome 60, and in Firefox 55 (but not in iOS Safari 10.3; that is most likely another question why it

相关标签:
3条回答
  • 2020-11-28 15:06

    You have the images set to height: 100%. But 100% of what? 100% of the container? 100% of the viewport? 100% of the row? If so, what's the height of the row?

    Chrome and Firefox make an educated guess about your intentions. They have implemented algorithms designed to go beyond spec guidance in order to improve user experience. They call these modifications "interventions".

    Safari doesn't do this. Safari adheres strictly to spec language, which states that a percentage height on an element must have a defined height on the parent, otherwise it is ignored.

    These browser differences are explained in more detail here:

    • CSS Grid Row Height Safari Bug
    • Chrome / Safari not filling 100% height of flex parent

    Then you have to consider that grid items, by default, cannot be smaller than their content. If your rows are set to 1fr, but the images are taller than the space allotted, the rows must expand. You can override this behavior with min-height: 0 / min-width: 0 or overflow with any value other than visible.

    This behavior is explained in more detail here:

    • Prevent grid items from stretching in CSS Grid Layout
    • Why doesn't flex item shrink past content size?

    Still, once you factor in the guidance above, you can probably get your layout to work in Safari with a combination of grid and flex properties:

    * {
      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

    0 讨论(0)
  • 2020-11-28 15:08

    I don't know how snugly you want the images to fit, but you could use minmax(). minmax() lets you set a minimum and maximum value for the grid-row size. Setting auto for the min and 33% for the max will let them get as small as the content needs to get, and up to 33% of the height of the grid container, but no bigger. This will keep all your grid items together at maximum height of 99% of the 60vh that the grid container takes up.

    This is not exactly the automatic way you were hoping to get... you're still declaring a size, even if it's relative. It does avoid the clunky-looking calc((60vh - 12px) / 3), though there's nothing really wrong with using that method, unless there are other constraints in your post.

    However, kukkuz' answer and resetting the min-height is a better solution and is what I was missing.

    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>

    0 讨论(0)
  • 2020-11-28 15:21

    You can use grid-template-rows: 1fr 1fr 1fr and more importantly you have to reset the min-width and min-height values of the grid items which defaults to auto (as much as the content).

    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

    This is similar to the auto flex item rule with flexboxes. See demo below where I reset them to 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>

    0 讨论(0)
提交回复
热议问题