Published on

The Ultimate Guide to Creating Checkerboard Backgrounds with CSS

Authors

'The Ultimate Guide to Creating Checkerboard Backgrounds with CSS'

Discover multiple techniques, from classic repeating gradients to modern CSS Grid, to create stunning, responsive, and customizable checkerboard backgrounds for your web projects.

Table of Contents

The checkerboard pattern is one of the most recognizable designs in the digital world. From the transparent backgrounds in image editors like Photoshop to the starting line of a digital race, its simple, alternating squares are both functional and iconic. But how do you create this seemingly simple pattern for your own web projects?

You might think it requires a repeating background image, and for a long time, that was the standard approach. Today, however, modern CSS offers powerful, flexible, and performant ways to generate this pattern with just a few lines of code. No extra HTTP requests, no image files to manage—just pure, scalable CSS.

In this comprehensive guide, we'll dive deep into the various methods for creating checkerboard backgrounds. We'll start with the most common and versatile technique using gradients, explore modern alternatives, and even touch on older methods for context. By the end, you'll not only know how to create a checkerboard pattern but also understand the pros and cons of each approach, enabling you to choose the perfect solution for any scenario.

The Go-To Method: repeating-linear-gradient

When it comes to generating patterns in CSS, gradients are your best friend. While we typically think of gradients as smooth transitions between colors, they can also create hard-edged lines and, by extension, complex patterns. The repeating-linear-gradient function is the workhorse for our checkerboard.

The key insight here is that a checkerboard isn't drawn square by square. Instead, it's created by layering two sets of perpendicular stripes on top of each other.

Step 1: Creating the Vertical Stripes

