日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
借助 :has 實現(xiàn)3D輪播圖

這次帶來一個比較常見的案例,3d 輪播圖,就像這樣的:

創(chuàng)新互聯(lián)建站主要從事網(wǎng)站建設(shè)、成都網(wǎng)站制作、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)安康,十載網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575

這個輪播圖有幾個需要實現(xiàn)的點:

  1. 3d 視覺,也就是中間大,兩邊小。
  2. 自動輪播,鼠標(biāo)放上自動暫停。
  3. 點擊任意卡片會立即跳轉(zhuǎn)到該卡片。

這次借助:has來實現(xiàn)這樣的功能,相信可以帶來不一樣的思路,一起看看吧!

溫馨提醒:兼容性要求需要 Chrome 101+,并且開始實驗特性(105+正式支持),Safari 15.4+,F(xiàn)irefox 官方說開啟實驗特性可以支持,但是實測并不支持。

一、3d 視覺樣式

這一部分才是重點。

首先我們來簡單布局一下,假設(shè)HTML是這樣的:


1

2

3

4

5

6

7

8

9

10

為了盡可能減少復(fù)雜度,我們可以將所有的變化都集中在一個類名上。

比如.current?表示當(dāng)前選中項,也就是中間的那項。這里采用絕對定位的方式,將所有卡片項都堆疊在一起,然后設(shè)置3d?視圖,將卡片的Z?軸往后移動一段距離,讓.current在所有卡片的最前面,實現(xiàn)近大遠(yuǎn)小的效果,具體實現(xiàn)如下:

.view {
position: relative;
width: 400px;
height: 250px;
transform-style: preserve-3d;
perspective: 500px;
}
.item {
position: absolute;
width: 100%;
height: 100%;
border-radius: 8px;
display: grid;
place-content: center;
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1);
transform: translate3d(0, 0, -100px);
}
.item.current {
transform: translate3d(0, 0, 0);
}

效果如下:

其實層級是這樣的,可以在 Chrome 圖層中看到:

現(xiàn)在,我們需要讓相鄰左右兩邊的都漏出來,右邊的比較容易,用相鄰兄弟選擇器??+??就可以了

.item.current + .item{
transform: translate3d(30%, 0, -100px);
}

那相鄰左邊的呢?以前是無解的,只能通過 JS 分別設(shè)置不同的類名,非常麻煩,但現(xiàn)在有了??:has??偽類,也可以輕松實現(xiàn)了,如下

.item:has(+.item.current){
transform: translate3d(-30%, 0, -100px);
}

效果如下:

不過還有一些臨界情況,比如在第一個卡片時,由于前面沒有兄弟節(jié)點了,所以就成了這樣。

所以需要再在第一個元素時,把最后一個元素放在它的左邊,第一個元素是:first-child?,最后一個元素是:last-child,所以實現(xiàn)是這樣的(最后一個元素處理同理)。

.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;
}

這樣就處理好了邊界情況。

進(jìn)一步,還可以向兩側(cè)露出兩個卡片,實現(xiàn)也是類似的,完整實現(xiàn)如下:

/*當(dāng)前項*/
.item.current {
transform: translate3d(0, 0, 0);
}
/*當(dāng)前項右1*/
.item.current + .item,
.item:first-child:has(~ .item.current:last-child) {
transform: translate3d(30%, 0, -100px);
}
/*當(dāng)前項左1*/
.item:has(+ .item.current),
.item.current:first-child ~ .item:last-child {
transform: translate3d(-30%, 0, -100px);
}
/*當(dāng)前項右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);
}
/*當(dāng)前項左2*/
.item:has(+.item + .item.current),
.item.current:first-child ~ .item:nth-last-child(2),
.item.current:nth-child(2) ~ .item:last-child{
transform: translate3d(-50%, 0, -150px);
}

這樣就實現(xiàn)了關(guān)于.current的全部樣式處理了,只用一個變量就控制了所有變化。

二、自動輪播和暫停

有了上面的處理,接下來的邏輯就非常簡單了,只需要通過js動態(tài)控制.current的變化就行了。

