CSS grid empty cells layout issue

19,111

Solution 1

They are not bunched up on the top right, they are bunched up on the rightmost column. Grid areas must be rectangular, not any other shape. The periodic table's layout is not rectangular, sadly.

Additionally, setting an element's grid-area will make it cover the whole area, not just one cell of it.

This causes the elements to bunch to the right, because the last column does form a rectangle.

If you want to auto-layout the elements, you could take the inverse approach, and define a bunch of "whitespace" rectangular areas, and put some elements there so they are ruled out of automatic flow.

Such an example:

/*
  backgrounds and spacings not needed, just there to
  enhance visualization of each element's boundaries.
*/

.element {
  margin: 2px;
  padding: 5px;
  border: 1px solid gray;
}

.spacerA {
  background: dodgerblue;
  grid-area: wa;
}

.spacerB {
  background: aqua;
  grid-area: wb;
}

.spacerC {
  background: skyblue;
  grid-area: wc;
}

.wrapper {
  display: grid;
  grid-template-columns: repeat(18, 1fr);
    grid-template-areas:
        '.  wa wa wa wa wa wa wa wa wa wa wa wa wa wa wa wa .'
        '.  .  wb wb wb wb wb wb wb wb wb wb .  .  .  .  .  .'
        '.  .  wb wb wb wb wb wb wb wb wb wb .  .  .  .  .  .'
        '.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .'
        '.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .'
        '.  .  wc .  .  .  .  .  .  .  .  .  .  .  .  .  .  .'
        '.  .  wc .  .  .  .  .  .  .  .  .  .  .  .  .  .  .';
}
<div class="wrapper">
<div class="spacerA"></div>
<div class="spacerB"></div>
<div class="spacerC"></div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
</div>

You can also get an empty row using the same spacer idea:

/*
  backgrounds and spacings not needed, just there to
  enhance visualization of each element's boundaries.
*/

.element {
  margin: 2px;
  padding: 5px;
  border: 1px solid gray;
}

.spacerA {
  background: dodgerblue;
  grid-area: wa;
}

.spacerB {
  background: aqua;
  grid-area: wb;
}

.spacerC {
  background: skyblue;
  grid-area: wc;
}

.spacerD {
  background: green;
  grid-area: wd;
  height: 2em;
}

.wrapper {
  display: grid;
  grid-template-columns: repeat(18, 1fr);
    grid-template-areas:
        '.  wa wa wa wa wa wa wa wa wa wa wa wa wa wa wa wa . '
        '.  .  wb wb wb wb wb wb wb wb wb wb .  .  .  .  .  . '
        '.  .  wb wb wb wb wb wb wb wb wb wb .  .  .  .  .  . '
        '.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . '
        '.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . '
        '.  .  wc .  .  .  .  .  .  .  .  .  .  .  .  .  .  . '
        '.  .  wc .  .  .  .  .  .  .  .  .  .  .  .  .  .  . '
        'wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd';
}
<div class="wrapper">
<div class="spacerA"></div>
<div class="spacerB"></div>
<div class="spacerC"></div>
<div class="spacerD"></div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
<div class="element">El</div>
</div>

Solution 2

I'd say that the periodic table is the wonderful use case not for named areas grid features, but for grid auto placement feature along with the :nth-child selectors. We can basically express the Periodical law itself in our CSS!

var elements = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og'];

document.querySelector('.wrapper').innerHTML = elements.map(el => '<div class="element">'+el+'</div>').join('');
.wrapper {
  display: grid;
  grid-template-columns: repeat(32, 1fr);
}

.element {
  border: 1px solid #ccc;
  margin: 0 -1px -1px 0;
  text-align: right;
  counter-increment: el;
  padding: 3px 2px;
}

/* Helium belongs to the last column, that is, it starts at second-to-last grid line */
.element:nth-child(2) {
  grid-column: -2;
}

/* Boron and Aluminim are 3rd group elements, that is, there are 6 columns since them,
   so they start at the 7th grid line counting from its end */
.element:nth-child(5),
.element:nth-child(13) {
  grid-column: -7;
}

/* similarly, Titanium and Zirconium start at 16th grid line from the grid end */
.element:nth-child(22),
.element:nth-child(40) {
  grid-column: -16;
}

