Web Development

Crafting a Zigzag Layout with CSS Grid and Transform: A Step-by-Step Guide

2026-05-08 10:00:45

Introduction

Have you ever wanted to break free from the rigid rows and columns of standard grid layouts? A zigzag layout brings visual rhythm to your design, making items cascade diagonally like a waterfall. While this might look complex, you can achieve it with a clever combination of CSS Grid and the transform property. This guide walks you through the process, ensuring you preserve accessibility and maintain a clean codebase.

Crafting a Zigzag Layout with CSS Grid and Transform: A Step-by-Step Guide
Source: css-tricks.com

What You Need

Prerequisites

Step-by-Step Instructions

Step 1: Set Up the HTML Structure

Start with a simple wrapper and a few items. This structure gives you a foundation to apply the grid and shift.

<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>

Step 2: Apply a Global Box-Sizing Reset

To ensure your items are exactly as tall as you specify, add a box-sizing reset. This prevents borders from adding extra height.

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

Step 3: Define the Grid Container

Turn the wrapper into a two-column CSS Grid. Set a max-width and center it horizontally.

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

Step 4: Style the Individual Items

Give each item a fixed height and a visible border so you can see the zigzag effect.

.item {
  height: 100px;
  border: 2px solid #333;
}

You can add background colors or padding later for visual flair.

Step 5: Shift the Even Items Down

Select every even item (the ones in the second column) and move them down by half their own height using transform: translateY(50%).

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

This creates the staggered, waterfall-like cascade.

Step 6: Understand the Selector Nuance

You might be tempted to use .item:nth-of-type(even). While it works here because all children are <div> elements, nth-of-type counts by element type, not class. If you mix element types (e.g., a <span> inside), it will break. The selector :nth-child(even of .item) is more precise because it filters by class first.

Step 7: Adjust for Variable Item Heights

If your items have different heights (e.g., due to varying content), translateY(50%) still works because 50% refers to the element's own height. The shift adapts automatically. However, maintaining a consistent visual rhythm may require you to set a minimum height or use a fixed pixel value like translateY(50px) if you prefer uniform shifts.

Step 8: Add Visual Enhancements (Optional)

Make the layout pop by adding background colors, rounded corners, and hover effects.

.item {
  background: #f0f0f0;
  border-radius: 8px;
  padding: 20px;
  transition: transform 0.3s ease;
}
.item:hover {
  transform: scale(1.05);
}

Note: If you add hover transforms, be careful not to override the vertical shift. Use a wrapper or combine transforms.

Conclusion and Tips

You now have a functional zigzag layout that preserves tab order (unlike flexbox with flex-direction: column and flex-wrap: wrap) and avoids the need for fixed container heights. The CSS Grid approach is clean and maintainable.

Experiment with different gap sizes, number of items, or even three-column zigzags by adjusting the selector (e.g., shift every third item). The same principle applies: target specific columns and translate them vertically.

Explore

How to Launch Your AI, Data, or Development Career with Microsoft's New Professional Certificates on Coursera How to Maximize Savings on Ecovacs Robot Vacuums After Tariff Price Cuts How the New Resident Evil Film Uses Elements from the Most Controversial Game in the Series How Wind and Solar Saved the UK £1.7 Billion in Gas Imports Since the Iran War: A Step-by-Step Guide 8 Critical Lessons from the Trivy and KICS Docker Hub Supply Chain Attacks in 2026