Home / Snippets / Animation & Motion /
Border draw
A border that traces itself on hover using pseudo-elements and scaleX/scaleY transitions.
Quick implementation
.border-draw {
position: relative;
display: inline-block;
padding: 1rem 2rem;
}
/* Top and bottom edges via ::before / ::after */
.border-draw::before,
.border-draw::after {
content: '';
position: absolute;
left: 0; right: 0;
height: 2px;
background: oklch(0.52 0.22 265);
transition: transform 0.35s ease;
}
.border-draw::before {
top: 0;
transform-origin: left;
transform: scaleX(0);
}
.border-draw::after {
bottom: 0;
transform-origin: right;
transform: scaleX(0);
}
/* Left and right edges via sibling spans (or extra pseudo on a wrapper) */
.border-draw .bd-left,
.border-draw .bd-right {
position: absolute;
width: 2px;
top: 0; bottom: 0;
background: oklch(0.52 0.22 265);
transition: transform 0.35s ease 0.35s;
}
.border-draw .bd-left { left: 0; transform-origin: bottom; transform: scaleY(0); }
.border-draw .bd-right { right: 0; transform-origin: top; transform: scaleY(0); }
/* Trigger on hover */
.border-draw:hover::before,
.border-draw:hover::after { transform: scaleX(1); }
.border-draw:hover .bd-left,
.border-draw:hover .bd-right { transform: scaleY(1); }
@media (prefers-reduced-motion: reduce) {
.border-draw::before,
.border-draw::after,
.border-draw .bd-left,
.border-draw .bd-right { transition: none; }
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building a CSS interaction library.
Goal: A border-draw hover effect — the border traces around an element on hover using only CSS, no JavaScript.
Technical constraints:
- Use ::before and ::after pseudo-elements for the top and bottom edges.
- Use two additional positioned elements (spans or a wrapper's children) for the left and right edges.
- Animate using transform: scaleX(0→1) and scaleY(0→1) with transform-origin to control draw direction.
- Sequence the vertical edges slightly after the horizontal ones using transition-delay.
- Use oklch() for border color, not hex or rgba().
- Include @media (prefers-reduced-motion: reduce) to disable transitions.
Framework variant (pick one):
A) Vanilla CSS — utility class applied to any inline or block element with two child spans for vertical edges.
B) React component — wraps children, injects the required spans and styles automatically.
Edge cases to handle:
- Works on both inline and block-level elements.
- Does not shift surrounding content (position: absolute edges, not border-width changes).
- Color and thickness should be CSS custom-property overrides.
- Ensure the parent has position: relative.
Return CSS and minimal HTML markup.
Why this matters in 2026
Border draw is a staple hover effect for navigation items, CTAs, and feature cards. Done in pure CSS — no JavaScript mousemove listeners — it is lightweight, accessible, and performant. The sequenced timing creates a satisfying "trace" feel that draws the eye without overwhelming motion-sensitive users.
The logic
Each edge is a thin rectangle anchored to one side of the container with position: absolute. The horizontal edges (top and bottom) start at transform: scaleX(0) and scale to 1 on hover; transform-origin controls which end leads the draw. The vertical edges follow with a transition-delay equal to the horizontal duration, creating a clockwise trace. Because only transform changes, no layout or paint work occurs — just compositing.
Accessibility & performance
@media (prefers-reduced-motion: reduce) sets transition: none on all edge elements, so the border appears instantly on hover rather than animating. transform is compositor-only — no layout recalculation triggered. Because the edges are purely decorative, they carry no semantic meaning; if you rely on this effect to convey focus state, pair it with a visible :focus-visible style using outline rather than the draw animation alone.