Deploy previews
Every branch gets its own URL the moment you push.
Two short beams of light chase each other around the card's outline while you hover. An SVG rect with pathLength 100 turns the dash pattern into percentages of the perimeter.
Also known as: animated border beam, glowing border light css, light running around border.
Every branch gets its own URL the moment you push.
<article class="hfx-card-border-beam">
<svg class="hfx-card-border-beam-frame" aria-hidden="true">
<rect class="hfx-card-border-beam-track" width="100%" height="100%" rx="12" pathLength="100"/>
<rect class="hfx-card-border-beam-beam" width="100%" height="100%" rx="12" pathLength="100"/>
</svg>
<span class="hfx-card-border-beam-chip">Live</span>
<h3>Deploy previews</h3>
<p>Every branch gets its own URL the moment you push.</p>
</article>.hfx-card-border-beam {
--c: var(--hfx-color, #3b82f6);
font-size: var(--hfx-size, 16px);
position: relative;
box-sizing: border-box;
width: 15em;
padding: 1.15em 1.25em 1.25em;
border-radius: 0.85em;
background: color-mix(in srgb, var(--c) 10%, #0b0f19);
color: #f3f4f6;
font-family: system-ui, sans-serif;
}
.hfx-card-border-beam-frame {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
overflow: visible;
pointer-events: none;
transition: filter 0.4s ease;
}
.hfx-card-border-beam:hover .hfx-card-border-beam-frame { filter: drop-shadow(0 0 0.3em var(--c)); }
.hfx-card-border-beam-frame rect {
rx: 0.85em;
fill: none;
stroke-width: 1.5;
}
.hfx-card-border-beam-track { stroke: color-mix(in srgb, #fff 14%, transparent); }
.hfx-card-border-beam-beam {
stroke: color-mix(in srgb, var(--c) 70%, #fff);
stroke-width: 2;
stroke-linecap: round;
stroke-dasharray: 18 32;
opacity: 0;
transition: opacity 0.4s ease;
}
.hfx-card-border-beam:hover .hfx-card-border-beam-beam {
opacity: 1;
animation: hfx-card-border-beam-run 3s linear infinite;
}
.hfx-card-border-beam-chip {
display: inline-flex;
align-items: center;
gap: 0.4em;
margin-bottom: 0.75em;
padding: 0.25em 0.6em;
border-radius: 99em;
background: color-mix(in srgb, var(--c) 22%, transparent);
color: color-mix(in srgb, var(--c) 45%, #fff);
font-size: 0.65em;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.hfx-card-border-beam-chip::before {
content: "";
width: 0.5em;
height: 0.5em;
border-radius: 50%;
background: currentColor;
}
.hfx-card-border-beam h3 {
font-weight: 600;
margin: 0 0 0.3em;
font-size: 1em;
}
.hfx-card-border-beam p {
margin: 0;
font-size: 0.8em;
line-height: 1.45;
color: color-mix(in srgb, #fff 62%, transparent);
}
@keyframes hfx-card-border-beam-run {
to { stroke-dashoffset: -100; }
}
@media (prefers-reduced-motion: reduce) {
.hfx-card-border-beam, .hfx-card-border-beam *, .hfx-card-border-beam::before, .hfx-card-border-beam::after, .hfx-card-border-beam *::before, .hfx-card-border-beam *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--hfx-color on the element or a parent.
Currently previewing #3b82f6.--hfx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.