一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

【動(dòng)畫進(jìn)階】極具創(chuàng)意的鼠標(biāo)交互動(dòng)畫

 leeyaya 2024-04-09 發(fā)布于北京

最近,群里在討論這么一個(gè)有趣的交互效果,來源于:v

通過審查元素,發(fā)現(xiàn)原效果借助了 Canvas 實(shí)現(xiàn)。

思索了一番,覺得這個(gè)效果利用 CSS 配合部分 Javascript 代碼完全也是可以做到的。

于是動(dòng)手嘗試了一番,最終完美的復(fù)刻了該效果:

過程中還是有非常多有意思的技巧存在的,因此,本文將帶大家一起,從 0 到 1 實(shí)現(xiàn)這個(gè)有趣的交互效果。

利用混合模式實(shí)現(xiàn)疊加效果

整個(gè)效果,比較核心的一塊便是當(dāng)鼠標(biāo) Hover 上去時(shí),整個(gè)元素疊加上一層黑色圖層,但是呈現(xiàn)了不一樣的疊加效果。

這個(gè)了解混合模式(mix-blend-mode)的同學(xué)應(yīng)該一下就能想到。

在之前,我們也有多篇文章講解過混合模式,感興趣的可以隨意快速瀏覽一下,下面是我寫過的 15 篇與混合模式相關(guān)的合集鏈接:

在這里,我們也快速過一下效果中需要用到的混合模式。

正常而言,假設(shè)我們有這么一個(gè) UI 效果:

