Pure TailwindMIT licensed

Tailwind Stacked Multi Color SVG Wave Section Divider

Two or three offset waves in tinted layers, so a change of background colour reads as depth instead of a line. The port replaces a ladder of :nth-child() + color-mix() rules with an opacity modifier on each layer’s own fill-* utility.

Live Demo
Plain CSSTailwind v4
Try it

Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49

Cruip · Affiliate link

Browse Cruip templates

The code

<section class="twd-04 w-full min-h-svh flex flex-col font-twd04-sans">

  <!-- Three tinted layers -->
  <div class="relative overflow-hidden bg-twd04-from text-white px-6 pt-18 pb-32 text-center">
    <h2 class="text-[clamp(25px,4vw,38px)] font-semibold">Layered depth, one hue</h2>
    <div aria-hidden="true" class="absolute inset-x-0 -bottom-px h-[clamp(70px,11vw,130px)] pointer-events-none">
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-to/30" viewBox="0 0 1440 130" preserveAspectRatio="none" focusable="false"><path d="M0,70 C260,20 520,120 780,74 C1040,28 1240,60 1440,40 L1440,130 L0,130 Z"></path></svg>
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-to/62" viewBox="0 0 1440 130" preserveAspectRatio="none" focusable="false"><path d="M0,86 C240,44 500,126 760,88 C1020,50 1250,96 1440,66 L1440,130 L0,130 Z"></path></svg>
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-to" viewBox="0 0 1440 130" preserveAspectRatio="none" focusable="false"><path d="M0,100 C220,70 480,132 740,102 C1000,72 1250,120 1440,92 L1440,130 L0,130 Z"></path></svg>
    </div>
  </div>
  <div class="bg-twd04-to text-twd04-toink px-6 pt-8 pb-16 text-center">
    <p class="text-[15px]">Back layers are stepped tints of one hue; only the front layer is opaque.</p>
  </div>

  <!-- Duotone offset ribbons -->
  <div class="relative overflow-hidden bg-twd04-navy text-white px-6 pt-17 pb-29 text-center">
    <h2 class="text-[clamp(25px,4vw,38px)] font-semibold">Two-colour ribbon seam</h2>
    <div aria-hidden="true" class="absolute inset-x-0 -bottom-px h-[clamp(64px,10vw,120px)] pointer-events-none">
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-accent" viewBox="0 0 1440 120" preserveAspectRatio="none" focusable="false"><path d="M0,54 C300,110 620,6 940,52 C1160,84 1300,92 1440,62 L1440,120 L0,120 Z"></path></svg>
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-shell" viewBox="0 0 1440 120" preserveAspectRatio="none" focusable="false"><path d="M0,74 C300,126 620,22 940,70 C1160,102 1300,110 1440,80 L1440,120 L0,120 Z"></path></svg>
    </div>
  </div>
  <div class="bg-twd04-shell text-twd04-navyink px-6 pt-8 pb-15 text-center">
    <p class="text-[15px] max-w-[52ch] mx-auto">An accent ribbon peeks out from under the opaque edge &mdash; brand colour, no extra markup weight.</p>
  </div>

</section>
@import "tailwindcss";

@theme {
  --color-twd04-from: #443a77;
  --color-twd04-from: oklch(0.34 0.12 285);
  --color-twd04-to: #eeeaf7;
  --color-twd04-to: oklch(0.95 0.03 285);
  --color-twd04-toink: #4a4173;
  --color-twd04-toink: oklch(0.4 0.09 285);
  --color-twd04-navy: #17323c;
  --color-twd04-navy: oklch(0.24 0.04 200);
  --color-twd04-navyink: #2b4b57;
  --color-twd04-navyink: oklch(0.38 0.05 200);
  --color-twd04-shell: #f6f9fa;
  --color-twd04-shell: oklch(0.97 0.01 200);
  --color-twd04-accent: #e0a92c;
  --color-twd04-accent: oklch(0.75 0.17 88);
  --font-twd04-sans: 'Space Grotesk', system-ui, sans-serif;
}

.twd-04 {
  width: 100%;
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-twd04-from: #443a77;
  --color-twd04-from: oklch(0.34 0.12 285);
  --color-twd04-to: #eeeaf7;
  --color-twd04-to: oklch(0.95 0.03 285);
  --color-twd04-toink: #4a4173;
  --color-twd04-toink: oklch(0.4 0.09 285);
  --color-twd04-navy: #17323c;
  --color-twd04-navy: oklch(0.24 0.04 200);
  --color-twd04-navyink: #2b4b57;
  --color-twd04-navyink: oklch(0.38 0.05 200);
  --color-twd04-shell: #f6f9fa;
  --color-twd04-shell: oklch(0.97 0.01 200);
  --color-twd04-accent: #e0a92c;
  --color-twd04-accent: oklch(0.75 0.17 88);
  --font-twd04-sans: 'Space Grotesk', system-ui, sans-serif;
}

.twd-04 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • .layer:nth-child(2) path{fill:color-mix(in oklab,var(--to) 62%,transparent)} becomes fill-twd04-to/62. This is the clearest single-line improvement in the whole port: the tint ladder is now visible as a ladder.
  • Because the layers are <svg> elements rather than paths, fill-* works directly and no [&_path]: variant is needed — fill inherits into the path.
  • No z-index utilities appear anywhere. DOM order is the stacking order for positioned siblings, and spelling it out would only create something to keep in sync.
  • UI change from the CSS original: the caption under each stack was opacity:.75 mid-grey on near-white, roughly 3.4:1. Both now use dedicated full-opacity ink tokens (--color-twd04-toink, --color-twd04-navyink) that clear 4.5:1.
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 demo 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: Tailwind Stacked Multi Color SVG Wave Section Divider
Source: https://codefronts.com/layouts/tailwind-css-wave-section-dividers/tailwind-stacked-multi-color-svg-wave-section-divider/

