By Tim King · Updated
CSS Wave Generator
Wavy Section Dividers as a Background
OneTask is free, with no sign-up, and built by one person.
If this tool saved you time, a coffee helps keep new ones coming.
How the CSS Wave Generator works
This CSS wave generator builds a wavy section divider you can paste straight into a stylesheet. A wavy edge between two page sections is one of the most requested decorative effects and one of the most awkward to do by hand. This tool draws the wave as an SVG path, encodes it as a data URI and positions it on the chosen edge of a section, so the whole divider lives in a few lines of CSS.
How the CSS wave generator draws the divider
CSS cannot draw curves as a box edge — border-radius gives you one arc per corner and nothing else.
The practical way to get a wavy edge is an SVG shape, and the cleanest way to ship an SVG shape is as
a background-image data URI on an absolutely positioned pseudo-element or child. That is what the
generated code does: the .wave element sits at the top or bottom of a position: relative section,
spans the full width, and paints the wave in the colour of the next section so it looks as if that
section is cutting into this one.
How the path is built. The wave is a chain of cubic Bézier curves along a 1440-unit-wide viewBox,
one crest and one trough per wave, closed down to the bottom edge to make a filled shape. The
preserveAspectRatio='none' attribute lets the browser stretch that viewBox to whatever width and
height the element has, so the wave count stays fixed and the curves get wider or narrower with the
viewport. That is usually what you want for a divider; if you need waves that keep their shape and
repeat instead, set a fixed background-size width and repeat-x.
Top or bottom. A bottom wave sits at the section's lower edge and is painted in the colour of what
follows. A top wave is the same path flipped with transform: scaleY(-1) and painted in the colour of
what precedes. Either way the section itself needs position: relative so the absolutely positioned
wave is placed against it, and usually overflow: hidden or enough padding on that edge so content
does not sit under the wave.
Colours. The wave colour must match the neighbouring section's background exactly, including any gradient — a solid wave over a gradient section shows an obvious seam. For gradient sections, put the wave inside the gradient section instead, painted in the neighbour's solid colour.
Why not clip-path? clip-path: path() can cut a wavy edge off the section itself, which avoids the
extra element, but it clips the section's content too and the path units are pixels, so it does not
scale with the width. The SVG background approach scales cleanly and leaves the content alone. The
clip-path generator on this site covers the other approach for polygons and simple shapes.
Accessibility and performance. The wave is purely decorative, so it belongs in CSS rather than in
the HTML as an inline <svg>, keeping it out of the accessibility tree. As a background it is rendered
once and cached; a data URI of this size adds well under a kilobyte to the stylesheet.
Fine-tuning. The generated path has a fixed crest amplitude of 90% of the half-height. Open the SVG path in the SVG path visualiser to adjust individual control points if you want asymmetric or layered waves, then paste the edited path back into the data URI.
FAQ
Why is there a hairline gap between the wave and the next section?
Sub-pixel rounding at the section boundary. Extend the wave by one pixel — bottom: -1px — or give
the wave element a height one pixel taller than the SVG so it overlaps the neighbour and hides the
seam.
Can I stack two waves for a layered look?
Yes. Add a second wave element with a different wave count or height and a semi-transparent colour, or generate two rules with different counts and place both at the same edge. The lower-opacity wave in front gives the common "double wave" hero footer.
Why does the wave look squashed on wide screens?
Because preserveAspectRatio='none' stretches the fixed number of waves across the full width. Either
increase the wave count, or replace 100% 100% in background-size with a fixed width such as 600px 100% and set background-repeat: repeat-x so the waves tile at a constant size.
Does this work in every browser?
SVG data URIs as backgrounds work in every browser in use today. The only encoding requirement is that
<, > and # are percent-encoded and the whole URI is quoted, which the generated code already
handles.
Can I animate the wave?
Animate background-position-x on a tiled wave (fixed background-size, repeat-x) to make it drift
sideways, which is cheap because the image is cached. Morphing the wave shape itself needs an inline
SVG with animated path data rather than a background.
See also: all Shapes & SVG tools, Layout & Spacing, Shadows & Motion, UI Components, Forms & Inputs, Colour.
Related tools
CSS Pattern Generator
Repeating background patterns built from CSS gradients, no images.
Mesh Gradient Generator
Pure-CSS mesh gradients from stacked radial layers.
CSS Divider Generator
Slanted, curved, zigzag and wave section dividers in pure CSS.
Torn Paper Edge
A ripped, jagged paper edge on a card or section.
Blob Generator
Make organic blob shapes with border-radius.