Two accent bars press in from the sides, the word squashes narrow and stretches tall, then let go and it springs back past its width before settling. One registered number drives word and bars.
Also known as: squash and stretch text, squeeze text css, squishy text animation.
<div class="txt-squeeze-text"><span>Squeeze</span></div>
@property --txt-squeeze-text-k {
syntax: "<number>";
inherits: true;
initial-value: 1;
}
.txt-squeeze-text {
--c: var(--txt-color, #3b82f6);
font-size: calc(var(--txt-size, 32px) * 2);
font-family: system-ui, sans-serif;
font-weight: 900;
line-height: 1.2;
position: relative;
display: inline-block;
letter-spacing: -0.02em;
animation: txt-squeeze-text-press 3.4s infinite;}
.txt-squeeze-text span {
display: inline-block;
transform-origin: 50% 80%;
transform: scale(var(--txt-squeeze-text-k), calc(1 + (1 - var(--txt-squeeze-text-k)) * 0.6));
}
/* the bars ride the word's edges: 50% from the middle times the squeeze */
.txt-squeeze-text::before,
.txt-squeeze-text::after {
content: "";
position: absolute;
top: 50%;
width: 0.13em;
height: 1.15em;
border-radius: 0.1em;
background: var(--c);
box-shadow: 0 0.08em 0.25em color-mix(in srgb, var(--c) 35%, transparent);
translate: 0 -50%;
}
.txt-squeeze-text::before { left: calc(50% - 50% * var(--txt-squeeze-text-k) - 0.26em); }
.txt-squeeze-text::after { right: calc(50% - 50% * var(--txt-squeeze-text-k) - 0.26em); }
@keyframes txt-squeeze-text-press {
0%, 8% { --txt-squeeze-text-k: 1; animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
36% { --txt-squeeze-text-k: 0.74; animation-timing-function: ease-in-out; }
46% { --txt-squeeze-text-k: 0.71; animation-timing-function: cubic-bezier(0.2, 0.9, 0.3, 1); }
53% { --txt-squeeze-text-k: 1.13; animation-timing-function: ease-in-out; }
60% { --txt-squeeze-text-k: 0.95; animation-timing-function: ease-in-out; }
67% { --txt-squeeze-text-k: 1.03; animation-timing-function: ease-in-out; }
74%, 100% { --txt-squeeze-text-k: 1; }
}
@media (prefers-reduced-motion: reduce) {
.txt-squeeze-text { animation: none; }
}
@media (prefers-reduced-motion: reduce) {
.txt-squeeze-text, .txt-squeeze-text *, .txt-squeeze-text::before, .txt-squeeze-text::after, .txt-squeeze-text *::before, .txt-squeeze-text *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--txt-color on the element or a parent.
Currently previewing #3b82f6.--txt-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 40px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.