Scroll shadows are when you can see a little inset shadow on elements if (and only if) you can scroll in that direction. It’s just good UX. You can actually pull it off in CSS, which I think is amazing and one of the great CSS tricks. Except… it just doesn’t work on iOS Safari. It used to work, and then it broke in iOS 13, along with some other useful CSS things, with no explanation why and has never been fixed but is now fixed, at least as of July 2022 (thanks Ronald!).
Here’s a pure CSS example so you can see it work in all browsers. Screenshots:
![](https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/09/Screen-Shot-2021-09-27-at-2.25.04-PM.png?resize=530%2C502&ssl=1)
![](https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/09/Screen-Shot-2021-09-27-at-2.25.14-PM.png?resize=588%2C506&ssl=1)
![](https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/09/Screen-Shot-2021-09-27-at-2.25.19-PM.png?resize=552%2C490&ssl=1)
I’m bringing this up now because I see Jonnie Hallman is blogging about it again. He mentioned it as an awesome little detail back in May. There are certain interfaces where scroll shadows really extra make sense.
![](https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/09/Screen_Shot_2021-09-05_at_9.52.01_AM.webp?resize=1330%2C1020&ssl=1)
Taking a step back, I thought about the solution that currently worked, using scroll events. If the scroll area has scrolled, show the top and left shadows. If the scroll area isn’t all the way scrolled, show the bottom and right shadows. With this in mind, I tried the simplest, most straight-forward, and least clever approach by putting empty divs at the top, right, bottom, and left of the scroll areas. I called these “edges”, and I observed them using the Intersection Observer API. If any of the edges were not intersecting with the scroll area, I could assume that the edge in question had been scrolled, and I could show the shadow for that edge. Then, once the edge is intersecting, I could assume that the scroll area has reached the edge of the scroll, so I could hide that shadow.
Clever clever. No live demo, unfortunately, but read the post for a few extra details on the implementation.
Other JavaScript-powered examples
I do think if you’re going to do this you should go the IntersectionObserver
route though. Would love to see someone port the best of these ideas all together (wink wink).
Also do check out this article be lea verou
https://lea.verou.me/2012/04/background-attachment-local/
Still a fan of the pure CSS approach. In Safari (on iOS) these shadows are rendered in the correct position, but they don’t get re-rendered as you scroll. Using a little tad of JS you can force a re-render.
See https://www.bram.us/2019/10/24/pure-css-scroll-shadows-vertical-horizontal/#note-mobilesafari for details + code.
UPDATE: Turns out this workaround no longer works in iOS15
The pure CSS example (
Here’s a pure CSS example so you can see it work in all browsers except iOS Safari.
) is actually working for me on iOS Safari.It was holding me back using that super easy and clean way of doing it, but now that it works it is my absolute favourite way.
(Would be great if the article could be updated)
You bet, thanks for the heads up!