HTML復(fù)制代碼<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit.....</div>
CSS復(fù)制代碼body {    background: #eee;}div {    width: 400px;    background: #42b983;    color: #fff;    border: 3px solid #333;    border-radius: 5px;}

效果如下:

我們利用 div 的偽元素,在其元素本身上疊加一個(gè)純白色塊:

CSS復(fù)制代碼div::before {  content: "";  position: absolute;  inset: -10px;  background: #fff;  z-index: 1;}

正常而言,由于疊加了一個(gè)白色色塊在元素之上,肯定是什么都看不到了:

而 CSS 中,混合模式(mix-blend-mode)的作用,就是將多個(gè)圖層混合得到一個(gè)新的效果。

如果,我們給上述效果中的偽元素,添加一個(gè) mix-blend-mode: difference,則會(huì)得到如下效果:

CSS復(fù)制代碼div::before {  content: "";  position: absolute;  inset: -10px;  background: #fff;  z-index: 1;  mix-blend-mode: difference;}

效果如下:

其中,混合模式 mix-blend-mode: difference 意為差值模式。該混合模式會(huì)查看每個(gè)通道中的顏色信息,比較底色和繪圖色,用較亮的像素點(diǎn)的像素值減去較暗的像素點(diǎn)的像素值。

與白色混合將使底色反相;與黑色混合則不產(chǎn)生變化

通俗一點(diǎn)就是上方圖層的亮區(qū)將下方圖層的顏色進(jìn)行反相,暗區(qū)則將顏色正常顯示出來,效果與原圖像是完全相反的顏色。

并且,由于我們?cè)O(shè)置了 body 的顏色,所以在動(dòng)畫的一開始,偽元素白色的背景色與 body 的白色通過混合模式疊加直接變成了黑色。

實(shí)現(xiàn)鼠標(biāo) cursor 動(dòng)畫

仔細(xì)看我們整體要實(shí)現(xiàn)的效果,其中鼠標(biāo)樣式與平常不太一樣:

接下來,我們就需要實(shí)現(xiàn)這么個(gè)效果,**把我們的 Curosr 鼠標(biāo)樣式,改成兩個(gè)小圓點(diǎn),并且外層圓點(diǎn)的運(yùn)動(dòng)帶一點(diǎn)延遲效果。

這個(gè)也好實(shí)現(xiàn),我們?cè)?有意思的鼠標(biāo)指針交互探究 中,有實(shí)現(xiàn)過一個(gè)類似的效果:

修改鼠標(biāo)樣式

首先,第一個(gè)問題,我們可以看到,上圖中,鼠標(biāo)指針的樣式被修改成了一個(gè)圓點(diǎn):

正常而言應(yīng)該是這樣:

如何實(shí)現(xiàn)呢?原來在 CSS 中,我們可以通過 cursor 樣式,對(duì)鼠標(biāo)指針形狀進(jìn)行修改。

利用 cursor 修改鼠標(biāo)樣式

cursor CSS 屬性設(shè)置鼠標(biāo)指針的類型,在鼠標(biāo)指針懸停在元素上時(shí)顯示相應(yīng)樣式。

CSS復(fù)制代碼cursor: auto;cursor: pointer;...cursor: zoom-out;/* 使用圖片 */cursor: url(hand.cur)/* 使用圖片,并且設(shè)置 fallback 兜底 */cursor: url(hand.cur), pointer;

比不過在這里,我們需要通過 cursor: none 隱藏頁面的鼠標(biāo)指針:

CSS復(fù)制代碼{    cursor: none;}

如此一來,頁面上的鼠標(biāo)指針就消失了:

通過全局事件監(jiān)聽,模擬鼠標(biāo)指針

既然,消失了,我們就簡(jiǎn)單模擬一個(gè)鼠標(biāo)指針。

我們首先實(shí)現(xiàn)一個(gè) 10px x 10px 的圓形 div,設(shè)置為基于 <body> 絕對(duì)定位:

HTML復(fù)制代碼<div id="g-pointer"></div>
CSS復(fù)制代碼#g-pointer {    position: absolute;    top: 0;    left: 0;    width: 10px;    height: 10px;    background: #000;    border-radius: 50%;}

那么,在頁面上,我們就得到了一個(gè)圓形黑點(diǎn):

接著,通過事件監(jiān)聽,監(jiān)聽 body 上的 mousemove,將小圓形的位置與實(shí)時(shí)鼠標(biāo)指針位置重合:

Javascript復(fù)制代碼const element = document.getElementById("g-pointer");const body = document.querySelector("body");function setPosition(x, y) {  element.style.transform  = `translate(${x}px, ${y}px)`;                }body.addEventListener('mousemove', (e) => {  window.requestAnimationFrame(function(){    setPosition(e.clientX - 5, e.clientY - 5);  });});

這樣,如果不設(shè)置 cursor: none,將會(huì)是這樣一個(gè)效果:

再給 body 加上 cursor: none,就相當(dāng)于模擬了一個(gè)鼠標(biāo)指針:

在這個(gè)基礎(chǔ)上,由于現(xiàn)在的鼠標(biāo)指針,實(shí)際上是個(gè) div,因此我們可以給它加上任意的交互效果。

好,我們把上述內(nèi)容無縫銜接到本效果中,并且,我們其實(shí)需要同時(shí)模擬兩個(gè)鼠標(biāo),并且讓第二個(gè)指針的動(dòng)畫,帶有一點(diǎn)延遲效果,完整的代碼:

HTML復(fù)制代碼<div id="g-pointer-1"></div><div id="g-pointer-2"></div>
CSS復(fù)制代碼#g-pointer-1,#g-pointer-2 {    position: absolute;    top: 0;    left: 0;    width: 12px;    height: 12px;    background: #999;    border-radius: 50%;    background-color: #4caf50;}#g-pointer-2 {    width: 42px;    height: 42px;    background: #fff;    transition: .15s ease-out;}
Javascript復(fù)制代碼const body = document.querySelector("body");const element = document.getElementById("g-pointer-1");const element2 = document.getElementById("g-pointer-2");const halfAlementWidth = element.offsetWidth / 2;const halfAlementWidth2 = element2.offsetWidth / 2;body.addEventListener("mousemove", (e) => {    window.requestAnimationFrame(function () {        setPosition(e.clientX, e.clientY);    });});function setPosition(x, y) {    window.requestAnimationFrame(function () {        element.style.transform = `translate(${x - halfAlementWidth}px, ${            y - halfAlementWidth        }px)`;        element2.style.transform = `translate(${x - halfAlementWidth2}px, ${            y - halfAlementWidth2        }px)`;    });}

這樣,我們就完成了頁面鼠標(biāo)樣式的改造。不過,有一點(diǎn)需要注意的是,利用模擬的鼠標(biāo)指針去 Hover 元素,Click 元素的時(shí)候,會(huì)發(fā)現(xiàn)這些事件都無法觸發(fā)。

這是由于,此時(shí)被隱藏的指針下面,其實(shí)懸浮的我們模擬鼠標(biāo)指針,因此,所有的 Hover、Click 事件都觸發(fā)在了這個(gè)元素之上。

當(dāng)然,這個(gè)也非常好解決,我們只需要給模擬指針的元素,添加上 pointer-events: none,阻止默認(rèn)的鼠標(biāo)事件,讓事件透?jìng)骷纯伞?/p>

同時(shí),我們也可以給這個(gè)模擬鼠標(biāo)元素,加上一個(gè)混合模式。如此一來,我們需要給兩個(gè)鼠標(biāo)元素,再加上兩個(gè)樣式:

