Menu items hang like shop tags on strings from a rail and swing on hover, settling in a damped pendulum. The pivot is a transform-origin above the tag, at the top of its string.
Also known as: hanging menu swing, pendulum hover css, swing animation nav.
<nav class="hfx-nav-swing-tags"> <a href="#">Shop</a> <a href="#">Journal</a> <a href="#">Stockists</a> <a href="#">About</a> </nav>
.hfx-nav-swing-tags {
--c: var(--hfx-color, #3b82f6);
display: flex;
align-items: center;
font: 600 var(--hfx-size, 16px)/1.2 system-ui, sans-serif;
align-items: flex-start;
gap: 0.9em;
padding: 0 0.6em;
border-top: 0.12em solid color-mix(in srgb, var(--c) 45%, transparent);}
.hfx-nav-swing-tags a {
position: relative;
margin-top: 1.1em;
padding: 0.45em 0.8em;
border: 1px solid color-mix(in srgb, var(--c) 40%, transparent);
border-radius: 0.4em;
background: color-mix(in srgb, var(--c) 8%, transparent);
color: inherit;
text-decoration: none;
transform-origin: 50% -1.1em;
transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}
.hfx-nav-swing-tags a::before {
content: "";
position: absolute;
left: 50%;
bottom: 100%;
width: 1px;
height: 1.1em;
background: color-mix(in srgb, var(--c) 55%, transparent);
}
.hfx-nav-swing-tags a:is(:hover, :focus-visible) {
border-color: var(--c);
background: color-mix(in srgb, var(--c) 14%, transparent);
color: var(--c);
animation: hfx-nav-swing-tags-swing 1.2s ease-in-out;
}
@keyframes hfx-nav-swing-tags-swing {
0%, 100% { transform: rotate(0); }
15% { transform: rotate(12deg); }
35% { transform: rotate(-8deg); }
55% { transform: rotate(5deg); }
75% { transform: rotate(-2deg); }
}
@media (prefers-reduced-motion: reduce) {
.hfx-nav-swing-tags, .hfx-nav-swing-tags *, .hfx-nav-swing-tags::before, .hfx-nav-swing-tags::after, .hfx-nav-swing-tags *::before, .hfx-nav-swing-tags *::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.