滚动阴影

这可能是我最喜欢的 CSS 技巧了!它利用四个分层的背景渐变,在可以滚动的容器顶部和底部显示阴影,以指示可以朝该方向滚动。这是一种很好的用户体验,而且现在比 2012 年发明它时更重要,因为无滚动条的 UI 越来越普遍。

滚动阴影的想法非常合理。当容器向下滚动时,您可以在顶部看到一个阴影,这清楚地表明您可以向上滚动。如果可以向下滚动,则底部也会出现阴影,除非您已经滚动到底部。

这可能是我最喜欢的 CSS 技巧。这个想法来自 Roman Komarov,但 Lea Verou 想出了更精妙的 CSS 技巧并将其推广

滚动阴影是一种非常好的用户体验,几乎让人怀疑它为什么不是原生浏览器功能,或者至少在 CSS 中更容易实现。您可以称其为可供性,一种明显的视觉提示,表明滚动是可能的还是已经完成,不需要任何学习。

以下是一个可运行的示例

理解它是如何工作的有点费脑,部分原因是它使用了background-attachment: local;,这至少可以说是一种很少使用的属性。以下是一个尝试

  1. 这里有两种类型的阴影
    1. 普通阴影
    2. 覆盖阴影
  2. 所有阴影都是使用背景渐变创建的。例如,一个非重复的radial-gradient,大小和位置在元素的中心顶部,看起来像一个阴影。
  3. 覆盖阴影通过多个背景的堆叠顺序置于这些普通阴影之上,并且能够完全隐藏它们。
  4. 普通阴影使用background-attachment的默认值,即scroll,您会很熟悉它,因为它是背景通常工作的方式,您实际上不需要考虑它。背景只是在那里,位于元素可见部分的位置,并且不会随着元素滚动而移动。
  5. 溢出阴影使用不寻常的background-attachment: local;,它将它们放置在元素的顶部和底部边缘,考虑元素的整个滚动高度。它们随着元素滚动位置的移动而移动。

因此,想象一下这种情况:元素垂直溢出,并且目前已滚动到最顶部。顶部阴影和顶部覆盖阴影都在元素的顶部。覆盖阴影在顶部,隐藏了阴影,就好像它不存在一样。向下滚动一点,覆盖阴影就会粘在元素的最顶部,现在被溢出隐藏了,所以您再也看不到覆盖阴影,阴影就会显示出来。在底部,您一直都能看到阴影,因为覆盖阴影粘在元素的最底部,而阴影粘在可见区域的底部。滚动到底部,覆盖阴影将与底部阴影重叠,将其隐藏。这说起来很长,但它确实有效!

它很美妙,因为它只需要几行代码,您可以将其应用于单个元素即可完成。

.scroll-shadows {
  max-height: 200px;
  overflow: auto;

  background:
    /* Shadow Cover TOP */
    linear-gradient(
      white 30%,
      rgba(255, 255, 255, 0)
    ) center top,
    
    /* Shadow Cover BOTTOM */
    linear-gradient(
      rgba(255, 255, 255, 0), 
      white 70%
    ) center bottom,
    
    /* Shadow TOP */
    radial-gradient(
      farthest-side at 50% 0,
      rgba(0, 0, 0, 0.2),
      rgba(0, 0, 0, 0)
    ) center top,
    
    /* Shadow BOTTOM */
    radial-gradient(
      farthest-side at 50% 100%,
      rgba(0, 0, 0, 0.2),
      rgba(0, 0, 0, 0)
    ) center bottom;
  
  background-repeat: no-repeat;
  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  background-attachment: local, local, scroll, scroll;
}

它也不必只适用于白色背景,但需要是纯色。

以下是一个将颜色抽象为 CSS 自定义属性的版本

这不仅可以成为 UI/UX 的一个小细节,而且在容器没有滚动条或任何其他 UI 指示可以滚动的情况下,它对于指示容器中是否有更多可以滚动的内容至关重要。考虑 Tyler Hall 的故事完美裁剪,他在其中分享了他家人对 iOS 13 中的分享面板感到困惑的经历。在这个截图中,完全不清楚您可以向下滚动。

其他技巧

也许阴影可以根据要滚动的内容大小或强度进行调整?

Hakim El Hattab 曾经在推特上发布了一个例子,它很好地展示了这一点。

请注意该演示使用了一些 JavaScript 代码来完成。当然,我喜欢纯 CSS 版本,特别是它非常容易应用于单个元素。但是,还有许多使用 JavaScript 的版本,例如

  • 这个版本在需要时插入和淡入淡出阴影
  • 这个版本使用 React Hooks
  • 这个版本使用 Intersection Observer API

尽管我喜欢只在 CSS 中使用它,但您可能想要选择基于 JavaScript 的解决方案还有一个原因:iOS Safari。早在 2019 年 6 月,当 iOS 13 发布时,该版本(以及所有后续版本)中的 Safari 版本无法使用此技术。我实际上并不知道为什么。它看起来像是 bug。它与聪明的基于 CSS 的视差效果在 iOS Safari 上失效的同时失效。这可能与他们如何“缓存”网站的某些已绘制层有关。如果他们能修复它就好了。