One of the most self-explanatory ways to let the user know that an element is scrollable is to use some sort of fading overlay on the scrollable ends of a container. I wonder how could this be done in a clean way.
I want the elements to have overlay only when there is more content to scroll to, I've seen examples which had stationary faded overlays but those are imperfect IMO.
You can use ::before and ::after pseudo elements that are positioned absolutely. Here is the structure:
<div className="outer-container"> <!-- overflow-x: hidden -->
<div className="inner-container"> <!-- flex & overflow-x: scroll -->
<div>1</div>
<div>2</div>
<div>3</div>
...
</div>
</div>
.outer-container {
overflow-x: hidden;
position: relative;
}
.outer-container::before {
content: "";
position: absolute;
top: 0;
left: 0;
bottom: 0;
background: linear-gradient(to right, #fff, transparent);
width: 3rem;
}
.outer-container::after {
/* same */
right: 0;
background: linear-gradient(to left, #fff, transparent);
/* same */
}
.inner-container {
display: flex;
flex-direction: row;
overflow-x: scroll;
}
The reason we use two containers is that we need to keep the absolute elements (::before & ::after) stationary and prevent them from moving with the scrollable inner container.
Also to let the user know that s/he is at the end of the element boundaries, we can use the logic below:
.scrollLeft > 0.offsetWidth + .scrollLeft < .scrollWidthSo that when the user scrolls to the beginning or end of the scrollable container, those overlays hide.
I made an example using react and styled-components, you can see it here: https://codesandbox.io/s/horizontal-scroll-with-overlay-elements-uhec0?file=/src/App.tsx