在设计前端页面时,常常会遇到这种情况:可滚动容器的边界并非父容器的边界,导致子元素溢出造成裁切,让页面产生比较怪异的视觉效果(左图)
添加遮罩之后,效果自然了许多(右图)
纯色遮罩
以上图的这种情况举例,我们需要做的,是在可滚动容器的顶部和底部分别放置一个线性渐变的纯色遮罩,遮挡生硬的裁切线。创建两个元素 .top-mask
、.bottom-mask
来作为遮罩,遮罩的颜色与父容器背景一致,使用 absolute 定位。
直接为可滚动容器设置 position: relative
是行不通的,这会导致遮罩跟随容器滚动。所以需要在可滚动容器外部再嵌套一层 relative 定位的元素,使两个遮罩根据其位置定位,最终的结构大概是下面这样的:
在 Codepen 查看演示
后续为了优化视觉效果,可以根据条件显示/隐藏对应的 mask 元素(滚动条在顶部时不显示 top-mask,反之亦然)
改进:Alpha 遮罩
上面的这种方法有许多缺陷:
- 引入了许多额外的元素,致使整体布局变得复杂。
- 蒙版覆盖在可滚动容器之上,需要使用
pointer-events: none;
避免影响滚动操作。 - 仅适用于父容器为纯色的场景,在父容器有透明度、有背景图案或渐变时,遮罩会露馅。
是否有一种方法,在不引入额外元素、不使用绝对定位的条件下,解决这些缺陷呢?这时候就可以用到 mask
CSS属性。mask
属性允许提供一张图片作为蒙版,改变元素的可视区域。我们只需要生成一个线性渐变,将其作为可滚动容器的蒙版即可。
使用linear-gradient创建一个多段的线性渐变,得到图中的蒙版效果。
接着,将得到的渐变图案作为 mask 应用到滚动容器上,为了便于自定义,将这里的遮罩高度 25px
提取出来,以 CSS 变量的形式提供。下面是完整的样式:
因为我们将容器两侧的遮罩合并到了一个线性渐变中,想要控制其中一侧的遮罩就不太容易了,为了实现遮罩的独立控制,额外定义了 --show-top-mask
和 --show-bottom-mask
变量。最终的效果如下图所示:
在 CodePen 查看