Search code examples
csscss-gridsubgrid

How can I achieve full bleed within a nested grid?


I want to have the ability to do full bleeds (displaying an item from edge to edge on the viewport) within my grid setup. I would like to have the item with the class full-bleed to span the design-grid and wrapper-grid.

I am open to other ways of constructing the DOM to get this to work, but I would like to keep using grid instead of absolute positioning.

.wrapper-grid {
  display: grid;
  grid-template-columns: 1fr min(65ch, 100%) 1fr;
  row-gap: 1rem;
}

.design-grid {
  display: grid;
  /* I can't have subgrid and declare a new grid */
  /* grid-template-clomns: subgrid; */
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}

.wrapper-grid>* {
  grid-column: 2;
}

.full-bleed {
  grid-column: 1 / -1;
}

.item {
  height: 40px;
  background-color: #f1f1f1;
}
<body class="wrapper-grid">
  <div class="design-grid">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item full-bleed">This item should go to both edges of the viewport</div>
    <div class="item"></div>
  </div>
</body>


Solution

  • Here is an idea using margin with some calculation. Also you don't have to use a nested grid configuration. One grid is enough.

    Related article from my blog to understand the use of margin-inline: https://css-tip.com/center-max-width/

    .wrapper-grid {
      --w: 65ch; /* the max width*/
      
      margin-inline: max(0px, (100vw - var(--w))/2);
    }
    
    .design-grid {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 1rem;
    }
    
    .full-bleed {
      grid-column: 1 / -1;
      /* this one is the opposite of the above to negate it and get the full bleed effect */
      margin-inline: min(0px, (var(--w) - 100vw)/2);
    }
    
    .item {
      height: 40px;
      background-color: #f1f1f1;
    }
    <body class="wrapper-grid">
      <div class="design-grid">
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item full-bleed">This item should go to both edges of the viewport</div>
        <div class="item"></div>
      </div>
    </body>

    And in case you want to keep your nested grid

    .wrapper-grid {
      --w: 65ch; /* the max width*/
      
      display: grid;
      grid-template-columns: 1fr min(var(--w), 100%) 1fr;
      row-gap: 1rem;
    }
    
    .design-grid {
      display: grid;
      grid-column: 2;
      grid-template-columns: repeat(4, 1fr);
      gap: 1rem;
    }
    
    .full-bleed {
      grid-column: 1 / -1;
      /* this one is the opposite of the above to negate it and get the full bleed effect */
      margin-inline: min(0px, (var(--w) - 100vw)/2);
    }
    
    .item {
      height: 40px;
      background-color: #f1f1f1;
    }
    <body class="wrapper-grid">
      <div class="design-grid">
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item full-bleed">This item should go to both edges of the viewport</div>
        <div class="item"></div>
      </div>
    </body>