Sticky elements (position: sticky;) are very similar to fixed elements ( position: fixed;) in that they both maintain their position on the screen, even as the user scrolls up or down the page. The difference? A sticky element remains confined to the parent container it is in. Compare sticky example above with this one that uses the same concept using a fixed element instead:

I’m not doing much to the sticky elements, except styling them. They’re already doing what they need to do: stick to the screen. All that’s left is to create a cover and some space for the elements to come in and leave as the page scrolls.

There are probably a bunch of ways we can create a cover on the article that sticky elements can pass and hide under on a page — I went with a background-image.

The background linear gradient is applied to the article and runs from top to bottom, starting with 50px of transparency and a color change with a hard stop at 50px. The calc stuff? That’s how I’m telling the color to continue but leave 50px at the bottom. Then we go transparent again. That means we have two 50px transparent stripes, one at the top and one at the bottom with equal heights matching the heights of the category heading and the footer.

The category header and the article footer are the elements that slide in and out of the text, so their heights are the ones that determine how long the transparent stripes will be at the top and bottom of the gradient.

How this all comes together is that both the category header and article title stick to the screen when their tops align with the top of the viewport. The title stacks on top of the category header and, when it starts sticking at the top of the viewport, hides the category header altogether.

As for the footer, it’s already stuck 100px above the bottom of the screen (within the article’s boundary), but you won’t see it since it’s pushed behind the content using z-index:-1. It’ll be visible once we scroll past the beginning of the last transparent stripe of article’s background.

.footer {
bottom: 100px;
margin: 50px auto auto auto;
z-index: -1;
}

Because the category header is just content with nothing to conceal with but the text itself, it’s a good idea to give the last sticky element (the footer) a top margin of 50px (to keep things equal) so that you won’t see it behind the category header while scrolling.

That’s it!

Now, of course, you’ll want to make this your own and change it up, like the dimensions, number of elements, and type of content. The key is to create those covers that allow your sticky elements to hide behind and be revealed as they pass through — again, probably different ways to go about that, but I went with transparent stripes in a gradient.

What, another example? Sure!

Here’s another example with horizontal scrolling (and a horizontal gradient), that might be ideal for applying this concept to mobile devices:

Notice again that we’re going with the same two 50px transparent stripes as before — the only difference being that we’re applying it to the width instead of the height.

Both of the sticky elements (the title and image) will slide under and through the article. So, in order to avoid overlapping them during scroll, the title gets a right margin that’s equal to the image’s width, which is 50px (plus an additional 2px for a cleaner line in Chrome).

Here’s what’s going on: as we scroll horizontally, the title sticks 20px from the screen’s left edge and the image sticks 150px from the same. Because they both have z-index: -1;, they’ll disappear under the article (well, the background gradient) — they are hidden as they pass through the solid color of the gradient and are revealed by the transparent stripes.

OK, one more example

Before wrapping up, let me show you one more example that inspired this post. It’s a site footer that reveals itself on scroll. I first saw this design at Ryan Seddon’s website a long time ago.

This design is usually done by using a "fixed" footer that’s given some space at the end of the page to come out to, using margin. I thought if fixed elements can do that for the whole page, then maybe sticky elements can do something similar for individual elements — and hence what I came up with so far.

Consequently, we can accomplish this same effect using the sticky techniques we’ve covered so far.

Share this:

Comments

I have been playing around with using sticky elements using z-index to place them over scrolling background elements and tying everything together using css-grid with a parent container including both the sticky and scrolling elements. This all works great in html/css and when converted to both react or vue it continues to work great. However, if I try to break things down into components in either react or vue, the unifying css-grid falls apart. I guess this is more of a css-grid question than a “sticky” element question. Sorry. If you have any suggestions as to how to make a css-grid work across several react, or vue, components within a css-grid parent container holding all of them together, please let me know. The reason I want to use components is so that I can hide/show or load/remove things in groups and do other react/vue goodness stuff that makes more sense using components. The css-grid related css is all in one file that is imported to the individual component files. I think the problem may be the absence of CSS-grid sub-grids in the CSS-grid api, but I am not sure. I hope that all makes sense. Thanks: Jim

Since this effect requires the revealed element the be stacked beneath with negative z-index, it renders the element inaccessible to pointer events. Not necessarily a significant issue for something like a graphic/ornament but if I’m understanding correctly, that element could not contain an interactive element such as a link/button. Do you have an implementation that would allow interaction? It would be really cool to say reveal a toolbar of options.

👋

CSS-Tricks* is created, written by, and maintained by Chris Coyier and a team of swell people. It is built on WordPress and powered up by Jetpack. It is made possible through sponsorships from products and services we like.