<div class="container">
<p>We want to indicate if there's more to scroll by adding a decreased opacity on the top or bottom element.</p>
<p>However, if we're at the top, we don't want to decrease the opacity of the first element. And if we're at the bottom, we don't want to decrease the opacity of the last element.</p>
<p>We'll use <a href="https://caniuse.com/mdn-css_properties_animation-timeline">Scroll Driven Animations</a> for this usecase and <a href="https://caniuse.com/mdn-css_at-rules_property">@property</a>. Chrome only for now. Do not use in production.</p>
<div class="scroll">
<p class="message me">Hey!</p>
<p class="message you">Hey!</p>
<p class="message me">What's up?</p>
<p class="message you">All good, you?</p>
<p class="message me">All good.</p>
<p class="message you">Cool.</p>
<p class="message me">Cool.</p>
<p class="message you">Cool.</p>
<p class="message me">Cool.</p>
<p class="message you">Cool.</p>
<p class="message me">Cool.</p>
<p class="message you">Cool.</p>
<p class="message me">Cool.</p>
<p class="message you">Cool.</p>
<p class="message me">Cool.</p>
<p class="message you">👋</p>
<p class="message me">👋</p>
</div>
</div>
@supports (animation-timeline: view()) {
@keyframes y-distribution {
0% { opacity: 0.3; }
25% { opacity: 1 }
75% { opacity: 1 }
100% { opacity: 0.3; }
}
.message {
animation: y-distribution ease-in-out reverse both;
animation-timeline: view();
animation-range: normal;
}
}
/* Global styles */
body {
min-height: 100vh;
min-height: 100dvh;
background: #f0f0f0;
font-family: system-ui, sans-serif;
padding-top: 1rem;
}
.container {
max-width: 30rem;
margin: 0 auto;
}
.scroll {
max-height: 500px;
overflow-y: auto;
margin-top: 3rem;
}
.message {
padding: 1rem;
border-radius: 1rem;
}
.message + .message {
margin-top: 1rem;
}
.message.you {
margin-right: 2rem;
background: white;
}
.message.me {
margin-left: 2rem;
background: rgb(207 58 0);
color: white;
text-align: right;
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.