Search code examples
htmlcssgrid-layout

Different classes seem to interfere with each other


I am in the process of developing some code to create a "grid layout" and everything seems to be ok, at least at first glance with each individual class working as expected.

When I mix the classes though, namely put a different class in each row, things get quite confusing as the classes seemingly interfere with each other while they shouldn't (except if I'm missing something).

I have created a jsFiddle and a snippet to illustrate my problem the best possible.

What could be causing this issue and how can I possibly fix it?

Note: If you try removing some of the div elements you will notice that when not mixed they are aligned perfectly.

.container {
  width: 75%;
}
.grid-x2 {
  width: 47.5%;
}
.grid-x3 {
  width: 30%;
}
.grid-x4 {
  width: 21.25%;
}
.grid-x5 {
  width: 16%;
}
.grid-x2:nth-of-type(2n + 1),
.grid-x3:nth-of-type(3n + 1),
.grid-x4:nth-of-type(4n + 1),
.grid-x5:nth-of-type(5n + 1) {
  margin-right: 2.5%;
}
.grid-x3:nth-of-type(3n + 2),
.grid-x4:not(:nth-of-type(4n)):not(:nth-of-type(4n + 1)),
.grid-x5:not(:nth-of-type(5n)):not(:nth-of-type(5n + 1)) {
  margin-left: calc(2.5% - 4px);
  margin-right: 2.5%;
}
.grid-x2:nth-of-type(2n),
.grid-x3:nth-of-type(3n),
.grid-x4:nth-of-type(4n),
.grid-x5:nth-of-type(5n) {
  margin-left: calc(2.5% - 4px);
}
.grid-x2:nth-last-of-type(n + 3),
.grid-x3:nth-last-of-type(n + 4),
.grid-x4:nth-last-of-type(n + 5),
.grid-x5:nth-last-of-type(n + 6) {
  margin-bottom: 5%;
}
.grid-x2,
.grid-x3,
.grid-x4,
.grid-x5 {
  vertical-align: top;
  display: inline-block;
}
<div class="container" style="border: 1px solid red;">
  <div class="grid-x2" style="height: 25px; background-color: black;"></div>
  <div class="grid-x2" style="height: 25px; background-color: black;"></div>
  <div class="grid-x2" style="height: 25px; background-color: black;"></div>
  <div class="grid-x2" style="height: 25px; background-color: black;"></div>
  <div class="grid-x3" style="height: 25px; background-color: black;"></div>
  <div class="grid-x3" style="height: 25px; background-color: black;"></div>
  <div class="grid-x3" style="height: 25px; background-color: black;"></div>
  <div class="grid-x3" style="height: 25px; background-color: black;"></div>
  <div class="grid-x3" style="height: 25px; background-color: black;"></div>
  <div class="grid-x3" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x4" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
  <div class="grid-x5" style="height: 25px; background-color: black;"></div>
</div>


Solution

  • The idea with grids is that each row should be a self contained.

    The main problem here being the margins. The :nth-of-type(..) works on the node type so it counts all divs under the same container (it does not reset each time you change the class).

    Something like the following

    .container {
      width: 75%;
    }
    .grid-x2 {
      width: 47.5%;
    }
    .grid-x3 {
      width: 30%;
    }
    .grid-x4 {
      width: 21.25%;
    }
    .grid-x5 {
      width: 16%;
    }
    .grid-x2:nth-of-type(2n + 1),
    .grid-x3:nth-of-type(3n + 1),
    .grid-x4:nth-of-type(4n + 1),
    .grid-x5:nth-of-type(5n + 1) {
      margin-right: 2.5%;
    }
    .grid-x3:nth-of-type(3n + 2),
    .grid-x4:not(:nth-of-type(4n)):not(:nth-of-type(4n + 1)),
    .grid-x5:not(:nth-of-type(5n)):not(:nth-of-type(5n + 1)) {
      margin-left: calc(2.5% - 4px);
      margin-right: 2.5%;
    }
    .grid-x2:nth-of-type(2n),
    .grid-x3:nth-of-type(3n),
    .grid-x4:nth-of-type(4n),
    .grid-x5:nth-of-type(5n) {
      margin-left: calc(2.5% - 4px);
    }
    .grid-x2:nth-last-of-type(n + 3),
    .grid-x3:nth-last-of-type(n + 4),
    .grid-x4:nth-last-of-type(n + 5),
    .grid-x5:nth-last-of-type(n + 6) {
      margin-bottom: 5%;
    }
    .grid-x2,
    .grid-x3,
    .grid-x4,
    .grid-x5 {
      vertical-align: top;
      display: inline-block;
    }
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x2" style="height: 50px; background-color: black;"></div>
      <div class="grid-x2" style="height: 50px; background-color: black;"></div>
    </div>
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x2" style="height: 50px; background-color: black;"></div>
      <div class="grid-x2" style="height: 50px; background-color: black;"></div>
    </div>
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x3" style="height: 50px; background-color: black;"></div>
      <div class="grid-x3" style="height: 50px; background-color: black;"></div>
      <div class="grid-x3" style="height: 50px; background-color: black;"></div>
    </div>
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x3" style="height: 50px; background-color: black;"></div>
      <div class="grid-x3" style="height: 50px; background-color: black;"></div>
      <div class="grid-x3" style="height: 50px; background-color: black;"></div>
    </div>
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
    </div>
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
      <div class="grid-x4" style="height: 50px; background-color: black;"></div>
    </div>
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
    </div>
    <div class="container" style="border: 1px solid red;">
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
      <div class="grid-x5" style="height: 50px; background-color: black;"></div>
    </div>


    The alternative would be to use the grid items just for the sizing (without margins) and use box-sizing:border-box and paddings to create the spacing. But his would require inner elements for the actual styling.


    The latest (and best on modern browsers) would be to use the flexbox. (see https://philipwalton.github.io/solved-by-flexbox/demos/grids/)