Highlight Text When a User Scrolls Down to That Piece of Text


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.

Here the element is maybe 20% up the current viewport, so the animation is 80% finished.

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.