Let's start by creating a simple set of vertical stripes. We'll use two colors: a light gray (#eee) and a slightly darker gray (#ccc).

To create a hard stop between colors in a gradient, you specify the same position for the end of one color and the start of the next.

.checkerboard {
  background-image: linear-gradient(to right, #eee 50%, #ccc 50%);
  background-size: 40px 40px;
}

This gives us one light gray stripe and one dark gray stripe. The background-size property is crucial here; it defines the size of our repeating pattern tile. In this case, the tile is 40px wide, so each stripe is 20px wide.

Now, let's make it repeat with repeating-linear-gradient. The syntax is a bit more verbose but gives us precise control.

.checkerboard {
  background-image: repeating-linear-gradient(
    to right, /* or 90deg */
    #eee 0, 
    #eee 20px, 
    #ccc 20px, 
    #ccc 40px
  );
}

Let's break that down:

  • to right: The gradient runs from left to right.
  • #eee 0, #eee 20px: The first 20 pixels are solid #eee.
  • #ccc 20px, #ccc 40px: The next 20 pixels (from 20px to 40px) are solid #ccc.

The pattern repeats every 40px, giving us a clean set of vertical stripes.

Step 2: Layering the Horizontal Stripes

CSS allows us to layer multiple background images on top of each other. We can provide a comma-separated list of backgrounds to the background-image property. The first one in the list is the topmost layer.

We'll create our horizontal stripes using the same logic, but we'll change the gradient direction to to bottom (or 180deg).

/* This is not the final code, just an illustration */
.checkerboard {
  background-image: 
    /* Horizontal Stripes (top layer) */
    repeating-linear-gradient(
      to bottom, 
      #eee 0, 
      #eee 20px, 
      #ccc 20px, 
      #ccc 40px
    ),
    /* Vertical Stripes (bottom layer) */
    repeating-linear-gradient(
      to right, 
      #eee 0, 
      #eee 20px, 
      #ccc 20px, 
      #ccc 40px
    );
}

If you try this, you'll only see the horizontal stripes. Why? Because the top layer (#eee and #ccc) is completely opaque, obscuring the layer beneath it. To create the checkerboard effect, we need to introduce transparency.

We'll make one of the colors in our top layer transparent.

Step 3: The Final Assembly with Transparency

Let's refine our horizontal (top) layer. We'll replace one of the colors with transparent. It's more efficient to use a color with an alpha channel like rgba(0, 0, 0, 0) or the transparent keyword.

Here's the final, working code:

.checkerboard-final {
  width: 100%;
  height: 300px;
  background-color: #eee; /* Base color for the transparent squares */

  background-image: 
    repeating-linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc 100%),
    repeating-linear-gradient(45deg, #ccc 25%, #eee 25%, #eee 75%, #ccc 75%, #ccc 100%);

  background-position: 0 0, 20px 20px;
  background-size: 40px 40px;
}

Wait, this looks different! The above code creates a diagonal checkerboard, which is a common variation. Let's correct it for the classic grid pattern. The principle of layering remains the same.

The simplest way to think about it is to create a grid of squares using just one repeating-linear-gradient and clever positioning.

Here is the most common and robust implementation:

.checkerboard {
  --square-size: 20px; /* Size of one square */
  --color1: #eee;
  --color2: #ccc;
  
  width: 100%;
  height: 300px;

  background-image:
    linear-gradient(45deg, var(--color2) 25%, transparent 25%),
    linear-gradient(-45deg, var(--color2) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--color2) 75%),
    linear-gradient(-45deg, transparent 75%, var(--color2) 75%);

  background-size: var(--square-size) var(--square-size);
  background-color: var(--color1);

  background-position:
    0 0, 
    0 calc(var(--square-size) / 2),
    calc(var(--square-size) / 2) calc(var(--square-size) * -1 / 2),
    calc(var(--square-size) * -1 / 2) 0;
}

This looks complex! It works by creating four diagonal gradients that form the corners of the darker squares. While powerful, it's not the most intuitive.

Let's go back to our stripe layering method, which is often easier to reason about. Here is a much simpler and more widely used gradient approach:

.checkerboard {
  --square-size: 40px; /* This is the size of the repeating 2x2 tile */
  --color1: #eee;
  --color2: #ccc;

  width: 100%;
  height: 300px;

  background-color: var(--color1);
  background-image: 
    linear-gradient(var(--color2) 50%, transparent 50%),
    linear-gradient(to right, transparent 50%, var(--color2) 50%);
  
  background-size: var(--square-size) var(--square-size);
  background-position: 0 0, calc(var(--square-size) / 2) 0;
}

This is much cleaner. We create a horizontal stripe and a vertical stripe, both half the size of the tile, and offset one of them to form the checkerboard pattern. But even this can be simplified!

The most elegant repeating-linear-gradient solution:

.checkerboard {
  --square-size: 20px; /* The actual size of each square */
  --color1: #eee;
  --color2: #ccc;

  width: 100%;
  height: 300px;

  background-image: 
    repeating-linear-gradient(45deg, var(--color2) 0, var(--color2) var(--square-size), var(--color1) var(--square-size), var(--color1) calc(2 * var(--square-size)));
  
  background-size: calc(2 * var(--square-size)) calc(2 * var(--square-size));
}

This version uses a single diagonal repeating gradient. It creates diagonal stripes of each color, and when the background-size crops them into a repeating square tile, the illusion of a checkerboard is formed.

Best Practice: Using CSS Custom Properties

As you saw in the examples, using CSS Custom Properties (Variables) makes your pattern incredibly easy to manage. Instead of digging through complex gradient syntax to change a color or size, you can modify the variables at the top of your rule.

.checkerboard {
  --checker-size: 20px;
  --checker-color1: #f0f0f0;
  --checker-color2: #333;

  /* ... gradient code using these variables ... */
}

.dark-mode .checkerboard {
  --checker-color1: #444;
  --checker-color2: #111;
}

This makes your component themeable and much more maintainable.

Pros of the Gradient Method:

  • Pure CSS: No external files or dependencies.
  • Highly Performant: GPU-accelerated and very lightweight.
  • Scalable: The pattern is vector-based and looks sharp on all screen resolutions.
  • Customizable: Trivial to change colors, size, and even angle.

Cons:

  • Syntax: The gradient syntax can be intimidating for beginners.
  • Abstract: You're not drawing squares, but layering stripes, which can be a mental hurdle.

The Modern Angle: repeating-conic-gradient

Conic gradients, which radiate from a central point (like a cone), provide another elegant way to create a checkerboard. This method can feel more intuitive for a simple 2x2 tile.

The idea is to create a four-quadrant pattern and then repeat it.

.checkerboard-conic {
  --square-size: 40px;
  --color1: #fff;
  --color2: #dcdcdc;

  width: 100%;
  height: 300px;

  background-image: repeating-conic-gradient(
    var(--color1) 0% 25%, 
    var(--color2) 25% 50%, 
    var(--color1) 50% 75%, 
    var(--color2) 75% 100%
  );

  background-size: var(--square-size) var(--square-size);
}

Let's dissect the repeating-conic-gradient:

  • var(--color1) 0% 25%: The first quadrant (from 0 to 90 degrees) is color1.
  • var(--color2) 25% 50%: The second quadrant (from 90 to 180 degrees) is color2.
  • var(--color1) 50% 75%: The third quadrant is color1 again.
  • var(--color2) 75% 100%: The final quadrant is color2.

This creates a single 2x2 check pattern. The background-size property then shrinks this pattern down to our desired 40px by 40px and tiles it across the element, creating the full checkerboard effect.

Pros of the Conic Gradient Method:

  • Intuitive Syntax: The quadrant-based syntax is often easier to understand than layered linear gradients.
  • Concise: A single gradient function does all the work.
  • Powerful: Great for other radial or pie-chart-like patterns.

Cons:

  • Browser Support: While very good in modern browsers, it's slightly less supported than linear gradients (e.g., no support in IE11, if you still need that).

The Structural Method: Using CSS Grid (When You Need Interactive Squares)

So far, we've only created backgrounds. But what if you need each square to be an actual DOM element that can contain content or respond to events (like hover or click)? In this specific scenario, CSS gradients won't work. We need to build the checkerboard structurally with HTML and CSS Grid.

This method is not for general-purpose backgrounds. It comes with significant performance overhead due to the large number of DOM elements it creates. Use it only when interactivity is a requirement.

Step 1: The HTML and JavaScript

It's impractical to write out hundreds of <div> tags by hand. We'll use a simple JavaScript snippet to generate our grid cells.

HTML:

<div id="checkerboard-grid" class="checkerboard-grid"></div>

JavaScript:

const gridContainer = document.getElementById('checkerboard-grid');
const numberOfCells = 200; // Adjust as needed

for (let i = 0; i < numberOfCells; i++) {
  const cell = document.createElement('div');
  cell.classList.add('grid-cell');
  gridContainer.appendChild(cell);
}

Step 2: The CSS Grid and Cell Styling

Now, we'll use CSS Grid to arrange these divs and :nth-child selectors to color them.

.checkerboard-grid {
  display: grid;
  /* Create as many 50px columns as will fit */
  grid-template-columns: repeat(auto-fill, minmax(50px, 1fr));
  /* We don't define rows, we let them wrap automatically */
}

.grid-cell {
  width: 50px;
  height: 50px;
  background-color: #eee;
}

/* This simple approach only creates stripes */
.grid-cell:nth-child(even) {
  background-color: #ccc;
}

This gives us alternating colors, but they form stripes, not a checkerboard. To create a true checkerboard, the coloring logic needs to account for both rows and columns. This is tricky with pure CSS because the :nth-child selector works on a flat list of siblings.

A common trick involves knowing the number of columns per row.

/* For a grid with exactly 10 columns per row */
.checkerboard-grid[data-columns="10"] .grid-cell {
  background-color: #eee;
}

/* Even cells in odd rows */
.checkerboard-grid[data-columns="10"] .grid-cell:nth-child(2n) {
  background-color: #ccc;
}

/* Odd cells in even rows */
.checkerboard-grid[data-columns="10"] .grid-cell:nth-child(n + 11):nth-child(-n + 20):nth-child(2n + 1),
.checkerboard-grid[data-columns="10"] .grid-cell:nth-child(n + 31):nth-child(-n + 40):nth-child(2n + 1) {
  /* ...this gets very complicated and brittle! */
  background-color: #ccc;
}

As you can see, the pure CSS approach is extremely fragile and complex. A much better way is to use a preprocessor like Sass or to add the coloring logic directly in your JavaScript when generating the cells. However, this moves us further away from a simple CSS solution.

Pros of the Grid Method:

  • Interactive: Each square is a DOM element, perfect for games, interactive infographics, or complex UI.

Cons:

  • Performance Cost: Creating hundreds or thousands of DOM elements is slow and memory-intensive.
  • Complexity: Requires JavaScript for practical generation and complex CSS or JS for proper coloring.
  • Not a Background: It's a structural component, not a simple background style.

For Posterity: The Old School Repeating Image

For many years, the only way to create a checkerboard was with a tiny, repeating image. You would create a small PNG or GIF, perhaps 20x20 pixels, containing four squares (two light, two dark).

.checkerboard-legacy {
  /* A 2x2 pixel image with two white and two gray pixels */
  background-image: url('checker-tile.png');
  background-repeat: repeat; 
}

While this still works, it's generally considered an outdated practice for simple patterns.

Pros:

  • Simple Concept: Easy for anyone to understand.
  • Maximum Browser Compatibility: Works on virtually any browser ever made.

Cons:

  • Extra HTTP Request: Requires fetching an image file, which can slow down initial page load.
  • Hard to Customize: Changing colors or size means editing the image file and re-uploading it.
  • Scaling Issues: Pixel-based images (like PNG/GIF) can look blurry or pixelated on high-DPI (Retina) displays. Using an SVG tile solves this but adds complexity.

Conclusion and Best Practices

We've explored four distinct methods for creating a checkerboard background in CSS, each with its own strengths and weaknesses.

Here's a quick summary to help you decide:

  1. repeating-linear-gradient / repeating-conic-gradient: This is the recommended approach for 99% of use cases. It's pure CSS, incredibly performant, scalable, and easy to customize with CSS Custom Properties. The conic version is slightly more modern and can be more intuitive, while the linear version has near-universal support.

  2. CSS Grid with DOM Elements: Use this only when you need interactive squares that are part of the page's structure. Be mindful of the significant performance implications.

  3. Repeating Image: Avoid this for simple patterns. It's an outdated technique that has been superseded by the far more flexible and performant CSS gradient methods.

Key Takeaways for a Professional Workflow:

  • Always use CSS Custom Properties (--vars) to define your checkerboard's size and colors. It makes your code clean, readable, and incredibly easy to maintain and theme.
  • Consider Accessibility. A high-contrast checkerboard can be visually distracting. If you place text over it, ensure the text has a solid, opaque background behind it to maintain readability. Low-contrast checkerboards should be purely decorative.
  • Layer It! Remember that a CSS checkerboard is just another background layer. You can place it behind other images (like a transparent logo) by listing them in the background-image property.

Mastering CSS patterns like the checkerboard is a fantastic way to level up your front-end skills. It pushes you to think creatively about how CSS properties can be combined in unexpected ways. So go ahead, experiment with the code, change the colors, tweak the sizes, and see what you can create!