The Magic of Clip Path
clip-path is often used for trimming elements into specific shapes, like triangles and circles. But what if I told you that it's also great for animations?
In this lesson, we'll dive into clip-path and explore some of the cool things you can do with it. Once you read it, you'll start seeing this CSS property being used everywhere.
The Basics
The clip-path property clips an element into a specific shape. We create a clipping region, and content outside this region becomes invisible while content inside stays visible. This lets us turn a rectangle into a circle, for example.
.avatar {
clip-path: circle(50%);
}Here's the key insight: clip-path has no effect on layout. An element with clip-path occupies the same space as it would without it, just like transform. The element is still there—we're just hiding parts of it.
Positioning with Coordinates
We position shapes using a coordinate system that starts at the top left corner (0, 0).
.element {
clip-path: circle(50% at 50% 50%);
}This means: create a circle with radius 50%, positioned at 50% from the left and 50% from the top (the center).
You can position the circle anywhere:
.element {
/* Circle in top-left corner */
clip-path: circle(30% at 0% 0%);
/* Circle in bottom-right corner */
clip-path: circle(30% at 100% 100%);
}Shape Functions
CSS provides several shape functions for clip-path:
circle() — Creates circular clips
.element {
clip-path: circle(50%); /* Fills the element */
clip-path: circle(100px at center); /* Fixed size */
}ellipse() — Creates oval clips
.element {
clip-path: ellipse(50% 30% at center);
}polygon() — Creates any shape with points
/* Triangle */
.element {
clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
}
/* Hexagon */
.element {
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
}inset() — Creates rectangular clips with offsets
This is the most powerful shape for animations. The values define how much to cut from each side: top, right, bottom, left.
.element {
/* No clipping - show everything */
clip-path: inset(0);
/* Hide everything */
clip-path: inset(100%);
/* Hide right half */
clip-path: inset(0 50% 0 0);
/* Hide left half */
clip-path: inset(0 0 0 50%);
/* Hide top half */
clip-path: inset(50% 0 0 0);
/* 10px border on all sides */
clip-path: inset(10px);
/* Rounded corners */
clip-path: inset(0 round 16px);
}The inset() function is what we'll use for animations. It lets us precisely control which parts of an element are visible.
Why Inset is Perfect for Animation
Think about what inset(0 50% 0 0) means: cut 0 from top, 50% from right, 0 from bottom, 0 from left. This hides the right half.
Now, if we animate from inset(0 100% 0 0) to inset(0 0 0 0), we reveal the element from left to right:
.reveal {
clip-path: inset(0 100% 0 0); /* Start: fully hidden from right */
transition: clip-path 0.5s ease;
}
.reveal.active {
clip-path: inset(0 0 0 0); /* End: fully visible */
}This is the foundation of clip-path animations: we animate the clipping region to reveal or hide content.
Building a Comparison Slider
Let's apply this knowledge. Comparison sliders show "before" and "after" by overlaying two images.
The technique:
- Stack two images on top of each other using
position: absolute - Apply
clip-path: inset(0 50% 0 0)to the top image to hide its right half - Adjust the inset value based on drag position
.comparison {
position: relative;
}
.comparison .after {
position: absolute;
inset: 0;
clip-path: inset(0 50% 0 0); /* Hide right half */
transition: clip-path 0.1s ease;
}When the user drags, we calculate the percentage and update the clip-path:
// If user drags to 30% from left
afterImage.style.clipPath = 'inset(0 70% 0 0)';This approach is hardware-accelerated and doesn't require extra DOM elements. The clipped image stays in place—we're just revealing more or less of it.
The Overlay Technique
Here's where it gets interesting. Instead of clipping a single element, we can overlay two identical elements and clip one to create highlight effects.
Imagine a row of tabs. The inactive state is gray text on a transparent background. The active state is white text on a blue background. Instead of changing styles on click, we:
- Render the tabs twice, stacked on top of each other
- The bottom layer shows the inactive state (gray text)
- The top layer shows the active state (white text on blue background)
- We clip the top layer to only show the active tab
<div class="tabs-wrapper">
<!-- Bottom layer: inactive appearance -->
<div class="tabs">
<button>Payments</button>
<button>Balances</button>
<button>Customers</button>
</div>
<!-- Top layer: active appearance, clipped -->
<div class="tabs tabs-active" style="clip-path: inset(0 75% 0 0 round 17px)">
<button>Payments</button>
<button>Balances</button>
<button>Customers</button>
</div>
</div>The top layer is positioned absolutely over the bottom layer. The clip-path only reveals the portion covering the active tab. When the user clicks a different tab, we animate the clip-path to slide over to the new tab.
This creates a smooth, fluid highlight effect that feels like a physical indicator sliding between tabs.
Calculating the Clip Path
To clip the overlay to exactly cover one tab, we need to calculate the tab's position:
function updateClipPath(activeTab) {
const container = document.querySelector('.tabs-active');
const containerWidth = container.offsetWidth;
// Get the active tab's position
const tabLeft = activeTab.offsetLeft;
const tabWidth = activeTab.offsetWidth;
const tabRight = tabLeft + tabWidth;
// Convert to percentages
const clipLeft = (tabLeft / containerWidth) * 100;
const clipRight = 100 - (tabRight / containerWidth) * 100;
// Apply the clip-path
container.style.clipPath = `inset(0 ${clipRight}% 0 ${clipLeft}% round 17px)`;
}The math:
clipLeft: How much to cut from the left (as a percentage)clipRight: How much to cut from the right (as a percentage)round 17px: Adds rounded corners to the clipped region
When combined with a CSS transition, the clip-path smoothly animates from one tab to another:
.tabs-active {
transition: clip-path 0.25s ease;
}Why This Technique Works
The overlay technique has several advantages:
- GPU-accelerated:
clip-pathanimations run on the compositor thread - No layout shifts: Elements don't move or resize
- Smooth color transitions: The active state "slides" into view rather than snapping
- Works with any content: Icons, text, badges—everything gets the treatment
The key insight is that we're not changing the tabs themselves. We're revealing and hiding a pre-styled overlay. This separation makes the animation buttery smooth.
Performance Considerations
clip-path is generally performant, but keep these tips in mind:
- Use simple shapes:
inset()andcircle()are faster than complexpolygon()shapes - Avoid clipping large areas: Clipping a small element is cheaper than clipping a full-page section
- Test on mobile: Some older devices struggle with
clip-pathanimations
Other Visual Effects
While clip-path is powerful for animations, CSS offers other visual effects worth knowing:
Transforms
Move, rotate, scale, and skew elements without affecting layout:
.element {
transform: translateX(100px) rotate(45deg) scale(1.2);
transform-origin: center; /* Pivot point */
}Transforms are GPU-accelerated and ideal for hover effects and animations.
Filters
Apply visual effects like blur and brightness:
.element {
filter: blur(5px);
filter: brightness(1.2) contrast(1.1);
filter: grayscale(100%);
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1));
}Backdrop Filter
Apply filters to content behind an element (frosted glass effect):
.glass-panel {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
}Masks
Hide parts of elements using images or gradients:
.fade-out {
mask-image: linear-gradient(to bottom, black 70%, transparent);
}Masks work with any content, unlike gradient overlays which require knowing the background color.
Check Your Understanding
What does clip-path: inset(0 50% 0 0) do?
Why is the overlay technique effective for tab animations?
What's the advantage of clip-path animations over width/height animations?
Practice
Build a tab component that uses the overlay technique. The icons and basic structure are provided—your job is to implement the clip-path animation that slides between tabs.
Summary
- clip-path basics: Clips elements into shapes without affecting layout
- inset() function: Defines rectangular clips with top, right, bottom, left offsets
- Animation foundation: Animate from
inset(0 100% 0 0)toinset(0)to reveal content - Overlay technique: Stack two identical elements, clip the styled one to create sliding highlights
- Calculating position: Use
offsetLeftandoffsetWidthto compute clip percentages - Performance:
clip-pathis GPU-accelerated; preferinset()over complex polygons - Transitions: Add
transition: clip-path 0.25s easefor smooth animations - Round corners: Use
inset(... round Xpx)for rounded clip regions