一般情況下,我們可能會想到用定時器setInterval,但這里,我們也可以不使用定時器,借助 CSS 動畫的力量,可以更輕松地完整這樣的交互。

要做的事情很簡單,給容器添加一個無關(guān)緊要的 CSS 動畫。

.view {
/**/
animation: scroll 3s infinite;
}
@keyframes scroll {
to {
transform: translateZ(.1px); /*無關(guān)緊要的動畫樣式*/
}
}

這樣就得到了一個時長為3s,無限循環(huán)的動畫了。

然后,監(jiān)聽animationiteration?事件,這個事件在動畫每次運(yùn)行一次就會回調(diào)一次,在這里也就是每3s?運(yùn)行一次,就像setInterval的功能一樣

GlobalEventHandlers.onanimationiteration - Web API 接口參考 | MDN (mozilla.org)[1]。

在animationiteration?回調(diào)中處理.current?邏輯,很簡單,移除當(dāng)前的.current?,給下一個添加.current,注意一下邊界就行了,具體實現(xiàn)如下:

view.addEventListener("animationiteration", () => {
const current = 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 進(jìn)行動畫的控制,再也無需監(jiān)聽鼠標(biāo)移入移出事件了。

.view:hover{
animation-play-state: paused;
}

效果如下(方便演示,速度調(diào)快了)。

三、點擊快速切換

點擊切換,我其實最先想到的是通過:checked,也就是類似單選,比如:








但是目前來看??:has??偽類貌似不支持多層嵌套,比如下面這條語句。

.item:has(+.item:has(:checked)){
/*不生效*/
}

.item:has(:checked)選中的是子元素被選中的父級,然后.item:has(+.item:has(:checked))表示選中它的前面一個兄弟節(jié)點,這樣就能實現(xiàn)選中功能了,可惜現(xiàn)在并不支持(以后可能支持)。

沒辦法,只能通過傳統(tǒng)方式來實現(xiàn),直接綁定監(jiān)聽click事件。

view.addEventListener("click", (ev) => {
const current = view.querySelector(".current") || view.firstElementChild;
current.classList.remove("current");
ev.target.closest('.item').classList.add("current");
});

效果如下:

完整代碼可以查看線上 demo:CSS 3d scroll (codepen.io)[2]或者CSS 3dscroll(runjs.work)[3]。

四、總結(jié)一下

以上就是借助:has偽類來實現(xiàn)一個3d輪播圖的全部細(xì)節(jié)了,所有的視覺變化全部在 CSS 中完成,JS 只需要處理切換邏輯就行了,相比以前而言,實現(xiàn)上更加簡潔和優(yōu)雅,下面總結(jié)一下。

  1. 3d 視覺樣式可以通過transform-style: preserve-3d;實現(xiàn)近大遠(yuǎn)小的效果。
  2. 通過.item:has(+.item.current)可以設(shè)置當(dāng)前項前面的兄弟節(jié)點。
  3. 還需要考慮第一個和最后一個這兩種臨界情況。
  4. 輪播圖自動輪播和暫停可以借助animationiteration?回調(diào),這種方式的優(yōu)勢是可以通過:hover控制。
  5. :has偽類貌似不支持多層嵌套,希望以后可以支持吧~

:has非常強(qiáng)大,目前唯一的缺陷在于兼容性。好在瀏覽器對于這一新特性跟進(jìn)的都比較積極,明年這個時候差不多可以在內(nèi)部項目用起來了。

參考資料

?[1]GlobalEventHandlers.onanimationiteration - Web API 接口參考 | MDN (mozilla.org): https://developer.mozilla.org/zh-CN/docs/Web/API/Element/animationiteration_event。

[2]CSS 3d scroll (codepen.io): https://codepen.io/xboxyan/pen/PoeGjdg。

[3]CSS 3dscroll(runjs.work): https://runjs.work/projects/6a42a4c284e4442c。?


文章標(biāo)題:借助 :has 實現(xiàn)3D輪播圖
分享URL:http://m.5511xx.com/article/cdieidd.html