12 / 20
All 20 in 20 CSS SVG Stroke Buttons
- 01SVG Stroke Draw Button Border on Hover
- 02Stroke Dashoffset Button Outline Animation
- 03Corner Start Perimeter Draw Button
- 04Two Path Split Border Draw Button
- 05Rounded Rect Stroke Button with rx Radius
- 06Dashed Marching Ants Button Border
- 07Gradient Stroke Button with SVG linearGradient
- 08Stroke Draw Button That Reverses on Mouse Leave
- 09Focus Visible Stroke Outline for Keyboard Users
- 10Non Scaling Stroke Button That Resizes with Text
- 11Stroke Draw Button with pathLength Normalization
- 12Dual Layer Stroke Button with Offset Trailing Path
- 13Sequential Stroke and Label Fade Button
- 14Icon Plus Border Stroke Draw Together
- 15Stroke Draw Submit Button Loading State
- 16Stroke Draw Button Disabled and Error States
- 17Scroll Triggered Button Stroke with animation-timeline
- 18Stroke Draw Button Group with Staggered Delay
- 19Reduced Motion Fallback for Stroke Buttons
- 20Variable Width Stroke Button with Text Length
Dual Layer Stroke Button with Offset Trailing Path
A telemetry panel where the lap button is a skewed blade, not a rectangle, and its outline is drawn twice: a crisp 2px leader and a wide, blurred follower running 90ms behind it. The gap between them opens mid-draw and closes at the end, which the eye reads as speed rather than as two separate lines.
Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149
Nucleo · Affiliate link
The code
<section class="svgb-12">
<input class="svgb-12__ti" type="checkbox" id="svgb-12-theme">
<label class="svgb-12__toggle" for="svgb-12-theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="svgb-12__sr">Switch colour scheme</span>
</label>
<div class="svgb-12__stage">
<div class="svgb-12__panel">
<div class="svgb-12__telem">
<div class="svgb-12__t"><span class="svgb-12__tk">Lap</span><span class="svgb-12__tv">14</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Delta</span><span class="svgb-12__tv svgb-12__tv--good">-0.412</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Tyre</span><span class="svgb-12__tv">C3 · 62%</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">ERS</span><span class="svgb-12__tv">2.1 MJ</span></div>
</div>
<button class="svgb-12__blade" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__trail" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__lead" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Push lap</span>
</button>
<button class="svgb-12__blade svgb-12__blade--comet" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__comet" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__spark" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Deploy overtake</span>
</button>
<p class="svgb-12__note">leader 620ms · trail 800ms + 90ms · paint order: trail first</p>
</div>
</div>
</section><section class="svgb-12">
<input class="svgb-12__ti" type="checkbox" id="svgb-12-theme">
<label class="svgb-12__toggle" for="svgb-12-theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="svgb-12__sr">Switch colour scheme</span>
</label>
<div class="svgb-12__stage">
<div class="svgb-12__panel">
<div class="svgb-12__telem">
<div class="svgb-12__t"><span class="svgb-12__tk">Lap</span><span class="svgb-12__tv">14</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Delta</span><span class="svgb-12__tv svgb-12__tv--good">-0.412</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Tyre</span><span class="svgb-12__tv">C3 · 62%</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">ERS</span><span class="svgb-12__tv">2.1 MJ</span></div>
</div>
<button class="svgb-12__blade" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__trail" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__lead" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Push lap</span>
</button>
<button class="svgb-12__blade svgb-12__blade--comet" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__comet" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__spark" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Deploy overtake</span>
</button>
<p class="svgb-12__note">leader 620ms · trail 800ms + 90ms · paint order: trail first</p>
</div>
</div>
</section>@import url('https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
.svgb-12 {
--svgb-12-bg: #08090a;
--svgb-12-bg: oklch(0.145 0.002 250);
--svgb-12-fg: #edeff1;
--svgb-12-fg: oklch(0.95 0.003 250);
--svgb-12-muted: #83878d;
--svgb-12-muted: oklch(0.645 0.008 250);
--svgb-12-rest: rgba(237, 239, 241, 0.14);
--svgb-12-rest: oklch(0.95 0.003 250 / 0.14);
--svgb-12-stroke: #00e5ff;
--svgb-12-stroke: oklch(0.85 0.15 205);
--svgb-12-good: #7cff8f;
--svgb-12-good: oklch(0.89 0.18 145);
--svgb-12-blend: screen;
position: relative;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--svgb-12-bg);
color: var(--svgb-12-fg);
font-family: 'Saira Condensed', system-ui, sans-serif;
overflow: hidden;
}
.svgb-12 *,
.svgb-12 *::before,
.svgb-12 *::after {
box-sizing: border-box;
}
.svgb-12::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), radial-gradient(70% 60% at 50% 40%, color-mix(in oklab, var(--svgb-12-stroke) 8%, transparent), transparent 70%);
}
.svgb-12__stage {
position: relative;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(22px, 5vw, 70px);
}
.svgb-12__panel {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: clamp(16px, 3vw, 26px);
width: 100%;
max-width: 420px;
}
.svgb-12__telem {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px 20px;
width: 100%;
}
.svgb-12__t {
display: flex;
flex-direction: column;
gap: 2px;
padding-block-end: 8px;
border-block-end: 1px solid var(--svgb-12-rest);
}
.svgb-12__tk {
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 9.5px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--svgb-12-muted);
}
.svgb-12__tv {
font-size: 26px;
font-weight: 700;
font-style: italic;
letter-spacing: -0.01em;
font-variant-numeric: tabular-nums;
}
.svgb-12__tv--good {
color: var(--svgb-12-good);
}
.svgb-12__blade {
position: relative;
inline-size: min(340px, 92vw);
block-size: 78px;
display: grid;
place-items: center;
border: 0;
padding: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 20px;
font-weight: 600;
font-style: italic;
letter-spacing: 0.1em;
text-transform: uppercase;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
isolation: isolate;
}
.svgb-12__btext {
position: relative;
z-index: 2;
transition: color 300ms ease, letter-spacing 400ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__btext,
.svgb-12__blade:focus-visible .svgb-12__btext {
color: var(--svgb-12-stroke);
letter-spacing: 0.16em;
}
.svgb-12__blade:focus-visible {
outline: none;
box-shadow: 0 0 0 3px color-mix(in oklab, var(--svgb-12-stroke) 34%, transparent);
}
.svgb-12__frame {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
overflow: visible;
}
.svgb-12__frame path {
fill: none;
stroke-linejoin: miter;
}
.svgb-12__base {
stroke: var(--svgb-12-rest);
stroke-width: 1.4px;
}
.svgb-12__trail {
stroke: var(--svgb-12-stroke);
stroke-width: 7px;
opacity: 0.36;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 10px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 800ms cubic-bezier(0.22, 1, 0.36, 1) 90ms;
}
.svgb-12__lead {
stroke: var(--svgb-12-stroke);
stroke-width: 2px;
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 620ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__trail,
.svgb-12__blade:focus-visible .svgb-12__trail,
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
stroke-dashoffset: 0;
}
.svgb-12__comet {
stroke: var(--svgb-12-stroke);
stroke-width: 6px;
opacity: 0.32;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 12px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 0.16 0.84;
stroke-dashoffset: 0.16;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__spark {
stroke: var(--svgb-12-fg);
stroke-width: 2.4px;
stroke-dasharray: 0.045 0.955;
stroke-dashoffset: 0.045;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__blade--comet:hover .svgb-12__comet,
.svgb-12__blade--comet:focus-visible .svgb-12__comet {
stroke-dashoffset: -0.84;
}
.svgb-12__blade--comet:hover .svgb-12__spark,
.svgb-12__blade--comet:focus-visible .svgb-12__spark {
stroke-dashoffset: -0.955;
}
.svgb-12__note {
margin: 0;
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 10.5px;
letter-spacing: 0.04em;
color: var(--svgb-12-muted);
}
.svgb-12__ti {
position: absolute;
opacity: 0;
pointer-events: none;
}
.svgb-12__toggle {
position: absolute;
z-index: 5;
inset-block-start: 16px;
inset-inline-end: 16px;
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border-radius: 4px;
border: 1px solid color-mix(in oklab, currentColor 22%, transparent);
background: color-mix(in oklab, currentColor 8%, transparent);
color: inherit;
cursor: pointer;
transition: background 160ms ease, transform 160ms ease;
}
.svgb-12__toggle:hover {
background: color-mix(in oklab, currentColor 15%, transparent);
}
.svgb-12__toggle:active {
transform: scale(0.94);
}
.svgb-12__toggle svg {
inline-size: 18px;
block-size: 18px;
transition: transform 400ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.svgb-12__ti:checked + .svgb-12__toggle svg {
transform: rotate(180deg);
}
.svgb-12__ti:focus-visible + .svgb-12__toggle {
outline: 2px solid currentColor;
outline-offset: 3px;
}
.svgb-12__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.svgb-12:has(#svgb-12-theme:checked) {
--svgb-12-bg: #f1f2f4;
--svgb-12-bg: oklch(0.955 0.003 250);
--svgb-12-fg: #101214;
--svgb-12-fg: oklch(0.185 0.004 250);
--svgb-12-muted: #555a60;
--svgb-12-muted: oklch(0.49 0.008 250);
--svgb-12-rest: rgba(16, 18, 20, 0.16);
--svgb-12-rest: oklch(0.185 0.004 250 / 0.16);
--svgb-12-stroke: #00647f;
--svgb-12-stroke: oklch(0.45 0.11 215);
--svgb-12-good: #0d6b2c;
--svgb-12-good: oklch(0.46 0.14 148);
--svgb-12-blend: multiply;
}
.svgb-12:has(#svgb-12-theme:checked)::before {
background: repeating-linear-gradient(45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px);
}
@media (prefers-reduced-motion: reduce) {
.svgb-12__trail,
.svgb-12__lead,
.svgb-12__comet,
.svgb-12__spark,
.svgb-12__btext {
transition: none;
filter: none;
}
.svgb-12__trail,
.svgb-12__comet,
.svgb-12__spark {
opacity: 0;
}
.svgb-12__lead {
stroke-dasharray: none;
stroke-dashoffset: 0;
opacity: 0;
}
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
opacity: 1;
}
.svgb-12__toggle,
.svgb-12__toggle svg {
transition: none;
}
}@import url('https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
.svgb-12 {
--svgb-12-bg: #08090a;
--svgb-12-bg: oklch(0.145 0.002 250);
--svgb-12-fg: #edeff1;
--svgb-12-fg: oklch(0.95 0.003 250);
--svgb-12-muted: #83878d;
--svgb-12-muted: oklch(0.645 0.008 250);
--svgb-12-rest: rgba(237, 239, 241, 0.14);
--svgb-12-rest: oklch(0.95 0.003 250 / 0.14);
--svgb-12-stroke: #00e5ff;
--svgb-12-stroke: oklch(0.85 0.15 205);
--svgb-12-good: #7cff8f;
--svgb-12-good: oklch(0.89 0.18 145);
--svgb-12-blend: screen;
position: relative;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--svgb-12-bg);
color: var(--svgb-12-fg);
font-family: 'Saira Condensed', system-ui, sans-serif;
overflow: hidden;
}
.svgb-12 *,
.svgb-12 *::before,
.svgb-12 *::after {
box-sizing: border-box;
}
.svgb-12::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), radial-gradient(70% 60% at 50% 40%, color-mix(in oklab, var(--svgb-12-stroke) 8%, transparent), transparent 70%);
}
.svgb-12__stage {
position: relative;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(22px, 5vw, 70px);
}
.svgb-12__panel {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: clamp(16px, 3vw, 26px);
width: 100%;
max-width: 420px;
}
.svgb-12__telem {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px 20px;
width: 100%;
}
.svgb-12__t {
display: flex;
flex-direction: column;
gap: 2px;
padding-block-end: 8px;
border-block-end: 1px solid var(--svgb-12-rest);
}
.svgb-12__tk {
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 9.5px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--svgb-12-muted);
}
.svgb-12__tv {
font-size: 26px;
font-weight: 700;
font-style: italic;
letter-spacing: -0.01em;
font-variant-numeric: tabular-nums;
}
.svgb-12__tv--good {
color: var(--svgb-12-good);
}
.svgb-12__blade {
position: relative;
inline-size: min(340px, 92vw);
block-size: 78px;
display: grid;
place-items: center;
border: 0;
padding: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 20px;
font-weight: 600;
font-style: italic;
letter-spacing: 0.1em;
text-transform: uppercase;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
isolation: isolate;
}
.svgb-12__btext {
position: relative;
z-index: 2;
transition: color 300ms ease, letter-spacing 400ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__btext,
.svgb-12__blade:focus-visible .svgb-12__btext {
color: var(--svgb-12-stroke);
letter-spacing: 0.16em;
}
.svgb-12__blade:focus-visible {
outline: none;
box-shadow: 0 0 0 3px color-mix(in oklab, var(--svgb-12-stroke) 34%, transparent);
}
.svgb-12__frame {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
overflow: visible;
}
.svgb-12__frame path {
fill: none;
stroke-linejoin: miter;
}
.svgb-12__base {
stroke: var(--svgb-12-rest);
stroke-width: 1.4px;
}
.svgb-12__trail {
stroke: var(--svgb-12-stroke);
stroke-width: 7px;
opacity: 0.36;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 10px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 800ms cubic-bezier(0.22, 1, 0.36, 1) 90ms;
}
.svgb-12__lead {
stroke: var(--svgb-12-stroke);
stroke-width: 2px;
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 620ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__trail,
.svgb-12__blade:focus-visible .svgb-12__trail,
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
stroke-dashoffset: 0;
}
.svgb-12__comet {
stroke: var(--svgb-12-stroke);
stroke-width: 6px;
opacity: 0.32;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 12px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 0.16 0.84;
stroke-dashoffset: 0.16;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__spark {
stroke: var(--svgb-12-fg);
stroke-width: 2.4px;
stroke-dasharray: 0.045 0.955;
stroke-dashoffset: 0.045;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__blade--comet:hover .svgb-12__comet,
.svgb-12__blade--comet:focus-visible .svgb-12__comet {
stroke-dashoffset: -0.84;
}
.svgb-12__blade--comet:hover .svgb-12__spark,
.svgb-12__blade--comet:focus-visible .svgb-12__spark {
stroke-dashoffset: -0.955;
}
.svgb-12__note {
margin: 0;
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 10.5px;
letter-spacing: 0.04em;
color: var(--svgb-12-muted);
}
.svgb-12__ti {
position: absolute;
opacity: 0;
pointer-events: none;
}
.svgb-12__toggle {
position: absolute;
z-index: 5;
inset-block-start: 16px;
inset-inline-end: 16px;
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border-radius: 4px;
border: 1px solid color-mix(in oklab, currentColor 22%, transparent);
background: color-mix(in oklab, currentColor 8%, transparent);
color: inherit;
cursor: pointer;
transition: background 160ms ease, transform 160ms ease;
}
.svgb-12__toggle:hover {
background: color-mix(in oklab, currentColor 15%, transparent);
}
.svgb-12__toggle:active {
transform: scale(0.94);
}
.svgb-12__toggle svg {
inline-size: 18px;
block-size: 18px;
transition: transform 400ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.svgb-12__ti:checked + .svgb-12__toggle svg {
transform: rotate(180deg);
}
.svgb-12__ti:focus-visible + .svgb-12__toggle {
outline: 2px solid currentColor;
outline-offset: 3px;
}
.svgb-12__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.svgb-12:has(#svgb-12-theme:checked) {
--svgb-12-bg: #f1f2f4;
--svgb-12-bg: oklch(0.955 0.003 250);
--svgb-12-fg: #101214;
--svgb-12-fg: oklch(0.185 0.004 250);
--svgb-12-muted: #555a60;
--svgb-12-muted: oklch(0.49 0.008 250);
--svgb-12-rest: rgba(16, 18, 20, 0.16);
--svgb-12-rest: oklch(0.185 0.004 250 / 0.16);
--svgb-12-stroke: #00647f;
--svgb-12-stroke: oklch(0.45 0.11 215);
--svgb-12-good: #0d6b2c;
--svgb-12-good: oklch(0.46 0.14 148);
--svgb-12-blend: multiply;
}
.svgb-12:has(#svgb-12-theme:checked)::before {
background: repeating-linear-gradient(45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px);
}
@media (prefers-reduced-motion: reduce) {
.svgb-12__trail,
.svgb-12__lead,
.svgb-12__comet,
.svgb-12__spark,
.svgb-12__btext {
transition: none;
filter: none;
}
.svgb-12__trail,
.svgb-12__comet,
.svgb-12__spark {
opacity: 0;
}
.svgb-12__lead {
stroke-dasharray: none;
stroke-dashoffset: 0;
opacity: 0;
}
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
opacity: 1;
}
.svgb-12__toggle,
.svgb-12__toggle svg {
transition: none;
}
}Here's a working CSS SVG Stroke Button 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: Dual Layer Stroke Button with Offset Trailing Path
Source: https://codefronts.com/components/css-svg-stroke-buttons/dual-layer-stroke-button-with-offset-trailing-path/
A telemetry panel where the lap button is a skewed blade, not a rectangle, and its outline is drawn twice: a crisp 2px leader and a wide, blurred follower running 90ms behind it. The gap between them opens mid-draw and closes at the end, which the eye reads as speed rather than as two separate lines.
## HTML
```html
<section class="svgb-12">
<input class="svgb-12__ti" type="checkbox" id="svgb-12-theme">
<label class="svgb-12__toggle" for="svgb-12-theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="svgb-12__sr">Switch colour scheme</span>
</label>
<div class="svgb-12__stage">
<div class="svgb-12__panel">
<div class="svgb-12__telem">
<div class="svgb-12__t"><span class="svgb-12__tk">Lap</span><span class="svgb-12__tv">14</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Delta</span><span class="svgb-12__tv svgb-12__tv--good">-0.412</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Tyre</span><span class="svgb-12__tv">C3 · 62%</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">ERS</span><span class="svgb-12__tv">2.1 MJ</span></div>
</div>
<button class="svgb-12__blade" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__trail" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__lead" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Push lap</span>
</button>
<button class="svgb-12__blade svgb-12__blade--comet" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__comet" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__spark" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Deploy overtake</span>
</button>
<p class="svgb-12__note">leader 620ms · trail 800ms + 90ms · paint order: trail first</p>
</div>
</div>
</section>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
.svgb-12 {
--svgb-12-bg: #08090a;
--svgb-12-bg: oklch(0.145 0.002 250);
--svgb-12-fg: #edeff1;
--svgb-12-fg: oklch(0.95 0.003 250);
--svgb-12-muted: #83878d;
--svgb-12-muted: oklch(0.645 0.008 250);
--svgb-12-rest: rgba(237, 239, 241, 0.14);
--svgb-12-rest: oklch(0.95 0.003 250 / 0.14);
--svgb-12-stroke: #00e5ff;
--svgb-12-stroke: oklch(0.85 0.15 205);
--svgb-12-good: #7cff8f;
--svgb-12-good: oklch(0.89 0.18 145);
--svgb-12-blend: screen;
position: relative;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--svgb-12-bg);
color: var(--svgb-12-fg);
font-family: 'Saira Condensed', system-ui, sans-serif;
overflow: hidden;
}
.svgb-12 *,
.svgb-12 *::before,
.svgb-12 *::after {
box-sizing: border-box;
}
.svgb-12::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), radial-gradient(70% 60% at 50% 40%, color-mix(in oklab, var(--svgb-12-stroke) 8%, transparent), transparent 70%);
}
.svgb-12__stage {
position: relative;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(22px, 5vw, 70px);
}
.svgb-12__panel {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: clamp(16px, 3vw, 26px);
width: 100%;
max-width: 420px;
}
.svgb-12__telem {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px 20px;
width: 100%;
}
.svgb-12__t {
display: flex;
flex-direction: column;
gap: 2px;
padding-block-end: 8px;
border-block-end: 1px solid var(--svgb-12-rest);
}
.svgb-12__tk {
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 9.5px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--svgb-12-muted);
}
.svgb-12__tv {
font-size: 26px;
font-weight: 700;
font-style: italic;
letter-spacing: -0.01em;
font-variant-numeric: tabular-nums;
}
.svgb-12__tv--good {
color: var(--svgb-12-good);
}
.svgb-12__blade {
position: relative;
inline-size: min(340px, 92vw);
block-size: 78px;
display: grid;
place-items: center;
border: 0;
padding: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 20px;
font-weight: 600;
font-style: italic;
letter-spacing: 0.1em;
text-transform: uppercase;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
isolation: isolate;
}
.svgb-12__btext {
position: relative;
z-index: 2;
transition: color 300ms ease, letter-spacing 400ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__btext,
.svgb-12__blade:focus-visible .svgb-12__btext {
color: var(--svgb-12-stroke);
letter-spacing: 0.16em;
}
.svgb-12__blade:focus-visible {
outline: none;
box-shadow: 0 0 0 3px color-mix(in oklab, var(--svgb-12-stroke) 34%, transparent);
}
.svgb-12__frame {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
overflow: visible;
}
.svgb-12__frame path {
fill: none;
stroke-linejoin: miter;
}
.svgb-12__base {
stroke: var(--svgb-12-rest);
stroke-width: 1.4px;
}
.svgb-12__trail {
stroke: var(--svgb-12-stroke);
stroke-width: 7px;
opacity: 0.36;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 10px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 800ms cubic-bezier(0.22, 1, 0.36, 1) 90ms;
}
.svgb-12__lead {
stroke: var(--svgb-12-stroke);
stroke-width: 2px;
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 620ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__trail,
.svgb-12__blade:focus-visible .svgb-12__trail,
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
stroke-dashoffset: 0;
}
.svgb-12__comet {
stroke: var(--svgb-12-stroke);
stroke-width: 6px;
opacity: 0.32;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 12px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 0.16 0.84;
stroke-dashoffset: 0.16;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__spark {
stroke: var(--svgb-12-fg);
stroke-width: 2.4px;
stroke-dasharray: 0.045 0.955;
stroke-dashoffset: 0.045;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__blade--comet:hover .svgb-12__comet,
.svgb-12__blade--comet:focus-visible .svgb-12__comet {
stroke-dashoffset: -0.84;
}
.svgb-12__blade--comet:hover .svgb-12__spark,
.svgb-12__blade--comet:focus-visible .svgb-12__spark {
stroke-dashoffset: -0.955;
}
.svgb-12__note {
margin: 0;
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 10.5px;
letter-spacing: 0.04em;
color: var(--svgb-12-muted);
}
.svgb-12__ti {
position: absolute;
opacity: 0;
pointer-events: none;
}
.svgb-12__toggle {
position: absolute;
z-index: 5;
inset-block-start: 16px;
inset-inline-end: 16px;
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border-radius: 4px;
border: 1px solid color-mix(in oklab, currentColor 22%, transparent);
background: color-mix(in oklab, currentColor 8%, transparent);
color: inherit;
cursor: pointer;
transition: background 160ms ease, transform 160ms ease;
}
.svgb-12__toggle:hover {
background: color-mix(in oklab, currentColor 15%, transparent);
}
.svgb-12__toggle:active {
transform: scale(0.94);
}
.svgb-12__toggle svg {
inline-size: 18px;
block-size: 18px;
transition: transform 400ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.svgb-12__ti:checked + .svgb-12__toggle svg {
transform: rotate(180deg);
}
.svgb-12__ti:focus-visible + .svgb-12__toggle {
outline: 2px solid currentColor;
outline-offset: 3px;
}
.svgb-12__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.svgb-12:has(#svgb-12-theme:checked) {
--svgb-12-bg: #f1f2f4;
--svgb-12-bg: oklch(0.955 0.003 250);
--svgb-12-fg: #101214;
--svgb-12-fg: oklch(0.185 0.004 250);
--svgb-12-muted: #555a60;
--svgb-12-muted: oklch(0.49 0.008 250);
--svgb-12-rest: rgba(16, 18, 20, 0.16);
--svgb-12-rest: oklch(0.185 0.004 250 / 0.16);
--svgb-12-stroke: #00647f;
--svgb-12-stroke: oklch(0.45 0.11 215);
--svgb-12-good: #0d6b2c;
--svgb-12-good: oklch(0.46 0.14 148);
--svgb-12-blend: multiply;
}
.svgb-12:has(#svgb-12-theme:checked)::before {
background: repeating-linear-gradient(45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px);
}
@media (prefers-reduced-motion: reduce) {
.svgb-12__trail,
.svgb-12__lead,
.svgb-12__comet,
.svgb-12__spark,
.svgb-12__btext {
transition: none;
filter: none;
}
.svgb-12__trail,
.svgb-12__comet,
.svgb-12__spark {
opacity: 0;
}
.svgb-12__lead {
stroke-dasharray: none;
stroke-dashoffset: 0;
opacity: 0;
}
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
opacity: 1;
}
.svgb-12__toggle,
.svgb-12__toggle svg {
transition: none;
}
}
```Here's a working CSS SVG Stroke Button 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: Dual Layer Stroke Button with Offset Trailing Path
Source: https://codefronts.com/components/css-svg-stroke-buttons/dual-layer-stroke-button-with-offset-trailing-path/
A telemetry panel where the lap button is a skewed blade, not a rectangle, and its outline is drawn twice: a crisp 2px leader and a wide, blurred follower running 90ms behind it. The gap between them opens mid-draw and closes at the end, which the eye reads as speed rather than as two separate lines.
## HTML
```html
<section class="svgb-12">
<input class="svgb-12__ti" type="checkbox" id="svgb-12-theme">
<label class="svgb-12__toggle" for="svgb-12-theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor" stroke="none"/></svg>
<span class="svgb-12__sr">Switch colour scheme</span>
</label>
<div class="svgb-12__stage">
<div class="svgb-12__panel">
<div class="svgb-12__telem">
<div class="svgb-12__t"><span class="svgb-12__tk">Lap</span><span class="svgb-12__tv">14</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Delta</span><span class="svgb-12__tv svgb-12__tv--good">-0.412</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">Tyre</span><span class="svgb-12__tv">C3 · 62%</span></div>
<div class="svgb-12__t"><span class="svgb-12__tk">ERS</span><span class="svgb-12__tv">2.1 MJ</span></div>
</div>
<button class="svgb-12__blade" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__trail" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__lead" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Push lap</span>
</button>
<button class="svgb-12__blade svgb-12__blade--comet" type="button">
<svg class="svgb-12__frame" viewBox="0 0 340 78" aria-hidden="true">
<path class="svgb-12__base" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__comet" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
<path class="svgb-12__spark" d="M26 3H337L314 75H3Z" pathLength="1" vector-effect="non-scaling-stroke"/>
</svg>
<span class="svgb-12__btext">Deploy overtake</span>
</button>
<p class="svgb-12__note">leader 620ms · trail 800ms + 90ms · paint order: trail first</p>
</div>
</div>
</section>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=Saira+Condensed:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
.svgb-12 {
--svgb-12-bg: #08090a;
--svgb-12-bg: oklch(0.145 0.002 250);
--svgb-12-fg: #edeff1;
--svgb-12-fg: oklch(0.95 0.003 250);
--svgb-12-muted: #83878d;
--svgb-12-muted: oklch(0.645 0.008 250);
--svgb-12-rest: rgba(237, 239, 241, 0.14);
--svgb-12-rest: oklch(0.95 0.003 250 / 0.14);
--svgb-12-stroke: #00e5ff;
--svgb-12-stroke: oklch(0.85 0.15 205);
--svgb-12-good: #7cff8f;
--svgb-12-good: oklch(0.89 0.18 145);
--svgb-12-blend: screen;
position: relative;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--svgb-12-bg);
color: var(--svgb-12-fg);
font-family: 'Saira Condensed', system-ui, sans-serif;
overflow: hidden;
}
.svgb-12 *,
.svgb-12 *::before,
.svgb-12 *::after {
box-sizing: border-box;
}
.svgb-12::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(1 0 0 / 0.022) 0 2px, transparent 2px 5px), radial-gradient(70% 60% at 50% 40%, color-mix(in oklab, var(--svgb-12-stroke) 8%, transparent), transparent 70%);
}
.svgb-12__stage {
position: relative;
min-height: 100svh;
display: grid;
place-items: center;
padding: clamp(22px, 5vw, 70px);
}
.svgb-12__panel {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: clamp(16px, 3vw, 26px);
width: 100%;
max-width: 420px;
}
.svgb-12__telem {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px 20px;
width: 100%;
}
.svgb-12__t {
display: flex;
flex-direction: column;
gap: 2px;
padding-block-end: 8px;
border-block-end: 1px solid var(--svgb-12-rest);
}
.svgb-12__tk {
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 9.5px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--svgb-12-muted);
}
.svgb-12__tv {
font-size: 26px;
font-weight: 700;
font-style: italic;
letter-spacing: -0.01em;
font-variant-numeric: tabular-nums;
}
.svgb-12__tv--good {
color: var(--svgb-12-good);
}
.svgb-12__blade {
position: relative;
inline-size: min(340px, 92vw);
block-size: 78px;
display: grid;
place-items: center;
border: 0;
padding: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: 20px;
font-weight: 600;
font-style: italic;
letter-spacing: 0.1em;
text-transform: uppercase;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
isolation: isolate;
}
.svgb-12__btext {
position: relative;
z-index: 2;
transition: color 300ms ease, letter-spacing 400ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__btext,
.svgb-12__blade:focus-visible .svgb-12__btext {
color: var(--svgb-12-stroke);
letter-spacing: 0.16em;
}
.svgb-12__blade:focus-visible {
outline: none;
box-shadow: 0 0 0 3px color-mix(in oklab, var(--svgb-12-stroke) 34%, transparent);
}
.svgb-12__frame {
position: absolute;
inset: 0;
inline-size: 100%;
block-size: 100%;
overflow: visible;
}
.svgb-12__frame path {
fill: none;
stroke-linejoin: miter;
}
.svgb-12__base {
stroke: var(--svgb-12-rest);
stroke-width: 1.4px;
}
.svgb-12__trail {
stroke: var(--svgb-12-stroke);
stroke-width: 7px;
opacity: 0.36;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 10px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 800ms cubic-bezier(0.22, 1, 0.36, 1) 90ms;
}
.svgb-12__lead {
stroke: var(--svgb-12-stroke);
stroke-width: 2px;
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 620ms cubic-bezier(0.22, 1, 0.36, 1);
}
.svgb-12__blade:hover .svgb-12__trail,
.svgb-12__blade:focus-visible .svgb-12__trail,
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
stroke-dashoffset: 0;
}
.svgb-12__comet {
stroke: var(--svgb-12-stroke);
stroke-width: 6px;
opacity: 0.32;
color: var(--svgb-12-stroke);
filter: drop-shadow(0 0 12px currentColor);
mix-blend-mode: var(--svgb-12-blend);
stroke-dasharray: 0.16 0.84;
stroke-dashoffset: 0.16;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__spark {
stroke: var(--svgb-12-fg);
stroke-width: 2.4px;
stroke-dasharray: 0.045 0.955;
stroke-dashoffset: 0.045;
transition: stroke-dashoffset 900ms linear;
}
.svgb-12__blade--comet:hover .svgb-12__comet,
.svgb-12__blade--comet:focus-visible .svgb-12__comet {
stroke-dashoffset: -0.84;
}
.svgb-12__blade--comet:hover .svgb-12__spark,
.svgb-12__blade--comet:focus-visible .svgb-12__spark {
stroke-dashoffset: -0.955;
}
.svgb-12__note {
margin: 0;
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 10.5px;
letter-spacing: 0.04em;
color: var(--svgb-12-muted);
}
.svgb-12__ti {
position: absolute;
opacity: 0;
pointer-events: none;
}
.svgb-12__toggle {
position: absolute;
z-index: 5;
inset-block-start: 16px;
inset-inline-end: 16px;
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border-radius: 4px;
border: 1px solid color-mix(in oklab, currentColor 22%, transparent);
background: color-mix(in oklab, currentColor 8%, transparent);
color: inherit;
cursor: pointer;
transition: background 160ms ease, transform 160ms ease;
}
.svgb-12__toggle:hover {
background: color-mix(in oklab, currentColor 15%, transparent);
}
.svgb-12__toggle:active {
transform: scale(0.94);
}
.svgb-12__toggle svg {
inline-size: 18px;
block-size: 18px;
transition: transform 400ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.svgb-12__ti:checked + .svgb-12__toggle svg {
transform: rotate(180deg);
}
.svgb-12__ti:focus-visible + .svgb-12__toggle {
outline: 2px solid currentColor;
outline-offset: 3px;
}
.svgb-12__sr {
position: absolute;
inline-size: 1px;
block-size: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.svgb-12:has(#svgb-12-theme:checked) {
--svgb-12-bg: #f1f2f4;
--svgb-12-bg: oklch(0.955 0.003 250);
--svgb-12-fg: #101214;
--svgb-12-fg: oklch(0.185 0.004 250);
--svgb-12-muted: #555a60;
--svgb-12-muted: oklch(0.49 0.008 250);
--svgb-12-rest: rgba(16, 18, 20, 0.16);
--svgb-12-rest: oklch(0.185 0.004 250 / 0.16);
--svgb-12-stroke: #00647f;
--svgb-12-stroke: oklch(0.45 0.11 215);
--svgb-12-good: #0d6b2c;
--svgb-12-good: oklch(0.46 0.14 148);
--svgb-12-blend: multiply;
}
.svgb-12:has(#svgb-12-theme:checked)::before {
background: repeating-linear-gradient(45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px), repeating-linear-gradient(-45deg, oklch(0 0 0 / 0.03) 0 2px, transparent 2px 5px);
}
@media (prefers-reduced-motion: reduce) {
.svgb-12__trail,
.svgb-12__lead,
.svgb-12__comet,
.svgb-12__spark,
.svgb-12__btext {
transition: none;
filter: none;
}
.svgb-12__trail,
.svgb-12__comet,
.svgb-12__spark {
opacity: 0;
}
.svgb-12__lead {
stroke-dasharray: none;
stroke-dashoffset: 0;
opacity: 0;
}
.svgb-12__blade:hover .svgb-12__lead,
.svgb-12__blade:focus-visible .svgb-12__lead {
opacity: 1;
}
.svgb-12__toggle,
.svgb-12__toggle svg {
transition: none;
}
}
```How this works
The lag is the whole effect. Give the follower a slightly longer duration and a small delay and the two heads separate mid-draw, then converge as both land on zero. Because the trail is wider and softer, the eye reads the gap as motion blur rather than as two lines.
.svgb-12__lead {
stroke-width: 2px;
transition: stroke-dashoffset 620ms cubic-bezier(.22,1,.36,1);
}
.svgb-12__trail {
stroke-width: 6px;
opacity: .45;
filter: drop-shadow(0 0 8px currentColor);
transition: stroke-dashoffset 780ms cubic-bezier(.22,1,.36,1) 90ms;
}Order matters in SVG. There is no z-index for SVG children — paint order is document order. The trail must come first in the markup so the crisp leader paints on top of it; swap them and the soft wide stroke smears over the sharp one.
Blend mode keeps the overlap honest. Where trail and leader coincide, two semi-transparent strokes of the same hue stack into a darker, dirtier line. screen on dark backgrounds makes that overlap brighter instead, which is how light actually behaves; on a light ground the same logic needs multiply.
One extra layer is the limit. Three or four stacked strokes look like a printing misregistration, and each one adds a filter pass. Two layers plus a drop-shadow is the point of diminishing returns.
Make it yours
- Widen the gap by raising the trail delay to 150ms for a slower, more liquid feel; drop it to 40ms for a tight metallic edge.
- Remove the
drop-shadowand instead give the trail 12px of stroke width at 0.12 opacity for a flat, printed halo. - Make the trail a different hue — a warm leader over a cool trail reads as chromatic aberration and suits editorial layouts.
- Use the comet variant for loading states: a 0.15 dash segment chasing a 0.05 leader around a normalised path.
- Match the trail's easing to the leader's exactly if the effect looks jittery; different curves make the gap pulse rather than open smoothly.
Gotchas — read before shipping
- SVG paints in document order and ignores
z-index. The soft trail must be written before the crisp leader. filteron an SVG child creates a new rasterised layer on every frame. One filtered path per button is fine; one per card in a grid of forty is not.- A drop-shadow inherits the element's own colour only if you pass
currentColor— hard-coding the glow hue means it will not follow the theme flip. - Stacked semi-transparent strokes of the same colour darken at the overlap unless you set a lightening blend mode, and blend modes need an
isolationboundary or they will reach the page background.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 15.4+ | 113+ | 111+ |
Stacked paths, transition-delay and filter: drop-shadow() work in all current engines. mix-blend-mode on SVG children is supported in Chromium, Firefox and Safari 15.4+; where it is missing the overlap is slightly darker and nothing breaks.