14 CSS Wave Section Dividers06 / 14

Pure CSSMIT licensed

Pure CSS clip path wave divider without SVG

For engineers who refuse to ship inline SVG in their markup: three CSS-only ways to cut a wave — modern clip-path: path(), a repeating radial-gradient mask, and an ellipse curve — all with no extra DOM node and nothing for the HTML payload to carry.

Published

Live Demo
Try it

The code

<div class="wsd-06-group">
<section class="wsd-06a">
  <div class="wsd-06a__a"><h2 class="wsd-06a__title">No SVG in the DOM</h2><p class="wsd-06a__copy">The curve is one CSS declaration.</p></div>
  <div class="wsd-06a__divider" role="presentation"></div>
  <div class="wsd-06a__b"><p class="wsd-06a__copy">clip-path: path() takes SVG path syntax straight in CSS.</p></div>
</section>
<section class="wsd-06b">
  <div class="wsd-06b__a"><h2 class="wsd-06b__title">Fluid without stretching</h2><p class="wsd-06b__copy">The wave tiles instead of squashing.</p></div>
  <div class="wsd-06b__divider" role="presentation"></div>
  <div class="wsd-06b__b"><p class="wsd-06b__copy">A repeating radial-gradient mask keeps every crest the same size at any viewport.</p></div>
</section>
<section class="wsd-06c">
  <div class="wsd-06c__a"><h2 class="wsd-06c__title">One-line dome curve</h2></div>
  <div class="wsd-06c__b"><p class="wsd-06c__copy">border-radius: 50% 50% 0 0 / 100% 100% 0 0 — the cheapest curve in CSS.</p></div>