Two or three offset waves in tinted layers, so a change of background colour reads as depth instead of a line. The port replaces a ladder of :nth-child() + color-mix() rules with an opacity modifier on each layer&rsquo;s own fill-* utility.
## HTML
```html
<section class="twd-04 w-full min-h-svh flex flex-col font-twd04-sans">

  <!-- Three tinted layers -->
  <div class="relative overflow-hidden bg-twd04-from text-white px-6 pt-18 pb-32 text-center">
    <h2 class="text-[clamp(25px,4vw,38px)] font-semibold">Layered depth, one hue</h2>
    <div aria-hidden="true" class="absolute inset-x-0 -bottom-px h-[clamp(70px,11vw,130px)] pointer-events-none">
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-to/30" viewBox="0 0 1440 130" preserveAspectRatio="none" focusable="false"><path d="M0,70 C260,20 520,120 780,74 C1040,28 1240,60 1440,40 L1440,130 L0,130 Z"></path></svg>
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-to/62" viewBox="0 0 1440 130" preserveAspectRatio="none" focusable="false"><path d="M0,86 C240,44 500,126 760,88 C1020,50 1250,96 1440,66 L1440,130 L0,130 Z"></path></svg>
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-to" viewBox="0 0 1440 130" preserveAspectRatio="none" focusable="false"><path d="M0,100 C220,70 480,132 740,102 C1000,72 1250,120 1440,92 L1440,130 L0,130 Z"></path></svg>
    </div>
  </div>
  <div class="bg-twd04-to text-twd04-toink px-6 pt-8 pb-16 text-center">
    <p class="text-[15px]">Back layers are stepped tints of one hue; only the front layer is opaque.</p>
  </div>

  <!-- Duotone offset ribbons -->
  <div class="relative overflow-hidden bg-twd04-navy text-white px-6 pt-17 pb-29 text-center">
    <h2 class="text-[clamp(25px,4vw,38px)] font-semibold">Two-colour ribbon seam</h2>
    <div aria-hidden="true" class="absolute inset-x-0 -bottom-px h-[clamp(64px,10vw,120px)] pointer-events-none">
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-accent" viewBox="0 0 1440 120" preserveAspectRatio="none" focusable="false"><path d="M0,54 C300,110 620,6 940,52 C1160,84 1300,92 1440,62 L1440,120 L0,120 Z"></path></svg>
      <svg class="absolute inset-x-0 bottom-0 block w-full h-full fill-twd04-shell" viewBox="0 0 1440 120" preserveAspectRatio="none" focusable="false"><path d="M0,74 C300,126 620,22 940,70 C1160,102 1300,110 1440,80 L1440,120 L0,120 Z"></path></svg>
    </div>
  </div>
  <div class="bg-twd04-shell text-twd04-navyink px-6 pt-8 pb-15 text-center">
    <p class="text-[15px] max-w-[52ch] mx-auto">An accent ribbon peeks out from under the opaque edge &mdash; brand colour, no extra markup weight.</p>
  </div>

</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-twd04-from: #443a77;
  --color-twd04-from: oklch(0.34 0.12 285);
  --color-twd04-to: #eeeaf7;
  --color-twd04-to: oklch(0.95 0.03 285);
  --color-twd04-toink: #4a4173;
  --color-twd04-toink: oklch(0.4 0.09 285);
  --color-twd04-navy: #17323c;
  --color-twd04-navy: oklch(0.24 0.04 200);
  --color-twd04-navyink: #2b4b57;
  --color-twd04-navyink: oklch(0.38 0.05 200);
  --color-twd04-shell: #f6f9fa;
  --color-twd04-shell: oklch(0.97 0.01 200);
  --color-twd04-accent: #e0a92c;
  --color-twd04-accent: oklch(0.75 0.17 88);
  --font-twd04-sans: 'Space Grotesk', system-ui, sans-serif;
}

.twd-04 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Each layer is its own absolutely positioned SVG in the same stacking container, filled with a stepped opacity of the destination colour. Because every tint is the same hue, the stack stays harmonious rather than looking like three unrelated ribbons.

<svg class="absolute inset-0 fill-twd04-to/30">…
<svg class="absolute inset-0 fill-twd04-to/62">…
<svg class="absolute inset-0 fill-twd04-to">…   <!-- opaque, last, joins the next section -->

Only the last layer is opaque, and it is the one that actually meets the next section, so the seam is solid no matter how the tints resolve. The duotone variant is the same idea with two layers and a 20px offset, so only a sliver of brand colour shows.

Make it yours

  • Two layers for restraint, three for a brochure feel; past four it turns to mush.
  • Shift each layer with bottom-1.5 … bottom-3.5 to control how much peeks out.
  • Use different paths per layer rather than one path offset — identical paths read mechanical.
  • Retint by editing --color-twd04-to only; every modifier follows.

Gotchas — read before shipping

  • The topmost layer must be fully opaque, or the previous section shows through the seam.
  • Let DOM order do the stacking. Adding z-index to absolute siblings inside one container is how these stacks start fighting.
  • Step one hue. Mixing unrelated hues at 30% and 62% produces mud, not depth.
  • Every layer needs pointer-events-none — three stacked layers over a CTA is three chances to eat the click.
  • fill-*/62 is an alpha on the paint, not an opacity on the element: do not reach for opacity-60, which would also fade a stroke or a filter.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Tailwind's opacity modifiers compile to color-mix(), which is exactly what the CSS original wrote by hand — so the support floor is unchanged from the hand-written version.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Search CodeFronts

Loading…