Search code examples
htmlcsscss-grid

Grid CSS container that scrolls horizontally when children use grid-column?


CODEPEN: https://codepen.io/matthewharwood/pen/ywKNVg

I'm trying to achieve this layout in GridCSS:

enter image description here

Problems:

I'm having trouble making the children .elements overflow their parent .grid when using grid-column: span 4;.

Note:

  • Children will peak on mobile
  • Grid will have scroll bars if children overflow
  • Children perfectly follow the grid.

Question: Is it possible to make CSS Grid Items overflow with a scroll bar when its children are aligned to the grid using grid-column? if so, what properties am I missing? If not, is are there any work arounds to achieve these layouts shown above, when using CSS Grid?

HTML:

<section>
  <div class="container">
    <div class="grid">
      <div class="element">
        <img src="https://placebear.com/400/500" alt="">
        <div class="copy">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
        </div>
      </div>
      <div class="element">
        <img src="https://placebear.com/400/500" alt="">
        <div class="copy">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
        </div>
      </div>
      <div class="element">
        <img src="https://placebear.com/400/500" alt="">
        <div class="copy">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
        </div>
      </div>
     <!-- UNCOMMENT BELOW   -->
    <!--       <div class="element">
    <img src="https://placebear.com/400/500" alt="">
    <div class="copy">
       Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
    </div>
  </div> -->
    </div>
  </div>
</section>

CSS:

section {
  width: 100%;
  display: block;
  box-sizing: border-box;
  padding: 64px 48px;
  background: green;
}

.container {
  margin: 0 auto;
  max-width: 1032px;
  background: rgba(244,244,244, .25);
}

.grid {
  display: grid;   
  grid-auto-flow: column;  
  grid-gap: 10px; 
  overflow: auto;
  grid-template-columns: repeat(12, 1fr);
  grid-gap: 48px;
}


.element {
  padding:30px 0;
  text-align: center;
  background: papayawhip;
  grid-column: span 4;
}

Solution

  • You simply need to get rid of grid-template-columns: repeat(12, 1fr);1. No need to define column template since your number of element is unknown, let the browser handle this automatically by defining the implicit grid.

    You may need to define grid-auto-columns to set the width of each column.

    section {
      width: 100%;
      display: block;
      box-sizing: border-box;
      padding: 64px 48px;
      background: green;
    }
    
    .container {
      margin: 0 auto;
      max-width: 1032px;
      background: rgba(244, 244, 244, .25);
    }
    
    .grid {
      display: grid;
      grid-auto-flow: column;
      overflow: auto;
      grid-gap: 48px;
      grid-auto-columns: minmax(40px, 1fr);
    }
    
    .element {
      padding: 30px 0;
      text-align: center;
      background: papayawhip;
      grid-column: span 4;
    }
    
    img {
      max-width: 100%;
    }
    <section>
      <div class="container">
        <div class="grid">
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
        </div>
      </div>
    </section>
    
    <section>
      <div class="container">
        <div class="grid">
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
          <div class="element">
            <img src="https://placebear.com/400/500" alt="">
            <div class="copy">
              Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sint, eveniet commodi?
            </div>
          </div>
    
        </div>
    </section>

    Remove grid-auto-columns: minmax(40px,1fr); from above and you will see this for the top grid:

    enter image description here

    The red lignes are your columns with 0 width and as you can see each item is simply equal to 3 gaps. By setting the minmax() we will use 1fr when there isn't overflow and only few elements (enough space for 1fr). When will have a lot of elements and the 1fr will get smaller you will fix the width to 40px.

    Basically each element will have a min-width equal to 4*40px + 3*48px in this case. and if you remove the 1fr and use grid-auto-columns: 40px; then the min-width will simply be the width.


    1 The issue when defining the template columns is that you will told the browser that you have 12 columns with 1fr and later you will be using more if you have more than 3 items thus the implicit grid will contain more than 12 columns and the browser may calculate their width differently from what you set.

    Here is as simplified example to illustrate:

    .grid {
      display:grid;
      grid-template-columns:repeat(4,1fr);
      grid-auto-flow: column;
    }
    img {
      grid-column:span 2;
      border:2px solid green;
      max-width:100%;
    }
    <div class="grid">
     <img src="https://picsum.photos/200/200?image=0">
     <img src="https://picsum.photos/200/200?image=0">
     <img src="https://picsum.photos/200/200?image=0">
     <img src="https://picsum.photos/200/200?image=0">
    </div>

    Notice how the width of the first 2 images is different from the last 2. The first ones are inside the grid you defined and the other inside the one created by the browsers.

    By only setting grid-auto-columns you are sure that all will have the same width:

    .grid {
      display:grid;
      grid-auto-flow: column;
      grid-auto-columns:minmax(40px,1fr);
    }
    img {
      grid-column:span 2;
      border:2px solid green;
      max-width:100%;
    }
    <div class="grid">
     <img src="https://picsum.photos/200/200?image=0">
     <img src="https://picsum.photos/200/200?image=0">
     <img src="https://picsum.photos/200/200?image=0">
     <img src="https://picsum.photos/200/200?image=0">
    </div>