Search code examples
javascriptcsscss-gridspacingsizing

Table with CSS Grid: give all columns of same type width of entry with widest content?


I have the following table design, laid out with CSS Grid (see first snippet).

Is it possible to make all columns of the same type/class (e.g. .Table_col_day) as wide as the column of that type/class with the widest content, with CSS/without JS? The solution doesn’t have to be CSS Grid based.

See the second code snippet for a quick JS-based solution, to illustrate what I'd like to do.

.Table__row {
  background-color: plum;
  
  display: grid;
  grid-template-columns: 0.5fr 0.5fr 1fr;
}

.Table__row:nth-of-type(even) {
  background-color: lime;
}
<div class="Table">

  <div class="Table__row">
    <div class="Table__day">Mon</div>
    <div class="Table__time">10am</div>
    <div class="Table__title">Some event</div>
  </div>

  <div class="Table__row">
    <div class="Table__day">Tue</div>
    <div class="Table__time">12:30pm</div>
    <div class="Table__title">Another event</div>
  </div>

  <div class="Table__row">
    <div class="Table__day">Wed</div>
    <div class="Table__time">9:00am</div>
    <div class="Table__title">A different event</div>
  </div>

</div>

Javascript-based solution (determine widest column content, then manually set grid column styles of row element)

function resizeColumns(SELECTOR) {
  const colElements = document.querySelectorAll(SELECTOR);
  //////
  const widths = [...colElements].map(el => el.querySelector('span').offsetWidth);
  const width_max = Math.max(...widths);
  //////
  for(let col of colElements) {
    col.parentNode.style.gridTemplateColumns = `${width_max}px 0.5fr 1fr`;
  }
}

resizeColumns('.Table__col_day');
.Table__row {
  background-color: plum;
  display: grid;
  grid-template-columns: 0.5fr 0.5fr 1fr;
}

.Table__row:nth-of-type(even) {
  background-color: lime;
}
<div class="Table">

  <div class="Table__row">
    <div class="Table__col_day">
      <span>Mon</span>
    </div>
    <div class="Table__col_time">
      <span>10am</span>
    </div>
    <div class="Table__col_title">
      <span>Some event</span>
    </div>
  </div>

  <div class="Table__row">
    <div class="Table__col_day">
      <span>Tue</span>
    </div>
    <div class="Table__col_time">
      <span>12:30pm</span>
    </div>
    <div class="Table__col_title">
      <span>Another event</span>
    </div>
  </div>

  <div class="Table__row">
    <div class="Table__col_day">
      <span>Wed</span>
    </div>
    <div class="Table__col_time">
      <span>9:00am</span>
    </div>
    <div class="Table__col_title">
      <span>A different event</span>
    </div>
  </div>

</div>


Solution

  • You said it at the beginning: "table design" so use table

    .Table {
      display: table;
      width: 100%;
    }
    
    .Table__row {
      background-color: plum;
      display: table-row;
    }
    
    .Table__row > * {
      display: table-cell;
      white-space: nowrap;
    }
    
    .Table__row > *:not(.Table__day) {
      width: 50%;
    }
    
    .Table__row:nth-of-type(even) {
      background-color: lime;
    }
    <div class="Table">
    
      <div class="Table__row">
        <div class="Table__day">Mon</div>
        <div class="Table__time">10am</div>
        <div class="Table__title">Some event</div>
      </div>
    
      <div class="Table__row">
        <div class="Table__day">Tue</div>
        <div class="Table__time">12:30pm</div>
        <div class="Table__title">Another event</div>
      </div>
    
      <div class="Table__row">
        <div class="Table__day">Wed</div>
        <div class="Table__time">9:00am</div>
        <div class="Table__title">A different event</div>
      </div>
    
    </div>

    Or consider display:contents if you want to keep display:grid;

    .Table {
      display: grid;
      grid-template-columns: auto 1fr 1fr;
    }
    
    .Table__row {
      display: contents;
    }
    .Table__row > * {
      background-color: plum;
    }
    
    .Table__row:nth-of-type(even) > * {
      background-color: lime;
    }
    <div class="Table">
    
      <div class="Table__row">
        <div class="Table__day">Mon</div>
        <div class="Table__time">10am</div>
        <div class="Table__title">Some event</div>
      </div>
    
      <div class="Table__row">
        <div class="Table__day">Tue</div>
        <div class="Table__time">12:30pm</div>
        <div class="Table__title">Another event</div>
      </div>
    
      <div class="Table__row">
        <div class="Table__day">Wed</div>
        <div class="Table__time">9:00am</div>
        <div class="Table__title">A different event</div>
      </div>
    
    </div>