最近小组遇到一个设计实现的一个问题,大概就是一个横向滑动列表,在最右侧实现一个遮罩层然后让元素从底部溜入的场景,然后点击这个遮罩层穿透到对应的列表元素上去。
其实一般思路就是借助一个元素来实现遮罩效果或者稍微优化一些,使用伪类,但是他们都会拦截鼠标的交互,无法将交互应用到遮罩层下方的列表元素上,这也是这个问题的难点所在。
这个项目我没有参与,但是在开会的时候我们组长将问题抛出了,他们也是花了一些时间来解决,但最终解决的方法使用了css的 touch-action、 cursor-event 等不常用的属性(大家可以自行尝试),组长貌似也是觉得这个解决方案不够普遍、优雅,所以也就抛出来向大家征求有没有更好的方案,但是当时大家似乎也没啥好的建议。
回到家后,刚好我手头上有一本《css揭秘》,我就想看看有没有这个场景的解决方法,还真让我找到了,而且还非常简单,核心就是一句话, ** box-shadow 只是能引起视觉上的效果 无法阻止鼠标交互 **
所以问题就豁然开朗了,只要借助box-shadow来实现视觉上的遮罩就ok了。
下面我们来实际操作一下:
首先将场景UI生成:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
ul {
width: 200px;
height: 50px;
list-style: none;
overflow-x: auto;
white-space: nowrap;
background-color: #ccc;
}
ul::-webkit-scrollbar {
display: none;
}
ul>li {
margin-left: 10px;
display: inline-block;
border-bottom: 5px solid red;
}
</style>
</head>
<body>
<ul id="list">
<li>aaaa</li>
<li>bbbb</li>
<li>cccc</li>
<li>dddd</li>
<li>eeee</li>
<li>ffff</li>
<li>gggg</li>
<li>hhhh</li>
<li>iiii</li>
<li>jjjj</li>
</ul>
<script>
const ul = document.querySelector("#list")
ul.addEventListener('click', (e) => {
const item = e.target;
console.log(item);
}, true)
</script>
</body>
</html>
效果如下:
并且我们点击对应元素,就会在控制台里面打印出来。
然后我们借助伪元素来添加遮罩层,其实这里我也踩了一些坑,我把我踩过的坑先记录一下,然后过渡到最终的结果
首先大方向是借助box-shadow 而且是伪元素的box-shadow,所以第一次我是这么写的,我们暂且称之为1.0
// 1.0
ul::before {
position: fixed;
width: 50px;
height: 30px;
left: 198px;
content: '';
box-shadow: inset 50px 30px red;
}
效果如下,我们用红色来标识伪元素
我们采用了inset box-shadow,看上去基本没啥问题,可是当我们点击上去之后,发现控制台打印的是
是当前伪元素ul,而并非伪元素下面的li,所以虽然我们给伪元素着色的方式是采用了box-shadow,但是其实还是在伪元素这个元素本身上面做文章,所以我们点击的还是元素,并非box-shadow,所以我们再次明确一下我们的目标:
借助伪元素来实现遮罩,并且使用box-shadow来实现遮罩效果,而且点击一定要点击到box-shadow上,
所以我们就不能使用inset,就正常让box-shadow脱离元素就好了,所以2.0应运而生,为了让大家看的更清楚,先给出2.0.1:
我们用蓝色来标注伪元素,用红色来标注阴影
// 2.0.1
ul::before {
position: fixed;
width: 50px;
height: 30px;
left: 0;
content: '';
background-color: blue;
box-shadow: 50px 0 red;
}
然后我们接下来要做的其实就是让伪元素本身“消失”,只留下红色的阴影部分,
切记不能使用display:none visibility:hidden opacity:0这三种方法,因为阴影是相对于他的元素的,元素消失不见,阴影也就随之而去了
其实到这一步解决方法也就多种多样了,我们可以分别设置位移:将蓝色移出视口外,将红色阴影移到最右侧
// 2.0.2
ul::before {
position: fixed;
width: 50px;
height: 30px;
left: -50px;
content: '';
background-color: blue;
box-shadow: 248px 0 red;
}
效果如下:
我们点击红色阴影后 成功穿透到了下面的自元素
也可以不用移动伪元素,将伪元素本身设置为透明
ul::before {
position: fixed;
width: 50px;
height: 30px;
content: '';
background-color: transparent;
box-shadow: 150px 0 red;
}
到这里基本上可以解决问题了,而且也不复杂,但其实还可以优化,最后,给出我的终极解决方案:利用box-shadow可以设置多个阴影,结合我们1.0没有成功的inset来实现
ul::before {
position: fixed;
width: 50px;
height: 30px;
content: '';
box-shadow: inset 50px 30px transparent,
150px 0 2px red;
}
写在后面,前端技术日新月异,更新换代,日积月累,量变质变。