Search code examples
csscss-grid

CSS grid - dynamic column at the start of the grid


I've read the following:

Can I make a CSS grid with dynamic number of rows or columns?

CSS Grid layout for dynamic content

and a few other questions. They cover dynamic columns at the end of the grid with grid-auto-columns. The dynamic column I have is added at the start of the grid.


I have a layout that looks like this.

body {
  background: #131418;
  margin: 1em;
}

:root {
  --extra-section: 70px;
}

.container {
  padding: 0.5em;
  border: 1px solid silver;
  color: silver;
  /* grid */
  display: grid;
  grid-template-columns: 1fr auto repeat(3, minmax(var(--extra-section), auto));
  grid-auto-columns: var(--extra-section);
  grid-auto-flow: column;
  grid-column-gap: 0.5em;
  align-items: center;
}
<div class="container">
  <div class="title">
    Lorem ipsum dolor sit amet, consectetur
  </div>
  <div class="people">
    <img src="https://i.pravatar.cc/25" />
    <img src="https://i.pravatar.cc/25" />
    <img src="https://i.pravatar.cc/25" />
  </div>
  <div class="likes">9</div>
  <div class="bookmarks">4</div>
  <div class="shares">2</div>
</div>

Sometimes the number of small columns on the right is more than three. This is not an issue, and I have managed to fix that with

grid-auto-columns: var(--extra-section);
grid-auto-flow: column;

since they're always the same width.

My issue is that there's a checkbox that appears on the far left based on a user action. Like so

body {
  background: #131418;
  margin: 1em;
}

:root {
  --extra-section: 70px;
}

.container {
  padding: 0.5em;
  border: 1px solid silver;
  color: silver;
  /* grid */
  display: grid;
  grid-template-columns: 1fr auto repeat(3, minmax(var(--extra-section), auto));
  grid-auto-columns: var(--extra-section);
  grid-auto-flow: column;
  grid-column-gap: 0.5em;
  align-items: center;
}
<div class="container">
  <div class="select">
    <label>
      <input type="checkbox">
    </label>
  </div>
  <div class="title">
    Lorem ipsum dolor sit amet, consectetur
  </div>
  <div class="people">
    <img src="https://i.pravatar.cc/25" />
    <img src="https://i.pravatar.cc/25" />
    <img src="https://i.pravatar.cc/25" />
  </div>
  <div class="likes">9</div>
  <div class="bookmarks">4</div>
  <div class="shares">2</div>
</div>

When that happens, the layout gets messed up. It's not very obvious in the preview, so please open it in full screen to see the issue.

enter image description here

I understand why that's happening because I've defined an explicit grid and now the checkbox is taking 1fr.

This extra checkbox is only added in a given state. When that occurs, a class is also added to the container selecting. So, here's what I'm doing right now to try to fix this. I redefine the grid columns when that class is added.

body {
  background: #131418;
  margin: 1em;
}

:root {
  --extra-section: 70px;
}

.container {
  padding: 0.5em;
  border: 1px solid silver;
  color: silver;
  /* grid */
  display: grid;
  grid-template-columns: 1fr auto repeat(3, minmax(var(--extra-section), auto));
  grid-auto-columns: var(--extra-section);
  grid-auto-flow: column;
  grid-column-gap: 0.5em;
  align-items: center;
}

.container.selecting {
  grid-template-columns: auto 1fr auto repeat(3, var(--extra-section));
}
<div class="container selecting">
  <div class="select">
    <label>
      <input type="checkbox">
    </label>
  </div>
  <div class="title">
    Lorem ipsum dolor sit amet, consectetur
  </div>
  <div class="people">
    <img src="https://i.pravatar.cc/25" />
    <img src="https://i.pravatar.cc/25" />
    <img src="https://i.pravatar.cc/25" />
  </div>
  <div class="likes">9</div>
  <div class="bookmarks">4</div>
  <div class="shares">2</div>
</div>

enter image description here

There's a bunch of other elements below this one just like it and they all share the same layout and CSS. When the checkbox is added to one, it's added to the rest of them as well. Kind of like a table if you would.

My goal is to give as much space to the title section as possible.

My question is:

Can I achieve that without having to redefine the template? As in, set it once, and it would adjust automatically if the checkbox is added while giving as much space to the title as possible?

I would like to solve this with grid and not flexbox because everything else in the layout uses grid and I'd love to keep it that way.


Solution

  • Yes, you can.

    The grid layout allows you to set multiple elements in the very same defined cell.

    You could set .select and .title inside the first column and first-row. (similar effect to absolute positionning somehow)

    If the .select (is here) stands ahead the .title, give the .title a margin or a padding to leave space for the checkbox.


    Live example below with and without the .select box

    body {
      background: #131418;
      margin: 1em;
    }
    
    :root {
      --extra-section: 70px;
    }
    
    .container {
      padding: 0.5em;
      border: 1px solid silver;
      color: silver;
      /* grid */
      display: grid;
      grid-template-columns: 1fr auto repeat(3, minmax(var(--extra-section), auto));
      grid-auto-columns: var(--extra-section);
      grid-auto-flow: column;
      grid-column-gap: 0.5em;
      align-items: center;
    }
    
    body {
      background: #131418;
      margin: 1em;
    }
    
    :root {
      --extra-section: 70px;
    }
    
    .container {
      padding: 0.5em;
      border: 1px solid silver;
      color: silver;
      /* grid */
      display: grid;
      grid-template-columns: 1fr auto repeat(3, minmax(var(--extra-section), auto));
      grid-auto-columns: var(--extra-section);
      grid-auto-flow: column;
      grid-column-gap: 0.5em;
      align-items: center;
    }
    .container .select,
    .container .title {
      grid-column:1;
      grid-row:1;
    }
    .select {position:relative;/* bring it up front to be clickable */}
    .container .select + .title {
      padding-inline-start:1.5rem;/* or padding-left for ltr direction */
    }
    <div class="container">
      <div class="select">
        <label>
          <input type="checkbox">
        </label>
      </div>
      <div class="title">
        Lorem ipsum dolor sit amet, consectetur
      </div>
      <div class="people">
        <img src="https://i.pravatar.cc/25" />
        <img src="https://i.pravatar.cc/25" />
        <img src="https://i.pravatar.cc/25" />
      </div>
      <div class="likes">9</div>
      <div class="bookmarks">4</div>
      <div class="shares">2</div>
    </div>
    <hr>
    <div class="container">
      <div class="title">
        Lorem ipsum dolor sit amet, consectetur
      </div>
      <div class="people">
        <img src="https://i.pravatar.cc/25" />
        <img src="https://i.pravatar.cc/25" />
        <img src="https://i.pravatar.cc/25" />
      </div>
      <div class="likes">9</div>
      <div class="bookmarks">4</div>
      <div class="shares">2</div>
    </div>

    padding or margin on .title could also always be there ,tokeep the same alignment any time.

    Note: position:relative is there to put .select on top of .title if padding is the option taken.