</section>
</div>
.wsd-06-group {
  width: 100%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.wsd-06-group > section {
  width: 100%;
}

.wsd-06a,
.wsd-06a *,
.wsd-06a *::before,
.wsd-06a *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.wsd-06a {
  --a: oklch(0.3 0.08 150);
  --b: oklch(0.96 0.02 150);
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.wsd-06a__a {
  background: var(--a);
  color: #fff;
  padding: 64px 24px 34px;
  text-align: center;
}

.wsd-06a__title {
  font-size: clamp(24px,3.8vw,36px);
  margin-bottom: 8px;
}

.wsd-06a__copy {
  font-size: 15px;
  opacity: .8;
}

.wsd-06a__divider {
  height: 100px;
  background: var(--b);
  clip-path: path('M0,44 C240,110 480,-6 720,38 C960,82 1200,110 1440,58 L1440,100 L0,100 Z');
  margin-top: -1px;
}

.wsd-06a__b {
  background: var(--b);
  color: oklch(0.3 0.06 150);
  padding: 14px 24px 60px;
  text-align: center;
}

.wsd-06a__b .wsd-06a__copy {
  opacity: .74;
}

.wsd-06b,
.wsd-06b *,
.wsd-06b *::before,
.wsd-06b *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.wsd-06b {
  --a: oklch(0.35 0.13 268);
  --b: oklch(0.97 0.01 268);
  --pitch: 74px;
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.wsd-06b__a {
  background: var(--a);
  color: #fff;
  padding: 62px 24px 32px;
  text-align: center;
}

.wsd-06b__title {
  font-size: clamp(24px,3.8vw,36px);
  margin-bottom: 8px;
}

.wsd-06b__copy {
  font-size: 15px;
  opacity: .8;
}

.wsd-06b__divider {
  height: 42px;
  background: var(--b);
  -webkit-mask: radial-gradient(calc(var(--pitch)/2) at 50% 100%,transparent 98%,#000) repeat-x 0 0/var(--pitch) 42px;
  mask: radial-gradient(calc(var(--pitch)/2) at 50% 100%,transparent 98%,#000) repeat-x 0 0/var(--pitch) 42px;
  margin-top: -1px;
}

.wsd-06b__b {
  background: var(--b);
  color: oklch(0.32 0.08 268);
  padding: 12px 24px 58px;
  text-align: center;
}

.wsd-06b__b .wsd-06b__copy {
  opacity: .74;
  max-width: 52ch;
  margin: 0 auto;
}

.wsd-06c,
.wsd-06c *,
.wsd-06c *::before,
.wsd-06c *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.wsd-06c {
  --a: oklch(0.42 0.15 25);
  --b: oklch(0.97 0.02 25);
  font-family: 'Segoe UI',system-ui,sans-serif;
  overflow: hidden;
}

.wsd-06c__a {
  background: var(--a);
  color: #fff;
  padding: 62px 24px 52px;
  text-align: center;
}

.wsd-06c__title {
  font-size: clamp(24px,3.8vw,36px);
}

.wsd-06c__b {
  position: relative;
  background: var(--b);
  color: oklch(0.34 0.09 25);
  padding: 46px 24px 58px;
  text-align: center;
  border-radius: 50% 50% 0 0/72px 72px 0 0;
  margin-top: -40px;
  width: 112%;
  margin-left: -6%;
}

.wsd-06c__copy {
  font-size: 15px;
  opacity: .76;
  max-width: 52ch;
  margin: 0 auto;
}
/* No JavaScript — a fixed-height strip clipped with clip-path:path(). Note path() units are px, so this variant is intentionally fixed-height. */

/* No JavaScript — a tiled radial-gradient mask carves identical scallops; wider screens get more crests instead of wider ones. */

/* No JavaScript — an over-wide block with an elliptical border-radius pulled up over the previous section makes a dome with zero masking. */
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Wave Section Divider from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Pure CSS clip path wave divider without SVG
Source: https://codefronts.com/layouts/css-wave-section-dividers/pure-css-clip-path-wave-divider-without-svg/

For engineers who refuse to ship inline SVG in their markup: three CSS-only ways to cut a wave — modern clip-path: path(), a repeating radial-gradient mask, and an ellipse curve — all with no extra DOM node and nothing for the HTML payload to carry.
## HTML
```html
<div class="wsd-06-group">
<section class="wsd-06a">
  <div class="wsd-06a__a"><h2 class="wsd-06a__title">No SVG in the DOM</h2><p class="wsd-06a__copy">The curve is one CSS declaration.</p></div>
  <div class="wsd-06a__divider" role="presentation"></div>
  <div class="wsd-06a__b"><p class="wsd-06a__copy">clip-path: path() takes SVG path syntax straight in CSS.</p></div>
</section>
<section class="wsd-06b">
  <div class="wsd-06b__a"><h2 class="wsd-06b__title">Fluid without stretching</h2><p class="wsd-06b__copy">The wave tiles instead of squashing.</p></div>
  <div class="wsd-06b__divider" role="presentation"></div>
  <div class="wsd-06b__b"><p class="wsd-06b__copy">A repeating radial-gradient mask keeps every crest the same size at any viewport.</p></div>
</section>
<section class="wsd-06c">
  <div class="wsd-06c__a"><h2 class="wsd-06c__title">One-line dome curve</h2></div>
  <div class="wsd-06c__b"><p class="wsd-06c__copy">border-radius: 50% 50% 0 0 / 100% 100% 0 0 — the cheapest curve in CSS.</p></div>
</section>
</div>
```
## CSS
```css
.wsd-06-group {
  width: 100%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.wsd-06-group > section {
  width: 100%;
}

.wsd-06a,
.wsd-06a *,
.wsd-06a *::before,
.wsd-06a *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.wsd-06a {
  --a: oklch(0.3 0.08 150);
  --b: oklch(0.96 0.02 150);
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.wsd-06a__a {
  background: var(--a);
  color: #fff;
  padding: 64px 24px 34px;
  text-align: center;
}

.wsd-06a__title {
  font-size: clamp(24px,3.8vw,36px);
  margin-bottom: 8px;
}

.wsd-06a__copy {
  font-size: 15px;
  opacity: .8;
}

.wsd-06a__divider {
  height: 100px;
  background: var(--b);
  clip-path: path('M0,44 C240,110 480,-6 720,38 C960,82 1200,110 1440,58 L1440,100 L0,100 Z');
  margin-top: -1px;
}

.wsd-06a__b {
  background: var(--b);
  color: oklch(0.3 0.06 150);
  padding: 14px 24px 60px;
  text-align: center;
}

.wsd-06a__b .wsd-06a__copy {
  opacity: .74;
}

.wsd-06b,
.wsd-06b *,
.wsd-06b *::before,
.wsd-06b *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.wsd-06b {
  --a: oklch(0.35 0.13 268);
  --b: oklch(0.97 0.01 268);
  --pitch: 74px;
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.wsd-06b__a {
  background: var(--a);
  color: #fff;
  padding: 62px 24px 32px;
  text-align: center;
}

.wsd-06b__title {
  font-size: clamp(24px,3.8vw,36px);
  margin-bottom: 8px;
}

.wsd-06b__copy {
  font-size: 15px;
  opacity: .8;
}

.wsd-06b__divider {
  height: 42px;
  background: var(--b);
  -webkit-mask: radial-gradient(calc(var(--pitch)/2) at 50% 100%,transparent 98%,#000) repeat-x 0 0/var(--pitch) 42px;
  mask: radial-gradient(calc(var(--pitch)/2) at 50% 100%,transparent 98%,#000) repeat-x 0 0/var(--pitch) 42px;
  margin-top: -1px;
}

.wsd-06b__b {
  background: var(--b);
  color: oklch(0.32 0.08 268);
  padding: 12px 24px 58px;
  text-align: center;
}

.wsd-06b__b .wsd-06b__copy {
  opacity: .74;
  max-width: 52ch;
  margin: 0 auto;
}

.wsd-06c,
.wsd-06c *,
.wsd-06c *::before,
.wsd-06c *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.wsd-06c {
  --a: oklch(0.42 0.15 25);
  --b: oklch(0.97 0.02 25);
  font-family: 'Segoe UI',system-ui,sans-serif;
  overflow: hidden;
}

.wsd-06c__a {
  background: var(--a);
  color: #fff;
  padding: 62px 24px 52px;
  text-align: center;
}

.wsd-06c__title {
  font-size: clamp(24px,3.8vw,36px);
}

.wsd-06c__b {
  position: relative;
  background: var(--b);
  color: oklch(0.34 0.09 25);
  padding: 46px 24px 58px;
  text-align: center;
  border-radius: 50% 50% 0 0/72px 72px 0 0;
  margin-top: -40px;
  width: 112%;
  margin-left: -6%;
}

.wsd-06c__copy {
  font-size: 15px;
  opacity: .76;
  max-width: 52ch;
  margin: 0 auto;
}
```

## JavaScript
```js
/* No JavaScript — a fixed-height strip clipped with clip-path:path(). Note path() units are px, so this variant is intentionally fixed-height. */

/* No JavaScript — a tiled radial-gradient mask carves identical scallops; wider screens get more crests instead of wider ones. */

/* No JavaScript — an over-wide block with an elliptical border-radius pulled up over the previous section makes a dome with zero masking. */
```

How this works

clip-path: path() accepts the same SVG path syntax, but in CSS. The catch: path() coordinates are in pixels, not a viewBox, so it does not stretch — pair it with a fixed-height divider strip, or use clip-path with percentage-based polygon()/ellipse() when you need fluid width.

.divider{height:100px;clip-path:path('M0,40 C360,120 1080,-40 1440,40 L1440,100 L0,100Z')}

mask + repeating radial-gradient is the fully fluid alternative: the gradient tiles at a fixed pitch, so the wave keeps its size and simply repeats more times on wider screens — which is often more attractive than a stretched curve.

Make it yours

  • Change scallop pitch via the mask's background-size (e.g. 56px 34px → 96px 48px).
  • Switch ellipse(100% 60% at 50% 100%) for a single soft dome.
  • Use clip-path on the section itself to avoid an extra element entirely.
  • Animate clip-path between two same-command paths for a morphing edge.

Gotchas — read before shipping

  • path() does not scale — use fixed height or switch to mask/percentages for fluid layouts.
  • Clipping a section clips its box shadow and any absolutely positioned children too.
  • Always ship both -webkit-mask and mask for Safari.
  • Overlap by 1px (margin-top:-1px) so anti-aliasing does not reveal a hairline.

Browser support

ChromeSafariFirefoxEdge
88+ (path()) / 120+ (mask unprefixed)13.1+ with -webkit-mask97+88+ (path()) / 120+ (mask unprefixed)

mask-image is the most portable; clip-path:path() needs Chrome 88+/Safari 13.1+. Without support the strip renders as a straight-edged band — a graceful, non-broken fallback.

Techniques used in this demo

Search CodeFronts

Loading…