How to Create a Staggered Zigzag CSS Grid Layout

By

Introduction

Most grid layouts sit in neat rows, perfectly aligned—like soldiers in formation. But sometimes you want something with more rhythm—a layout where items cascade diagonally, like water flowing down a waterfall. This is the zigzag layout. And building it requires a small trick that reveals something fascinating about how CSS transforms actually work. In this step-by-step guide, you'll learn to create this dynamic effect using CSS Grid and a simple transform: translateY() trick, while avoiding common pitfalls like broken tab order and brittle fixed heights.

How to Create a Staggered Zigzag CSS Grid Layout
Source: css-tricks.com

What You Need

No JavaScript is required. All the magic happens in CSS.

Step 1: Set Up the HTML Structure

Start with a wrapper container and a few child items. For a two-column zigzag, you can use 5 or more items, but the pattern works with any even number. Here's a sample structure:

<div class="wrapper">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
</div>

Keep it simple. The .item class will be used for styling and targeting. No extra markup needed.

Step 2: Apply Global Box-Sizing

Before you write any grid styles, add a global reset for box-sizing. This ensures that borders and padding are included in the element's total width and height. Without this, your items might not be exactly 100px tall (if you set a fixed height), which will mess up the transform offset later.

*, *::before, *::after {
  box-sizing: border-box;
}

This single rule prevents unexpected dimensions.

Step 3: Create the Two-Column Grid

Turn the wrapper into a grid container with two equal columns. Set a max-width for readability and center it.

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  max-width: 800px;
  margin: 0 auto;
}

The gap creates space between items. You can adjust it later. Now your items will sit side-by-side in two columns, one row after another.

Step 4: Style the Grid Items

Give each item a fixed height and a border (or background) so you can see the effect. Without a height, the transform won't have a reference.

.item {
  height: 100px;
  border: 2px solid #333;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
}

The flex properties are optional but help center the numbers inside each box.

Step 5: Shift Even Items Down with Transform

Now the key trick: target every even item that is a child of .wrapper and move it down by half its own height. Use :nth-child(even of .item) for precise class-based selection.

.wrapper .item:nth-child(even of .item) {
  transform: translateY(50%);
}

Why translateY(50%)? Because 50% of the element's own height shifts it exactly halfway down. This creates the zigzag stagger: even items are offset, while odd items stay in place. The result is a cascading “waterfall” effect.

Note: :nth-of-type(even) might work in this demo, but it selects by tag name, not class. If you ever mix element types, you'll get unexpected matches. :nth-child(even of .item) is safer.

Step 6: Adjust Gap and Positioning for Perfect Stagger

You may notice the stagger is off by a few pixels due to the gap. By default, items start at the top of their cell. The gap applies between grid cells, not between the items' visual positions after transform. To fix this, remove the gap and use margins on items instead, or adjust the transform value slightly.

One reliable approach: set the grid gap to 0 and use margin-bottom on all items equal to the desired gap. Then the even items' transform will align correctly.

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0; /* remove grid gap */
  max-width: 800px;
  margin: 0 auto;
}
.item {
  height: 100px;
  border: 2px solid #333;
  margin-bottom: 16px; /* replace gap */
  /* ... other styles */
}

Now the translateY(50%) shifts the even items by exactly half their (content + border) height, creating a perfectly staggered layout.

Step 7: Add More Items and Test Responsiveness

The pattern works for any number of items. Add more to the wrapper and see the zigzag continue. Because the grid auto-places items, the stagger repeats every two items. For a longer cascade, you can increase the number of items.

Test on different screen sizes. The grid is responsive—columns will stay side-by-side unless you add a media query to stack them on small screens.

Tips for Success

With these steps, you now have a flexible, accessible zigzag layout using CSS Grid and a single transform—no JavaScript, no fragile heights, just clean code.

Tags:

Related Articles

Recommended

Discover More

Critical Git Push Flaw: How GitHub Contained a Remote Code Execution Attack in Under Two HoursDecade-Long Linux Kernel Flaw Enables Arbitrary Page Cache Corruption via AEAD SocketsMusk Legal Team May Have Committed Critical Error During Testimony in Altman TrialUnprecedented Security: How Claude Mythos Uncovered 271 Firefox VulnerabilitiesCadillac Builds 685-HP V8 Manual Sedan – But It's Not for Sale