Border-draw button
Button whose border draws itself around the label on hover
Techniques: pathLength · stroke-dashoffset · transition-reversal · letter-spacing
<!--
============================================================
SVGarden — https://www.svgarden.dev
Author : Simon-Pierre Boucher
Contact: contact@spboucher.ai
File : snippets/buttons/btn-border-draw.html
Desc : Button whose border draws itself around the label on hover
============================================================
-->
<button class="sg-btn-border-draw" type="button" style="--sg-color:#7F77DD; --sg-size:16px; --sg-duration:0.6s;">
<svg viewBox="0 0 100 40" preserveAspectRatio="none" aria-hidden="true" focusable="false">
<rect class="sg-btn-border-draw-track" x="1.5" y="1.5" width="97" height="37" rx="9" pathLength="100" />
<rect class="sg-btn-border-draw-ink" x="1.5" y="1.5" width="97" height="37" rx="9" pathLength="100" />
</svg>
<span class="sg-btn-border-draw-label">Draw me in</span>
</button>
<style>
.sg-btn-border-draw {
position: relative;
appearance: none;
border: 0;
background: transparent;
color: inherit;
font: inherit;
font-size: var(--sg-size);
font-weight: 600;
padding: 0.75em 1.6em;
cursor: pointer;
}
.sg-btn-border-draw svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.sg-btn-border-draw rect {
/* no non-scaling-stroke here: Chromium computes dash patterns in screen
space with it, which breaks the pathLength=100 normalization */
fill: none;
stroke: var(--sg-color);
stroke-width: 2;
stroke-linecap: round;
}
.sg-btn-border-draw-track {
opacity: 0.25;
}
.sg-btn-border-draw-ink {
/* gap 102 > pathLength so the round end-caps never bleed onto the path at rest */
stroke-dasharray: 100 102;
stroke-dashoffset: 101;
transition: stroke-dashoffset var(--sg-duration) ease-in-out;
}
.sg-btn-border-draw-label {
letter-spacing: 0.02em;
transition: letter-spacing var(--sg-duration) ease;
}
.sg-btn-border-draw:hover .sg-btn-border-draw-ink,
.sg-btn-border-draw:focus-visible .sg-btn-border-draw-ink {
stroke-dashoffset: 0;
}
.sg-btn-border-draw:hover .sg-btn-border-draw-label,
.sg-btn-border-draw:focus-visible .sg-btn-border-draw-label {
letter-spacing: 0.09em;
}
</style>