How to make a grid item inside a max-width container to span the full width?

Viewed 1512

CSS grid is located on a page with a max-width:

enter image description here

body {
  outline: 1px solid black;
}

.max-width {
  max-width: 400px;
  margin: 0 auto;
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
}

.first-grid-item {
  grid-column: 1 / -1;
  background-color: #ccc;
}

.second-grid-item {
  grid-column: 1 / -1;
  background-color: tomato;
}

@media (min-width: 576px) {
  .max-width {
    max-width: 500px;
  }
  .first-grid-item {
    grid-column: 1 / 9;
  }
  .second-grid-item {
    grid-column: 9 / 13;
  }
}
<div class="max-width">
  <div class="grid">
    <div class="first-grid-item">First</div>
    <div class="second-grid-item">Second</div>
  </div>
</div>

On smaller screens, the layout changes and the second grid item is placed below the first one:

enter image description here

Now, a new requirement comes in to add a full-width background color to the second item on the smaller screens so it looks like this:

enter image description here

How would you achieve this?


Notes:

  • The grid can appear in the middle of a page somewhere, it's not necessarily the only element on the page. Example: here
  • Grid items can have variable height which isn't known in advance. Example: here
  • When the screen size is:
    • below 400px - the grid should occupy the full screen size.
    • between 400px and 575px (inclusive) - the grid should occupy exactly 400px (which is the max-width on smaller screens).
    • at least 576px - the grid should occupy exactly 500px (which is the max-width on larger screens).
  • You are allowed to change the HTML if you think there is a more natural way to implement this. Just make sure that elements don't move from where they need to be.
3 Answers

On small screen you don't really need a grid.

Here is my try:

body {
  outline: 1px solid black;
}

.first-grid-item{
  max-width: 400px; /* Only restrict the first item */
  margin: 0 auto;
}

.first-grid-item {
  background-color: #ccc;
}

.second-grid-item {
  background-color: tomato;
  padding:0 calc(50% - 200px); /* to have the content inside the 400px (remove this if not)*/
}

@media (min-width: 576px) {
  .max-width {
    max-width: 500px;
    margin: 0 auto;
  }
  /* only here we need the grid */
  .grid {
    display: grid; 
    grid-template-columns: repeat(12, 1fr);
  }
  /**/
  .first-grid-item {
    grid-column: 1 / 9;
    margin:0; /* reset margin */
    max-width: 100%; /* reset max-width */
  }
  .second-grid-item {
    grid-column: 9 / 13;
    background-color: lightblue;
    padding:0; /* reset padding */
  }
}
<div class="max-width">
  <div class="grid">
    <div class="first-grid-item">First</div>
    <div class="second-grid-item">Second</div>
  </div>
</div>

You can also do it like below:

body {
  outline: 1px solid black;
}

.max-width {
  max-width: 500px;
  margin: 0 auto;
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
}

.first-grid-item {
  grid-column: 1 / 9;
  background-color: #ccc;
}

.second-grid-item {
  grid-column: 9 / 13;
  background-color: lightblue;
}

@media (max-width: 576px) {
  .max-width {
    max-width: 100%;
  }
  .grid {
    display: block;
  }
  .first-grid-item {
    max-width: 400px;
    margin: 0 auto;
  }
  .second-grid-item {
    background-color: tomato;
    padding: 0 calc(50% - 200px);
  }
}
<div class="max-width">
  <div class="grid">
    <div class="first-grid-item">First</div>
    <div class="second-grid-item">Second</div>
  </div>
</div>

To have the different coloration, mutliple background can easily do it

body {
  outline: 1px solid black;
}

.max-width {
  max-width: 500px;
  margin: 0 auto;
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
}

.first-grid-item {
  grid-column: 1 / 9;
  background-color: #ccc;
}

.second-grid-item {
  grid-column: 9 / 13;
  background: 
    linear-gradient(lightblue,lightblue) content-box,
    tomato;
}

@media (max-width: 576px) {
  .max-width {
    max-width: 100%;
  }
  .grid {
    display: block;
  }
  .first-grid-item {
    max-width: 400px;
    margin: 0 auto;
  }
  .second-grid-item {
    padding: 0 calc(50% - 200px);
  }
}
<div class="max-width">
  <div class="grid">
    <div class="first-grid-item">First</div>
    <div class="second-grid-item">Second</div>
  </div>
</div>

The only way I can think of to do this is using a ::before and ::after element on the second-grid-item and overflowing the body. You would need to essentially set overflow: hidden on the body for this to work so it doesn't set horizontal scrolling:

body {
  outline: 1px solid black;
  overflow: hidden;
}

.max-width {
  max-width: 400px;
  margin: 0 auto;
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
}

.first-grid-item {
  grid-column: 1 / -1;
  background-color: #ccc;
}

.second-grid-item {
  grid-column: 1 / -1;
  background-color: tomato;
  position: relative;
}

.second-grid-item::before,
.second-grid-item::after {
  content: '';
  display: block;
  position: absolute;
  left: -50%;
  top: 0;
  width: calc( 100% - 200px);
  height: 100%;
  background: powderblue;
}

.second-grid-item::after {
  left: auto;
  right: -50%;
}

@media (min-width: 576px) {
  .first-grid-item {
    grid-column: 1 / 9;
  }
  .second-grid-item {
    grid-column: 9 / 13;
  }
  .second-grid-item::before,
  .second-grid-item::after {
    display: none;
  }
}
<div class="max-width">
  <div class="grid">
    <div class="first-grid-item">First</div>
    <div class="second-grid-item">Pharetra eros mi eros accumsan dui. Pellentesque ipsum iaculis. Mi neque in nonummy venenatis vestibulum. Class egestas adipiscing nisl tellus quam ut in amet. Nostra nunc leo lorem eget ipsum elit eget metus nam sed pede. Nam nibh risus sit dui nullam.
      Consequat luctus tempus.
    </div>
  </div>
</div>

Here's a codepen: https://codepen.io/chrislafrombois/pen/qBOMopG

Why not Simply move the width constraint to the grid ?

body {
  outline: 1px solid black;
}


/* Became .wrapper */


/* .max-width {
  max-width: 400px;
  margin: 0 auto;
} */

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
}

.first-grid-item {
  grid-column: 1 / -1;
  background-color: #ccc;
}

.second-grid-item {
  grid-column: 1 / -1;
  background-color: tomato;
}

@media (min-width: 576px) {
  /* Became .wrapper */
  /* .max-width {
    max-width: 500px;
  } */
  .first-grid-item {
    grid-column: 1 / 9;
  }
  .second-grid-item {
    grid-column: 9 / 13;
  }
}


/* New */

.grid {
  max-width: 400px;
  margin: 0 auto;
}

.wrapper {
  background: linear-gradient(orange, orange) 0 100% / 100% 50% no-repeat;
}

@media (min-width: 576px) {
  .grid {
    max-width: 500px;
  }
  .wrapper {
    background: none;
  }
}
<p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.
</p>
<div class="wrapper">
  <div class="grid">
    <div class="first-grid-item">First</div>
    <div class="second-grid-item">Second</div>
  </div>
</div>
<p>
  There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable.
</p>

Related