Yet another scroll shadows implementation

Amal Jossy,cssjavascript

Can this content be scrolled or not? Try and you can find out. It's not always obvious that some content can be scrolled without trying to scroll first. The article, "perfectly-cropped", illustrates this concern. Another example is with forms, if not all mandatory fields can be seen without scrolling, the user will have to submit the form and read the error message to figure out what was missing. In smallcase apps, we let users submit forms only after passing the validations.

Form without scrollForm with scroll

A common solution is to use shadows, if there is content left to scroll, show a shadow. When there is no content left to scroll, remove the shadow. It's a solved problem. Some implementations are:

After reading all these solutions, I created the implementation that suited my needs best.

CSS-only solution

The CSS-only solution makes use of the background-attachment (opens in a new tab) property. The idea is explained in css-tricks (opens in a new tab). The shadows are backgrounds, which means they show behind any content in the scrollable area. We can't use this solution when certain elements don't have transparent backgrounds as content. The shadow will appear behind images, divs with their background, form elements etc. as shown in the codepen example.

With javascript

We can utilize the scroll event or IntersectionObserver. Using the scroll event lets us know how much content is left and use that information to vary the intensity as seen in this pen (opens in a new tab). Too much code listening to scroll events can degrade performance. Take care not to overdo it and to implement debounce. My requirement didn't need varying intensity so I went ahead with the IntersectionObserver. The gradient backgrounds won't help as the shadow should come over the content. A box-shadow also doesn't cover elements that are expected to have pointer-events like <input />. However, we can use gradient backgrounds on pseudo-elements and layer them on top of the content. The pseudo-elements should not prevent content from receiving pointer events either. The implementation can be understood from the cushion app blog (opens in a new tab).