“Raise the curtains” is what I call an effect where the background goes from dark to light on scroll, and the content on top also goes from light to dark while in a sticky position.
First, we need a container for the curtain, which we’ll give a .curtain class. Then, inside the .curtain, we have the an .invert child element that will serve as our “sticky” box. And, finally, we have the content inside this box — a good old-fashioned <h2> element for this specific example.
Let’s set up some CSS variables
There are three values we know we’ll need upfront. Let’s make CSS variables out of them so it’s easy to write them into our styles and easily change them later if we need to.
Next, we can define our .curtain element using the following techniques:
A linear-gradient for the “split” background
min-height for the extra space at the bottom of the container
We use the ::after pseudo-element to add the extra space to the bottom. This way, our “sticky” content will actually stick to the container while scrolling past the ::after element. It’s an illusion.
.curtain {
/** create the "split" background **/
background-image: linear-gradient(to bottom, var(--color2) 50%, var(--color1) 50%);
}
/** add extra space to the bottom (need this for the "sticky" effect) **/
.curtain::after {
content: "";
display: block;
min-height: var(--minh);
}
Making sticky content
Next up, we need to make our content “sticky” in the sense that it sits perfectly inside the container as the background and text swap color values. In fact, we already gave the .curtain‘s child element an .invert class that we can use as the sticky container.
Stay with me for a moment — here’s how this is going to play out:
position: sticky and top define the stickiness and where it sticks.
mix-blend-mode: difference blends the color of the content inside the <h2> element into the .curtain‘s background gradient.
display: flex centers the content for presentation.
min-height defines the height of the container and allows for the extra space at the bottom.
color sets the color of the h2 heading.
Now to put that into CSS code!
.invert {
/** make the content sticky **/
position: sticky;
top: 20px;
/** blend the content with the contrast effect **/
mix-blend-mode: difference;
/** center the content **/
display: flex;
align-items: center;
justify-content: center;
/** set the minimum height of the section **/
min-height: var(--minh);
}
h2 {
/** set the color of the text **/
color: var(--color1);
}
There are many things going on here, so let’s explain each one of them.
First, we have a sticky position that is self-explanatory and flexbox to help center the content. Nothing new or particularly tricky about this.
The content’s height is set using CSS variable and the value is the same height value as the .curtain::after pseudo-element.
The mix-blend-mode: difference declaration blends our content with the background. The difference value is complicated, but you might visualize it like inverted text color against the background. Here’s a nice demo from the CSS-Tricks Almanac showing off the different mix-blend-mode values:
To make the blending work, we need to set the color of our heading. In this case, we’re assigning a light color value (wheat) to the --color1 variable.
“Raise the Curtains” Demo
Gotchas
I experienced a few problems while working out the details of the “raise the curtain” effect. If you want to add images to the “sticky” content, for example, avoid using images that don’t look good when their colors are inverted. Here’s a quick demo where I made a simple SVG and transparent PNG image, and it looks good.
Another gotcha: there’s no way to set mix-blend-mode: difference on specific child elements, like headings, while avoiding the effect on images. I discovered there are several reasons why it doesn’t work, the first of which is that position: sticky cancels the blending.
The same goes when using something like transform: skewY on the container to add a little “tilt” to things. I suspect other properties don’t play well with the blending, but I didn’t go that far to find out which ones.
Here’s the demo without scrolling that removes the troubling properties:
Curtain call!
I enjoyed building this component, and I always love it when I can accomplish something using only HTML and CSS, especially when they work smoothly on every browser.
What will make with it? Is there a different way you would approach a “raise the curtain” effect like this? Let me know in the comments!
Space art has been rising in popularity thanks to people’s curiosity for the unknown and the beautiful images from NASA that amazed and inspired us over the years. Today designers are letting their imagination run wild, and creating some of their own space art in the form of Photoshop brushes. In this article, you will...
Your web hosting plays a crucial role in your website’s speed, performance, and security. Therefore, it’s important to make sure that you choose a reliable provider. Our DreamHost review will help you decide whether this well-known host is the right fit for you.