Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS grid empty cells layout issue

Tags:

html

css

css-grid

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?

like image 791
Adam.V Avatar asked Jul 14 '18 17:07

Adam.V


2 Answers

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>
like image 85
Ilya Streltsyn Avatar answered Oct 06 '22 01:10

Ilya Streltsyn


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>
like image 42
Kroltan Avatar answered Oct 06 '22 02:10

Kroltan