/* just some decoration :) */
.element::before {
  content: counter(el);
  font-size: .75em;
  text-align: left;
  display: block;
  color: #888;
}
<div class="wrapper"></div>

With minimal change, you can then modify the presentation of the table, e.g., moving Lanthanide and Actinide into the separate rows:

var elements = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og'];

document.querySelector('.wrapper').innerHTML = elements.map(el => '<div class="element">'+el+'</div>').join('');
.wrapper {
  display: grid;
  grid-template-columns: repeat(18, 1fr);
  grid-auto-rows: 1fr;
}

.element {
  border: 1px solid #ccc;
  margin: 0 -1px -1px 0;
  text-align: right;
  counter-increment: el;
  padding: 3px 2px;
}

/* Helium belongs to the last column, that is, it starts at second-to-last grid line */
.element:nth-child(2) {
  grid-column: -2;
}

/* Boron and Aluminim are 3rd group elements, that is, there are 6 columns since them,
   so they start at the 7th grid line counting from its end */
.element:nth-child(5),
.element:nth-child(13) {
  grid-column: -7;
}

/* similarly, Titanium and Zirconium (as well as Hafnium and Rutherfordium)
   start at 16th grid line from the grid end */
.element:nth-child(22),
.element:nth-child(40) {
  grid-column: -16;
}

/* Lanthanide */
.element:nth-child(n + 57):nth-child(-n + 71) {
  background-color: pink;
}
.element:nth-child(n + 58):nth-child(-n + 71) {
  grid-row: 9;
}

/* Actinide */
.element:nth-child(n + 89):nth-child(-n + 103) {
  background-color: yellow;
}
.element:nth-child(n + 90):nth-child(-n + 103) {
  grid-row: 10;
}


/* just some decoration :) */
.element::before {
  content: counter(el);
  font-size: .75em;
  text-align: left;
  display: block;
  color: #888;
}
<div class="wrapper"></div>
Share:
19,111

Related videos on Youtube

Adam.V
Author by

Adam.V

Updated on June 04, 2022

Comments

  • Adam.V
    Adam.V about 2 years

    I'm trying to make a periodic table with CSS grid. To do that, I would need empty cells in multiple rows - I'm trying to achieve that with the documentation shown here: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Grid_Template_Areas

    HTML

    <div class="wrapper">
        <div class="element">El</div>
        //repeated 90 times
    </div>
    

    CSS

    .element {
      grid-area: el;
    }
    .wrapper {
      display: grid;
      grid-template-columns: repeat(18, 1fr);
        grid-template-areas:
            'el . . . . . . . . . . . . . . . . el'
            'el el . . . . . . . . . . el el el el el el'
            'el el . . . . . . . . . . el el el el el el'
            'el el el el el el el el el el el el el el el el el el'
            'el el el el el el el el el el el el el el el el el el'
            'el el . el el el el el el el el el el el el el el el'
            'el el . el el el el el el el el el el el el el el el';
    }
    

    However, when rendered, it seems as if everything gets bunched up in the top right, as shown here: https://jsfiddle.net/agreyfield91/9qnwv16u/9/. Why is this?

    • Rainbow
      Rainbow almost 6 years
      keep in mind, you can't name two element with the same grid-area name.
  • Adam.V
    Adam.V almost 6 years
    Your method works great - but how would you create an entire blank row (to separate the last two rows of elements)? Adding another ''wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd wd' doesn't seem to do anything.
  • Kroltan
    Kroltan almost 6 years
    @Adam.V Do note in the HTML i had to create the filler elements myself and position them.
  • Adam.V
    Adam.V almost 6 years
    Yeah, I repeated the same process for all the other spacings. Is there a special interaction when an entire row is blank?
  • Kroltan
    Kroltan almost 6 years
    @Adam.V The element in it must have a specific height, or you must specify the height of the row. I edited the answer with an example.
  • Adam.V
    Adam.V almost 6 years
    I see! Forgot about the height. Thank you.
  • Eric Wu
    Eric Wu about 5 years
    That is beautiful.
  • flyer
    flyer almost 4 years
    I know this is off topic, but I cannot hear talk of Lanthanide and Actinide without thinking of the Simpsons: youtube.com/watch?v=iF8_Qq7exVA&ab_channel=B