This article focuses on generating a CSS checkerboard background with
repeating-linear-gradient. The core technique is to layer horizontal and vertical gradients and keep the color stops perfectly aligned with thebackground-sizecycle to avoid stretching, gaps, and misalignment. Keywords: CSS backgrounds,repeating-linear-gradient, checkerboard.
Technical specifications at a glance
| Parameter | Description |
|---|---|
| Language | CSS3 |
| Core capabilities | Background texture generation, repeating gradients, transparent overlay |
| License | CC 4.0 BY-SA (as declared in the source) |
| Star count | Not provided; not a GitHub project |
| Core dependency | Browser CSS gradient rendering engine |
| Key properties | background-image, background-size, transparent |
The correct checkerboard background implementation depends on layering bidirectional repeating gradients
Many people assume that stacking two gradients is enough to create a checkerboard, but the real deciding factor is whether the cycles match exactly. A checkerboard is not fundamentally about “drawing squares.” It is about intersecting horizontal and vertical stripes so that only the overlapping regions are colored.
When two repeating-linear-gradient layers use the same repeat length and start drawing from 0, the browser can generate a regular grid. If even one stop is offset, the first cell will shift out of alignment, which becomes especially obvious when the pattern is enlarged.
.board {
width: 240px;
height: 240px;
background-color: #fff; /* The base color determines the color of non-overlapping areas */
background-image:
repeating-linear-gradient(
0deg,
#222 0,
#222 10px, /* Draw the dark horizontal stripe for the first 10px */
transparent 10px,
transparent 20px /* Keep the next 10px transparent to form one cycle */
),
repeating-linear-gradient(
90deg,
#222 0,
#222 10px, /* Draw the dark vertical stripe for the first 10px */
transparent 10px,
transparent 20px /* Must match the horizontal gradient cycle exactly */
);
background-size: 20px 20px; /* The cycle must align with 0→20px */
}
This code creates a stable 10px-cell checkerboard background by intersecting horizontal and vertical repeating gradients.
transparent is the key to rendering a crisp checkerboard
If the second color stop is not transparent and you use white or another solid color instead, the two background layers will overwrite or blend with each other. The result is often stripes, solid blocks, or grayish edges instead of a clean checkerboard.
The value of transparent is simple: non-hit areas do not participate in coloring at all, so the underlying background color remains visible. Only the areas hit by both directions display the dark color. That is the core of the “color on intersection” model.
/* Incorrect example: this creates layered stripes, not a standard checkerboard */
.bad-board {
background-image:
repeating-linear-gradient(0deg, #000 0, #000 10px, #fff 10px, #fff 20px),
repeating-linear-gradient(90deg, #000 0, #000 10px, #fff 10px, #fff 20px);
}
The problem here is that both gradients actively fill solid-color regions. After layering, they tend to produce a mixed texture rather than a transparent overlap effect.
background-size must match the repeat cycle exactly
In principle, repeating-linear-gradient repeats on its own, but in a checkerboard use case, you should still explicitly declare background-size. This constrains the background tile dimensions and reduces stretching differences across browsers or zoom levels.
If the cycle is 20px, then background-size must be 20px 20px. If your gradient is defined with a 0-to-24px cycle but your background size is set to 20px 20px, the cell boundaries will be misaligned.
/* Variant: gray and white checkerboard */
.soft-board {
background-color: #fafafa;
background-image:
repeating-linear-gradient(0deg, #d0d0d0 0, #d0d0d0 12px, transparent 12px, transparent 24px),
repeating-linear-gradient(90deg, #d0d0d0 0, #d0d0d0 12px, transparent 12px, transparent 24px);
background-size: 24px 24px; /* Keep this aligned with the full cycle */
}
This example shows how to customize cell size and color by updating both the stop positions and background-size in sync.
Most common issues come from size relationships, not syntax
The four most common problems are these: omitting background-size, using inconsistent cycles between the two gradients, introducing background-position offsets without synchronizing dimensions, and letting background-color or other background declarations override the gradient layers.
Another subtle issue is scaling and transforms. In some older versions of Edge, transform, page zoom, or high-DPI rendering can introduce jagged edges and first-cell offsets. That is not necessarily a coding mistake. It is a rendering implementation difference.
/* Debugging tip: lock the size first, then introduce offsets step by step */
.debug-board {
background-color: #fff;
background-image:
repeating-linear-gradient(0deg, red 0, red 8px, transparent 8px, transparent 16px),
repeating-linear-gradient(90deg, blue 0, blue 8px, transparent 8px, transparent 16px);
background-size: 16px 16px;
}
This code uses red and blue layers to help you verify whether the horizontal and vertical cycles align, which makes it useful for quickly debugging offset issues.
Compatibility decisions should be based on target browsers, not just writable syntax
Modern Chrome, Firefox, and Safari provide mature support for repeating-linear-gradient, so you can use this approach directly in typical production web pages. However, if your project still needs to support IE, a gradient-only solution is not reliable. In that case, fall back to bitmaps, SVG, or pseudo-element drawing.
For a design system or component library, you should package the checkerboard as configurable variables, including cell size, foreground color, base color, and offsets. That makes the pattern reusable across dark themes, canvas editors, and transparent placeholder backgrounds.
A reusable CSS custom properties version is better for engineering use
:root {
--cell: 10px;
--period: 20px;
--mark: #333;
--base: #fff;
}
.checkerboard {
background-color: var(--base);
background-image:
repeating-linear-gradient(
0deg,
var(--mark) 0,
var(--mark) var(--cell), /* Use variables to control the cell size consistently */
transparent var(--cell),
transparent var(--period)
),
repeating-linear-gradient(
90deg,
var(--mark) 0,
var(--mark) var(--cell),
transparent var(--cell),
transparent var(--period)
);
background-size: var(--period) var(--period);
}
This code abstracts the checkerboard into variable-driven parameters, making it easy to reuse across a component library or theme system.
The structured FAQ addresses the questions developers care about most
FAQ 1: Why do I still see stripes after writing two gradients?
You are most likely using solid colors instead of transparent, or the stop cycles in the two directions do not match. A checkerboard depends on “transparent regions + color on overlap,” not simple two-color overlay.
FAQ 2: Why do the cells look blurry, distorted, or separated by gaps?
Usually, background-size does not match the full gradient cycle, or the element is being scaled, or browser DPI rendering is causing subpixel artifacts. Prioritize integer-based cycles and avoid adding offsets casually.
FAQ 3: Is this approach worth using in production?
Yes. It avoids image requests, supports theming, and scales easily, which makes it suitable for editor canvases, transparent background hint areas, and design system texture layers. But if you must support IE, prepare an SVG or bitmap fallback.
Core summary: This article reconstructs how to use CSS repeating-linear-gradient to build a stable checkerboard background. It focuses on bidirectional gradient layering, the transparent rendering mechanism, background-size alignment rules, common causes of misalignment, and browser compatibility boundaries.