Shape-Aware Shadows
box-shadow, border, and outline hug clip-path polygons via border-shape — pointed tag, notched ticket, chat bubble — with universal drop-shadow fallback.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Cards has 41 effects, including 6 free. Explore the category →
3 usage examples
How it works
The classic clip-path problem: the cut looks perfect, but box-shadow and border stay rectangular — the shadow bleeds outside the cut edges or disappears into the clipped zones. border-shape fixes this by redefining the CSS box model: the border, shadow, and outline follow the declared polygon as if the clipped shape were the box itself.
The effect defines three shapes via clip-path: polygon(…) on the .bsc-card--tag, .bsc-card--ticket, and .bsc-card--bubble variants. In supporting browsers — detected by @supports (border-shape: polygon(…)) — clip-path is cleared and replaced by border-shape with the same polygon. border and box-shadow then follow the exact geometry: a rim on the tag arrow, a shadow hugging the ticket notches, a drop beneath the bubble tail.
The fallback lives on the base .bsc-card rule: filter: drop-shadow() already follows the clip-path contour natively in all browsers. Inside the @supports block, filter is cleared (filter: none) to hand off to native box-shadow — a clean handoff with no double shadow. No JS errors, no visible degradation on Firefox or Safari.
The JS bound to #bscTag demonstrates the mechanic live: a click cycles through three polygons in the shapes[] array (left arrow, right arrow, rectangle) and updates either clipPath or borderShape depending on detected support. The shadow and border recalculate their geometry instantly — which is impossible to achieve with clip-path alone.
Accessibility
- prefers-reduced-motion: present in the CSS —
transition: noneandtransform: noneon hover cancel all animation when the OS signals a reduced-motion preference. - The
#bscTagbutton is a native<button>witharia-label="Carte étiquette — cliquer pour changer de forme"— activatable by keyboard (Enter/Space), in the normal tab order. :focus-visibleapplies a purple2px solid #a78bfaoutline withoutline-offset: 4pxon all focusable.bsc-cardelements.- Text contrast: white on the tag's purple gradient (#7c3aed → #db2777) reaches a ratio ≥ 5.5:1 — WCAG AA compliant.
- The ticket and bubble variants are non-interactive
<div>elements — no additionalroleortabindexneeded; only the tag (native button) is interactive.
Browser compatibility
border-shape is a cutting-edge CSS property detected by @supports. The drop-shadow + clip-path fallback covers all modern browsers without errors.
filter: drop-shadow() on .bsc-card already follows the clip-path contour natively. It is only cleared in the @supports block where box-shadow takes over — shapes remain visually clean on any browser without border-shape.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="demo-preview">
<div class="bsc-scene">
<!-- Pointed tag — click cycles shapes (bscTag required) -->
<button class="bsc-card bsc-card--tag" id="bscTag" type="button"
aria-label="Tag card — click to cycle shapes">
<span class="bsc-price">-40%</span>
<span class="bsc-label">Summer sale</span>
</button>
<!-- Notched ticket -->
<div class="bsc-card bsc-card--ticket">
<div class="bsc-ticket-main">
CONCERT
<span>Row F · Seat 12</span>
</div>
<div class="bsc-ticket-stub">A-12</div>
</div>
<!-- Chat bubble with bottom tail -->
<div class="bsc-card bsc-card--bubble">
<p>Your text here.</p>
</div>
</div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| clip-path / border-shape (polygon) | shape-specific polygon per variant | Define your geometry in clip-path (fallback) and paste the same value into border-shape (@supports). Both must stay in sync for consistent rendering. |
| background: linear-gradient(…) | purple/pink — navy/blue — teal | Each variant has its own gradient. Replace the color stops for your brand palette without touching the geometry. |
| filter: drop-shadow(…) (base) | 0 10px 22px rgba(0,0,0,.55) | Fallback shadow on .bsc-card (browsers without border-shape). Freely adjust offset, blur, and color. |
| box-shadow (@supports) | 0 10px 26px rgba(0,0,0,.55) + purple hover glow | Native shadow in border-shape browsers. Independent of filter; can take a tinted color for a brand glow on hover. |
| border (@supports) | 1.5px solid rgba(255,255,255,.22–.35) | Visible border only with border-shape (otherwise clip-path cuts it off). Opacity varies by variant: 0.35 tag, 0.22 ticket, 0.30 bubble. |
| shapes[] (JS, array ~line 7) | 3 polygons: left arrow, right arrow, rectangle | Shapes cycled on click on #bscTag. Add or remove polygons to extend the demo or lock to a single fixed shape. |
| transition (hover) | .35s cubic-bezier(.2,.9,.3,1.4) | Duration and easing of the translateY(-6px) and shadow change. Set to 0 in contexts where animation is unwanted. |
FAQ
clip-path, filter: drop-shadow already follows the cut — that's the fallback. But border and outline stay rectangular (clip-path simply cuts them off), and multi-layer or inset box-shadow is unavailable. border-shape redefines the box model: border, outline, and box-shadow (with multi-layer, inset, and color support) all follow the polygon geometry.clip-path: polygon(…) on the card variant, then paste the exact same value into border-shape inside the @supports block. The demo JS also syncs this polygon in the shapes[] array. To draw coordinates visually, use Firefox DevTools (built-in clip-path editor) or bennettfeely.com/clippy/.filter: drop-shadow() to .bsc-card and clip-path to each variant — a combination supported in all modern browsers. The @supports block progressively enhances the experience (native border + box-shadow) without ever breaking the fallback. The effect remains visually clean in Firefox and Safari.