Block Reveals in CSS
Published on May 11, 2022
I stole this snippet from the fantastic Jhey Tompkins
I’ve seen a few block reveals in CSS, but none of them have impressed me like this one. There’s a level of polish in this that really just brings happiness, so I thought I’d both store it for future use and play with it a little to see exactly what makes me like it so much. After fiddling a little, I believe it’s the easing - it hits just right
What exactly am I talking about?
<h1>
<span>Let's</span>
<span>Build</span>
<span>Stuuuuff!</span>
</h1>
/* Here the lineheight controls the size of the block */
h1 {
margin: 0;
font-size: clamp(2rem, 1rem + 10vmin, 10rem);
display: inline-flex;
align-items: flex-start;
flex-direction: column;
line-height: 0.8;
}
:root {
--primary: hsl(173, 80%, 40%);
--secondary: hsl(189, 94%, 43%);
--tertiary: hsl(239, 84%, 67%);
--speed: 0.65s;
}
/* The clip path is the most important thing here */
/* Is hides anything that is more than 20% wider than the element */
h1 span {
--color: var(--primary);
color: var(--color);
position: relative;
clip-path: inset(-20% 0);
animation-name: text-reveal, shimmy;
animation-duration: var(--speed);
animation-delay: calc((0.5 + var(--index)) * (var(--speed) / 3));
animation-fill-mode: both;
animation-timing-function: steps(1), ease-out;
}
/* Shift text 1 character to the left */
/* This causes a stagger effect which makes a huge impact */
@keyframes shimmy {
0% {
transform: translateX(-1ch);
}
}
/* Start the text off as hidden and then reveal it */
@keyframes text-reveal {
0% {
color: transparent;
}
50%, 100% {
color: var(--color);
}
}
/* Inset causes the block to overlap 20% on the x axis */
h1 span:after {
content: "";
position: absolute;
inset: -20% 0;
background-color: var(--color);
animation-name: block-reveal;
animation-duration: var(--speed);
animation-delay: calc((0.5 + var(--index)) * (var(--speed) / 3));
animation-fill-mode: both;
}
/* initial position of the block starts ahead of the text, */
/* drags slightly (10% of duration) */
/* and moves over text */
@keyframes block-reveal {
0% {
transform: translateX(-110%);
}
45%, 55% {
transform: translateX(0);
}
100% {
transform: translateX(110%);
}
}
h1 span:nth-of-type(1) {
--color: var(--primary);
--index: 0;
}
h1 span:nth-of-type(2) {
--color: var(--secondary);
--index: 1;
}
h1 span:nth-of-type(3) {
--color: var(--tertiary);
--index: 2;
}
I find it especially interesting to see what this looks like without the clipping mask