Reputation: 185
I can not seem to figure out how to style a scrollable div like the image below. Tutorials and examples that I found all fade the div out to the background colour, but I could not find one like this, does anyone have a solution? Does not need to have the inner divs and title as below, just needs to keep the white box unfaded, Thanks!
Upvotes: 7
Views: 18546
Reputation: 66208
You can use CSS mask-image
for browsers that support it (which is pretty common nowadays). Depending on your needs, JS might be needed (for example, if you wan to conditionally toggle the fading depending if the user has scrolled to the very top/bottom of the element).
To create a "bottom fadeout" effect, you can use this following CSS rule:
mask-image: linear-gradient(to bottom, black calc(100% - 48px), transparent 100%);
It basically says:
However, this only creates the bottom gradient. To mask both the top and the bottom, you will need to combine two gradients into one:
mask-image: linear-gradient(to bottom, transparent 0%, black 48px, black calc(100% - 48px), transparent 100%);
Now you ask: how do we hide the mask? Easy: if the color stops are spaced 0px apart, the mask will be black throughout, which will make it completely see through.
The JS part is simply toggling these color stops using classes. We use CSS custom properties that can be overridden by adding/removing a class. JS is used to sniff out the scroll position and toggle these classes. See proof-of-concept below:
function setClasses(el) {
const isScrollable = el.scrollHeight > el.clientHeight;
// GUARD: If element is not scrollable, remove all classes
if (!isScrollable) {
el.classList.remove('is-bottom-overflowing', 'is-top-overflowing');
return;
}
// Otherwise, the element is overflowing!
// Now we just need to find out which direction it is overflowing to (can be both).
// One pixel is added to the height to account for non-integer heights.
const isScrolledToBottom = el.scrollHeight < el.clientHeight + el.scrollTop + 1;
const isScrolledToTop = isScrolledToBottom ? false : el.scrollTop === 0;
el.classList.toggle('is-bottom-overflowing', !isScrolledToBottom);
el.classList.toggle('is-top-overflowing', !isScrolledToTop);
}
document.querySelector('#content').addEventListener('scroll', (e) => {
const el = e.currentTarget;
setClasses(el);
});
setClasses(document.querySelector('#content'));
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: #2a9d8f;
font-family: Arial, sans-serif;
}
.box {
width: 50vw;
height: 90vh;
background-color: #fff;
border-radius: 16px;
padding: 32px;
display: flex;
flex-direction: column;
}
.box h1 {
margin: 0;
}
#content {
overflow-y: auto;
-webkit-mask-image: linear-gradient(to bottom, transparent 0, black var(--top-mask-size, 0), black calc(100% - var(--bottom-mask-size, 0)), transparent 100%);
mask-image: linear-gradient(to bottom, transparent 0, black var(--top-mask-size, 0), black calc(100% - var(--bottom-mask-size, 0)), transparent 100%);
--top-mask-size: 0px;
--bottom-mask-size: 0px;
}
#content.is-top-overflowing {
--top-mask-size: 48px !important;
}
#content.is-bottom-overflowing {
--bottom-mask-size: 48px !important;
}
<article class="box">
<h1>Lorem ipsum</h1>
<section id="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel metus at tellus consectetur rhoncus. Aenean euismod eget mauris cursus tincidunt. Cras lectus dolor, suscipit nec porttitor a, tincidunt vel arcu. Etiam facilisis faucibus lectus
vitae pharetra. Fusce euismod lacus sit amet consequat mattis. Aliquam suscipit metus a nulla suscipit varius. In tempor suscipit pretium.</p>
<p>Vivamus aliquam eros eu orci finibus, id efficitur lorem placerat. Sed congue ipsum quis accumsan feugiat. Nunc imperdiet faucibus tellus, nec tincidunt ipsum dictum non. Quisque dui lacus, bibendum vitae lectus vel, vulputate tempus quam. Praesent
ullamcorper ultricies felis, at fermentum massa gravida quis. Pellentesque mollis, urna sed vehicula elementum, dolor lorem congue ipsum, eget ullamcorper ex arcu nec mi. Suspendisse potenti. Morbi pharetra eu nisi quis laoreet. Donec ut quam id
justo pulvinar volutpat eget ut magna.</p>
<p>Etiam aliquam eleifend dignissim. Donec sagittis tincidunt quam, eget venenatis mi sollicitudin et. Vestibulum id lectus mi. Aenean enim sem, viverra at velit ut, posuere dapibus tellus. Ut accumsan mi eu lectus sollicitudin ornare. Morbi eu semper
lacus lacus. Aenean id erat at nulla ornare consequat a at leo. In risus risus, blandit sit amet tortor sed, accumsan porttitor velit. Quisque interdum id ipsum quis convallis. Suspendisse vel pretium augue. Sed tincidunt, felis ut porta consectetur,
mauris urna hendrerit diam, nec aliquet augue ante quis metus.</p>
</section>
</article>
Upvotes: 21