漂泊的城 發表於 2026-5-3 22:16:43

使用CSS实现一个滚动阴影效果

<h3>背景</h3>
<p>为了良好的用户体验,需要在容器顶部可滚动的情况下增加一个阴影条,提示用户可向上滚动;如果容器顶部不可滚动,则不显示阴影条,效果如下图所示:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/20231212104518653.gif" /></p>
<h3>实现</h3>
<p>首先我们定义好dom和相应的样式:</p>
<div class="jb51code"><pre class="brush:xhtml;">&lt;!-- 容器 --&gt;
&lt;div class="container"&gt;
        &lt;!-- 阴影 --&gt;
    &lt;div class="shadow"&gt;&lt;/div&gt;
        &lt;!-- 占位用,使容器能够滚动 --&gt;
    1&lt;br/&gt;
    2&lt;br/&gt;
    3&lt;br/&gt;
    4&lt;br/&gt;
    5&lt;br/&gt;
    6&lt;br/&gt;
    7&lt;br/&gt;
    8&lt;br/&gt;
    9&lt;br/&gt;
    10&lt;br/&gt;
    11&lt;br/&gt;
    12&lt;br/&gt;
    13&lt;br/&gt;
    14&lt;br/&gt;
    15&lt;br/&gt;
    16&lt;br/&gt;
&lt;/div&gt;</pre></div>
<div class="jb51code"><pre class="brush:css;">// 给容器设置最大高度,使其产生滚动
.container {
    max-height: 200px;
    overflow-y: auto;
    border: 1px solid black;
    position: relative;
}
// 利用sticky定位实现吸顶效果
.shadow {
    position: sticky;
    visibility: hidden;
    top: 0;
    left: 0;
    right: 0;
    box-shadow: 0 10px 0 10px rgba(0, 0, 0, 0.2);
        // 如果不希望阴影挡住下方内容的点击事件的话
    pointer-events: none;
}</pre></div>
<p>核心的实现便是如何判断容器顶部是否还有滚动空间,我们用到<a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop" target="_blank">scrollTop</a>属性,如果scrollTop大于0,说明可以向上滚动:</p>
<div class="jb51code"><pre class="brush:js;">import { debounce } from 'https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.min.js';
// 容器
const container = document.querySelector('.container');
// 阴影
const shadow = document.querySelector('.shadow');
// 用到了lodash的防抖函数,
// 通过scrollTop是否大于0来判断容器顶部是否还有滚动空间,
// 从而控制shadow是否显示。
const handler = debounce((e) =&gt; {
    if (e.target.scrollTop &gt; 0) {
      shadow.style.visibility = 'visible';
    } else {
      shadow.style.visibility = 'hidden'
    }
}, 50, { leading: true });
// 监听滚动事件
container.addEventListener('scroll', handler);</pre></div>
<p>然后就实现了开头的滚动阴影效果。</p>
<h3>举一反三</h3>
<p>会了顶部阴影,那怎么实现底部、左侧、右侧阴影呢?聪明的你肯定脱口而出用scrollBottom、scrollLeft、scrollRight比较一下就行了。行吗?不太行哦,元素没有scrollBottom、</p>
<p>scrollRight属性,因此底部和右侧阴影不能用这个方法实现。那么应该怎么搞呢,也简单,用到元素的scrollWidth和scrollHeight就可以实现scrollBottom和scrollRight的效果:</p>
<div class="jb51code"><pre class="brush:js;">const scrollRight = scrollWidth - scrollLeft;
const scrollBottom = scrollHeight - scrollTop;
// 然后再使用前文的逻辑处理即可
......
// 但是这里还有个坑,
// 上述的scrollBottom和scrollRight是通过浮点数相减来的,
// 会有精度问题,因此比较时不是直接与0比较,而是用Number.EPSILON
// 举个栗子
scrollRight &gt; Number.EPSILON</pre></div>
<p>其实不止滚动阴影,还有一些效果也是可以用这个思路做的,比如下图中的指示器效果:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/20231212104518654.gif" /></p>
<h3>总结</h3>
<p>写篇小水文,混混经验。我发现长篇的干货数据不太好,反而是这样几分钟看完的小水文数据还挺好看的。虽然水,但是也有不少知识点:</p>
<ul><li>sticky定位实现吸顶效果</li><li>pointer-events实现鼠标事件穿透</li><li>判断元素某个方向是否可滚动</li><li>防抖函数以及立即执行</li><li>浮点数精度用EPSILON处理</li></ul>
頁: [1]
查看完整版本: 使用CSS实现一个滚动阴影效果