Odd Boxes

It’s understandable to hear “CSS Grid” and think it means all layouts will have obvious rows and columns that line up neatly. The example below demonstrates that we can break out of that rigid structure while still using Grid. I achieve this by using margin, transform: rotate(), and transform: translate() to varying degrees. The notes in boxes 1, 3, 4, and 7 indicate which boxes reside in which rows and columns.

The Finished Example Layout

1

Items 1 and 2 are in the same row. Items 1, 6, and half of 4 are in the same column.

Item 1 appears behind 3 because of the translateX(-90px) set on it.

2

3

Items 3–5 are in the same row and each spans two columns.

(Note: I didn’t focus on making this layout fully responsive, so it fails in narrow viewports. You could stack the boxes by default, and then apply the Grid layout at a breakpoint that’s wide enough to accommodate it.)

4

As is typical with Grid, the row below will push down or move up in accordance with the length of content in this row. So if I were to add more content to items 3, 4, or 5, the layout wouldn't break. This is one key difference between doing a layout like this with Grid and positioning the items absolutely.

5

6

7

Items 6 and 7 are in the same row. Item 7 is in the same column as 2 and half of 4.

The Code

HTML
<div class="container">
  <div class="item-1">
    <p>1</p>
    <p>Items 1 and 2 are in the same row. Items 1, 6, and half of 4 are in the same column.</p>
    <p>Item 1 appears behind 3 because of the <code>translateX(-90px)</code> set on it.</p>
  </div>
  
  <div class="item-2">
    <p>2</p>
  </div>
  
  <div class="item-3">
    <p>3</p>
    <p>Items 3–5 are in the same row and each spans two columns.</p>
    <p><small>(Note: I didn’t focus on making this layout fully responsive, so it fails in narrow viewports. You could stack the boxes by default, and then apply the Grid layout at a breakpoint that’s wide enough to accommodate it.)</small></p>
  </div>
  
  <div class="item-4">
    <p>4</p>
    <p>As is typical with Grid, the row below will push down or move up in accordance with the length of content in <em>this</em> row. So if I were to add more content to items 3, 4, or 5, the layout wouldn't break. This is one key difference between doing a layout like this with Grid and positioning the items absolutely.</p>
  </div>
  
  <div class="item-5">
    <p>5</p>
  </div>
  
  <div class="item-6">
    <p>6</p>
  </div>
  
  <div class="item-7">
    <p>7</p>
    <p>Items 6 and 7 are in the same row. Item 7 is in the same column as 2 and half of 4.</p>
  </div>
</div>

CSS
/* Basic Layout
-------------------------------------- */
.container {
  padding-top: 94px;
  /* Define the grid */
  display: grid;
  grid-gap: 2px;
  grid-template-columns: repeat(6, 1fr);
}

/* Place items on the gird */
.item-1,
.item-6 {
  grid-column: 3;
}

.item-3,
.item-4,
.item-5 {
  grid-column: span 2;
  grid-row: 2;
}

/* Break outside strict rows + columns
-------------------------------------- */
.item-1 {
  margin-left: -40px;
  margin-right: 30px;
}

.container .item-1 {
  padding-bottom: 35px;
}

.item-2 {
  margin-bottom: 40px;
  margin-top: -90px;
}

.item-3 {
  margin-bottom: -45px;
  margin-right: 60px;
  margin-top: -25px;
}

.item-4 {
  margin-bottom: 15px;
}

.item-5 {
  margin-left: 25px;
  margin-right: 50px;
}

.item-7 {
  margin-left: 25px;
  margin-bottom: -20px;
  transform: translate(90px, 35px);
}

/* Rotate items */
.item-1 {
  transform: rotate(-3deg) translateX(-90px);
}

.item-3,
.item-4,
.item-6 {
  transform: rotate(-6deg);
}

.item-2 {
  transform: rotate(5deg);
}

.item-5 {
  transform: rotate(15deg);
}

/* Generic styles for demo purposes
-------------------------------------- */
.container {
  font-family: Helvetica, Arial, sans-serif;
  max-width: 75rem;
}

.container > * {
  background-color: #ccc;
  padding: 1em;
  border: 1px solid #777;
  box-shadow: -7px 5px 10px #aaa;
  font-size: 0.9375rem;
}

.container > * p:first-child {
  margin-top: 0;
}

.container p {
  line-height: 1.35;
}

.item-2 {
  background-color: #999;
}

.item-3 {
  background-color: #bbb;
}

.item-6 {
  background-color: #777;
}