I was reading a great post on Lene Saile’s blog and noticed a cool little design feature on her site that highlights a line of text once you scroll to it. Here’s a video so you can see what I mean:
The highlighted line is done with a <mark>
element in HTML, which feels right. I noticed the class name on Lene’s implementation is .gsap-highlight
which implies GSAP is used which has as a great Scroll Trigger plugin. Let’s do this without JavaScript though, especially now that I’m hip to Scroll-Driven Animations.
Basic HTML
A paragraph with a mark (with a class):
<p>Lorem, ipsum dolor sit amet <mark class="scroll-highlight">consectetur adipisicing elit</mark>. Magnam voluptas aliquid, distinctio voluptatum neque qui modi. In adipisci ratione id officiis nulla veritatis, porro explicabo illum laudantium iure eius velit!</p>
Code language: HTML, XML (xml)
CSS Mark Styling in CSS
I just want a solid background on the mark. But I’m not going to use background-color
. Instead I’m going to use background-image
, because then I can control the background-size
which I ultimately want to animate. So:
mark.scroll-highlight {
background-size: 100% 100%;
background-repeat: no-repeat;
background-color: transparent;
background-image: linear-gradient(purple, purple);
}
Code language: CSS (css)
Now I can animate that background-size
from 0% 100%
to 100% 100%
which is the look we’re after. It even works when the text breaks across lines which is a miracle.
Now it’s a matter of when to run the animation.
Scroll-Driven Animation for the Mark
Here’s the whole trick:
mark.scroll-highlight {
background-size: 0 100%;
background-repeat: no-repeat;
background-color: transparent;
background-image: linear-gradient(purple, purple);
animation: mark-it linear;
animation-fill-mode: forwards;
animation-timeline: view();
animation-iteration-count: 1;
animation-range: contain 0% contain 25%;
}
@keyframes mark-it {
0% {
background-size: 0 100%;
}
100% {
background-size: 100% 100%;
}
}
Code language: CSS (css)
The coolest part to me is the animation-range
which gives us the opportunity to say when to start and end the animation with a solid amount of control. In the code above we’re saying to start the animation as soon as the element is fully within the viewport, then finish when it’s 25% of the way up the currently visible viewport.
Demo
Remember native support for Scroll-Driven Animations is essentially Chrome ‘n’ friends only right now. You could easily treat this as a progressive enhancement, wrapping the animation stuff in a @supports (animation-timeline: view()) { }
block or however you wanna do it.
Demo video:
Some similar ideas:
https://ryanmulligan.dev/blog/scroll-triggered-animations-style-queries/
Hi Chris,
in my opinion there’s a little possibility to do it better 😋
I forked your pen and I made a change on the mark when it’s in page but near the page bottom; now, you can’t see the text because it is white.
https://codepen.io/marcogargano/pen/RwdYGKo
What do you think?
Thanks for everything!!!