spb/svgarden Public
SVGarden — searchable bank of 74 self-contained SVG+CSS animation snippets (svgarden.dev)
HTML 79.2%
Astro 10.3%
JavaScript 6%
CSS 3.7%
Shell 0.8%
1<!--2 ============================================================3 SVGarden — https://www.svgarden.dev4 Author : Simon-Pierre Boucher5 Contact: contact@spboucher.ai6 File : snippets/hover/card-lift-border.html7 Desc : Card whose SVG border draws itself around it on hover8 ============================================================9-->10<!--svgarden11title: Card lift & border12slug: card-lift-border13category: hover14tags: [hover, card, border, draw]15difficulty: intermediate16techniques: [pathLength, stroke-dashoffset, transition-on-hover, preserveAspectRatio-none]17how_it_works: >18 An SVG rect stretched over the card (preserveAspectRatio="none", with a19 viewBox matched to the card's aspect ratio so the stroke stays visually even)20 starts fully hidden because its dash gap (102) is longer than the normalized21 path (pathLength 100) — the extra 2 units keep the round line caps off-path22 at rest. Hovering transitions stroke-dashoffset to zero, so the border traces23 itself around the perimeter — a transition, not a keyframe animation, which24 means it elegantly reverses when the pointer leaves instead of snapping.25customizable:26 - { var: "--sg-color", label: "Border", type: color, default: "#7F77DD" }27 - { var: "--sg-size", label: "Width", type: range, min: 140, max: 360, default: 220, unit: px }28 - { var: "--sg-duration", label: "Speed", type: range, min: 0.2, max: 2, step: 0.1, default: 0.7, unit: s }29created: 2026-08-1030-->31<div class="sg-card-lift-border" tabindex="0" style="--sg-color:#7F77DD; --sg-size:220px; --sg-duration:0.7s;">32 <svg viewBox="0 0 200 100" preserveAspectRatio="none" aria-hidden="true" focusable="false">33 <rect x="1" y="1" width="198" height="98" rx="8" pathLength="100" />34 </svg>35 <strong>Hover me</strong>36 <span>The border draws itself around the card, then un-draws on leave.</span>37</div>38<style>39 .sg-card-lift-border {40 position: relative;41 width: var(--sg-size);42 padding: 1.1rem 1.2rem;43 border-radius: 10px;44 background: rgba(127, 119, 221, 0.08);45 font-family: inherit;46 display: flex;47 flex-direction: column;48 gap: 0.4rem;49 cursor: pointer;50 transition: transform var(--sg-duration) ease;51 }52 .sg-card-lift-border strong { font-size: 1rem; }53 .sg-card-lift-border span { font-size: 0.85rem; opacity: 0.75; }54 .sg-card-lift-border svg {55 position: absolute;56 inset: 0;57 width: 100%;58 height: 100%;59 pointer-events: none;60 }61 .sg-card-lift-border rect {62 /* no non-scaling-stroke: Chromium computes dash patterns in screen space63 with it, which breaks the pathLength=100 normalization */64 fill: none;65 stroke: var(--sg-color);66 stroke-width: 2;67 stroke-linecap: round;68 stroke-dasharray: 100 102;69 stroke-dashoffset: 101;70 transition: stroke-dashoffset var(--sg-duration) ease-in-out;71 }72 .sg-card-lift-border:hover,73 .sg-card-lift-border:focus-visible {74 transform: translateY(-4px);75 }76 .sg-card-lift-border:hover rect,77 .sg-card-lift-border:focus-visible rect {78 stroke-dashoffset: 0;79 }80</style>81