I absolutely love the design of the Sandwich site. Among many beautiful features are these headlines with rainbow underlines that move as you scroll. It’s not scroll-jacking — it’s just a minor design feature that uses scroll position to enact a little movement.
To draw the rainbows themselves, we could use a linear gradient with hard-stops, the same kinda concept as drawing stripes in CSS. That’s a big ol’ chunk of CSS, which is fine, but I see they’ve opted for a background-image
instead. Here’s that as an SVG, which is 661 bytes (tiny tiny). We can make it look like an underline by setting the background-size
to limit the height and position it along the bottom with background-position
.
We’ll do it on an inline element so the underline breaks where the words break:
h1 {
span {
background-image: url(spectrum.svg);
background-repeat: repeat-x;
background-size: 100vw 0.2em;
background-position: left bottom 5px;
}
}
To animate it, we move the background-position-x
. Not a particularly performant thing to animate, but we’re not really animating it anyway — it’s just moving based on scroll position. Rather than manually manipulate the background-position-x
, we’ll set it with a custom property, then manipulate the custom property with JavaScript.
background-position-x: var(--scrollPos);
Updating that variable while the page scrolls is easy peezy:
window.addEventListener("scroll", e => {
let scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
let newPos = scrollTop + "px";
document.documentElement.style.setProperty('--scrollPos', newPos);
});
Here it is working!
See the Pen
Rainbow Underlines by Chris Coyier (@chriscoyier)
on CodePen.
See that kinda janky line where I’m either using document.body
or document.documentElement
? That’s a stupid cross-browser thing where the “scrolling element” is different in Safari versus everything else.
While doing this I learned that you can use document.scrollingElement
instead to avoid the pain there. I’ll leave a comment in the code about that, but leave the original line for posterity.
scrollingElement works on Chrome not problem with this line:
let scrollTop = document.scrollingElement.scrollTop;
Yeah man. At the end of the article I say:
Soooooooooooo cooooool. Thank you
Neat!
Nice :-) LGBT sites should have this as default, lol
Thanks for the article, have a great day!
This is really cool, but it literally is scrolljacking, though – it uses JS to listen to scroll and does stuff there.
So cute. Thanks for sharing it
The SVG could be reduced by almost half (down to 372 bytes):
But even so, a CSS gradient producing the exact same result is just 136 bytes:
live test
I also think it is better to use CSS gradients.
If we tilt rainbow-background and put transparent bar above it, when we scroll we get a visual illusion that the rainbow is moving.
To achieve this we can use
box-sizing
(border-box
) on the background in combination withbackground-attachment: fixed;
and transparentborder-bottom
.I think this should be responsive (with linear-gradient [Ana’s solution])… https://codepen.io/maddesigns/pen/XWJvJeR