Search code examples
cssflexboxcss-grid

CSS grid - calculated responsive layout overflows fixed-width parent container


I have a 1x4up grid layout that works great until I try to wrap it in a centered container div. Here is a Pen with the layout.

https://codepen.io/kirkbross/pen/XWEBRWw

I tried using @media queries for the var --fw, first setting it to 1320px, then 100vw at < 1320px, but all the other calculated variables don't take kindly to that approach. Thoughts?

The result should be the grid layout centered within 1320px parent, and begins shrinking responsively when the window hits 1319px.

.wrapper {
  width: 1320px;
  margin: 0 auto;
  max-width: 100%;
}

* {
  margin: 0;
  padding: 0;
}

.grid-container {
  --fw: 100vw;
  --w1: calc((var(--fw) - 40px + (var(--ratio) * 10px)) / 2);
  /* the width of the big rectangle */
  --ratio: calc(678 / 399);
  --h1: calc(var(--w1) / var(--ratio));
  /* the height of the big rectangle */
  --h: calc((var(--h1) - 10px) / 2);
  /* the height and width of the smaller rectangles */
  --w: calc(var(--h) * var(--ratio));
  display: inline-grid;
  gap: 10px;
  grid-template-areas: "A B C" "A D E";
  grid-template-columns: var(--w1) var(--w) var(--w);
  grid-template-rows: auto auto;
  box-sizing: border-box;
  border: solid 10px black;
  background-color: black;
  margin: 0 auto;
}

.grid-container>div {
  height: var(--h);
  width: var(--w);
}

img {
  width: 100%;
  height: 100%;
}

.grid-container> :nth-child(1) {
  width: var(--w1);
  height: var(--h1);
  grid-area: A;
}

.grid-container> :nth-child(2) {
  grid-area: B;
}

.grid-container> :nth-child(3) {
  grid-area: C;
}

.grid-container> :nth-child(4) {
  grid-area: D;
}

.grid-container> :nth-child(5) {
  grid-area: E;
}
/* this 1320px wrapper div breaks layout until the window is shrunk to the wrapper width*/

<div class="wrapper">
  <div class="grid-container">
    <div class="grid-item">
      <img src="https://picsum.photos/id/1015/678/399">
    </div>
    <div class="grid-item">
      <img src="https://picsum.photos/id/1015/678/399">
    </div>
    <div class="grid-item">
      <img src="https://picsum.photos/id/1015/678/399">
    </div>
    <div class="grid-item">
      <img src="https://picsum.photos/id/1015/678/399">
    </div>
    <div class="grid-item">
      <img src="https://picsum.photos/id/1015/678/399">
    </div>
  </div>
</div>


Solution

  • I'd suggest that the approach using a media query is the correct way to go, in order to modify the --fw custom property of the .grid-container to fit the circumstances of the current display:

    @media screen and (min-width: 1320px) {
      .grid-container {
        --fw: 1320px;
      }
    }
    

    .wrapper {
      width: 1320px;
      margin: 0 auto;
      max-width: 100%;
      overflow: hidden;
    }
    
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    .grid-container {
      --fw: 100vw;
      --w1: calc((var(--fw) - 40px + (var(--ratio) * 10px)) / 2);
      /* the width of the big rectangle */
      --ratio: calc(678 / 399);
      --h1: calc(var(--w1) / var(--ratio));
      /* the height of the big rectangle */
      --h: calc((var(--h1) - 10px) / 2);
      /* the height and width of the smaller rectangles */
      --w: calc(var(--h) * var(--ratio));
      display: inline-grid;
      gap: 10px;
      grid-template-areas: "A B C""A D E";
      grid-template-columns: var(--w1) var(--w) var(--w);
      grid-template-rows: auto auto;
      box-sizing: border-box;
      border: solid 10px black;
      background-color: black;
      margin: 0 auto;
    }
    
    .grid-container > div {
      height: var(--h);
      width: var(--w);
    }
    
    img {
      width: 100%;
      height: 100%;
    }
    
    .grid-container > :nth-child(1) {
      width: var(--w1);
      height: var(--h1);
      grid-area: A;
    }
    
    .grid-container > :nth-child(2) {
      grid-area: B;
    }
    
    .grid-container > :nth-child(3) {
      grid-area: C;
    }
    
    .grid-container > :nth-child(4) {
      grid-area: D;
    }
    
    .grid-container > :nth-child(5) {
      grid-area: E;
    }
    
    @media screen and (min-width: 1320px) {
      .grid-container {
        --fw: 1320px;
      }
    }
    <div class="wrapper">
      <div class="grid-container">
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
      </div>
    </div>

    In the above code I've chosen to target the screens on displays that are wider than 1320px since that appears to be the breakpoint you're targeting. It's entirely possible to reverse that, and instead target displays smaller than 1320px:

    @media screen and (max-width: 1320px) {
      .grid-container {
        --fw: 100vw;
      }
    }
    

    Of course this would require that the custom property be set to:

    --fw: 1320px
    

    In the 'non-queried' code.

    .wrapper {
      width: 1320px;
      margin: 0 auto;
      max-width: 100%;
      overflow: hidden;
    }
    
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    .grid-container {
      --fw: 1320px;
      --w1: calc((var(--fw) - 40px + (var(--ratio) * 10px)) / 2);
      /* the width of the big rectangle */
      --ratio: calc(678 / 399);
      --h1: calc(var(--w1) / var(--ratio));
      /* the height of the big rectangle */
      --h: calc((var(--h1) - 10px) / 2);
      /* the height and width of the smaller rectangles */
      --w: calc(var(--h) * var(--ratio));
      display: inline-grid;
      gap: 10px;
      grid-template-areas: "A B C""A D E";
      grid-template-columns: var(--w1) var(--w) var(--w);
      grid-template-rows: auto auto;
      box-sizing: border-box;
      border: solid 10px black;
      background-color: black;
      margin: 0 auto;
    }
    
    .grid-container > div {
      height: var(--h);
      width: var(--w);
    }
    
    img {
      width: 100%;
      height: 100%;
    }
    
    .grid-container > :nth-child(1) {
      width: var(--w1);
      height: var(--h1);
      grid-area: A;
    }
    
    .grid-container > :nth-child(2) {
      grid-area: B;
    }
    
    .grid-container > :nth-child(3) {
      grid-area: C;
    }
    
    .grid-container > :nth-child(4) {
      grid-area: D;
    }
    
    .grid-container > :nth-child(5) {
      grid-area: E;
    }
    
    @media screen and (max-width: 1320px) {
      .grid-container {
        --fw: 100vw;
      }
    }
    <div class="wrapper">
      <div class="grid-container">
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
        <div class="grid-item">
          <img src="https://picsum.photos/id/1015/678/399">
        </div>
      </div>
    </div>