SVG Masks and Shape Dividers: Create Stunning Section Transitions in CSS
Flat, horizontal lines between sections are boring. They're the web design equivalent of a plain white wall.
SVG masks and shape dividers transform those transitions into visual opportunities—waves that flow, curves that guide the eye, angles that create energy. And they do it without images, with perfect scalability, and minimal performance impact.
In this guide, you'll learn how to create and implement SVG shape dividers that make your layouts feel dynamic and polished.
What Are SVG Shape Dividers?
Shape dividers are SVG elements positioned between content sections to create non-rectangular transitions. Instead of Section A ending and Section B starting with a hard horizontal line, you get organic shapes that blend the two together.
Common shapes include:
- Waves (single or layered)
- Curves and arcs
- Diagonal angles
- Mountains and peaks
- Custom organic blobs
Why SVGs are perfect for this:
- Scale infinitely without quality loss
- Tiny file sizes (often under 1KB)
- Full CSS control for colors and animations
- No HTTP requests when inlined
- Responsive by default
Basic Implementation
Let's start with a simple wave divider.
The SVG
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider">
<path d="M0,0 C300,100 900,20 1200,100 L1200,120 L0,120 Z" fill="currentColor"/>
</svg>
Let's break down what's happening:
viewBox="0 0 1200 120"- Defines a 1200×120 coordinate systempreserveAspectRatio="none"- Allows the SVG to stretch to fill its container width- The
<path>draws a curve from left to right, then fills down to create a solid shape
The CSS
.section-light {
background: #f4f4f5;
padding: 4rem 2rem;
}
.section-dark {
background: #18181b;
color: white;
padding: 4rem 2rem;
}
.divider {
display: block;
width: 100%;
height: 80px;
color: #18181b; /* The color the divider transitions TO */
}
The HTML Structure
<section class="section-light">
<h2>Light Section Content</h2>
<p>Your content here...</p>
</section>
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider">
<path d="M0,0 C300,100 900,20 1200,100 L1200,120 L0,120 Z" fill="currentColor"/>
</svg>
<section class="section-dark">
<h2>Dark Section Content</h2>
<p>Your content here...</p>
</section>
The divider sits between sections, visually bridging the color change.
Essential Shape Divider Patterns
Here are the most useful divider shapes you'll need.
Simple Wave
A gentle, single-curve wave:
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider wave">
<path d="M0,60 Q300,120 600,60 T1200,60 L1200,120 L0,120 Z" fill="currentColor"/>
</svg>
.wave {
height: 60px;
}
Multi-Layer Waves
Overlapping waves create depth:
<div class="wave-container">
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="wave wave-back">
<path d="M0,40 Q300,100 600,40 T1200,40 L1200,120 L0,120 Z"/>
</svg>
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="wave wave-mid">
<path d="M0,60 Q300,120 600,60 T1200,60 L1200,120 L0,120 Z"/>
</svg>
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="wave wave-front">
<path d="M0,80 Q300,100 600,80 T1200,80 L1200,120 L0,120 Z"/>
</svg>
</div>
.wave-container {
position: relative;
height: 120px;
}
.wave {
position: absolute;
bottom: 0;
width: 100%;
height: 100%;
}
.wave-back { fill: rgba(99, 102, 241, 0.3); }
.wave-mid { fill: rgba(99, 102, 241, 0.5); }
.wave-front { fill: #6366f1; }
Diagonal Angle
Clean, modern diagonal cut:
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider angle">
<polygon points="0,0 1200,120 0,120" fill="currentColor"/>
</svg>
For a steeper angle, adjust the polygon points:
<!-- Steeper angle -->
<polygon points="0,0 1200,80 0,120"/>
<!-- Shallow angle -->
<polygon points="0,60 1200,120 0,120"/>
Curved Arc
Smooth arc transition:
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider curve">
<path d="M0,120 Q600,0 1200,120 Z" fill="currentColor"/>
</svg>
Flip it by changing the curve direction:
<!-- Curve up into next section -->
<path d="M0,0 Q600,120 1200,0 L1200,120 L0,120 Z"/>
Triangle/Arrow
Points toward content:
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider arrow">
<polygon points="0,0 600,120 1200,0 1200,120 0,120" fill="currentColor"/>
</svg>
Mountains/Peaks
Multiple peaks for a dramatic effect:
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider peaks">
<polygon points="0,120 200,40 400,80 600,20 800,60 1000,30 1200,80 1200,120" fill="currentColor"/>
</svg>
Organic Blob
Irregular, natural shape:
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider blob">
<path d="M0,60 C150,120 300,0 450,60 C600,120 750,30 900,80 C1050,130 1150,40 1200,70 L1200,120 L0,120 Z" fill="currentColor"/>
</svg>
Positioning Dividers
Dividers can appear at the top, bottom, or both edges of a section.
Bottom Divider (Most Common)
<section class="section with-bottom-divider">
<div class="content">...</div>
<svg class="divider divider-bottom" viewBox="0 0 1200 120" preserveAspectRatio="none">
<path d="..." fill="currentColor"/>
</svg>
</section>
.section {
position: relative;
}
.divider-bottom {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 80px;
color: #18181b; /* Color of NEXT section */
}
Top Divider
.divider-top {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 80px;
color: #f4f4f5; /* Color of PREVIOUS section */
transform: rotate(180deg);
}
Both Top and Bottom
<section class="section">
<svg class="divider divider-top">...</svg>
<div class="content">...</div>
<svg class="divider divider-bottom">...</svg>
</section>
.section {
position: relative;
padding: 120px 2rem; /* Extra padding for dividers */
}
Flipping and Mirroring
Reuse the same divider shape in different orientations.
Horizontal Flip
.divider-flip-x {
transform: scaleX(-1);
}
Vertical Flip
.divider-flip-y {
transform: scaleY(-1);
}
/* Or use rotation */
.divider-flip-y {
transform: rotate(180deg);
}
Both Axes
.divider-flip-both {
transform: scale(-1, -1);
}
Responsive Divider Heights
Dividers should scale appropriately on different screen sizes.
.divider {
height: 40px;
}
@media (min-width: 640px) {
.divider {
height: 60px;
}
}
@media (min-width: 1024px) {
.divider {
height: 80px;
}
}
@media (min-width: 1280px) {
.divider {
height: 120px;
}
}
Alternatively, use viewport units:
.divider {
height: clamp(40px, 8vw, 120px);
}
Animated Dividers
Add subtle motion to make dividers more dynamic.
Gentle Wave Motion
<svg viewBox="0 0 1200 120" preserveAspectRatio="none" class="divider animated-wave">
<path d="M0,60 Q300,120 600,60 T1200,60 L1200,120 L0,120 Z">
<animate
attributeName="d"
dur="10s"
repeatCount="indefinite"
values="
M0,60 Q300,120 600,60 T1200,60 L1200,120 L0,120 Z;
M0,80 Q300,40 600,80 T1200,80 L1200,120 L0,120 Z;
M0,60 Q300,120 600,60 T1200,60 L1200,120 L0,120 Z
"
/>
</path>
</svg>
CSS Animation Alternative
.animated-wave {
animation: wave-drift 8s ease-in-out infinite;
}
@keyframes wave-drift {
0%, 100% {
transform: translateX(0);
}
50% {
transform: translateX(-2%);
}
}
Parallax Layered Waves
.wave-back {
animation: wave-slow 12s ease-in-out infinite;
}
.wave-mid {
animation: wave-medium 8s ease-in-out infinite;
}
.wave-front {
animation: wave-fast 6s ease-in-out infinite;
}
@keyframes wave-slow {
0%, 100% { transform: translateX(0); }
50% { transform: translateX(-3%); }
}
@keyframes wave-medium {
0%, 100% { transform: translateX(0); }
50% { transform: translateX(-2%); }
}
@keyframes wave-fast {
0%, 100% { transform: translateX(0); }
50% { transform: translateX(-1%); }
}
Respect Motion Preferences
Always disable animations for users who prefer reduced motion:
@media (prefers-reduced-motion: reduce) {
.divider,
.wave-back,
.wave-mid,
.wave-front {
animation: none;
}
}
SVG Masks for Advanced Effects
Beyond simple dividers, SVG masks enable complex clipping effects.
Basic Mask Syntax
.masked-section {
-webkit-mask-image: url('mask.svg');
mask-image: url('mask.svg');
-webkit-mask-size: 100% auto;
mask-size: 100% auto;
-webkit-mask-position: bottom;
mask-position: bottom;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
Inline SVG Mask
.masked-section {
-webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 1200 120' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0,0 L1200,0 L1200,60 Q900,120 600,60 T0,60 Z' fill='white'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 1200 120' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0,0 L1200,0 L1200,60 Q900,120 600,60 T0,60 Z' fill='white'/%3E%3C/svg%3E");
}
Gradient Fade with Mask
Combine SVG mask with CSS gradient:
<section class="hero masked-fade">
<div class="content">Hero Content</div>
</section>
.masked-fade {
position: relative;
}
.masked-fade::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 200px;
background: linear-gradient(to bottom, transparent, #18181b);
-webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 1200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0,0 Q300,100 600,50 T1200,100 L1200,200 L0,200 Z' fill='white'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 1200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0,0 Q300,100 600,50 T1200,100 L1200,200 L0,200 Z' fill='white'/%3E%3C/svg%3E");
}
Creating Custom Shapes
Understanding SVG Path Commands
The d attribute in <path> uses these commands:
| Command | Meaning | Example | |---------|---------|---------| | M | Move to | M0,0 (start at 0,0) | | L | Line to | L100,50 (line to 100,50) | | Q | Quadratic curve | Q50,100 100,50 (curve with control point) | | C | Cubic curve | C20,80 80,80 100,50 (two control points) | | T | Smooth quadratic | T200,50 (continues previous curve) | | Z | Close path | Z (line back to start) |
Wave Generator Formula
Here's a JavaScript function to generate wave paths:
function generateWave(width, height, waves, amplitude) {
const points = [];
const step = width / (waves * 2);
points.push(`M0,${height / 2}`);
for (let i = 0; i <= waves * 2; i++) {
const x = i * step;
const y = i % 2 === 0
? height / 2 - amplitude
: height / 2 + amplitude;
points.push(`Q${x - step / 2},${y} ${x},${height / 2}`);
}
points.push(`L${width},${height} L0,${height} Z`);
return points.join(' ');
}
// Usage: generateWave(1200, 120, 3, 40)
// Creates a 1200x120 wave with 3 peaks and 40px amplitude
Design Tools
For complex custom shapes:
- Design in Figma/Illustrator - Draw your shape with pen tools
- Export as SVG - Copy the path data
- Optimize - Use SVG Minify to clean up
- Test - Use SVG Playground to preview
Or use our AI SVG Generator to create unique organic shapes and export them for use as dividers.
Performance Tips
Keep Paths Simple
Complex paths with hundreds of points render slower:
<!-- Avoid: Over-complicated path -->
<path d="M0,0 C1,2 3,4 5,6 C7,8 9,10 11,12..." /> <!-- 500+ points -->
<!-- Better: Simplified path -->
<path d="M0,60 Q300,120 600,60 T1200,60 L1200,120 L0,120 Z"/>
Use will-change for Animated Dividers
.animated-wave {
will-change: transform;
}
Lazy Load Below-the-Fold Dividers
For pages with many sections, consider lazy loading dividers that aren't immediately visible:
<svg class="divider" data-lazy-svg>
<!-- Path loaded via JavaScript when in viewport -->
</svg>
Browser Support
SVG dividers work in all modern browsers:
- Chrome 4+
- Firefox 3+
- Safari 3.2+
- Edge 12+
- Opera 10+
CSS masks have slightly less support:
- Requires
-webkit-prefix for Safari and older Chrome - IE11 doesn't support CSS masks (use positioned SVGs instead)
Common Mistakes to Avoid
Mistake 1: Forgetting preserveAspectRatio="none"
Without this, your SVG won't stretch to full width:
<!-- Won't stretch properly -->
<svg viewBox="0 0 1200 120">
<!-- Will stretch to fill container -->
<svg viewBox="0 0 1200 120" preserveAspectRatio="none">
Mistake 2: Wrong Color Direction
Remember: the divider color should match where you're transitioning TO, not from:
/* Transitioning FROM light TO dark */
.divider {
color: #18181b; /* The dark color, not the light one */
}
Mistake 3: Z-Index Issues
Dividers can get hidden behind content:
.section {
position: relative;
z-index: 1;
}
.divider {
position: relative;
z-index: 2;
}
Mistake 4: Not Accounting for Divider Height
Sections need padding to prevent content overlap:
.section-with-divider {
padding-bottom: calc(4rem + 80px); /* Regular padding + divider height */
}
Complete Example
Here's a full implementation:
<!DOCTYPE html>
<html>
<head>
<style>
* { margin: 0; box-sizing: border-box; }
.section {
position: relative;
padding: 6rem 2rem;
}
.section-hero {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
color: white;
min-height: 60vh;
display: flex;
align-items: center;
justify-content: center;
}
.section-features {
background: #fafafa;
}
.section-cta {
background: #18181b;
color: white;
}
.divider {
position: absolute;
left: 0;
width: 100%;
height: clamp(40px, 8vw, 100px);
display: block;
}
.divider-bottom {
bottom: 0;
}
.divider-top {
top: 0;
transform: rotate(180deg);
}
@media (prefers-reduced-motion: reduce) {
.divider { animation: none; }
}
</style>
</head>
<body>
<section class="section section-hero">
<h1>Welcome to Our Site</h1>
<svg class="divider divider-bottom" viewBox="0 0 1200 120" preserveAspectRatio="none">
<path d="M0,0 C300,120 900,0 1200,100 L1200,120 L0,120 Z" fill="#fafafa"/>
</svg>
</section>
<section class="section section-features">
<h2>Features</h2>
<svg class="divider divider-bottom" viewBox="0 0 1200 120" preserveAspectRatio="none">
<path d="M0,60 L600,120 L1200,60 L1200,120 L0,120 Z" fill="#18181b"/>
</svg>
</section>
<section class="section section-cta">
<h2>Get Started Today</h2>
</section>
</body>
</html>
Tools for Creating Shape Dividers
Design
- AI SVG Generator - Create custom organic shapes
- SVG Editor - Fine-tune divider paths
- SVG Playground - Preview and test dividers
Optimization
- SVG Minify - Reduce divider file sizes
- SVG Color Changer - Quickly adjust divider colors
Conversion
- SVG to React - Convert dividers to React components
Key Takeaways
- SVGs are ideal for dividers - Infinitely scalable, tiny file sizes, full CSS control
preserveAspectRatio="none"is essential - Without it, dividers won't stretch properly- Match colors to the destination - The divider takes the color of the section it transitions INTO
- Account for height in padding - Prevent content from overlapping dividers
- Animate with care - Subtle motion adds polish; excessive animation distracts
- Respect accessibility - Always support
prefers-reduced-motion
Shape dividers are one of those details that separate amateur layouts from professional ones. They're simple to implement but make a significant visual impact.
Related Articles: