Skip to content
WebTricks

CSS background pattern generator — stripes, checkerboard, grid, dots and zigzag in pure CSS

How every pattern in our CSS pattern generator is built with repeating-linear-gradient, radial-gradient and conic-gradient — with the actual CSS, scaling, animation, theming and performance notes.

A background pattern does not need a PNG, an SVG sprite or a data URI. Every classic texture — diagonal stripes, a checkerboard, graph paper, a dot grid, zigzag, crosshatch — is a small gradient tiled with background-size. Our CSS pattern generator builds seven of them interactively: pick a pattern, set two colors, drag the size, thickness and angle sliders, copy the declaration. This article explains what that output is actually doing, so you can modify it or write your own.

Patterns at a glance

PatternGradient functionTiled with background-size?Controls in the generator
Checkerboardone conic-gradientyessize
Dotsone radial-gradientyessize, thickness
Grid (graph paper)two linear-gradientsyessize, thickness
Diagonal stripesone repeating-linear-gradientno (self-repeating)size, angle
Vertical stripesone repeating-linear-gradientnosize
Zigzagfour linear-gradientsyes, with background-position offsetssize
Crosshatchtwo repeating-linear-gradientsnosize, thickness

Two ideas power all seven. First, a hard color stop — two stops at the same position, written color 25%, other 25% or with the shorthand other 0 50% — turns a smooth gradient into a crisp edge. Second, background-size tiles that one small image across the element, so a 20-pixel square becomes an infinite texture.

Checkerboard

A conic-gradient sweeps around the center of the tile. Splitting the sweep into four 25% quarters with alternating colors gives a 2×2 checker in one tile:

background-color: #3a3f4f;
background-image: conic-gradient(#2a2d3a 25%, #3a3f4f 0 50%, #2a2d3a 0 75%, #3a3f4f 0);
background-size: 40px 40px;

The 0 after each color means “start this stop where the previous one ended”, which is what produces the hard edge. Each checker square is half of background-size, so 40px tiles give 20px squares. The older two-gradient trick with background-position offsets still works, but the single conic-gradient is shorter and has no seam. Live version: checkerboard pattern.

Dots

One radial-gradient with a hard stop paints a filled circle in the center of each tile; everything beyond the radius is transparent so the background color shows through:

background-color: #0f1117;
background-image: radial-gradient(#3a3f4f 2px, transparent 2px);
background-size: 22px 22px;

2px is the dot radius (the thickness slider), 22px is the spacing. Add 0.5px to the transparent stop (transparent 2.5px) if the dots look jagged — that half-pixel ramp acts as anti-aliasing. Live version: dotted grid background.

Grid (graph paper)

Two linear gradients, one horizontal and one rotated 90°, each painting a thin line at the start of the tile and transparent after it:

background-color: #0f1117;
background-image:
  linear-gradient(#2a2d3a 1px, transparent 1px),
  linear-gradient(90deg, #2a2d3a 1px, transparent 1px);
background-size: 24px 24px;

The first gradient draws a 1px line along the top of every tile, the second along the left edge. Stack a second pair with a larger background-size and a bolder color for the classic graph-paper major/minor grid — see the graph paper grid snippet, which layers a 100px major grid over a 20px minor one.

Diagonal stripes (css diagonal stripes)

repeating-linear-gradient repeats its own stop list along the gradient line, so no background-size is needed. Two hard-edged bands of equal width give even stripes:

background-color: #12151c;
background-image: repeating-linear-gradient(45deg, #6b46ff 0 12px, #12151c 12px 24px);

The angle is the stripe direction; 12px is the width of one band measured perpendicular to the stripes. Because the gradient line runs through the element’s center, the stripes never show a tile seam at any angle — the reason this is preferable to a rotated tiled gradient. The generator’s angle slider rotates it; 135deg mirrors the direction. Live version: diagonal stripes.

Vertical stripes (and horizontal)

The same declaration at 90deg. Set 0deg (or 180deg) for horizontal stripes:

background-color: #12151c;
background-image: repeating-linear-gradient(90deg, #6b46ff 0 12px, #12151c 12px 24px);

Use unequal bands (0 4px, … 4px 24px) for pinstripes, or three colors for a hazard-tape look.

Zigzag

Zigzag is the trickiest: four linear-gradients at 45°, 135°, 225° and 315°, each painting a triangle in one corner of the tile, with two of them shifted by half a tile so the triangles join into a chevron:

background-color: #12151c;
background-image:
  linear-gradient(135deg, #6b46ff 25%, transparent 25%),
  linear-gradient(225deg, #6b46ff 25%, transparent 25%),
  linear-gradient(45deg, #6b46ff 25%, transparent 25%),
  linear-gradient(315deg, #6b46ff 25%, transparent 25%);
background-position: 12px 0, 12px 0, 0 0, 0 0;
background-size: 24px 24px;

The background-position list is positional: the first two gradients are offset by half the tile width (size / 2), the last two are not. If you change background-size, update the offsets to stay at exactly half or the chevrons tear. Live version: zigzag pattern.

Crosshatch

Two self-repeating diagonal gradients at +45° and −45°, each drawing a thin line then a transparent gap:

background-color: #0f1117;
background-image:
  repeating-linear-gradient(45deg, #2a2d3a 0 1px, transparent 1px 16px),
  repeating-linear-gradient(-45deg, #2a2d3a 0 1px, transparent 1px 16px);

1px is the line thickness, 16px the period. Make the two periods different (16px and 24px) for a woven, less mechanical texture. Live version: crosshatch pattern.

How background-size controls scale

For tiled patterns, background-size is the pattern scale: the gradient is defined in percentages of the tile, so changing the size scales everything proportionally. For the self-repeating ones (repeating-linear-gradient) the scale lives inside the stop list instead, which is why the generator rewrites the pixel values rather than setting background-size.

Three practical notes:

  • Use whole pixels. A 23.5px tile makes every other tile land on a half pixel and you get a faint moiré. The generator only emits integers.
  • Tiles start at the top-left corner. If the element’s size is not a multiple of the tile, the last row/column is cut. Usually invisible; if it matters, set background-position: center to center the cut instead.
  • Line widths do not scale with the tile. 1px stays 1px at any size, which is what you want for grids. For dots, scale the radius with the gap (about 10% of the gap looks balanced).

Animating a pattern

Tiled patterns animate by moving background-position. Shift by exactly one tile per loop and the animation is seamless:

.moving-stripes {
  background-image: repeating-linear-gradient(45deg, #6b46ff 0 12px, #12151c 12px 24px);
  background-size: 34px 34px;  /* 24px * sqrt(2) — one diagonal period */
  animation: slide 1s linear infinite;
}

@keyframes slide {
  to { background-position: 34px 0; }
}

For a self-repeating gradient the tile is undefined, so give it an explicit background-size equal to one period (for 45° stripes, the period along the x-axis is band × 2 × √2). This is exactly how the striped progress bar snippet runs its barber-pole effect. Animate background-position, not the gradient itself — gradients are not interpolable without @property, and moving the position is a cheap compositor-friendly change.

Theme-aware patterns with custom properties

Every snippet on the site drives its colors through :root variables, and you should do the same so one rule switches the pattern for dark mode:

:root {
  --pattern-fg: #2a2d3a;
  --pattern-bg: #0f1117;
  --pattern-size: 24px;
}

[data-theme="light"] {
  --pattern-fg: #e2e5ee;
  --pattern-bg: #ffffff;
}

.grid-bg {
  background-color: var(--pattern-bg);
  background-image:
    linear-gradient(var(--pattern-fg) 1px, transparent 1px),
    linear-gradient(90deg, var(--pattern-fg) 1px, transparent 1px);
  background-size: var(--pattern-size) var(--pattern-size);
}

Low-contrast patterns work best as page textures: keep the foreground within 10–15% lightness of the background (#0f1117 on #2a2d3a, not white on black), or readers will fight the lines. For patterns under text, the contrast checker tells you whether your text still passes against the brightest color in the pattern.

Performance: gradients vs PNG vs SVG

ApproachBytesScales with DPRThemableRepaint cost
CSS gradients~100–300 B of CSSyes, always crispone variable swaprasterized once per tile size, then tiled by the compositor
Tiled PNG1–20 KB per pattern, one requestblurry unless you ship 2× and 3×needs one file per themecheap
Inline SVG data URI200 B–2 KByesneeds URL-encoding the color into the URIre-decoded when the URI changes

Gradients win on every column that matters for a UI texture. Two caveats: browsers rasterize the gradient tile when it is first painted and again whenever its size or colors change, so animate background-position, not colors or size. And very large tiles (a 2000px background-size on a full-screen hero) rasterize a big bitmap — keep tiles under a few hundred pixels.

Conic gradients have been in every major browser since 2020 (Chrome 69, Firefox 83, Safari 12.1), and repeating-linear-gradient with the two-position stop shorthand (#000 0 12px) since Chrome 71, Firefox 64 and Safari 12.1. If you need to support anything older, write the double stop the long way: #000 0, #000 12px.

FAQ

How do I make a CSS checkerboard background?

One conic-gradient with four hard 25% stops, tiled with background-size: conic-gradient(#000 25%, #fff 0 50%, #000 0 75%, #fff 0) at background-size: 40px 40px gives 20px squares. The pattern generator lets you set both colors and the tile size and copies the declaration.

How do I make diagonal stripes in CSS?

Use repeating-linear-gradient(45deg, #6b46ff 0 12px, #12151c 12px 24px). The angle sets the direction, the pixel values set the band width, and no background-size is needed because the gradient repeats itself.

Why does my pattern have a visible seam?

Either the tile size is a fraction of a pixel (round it), the background-position offsets in a multi-gradient pattern like zigzag are not exactly half the tile, or you rotated a tiled gradient with transform instead of using the gradient’s own angle. Self-repeating gradients never seam.

Can I use a pattern with an image or gradient underneath?

Yes — background-image takes a comma-separated list and paints the first one on top. Put the pattern first and the photo or gradient last, and use transparent (not the background color) for the pattern’s gaps so the lower layer shows through.

Is a CSS pattern better than an SVG background?

For simple geometry (stripes, grids, dots, checks) CSS is smaller, scales perfectly and themes with a variable. Use SVG when the motif is a real shape — icons, hexagons, organic blobs — that gradients cannot draw.