CSS Dot Grid Background: How to Make a Dot Pattern (Free Generator)
A dot grid is a quiet, regular pattern of small dots behind your content. You see it on notebooks, whiteboards, design tools and landing pages. This post shows how to build one in plain CSS, with no image file, and how to drop it into HTML, Webflow, Framer, WordPress, Shopify or a React + Tailwind project.
If you'd rather not write it by hand, the free dot grid generator outputs the CSS, Tailwind classes and SVG for you. The examples below follow the same shape as its output.
The one-line dot pattern
CSS has no "dots" property. The trick is a radial-gradient() with a hard stop, repeated by background-size. Each tile is a small square with one dot in the middle:
.dots {
background-color: #f6f6f5;
background-image: radial-gradient(circle, rgba(17,17,17,0.55) 1.5px, transparent 2px);
background-size: 22px 22px;
}
How it works:
circlemakes the gradient round instead of an ellipse.- The first color stops at
1.5px, the second starts at2px. That half-pixel gap is a tiny soft edge, so the dot isn't jagged. Everything past it istransparent. background-size: 22px 22pxsets the tile, so the gradient repeats every 22px in both directions.- The gradient is centered in its tile by default, so each dot sits in the middle of its square.
The stop is the dot's radius, so the 1.5px above is a 3px dot. The generator uses the same approach: the stop is half the dot size, plus 0.5px for the soft edge.
Spacing and dot size
Two numbers control the whole look:
- Spacing is the tile size in
background-size. Smaller is denser. The generator allows 6px to 120px. - Dot size is twice the first stop. It can't be larger than the spacing, or neighboring dots would merge, so the generator caps it there.
Some starting points:
- Graph paper: 20px spacing, 2px dots, a grey like
#d4d4d4. - Subtle texture: 22px spacing, 3px dots, low opacity.
- Bold pattern: 16px spacing, 14px dots.
Opacity lives in the color. Write the dot color as rgba() (as above) and the dots soften without touching the text on top.
Offset and centered grids
Because the dot is centered in its tile, the pattern starts half a tile in from the top-left corner. That's already a centered grid. The generator doesn't have an offset control, but if you want to shift the grid by hand, use background-position:
.dots {
background-position: 11px 11px; /* half of the 22px tile */
}
Shifting by half a tile puts dots on the corner instead of the center. Use it to line the grid up with a layout edge or a card border.
Fade the edges with mask-image
A dot grid that stops dead at the edge of a section can look heavy. A mask fades the dots out. The catch: a mask applies to the whole element, so it would fade your background color too. The fix is to put the dots on a ::before layer, which is what the generator does when a fade is on:
.dot-grid {
position: relative;
isolation: isolate;
background-color: #f6f6f5;
}
.dot-grid::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
pointer-events: none;
background-image: radial-gradient(circle, rgba(17,17,17,0.55) 1.5px, transparent 2px);
background-size: 22px 22px;
mask-image: radial-gradient(ellipse at center, #000 30%, transparent 90%);
-webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 90%);
}
The mask is fully opaque (#000) up to 30% of the way out, then fades to nothing at 90%. For a one-sided fade, swap in a linear mask, such as linear-gradient(to bottom, #000 30%, transparent 90%).
isolation: isolate plus z-index: -1 keeps the dots behind your content without needing to wrap anything.
The generator also has a halftone mode, where dots shrink across the surface. Plain CSS can't size each dot separately, so the CSS and SVG output approximate it with a mask that fades the dots instead. The PNG download draws the real thing.
Square and plus dots with SVG
A radial gradient can only make round dots. For squares or plus signs, use a tiny inline SVG as the background-image. Here is a 24px plus-sign tile in a warm grey:
.plus {
background-color: #efefed;
background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Crect%20x='7.5'%20y='10.5'%20width='9'%20height='3'%20fill='%232a2a2a'%20fill-opacity='0.7'/%3E%3Crect%20x='10.5'%20y='7.5'%20width='3'%20height='9'%20fill='%232a2a2a'%20fill-opacity='0.7'/%3E%3C/svg%3E");
background-size: 24px 24px;
}
Two rectangles make the plus. The %3C and %3E are encoded < and >, %20 is a space, and %23 is #. Encoding them keeps the data URL free of raw spaces and brackets, so it works in a stylesheet, a Tailwind class and an HTML style attribute. For a square, use a single rect with equal width and height. Both stay sharp at any zoom level.
If you want a standalone SVG instead of CSS, the generator also outputs a self-contained <svg> with a <pattern> filled by a rect. Use it inline behind your content.
The Tailwind version
Tailwind's arbitrary values can hold the same thing. Underscores stand in for spaces:
<div class="bg-[#f6f6f5] bg-[image:radial-gradient(circle,_rgba(17,17,17,0.55)_1.5px,_transparent_2px)] bg-[size:22px_22px]">
<h1>Your headline</h1>
</div>
With a fade on, the generator's Tailwind output uses before: utilities for the dot layer, the same structure as the CSS above. Copy it from the tool rather than writing the mask by hand.
Dark mode
On a dark section, flip the two colors: a near-black background and light dots at a lower opacity so they don't glare.
.dots {
background-color: #111;
background-image: radial-gradient(circle, rgba(212,212,212,0.3) 1.5px, transparent 2px);
background-size: 22px 22px;
}
To follow the visitor's system setting, wrap the dark values in a media query:
@media (prefers-color-scheme: dark) {
.dots {
background-color: #111;
background-image: radial-gradient(circle, rgba(212,212,212,0.3) 1.5px, transparent 2px);
}
}
In Tailwind, add a dark: variant on the same arbitrary-value classes: dark:bg-[#111] dark:bg-[image:radial-gradient(circle,_rgba(212,212,212,0.3)_1.5px,_transparent_2px)]. The tile size stays the same, so you only override the colors.
For an accent, an ember orange like #e8794a works well as the dot color on a dark base. Keep the opacity low so it stays a texture.
CSS or PNG?
- CSS is resolution-independent, tiny, and easy to edit later. Use it for page and section backgrounds. It's text, not an image request.
- PNG is a fixed image. The generator downloads 1920×1080 for a wide hero or wallpaper, and 1000×1500 for Pinterest-style pins. Use it where you can't set CSS, such as slides, social graphics or an image fill.
The generator's preview shows the CSS at 1:1 pixels, so what you see is what you copy. Copy link gives you a URL that restores the same settings, handy for sharing with a client. Everything runs in your browser. Nothing is uploaded, and there's no sign-up.
Plain HTML
Paste the rule into your stylesheet and add the class:
<section class="dots" style="min-height: 70vh">
<h1>Your headline</h1>
</section>
Webflow
Give the section a class, then add an Embed element with a <style> block that targets it and paste the rule inside. More on the Webflow effects page.
Framer
Put the rule in Site Settings → Custom Code inside a <style> tag, and give the frame the class. See Framer effects.
WordPress and Shopify
- WordPress: give a Group block an Additional CSS class, then paste the rule under Appearance → Customize → Additional CSS.
- Shopify: paste the rule into
base.css, or into a section's{% style %}block, and add the class to the section.
React and Tailwind
Paste the declarations into a CSS file, or use the Tailwind classes straight on the element. A style object works too:
<section
style={{
backgroundColor: "#f6f6f5",
backgroundImage: "radial-gradient(circle, rgba(17,17,17,0.55) 1.5px, transparent 2px)",
backgroundSize: "22px 22px",
}}
>
<h1>Your headline</h1>
</section>
See React effects for more.
Performance and accessibility
- Static CSS is cheap. It's a few lines of text, with no script, no image request and no animation loop.
- It's decorative. Keep real text in HTML, not in a PNG, and don't rely on the dots to carry meaning. The pattern needs no alt text as a CSS background.
- Check text contrast. Dots add visual noise right behind your text. Keep them low in opacity and well below your text's contrast, and test the headline and body copy over the pattern, not just on a flat color. A fade helps by clearing the area behind the content.
- Keep dot size modest behind paragraphs. Big, bold dots are better behind a headline or in a margin than behind long body text.
When you need it to move
This technique is static. Plain CSS can't make each dot react to the pointer. For a grid that reacts to the cursor and ripples on click, Dot Grid Field draws it with WebGL from a single script tag, for $9 one-time. The step-by-step is in Animated Dot Grid Background in Webflow or Framer.
If a still background is enough, stay with CSS. It's lighter and has nothing to load.
See it in context
The free dot grid generator lets you try spacing, shape, fade and halftone and see the CSS change live. When you want the dots to respond, step up to Dot Grid Field, and for the rest of the catalog see /effects.
Pricing
The generator is free. Dot Grid Field, the animated WebGL version, is $9 one-time. The full catalog is available through the All-Access Pass for $49.
Pick a spacing, check your text contrast, and keep the CSS if a still background does the job.