当前位置: 首页 > 科技观察

使用:要实现3D轮播

时间:2023-03-13 19:52:22 科技观察

这次我们带来一个比较常见的案例,3d轮播,像这样:这个轮播有几个点需要实现:3D视觉,就是中间大,两边小。自动轮播,鼠标放置自动暂停。单击任何卡片将立即跳转到该卡片。这次我们用:has来实现这样一个功能,相信能带来不一样的想法,一起来看看吧!温馨提示:需要Chrome101+兼容,开启实验性功能(官方支持105+)。Safari15.4+,Firefox官方说可以支持实验特性,但实际测试不支持。1.3D视觉风格是重点。首先我们做一个简单的布局,假设HTML是这样的:1

2
3
4
5678910为了尽可能的降低复杂度,我们可以把所有的改动集中在一个类名上。比如.current表示当前选中的item,也就是中间那个。这里采用绝对定位的方式,将所有的卡片物品堆叠在一起,然后设置3d视图,将卡片的Z轴向后移动一定距离,使得.效果如下:.view{position:relative;宽度:400px;高度:250px;变换样式:保留3d;perspective:500px;}.item{position:absolute;宽度:100%;高度:100%;边界半径:8px;显示:网格;地点内容:中心;盒子阴影:2px2px10pxrgba(0,0,0,0.1);transform:translate3d(0,0,-100px);}.item.current{transform:translate3d(0,0,0);}效果如下:其实层级是这样的,可以看在Chrome层:现在,我们需要让相邻的左右两边泄漏出来,右边比较简单,只需要使用相邻兄弟选择器+.item.current+.item{transform:translate3d(30%,0,-100px);}相邻的左边呢?以前没办法,通过JS分别设置不同的类名很麻烦,现在有了:has伪类,也可以轻松实现,如下.item:has(+.item.current){transform:translate3d(-30%,0,-100px);}效果如下:但是还是有一些危急情况,比如第一张卡片,因为前面没有兄弟节点,所以它变成了这样。所以需要把最后一个元素放在第一个元素的左边,第一个元素是:first-child,最后一个元素是:last-child,所以实现是这样的(最后一个元素处理同理)..item.current:first-child~.item:last-child{transform:translate3d(-30%,0,-100px);opacity:1;}.item:first-child:has(~.item.current:last-child){transform:translate3d(30%,0,-100px);opacity:1;}这处理边缘情况。更进一步,两张卡片可以暴露在两边,实现类似,完整的实现如下:/*currentitem*/.item.current{transform:translate3d(0,0,0);}/*current右项1*/.item.current+.item,.item:first-child:has(~.item.current:last-child){transform:translate3d(30%,0,-100px);}/*current剩余项目1*/.item:has(+.item.current),.item.current:first-child~.item:last-child{transform:translate3d(-30%,0,-100px);}/*当前项右2*/.item.current+.item+.item,.item:first-child:has(~.item.current:nth-last-child(2)),.item:nth-child(2):has(~.item.current:last-child){transform:translate3d(50%,0,-150px);}/*当前项目还剩2*/.item:has(+.item+.item.current),.item.current:first-child~.item:nth-last-child(2),.item.current:nth-child(2)~.item:last-child{转换:translate3d(-50%,0,-150px);}这样就实现了所有关于.current的样式处理,所有的变化都只用一个变量来控制。2.自动轮播和暂停有了上面的处理,接下来的逻辑就很简单了,只需要通过js动态控制.current的变化即可。一般情况下,我们可能会想到使用定时器setInterval,但是在这里,我们也可以不使用定时器,借助CSS动画的力量,更容易完成这样的交互。要做的事情就是简单地向容器中添加一个无关紧要的CSS动画。.view{/**/animation:scroll3sinfinite;}@keyframesscroll{to{transform:translateZ(.1px);/*无关紧要的动画风格*/}}这给出了一个持续时间为3秒的无限循环动画。然后,监听animationiteration事件,每次动画运行都会回调,这里是每3s运行一次,就像setIntervalGlobalEventHandlers.onanimationiteration-WebAPI接口参考|MDN(mozilla.org)[1]。在animationiteration回调中处理.current逻辑非常简单。删除当前的.current并将.current添加到下一个。只注意边界。具体实现如下:view.addEventListener("animationiteration",()=>{constcurrent=view.querySelector(".current")||view.firstElementChild;current.classList.remove("current");if(current.nextElementSibling){current.nextElementSibling.classList.add("current");}else{view.firstElementChild.classList.add("current");}});使用animationiteration最大的好处就是可以直接通过css来控制动画,再也不用监听鼠标进出事件了。.view:hover{animation-play-state:paused;}效果如下(方便演示,速度调的比较快)。3.点击快速切换点击切换。其实我首先想到的是通过:checked,类似于radio选择,比如:但现在:有伪-class好像不支持多级嵌套,比如下面的语句。...has(:checked))表示选择它之前的兄弟节点,这样就可以实现选择的功能,可惜现在不支持了