CSS復(fù)制代碼#g-pointer-1,#g-pointer-2 {    // ...    mix-blend-mode: exclusion;    pointer-events: none;}

這樣,我們就成功地模擬了新的鼠標(biāo)樣式:

實(shí)現(xiàn)完整動(dòng)畫效果

好,基于上述效果鋪墊,我們就只剩下一個(gè)任務(wù)了,如何在 Hover 元素的時(shí)候,將鼠標(biāo)樣式外圈,吸附到整個(gè)元素之上:

要完成這個(gè)動(dòng)畫,必須需要借助 Javascript,通過事件的一些回調(diào)完成,總體而言整體思路如下:

  1. 兩個(gè)模擬鼠標(biāo)指針的元素 #g-pointer-1#g-pointer-2 依舊如上面描述的那般,通過 <body>mousemove 事件控制,不過在此過程中,額外需要知道是否經(jīng)過(Hover)了不同的元素

  2. 通過 mouseover 事件監(jiān)聽器,判斷當(dāng)前鼠標(biāo)是否懸停在我們需要進(jìn)行吸附擴(kuò)大動(dòng)畫的的元素上

  3. 通過 mouseout 事件,判斷鼠標(biāo)是否離開目標(biāo)元素

  4. 如果鼠標(biāo)懸停在目標(biāo)元素上,則計(jì)算當(dāng)前吸附的目標(biāo)元素的高寬、元素的 border-radius 及相對(duì)頁面右上角的坐標(biāo)

  5. 由于模擬的鼠標(biāo)元素,本身就是絕對(duì)定位,因此,可以通過第(3)步的計(jì)算,設(shè)置模擬的鼠標(biāo)元素新的高寬及絕對(duì)定位坐標(biāo),并且其坐標(biāo)不再隨鼠標(biāo)指針的變化而變化

  6. 只有當(dāng)鼠標(biāo)指針離開目標(biāo)元素,才復(fù)原模擬的鼠標(biāo)元素的大小,并且讓其重新跟隨鼠標(biāo)的移動(dòng)而移動(dòng)

本質(zhì)上而言,通過一句話概括,在整個(gè)鼠標(biāo)元素移動(dòng)的過程中,如果有懸停到任一元素上,則將外圈鼠標(biāo)元素 #g-pointer-2 的大小及坐標(biāo)更改,通過元素的高寬及 border-radius 變化實(shí)現(xiàn)視覺上的放大、縮小動(dòng)畫。

首先,通過 mouseovermouseout,我們可以得知我們的鼠標(biāo)元素,是否懸停在某些特定元素之上,譬如帶有 .g-animation 的元素:

HTML復(fù)制代碼<div class="g-animation">Lorem ...</div>// 模擬鼠標(biāo)指針的兩個(gè)元素<div id="g-pointer-1"></div><div id="g-pointer-2"></div>
javascript復(fù)制代碼window.addEventListener("mouseover", (event) => {    const target = event.target;    if (target.classList.contains("g-animation")) {        console.log('mouseover');    }});window.addEventListener("mouseout", (event) => {    const target = event.target;    if (target.classList.contains("g-animation")) {        console.log('mouseout');    }});// 剩余的模擬鼠標(biāo)移動(dòng)的 JavaScript 代碼// ...

這樣就能準(zhǔn)確知道元素是否懸停在某個(gè)目標(biāo)元素之上:

利用這兩種狀態(tài),我們就可以繼續(xù)實(shí)現(xiàn)剩余的放大吸附動(dòng)畫。

放大吸附動(dòng)畫其實(shí)也很簡(jiǎn)單,其核心就是在 mouseover 時(shí),計(jì)算出目標(biāo)元素的坐標(biāo)及高寬,再設(shè)置需要放大的外圈鼠標(biāo)元素的新的 widthheight、border-radiustransform。同時(shí),讓其不再跟隨真實(shí)的鼠標(biāo)運(yùn)動(dòng)而運(yùn)動(dòng)。

mouseout 時(shí),復(fù)原外圈鼠標(biāo)元素的大小及恢復(fù)其跟隨真實(shí)的鼠標(biāo)運(yùn)動(dòng)而運(yùn)動(dòng)。

如此一來,整個(gè)效果的完整的代碼如下:

HTML復(fù)制代碼// 代表了頁面不同的可以吸附的元素,它們的高寬、border-radius 各不相同<div class="g-animation">Lorem ...</div><div class="g-animation">Lorem ...</div><div class="g-animation">Lorem ...</div>// 模擬鼠標(biāo)指針的兩個(gè)元素<div id="g-pointer-1"></div><div id="g-pointer-2"></div>
CSS復(fù)制代碼body {    background: #fff;    cursor: none;}#g-pointer-1,#g-pointer-2{    position: absolute;    top: 0;    left: 0;    width: 12px;    height: 12px;    background: #999;    border-radius: 50%;    background-color: #4caf50;    z-index: 1;    mix-blend-mode: exclusion;    pointer-events: none;}#g-pointer-2 {    width: 42px;    height: 42px;    background: #fff;    transition: .15s ease-out;}
Javascript復(fù)制代碼const body = document.querySelector("body");const element = document.getElementById("g-pointer-1");const element2 = document.getElementById("g-pointer-2");const halfAlementWidth = element.offsetWidth / 2;const halfAlementWidth2 = element2.offsetWidth / 2;// 該變量用于跟蹤鼠標(biāo)是否懸停在具有類名為 .g-animation 的元素上let isHovering = false;// 判斷元素是否懸停在具有類名為 .g-animation 的元素上window.addEventListener("mouseover", (event) => {    const target = event.target;    if (target.classList.contains("g-animation")) {        isHovering = true;        const rect = target.getBoundingClientRect();        const style = window.getComputedStyle(target);        element2.style.width = `${rect.width + 20}px`;        element2.style.height = `${rect.height + 20}px`;        element2.style.borderRadius = `${style.borderRadius}`;        element2.style.transform = `translate(${rect.left - 10}px, ${            rect.top - 10        }px)`;    }});// 判斷元素是否離開在具有類名為 .g-animation 的元素上window.addEventListener("mouseout", (event) => {    const target = event.target;    if (target.classList.contains("g-animation")) {        isHovering = false;        // 樣式復(fù)原        element2.style.width = `42px`;        element2.style.height = `42px`;        element2.style.borderRadius = `50%`;    }});// 用于控制兩個(gè)鼠標(biāo)指針元素body.addEventListener("mousemove", (e) => {    window.requestAnimationFrame(function () {        setPosition(e.clientX, e.clientY);    });});function setPosition(x, y) {    window.requestAnimationFrame(function () {        element.style.transform = `translate(${x - halfAlementWidth}px, ${            y - halfAlementWidth        }px)`;        if (!isHovering) {            element2.style.transform = `translate(${x - halfAlementWidth2}px, ${                y - halfAlementWidth2            }px)`;        }    });}

如此一來,頁面上任意帶有 .g-animation 的元素,都可以允許模擬鼠標(biāo)的元素進(jìn)行吸附動(dòng)畫。

我們也就實(shí)現(xiàn)了文章最開頭的動(dòng)畫效果:

完整的代碼很少,你可以戳這里看完整的代碼及效果展示:CodePen Demo -- Cursor Hover Animation Demo

鏈接:https:///post/7347626854617202724

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美一级日韩中文字幕| 99久久国产精品成人观看| 久久精品中文扫妇内射| 日韩成人午夜福利免费视频| 国产日韩精品欧美综合区| 国产精品香蕉一级免费| 国产精品乱子伦一区二区三区| av国产熟妇露脸在线观看| 黄片在线免费观看全集| 精品人妻一区二区三区四在线| 精品国模一区二区三区欧美| 欧美日韩国产欧美日韩| 欧美成人免费视频午夜色| 午夜精品麻豆视频91| 亚洲一区二区福利在线| 黑人粗大一区二区三区| 欧美日韩精品人妻二区三区 | 99久久人妻精品免费一区| 尤物久久91欧美人禽亚洲| 日韩欧美国产精品自拍| 久久夜色精品国产高清不卡| 亚洲精品福利视频在线观看| 国产精品欧美激情在线播放| 日韩欧美综合中文字幕 | 少妇特黄av一区二区三区| 人妻露脸一区二区三区| 视频一区二区三区自拍偷| 色播五月激情五月婷婷| 日韩中文字幕视频在线高清版| 国产超薄黑色肉色丝袜| 色欧美一区二区三区在线| 亚洲五月婷婷中文字幕| 国产真人无遮挡免费视频一区| 精品香蕉一区二区在线| 91日韩欧美在线视频| 国产一区欧美一区日韩一区| 天海翼精品久久中文字幕| 精品欧美在线观看国产| 成人国产一区二区三区精品麻豆| 中国一区二区三区人妻| 亚洲欧洲日韩综合二区|