讓交互更加生動!有意思的滑鼠跟隨 3D 旋轉動效

来源:https://www.cnblogs.com/coco1s/archive/2022/04/26/16194072.html
-Advertisement-
Play Games

今天,群友問了這樣一個問題,如下所示的滑鼠跟隨交互效果,如何實現: 簡單分析一下,這個交互效果主要有兩個核心: 藉助了 CSS 3D 的能力 元素的旋轉需要和滑鼠的移動相結合 本文,就將講述如何使用純 CSS 實現類似的交互效果,以及,藉助 JavaScript 綁定滑鼠事件,快速還原上述效果。 純 ...


今天,群友問了這樣一個問題,如下所示的滑鼠跟隨交互效果,如何實現:

簡單分析一下,這個交互效果主要有兩個核心:

  1. 藉助了 CSS 3D 的能力
  2. 元素的旋轉需要和滑鼠的移動相結合

本文,就將講述如何使用純 CSS 實現類似的交互效果,以及,藉助 JavaScript 綁定滑鼠事件,快速還原上述效果。

純 CSS 實現元素的 3D 旋轉

如果不藉助 JavaScript,僅僅只是 CSS,如何實現類似的 3D 旋轉效果呢?

這裡會運用到一種名為正反旋轉相消或者是正負旋轉相消的小技巧。嗯,名字起的很奇怪,好像數學概念一樣。

在動畫中,旋轉是非常常用的屬性,

{
  transform: rotate(90deg);
}

如果我們給不同的層級的元素,添加不同方向的旋轉,會發生什麼呢?

首先假設一下場景,我們有這樣的一層 HTML 結構:

<div class="reverseRotate">
    <div class="rotate">
        <div class="content">正負旋轉相消3D動畫</div>
    </div>
</div>

樣式如下:

.content 內是我們的主要內容,好了,現在想象一下,如果父元素 .rotate 進行正向 linear 360° 旋轉,最外層的父級元素 .reverseRotate 進行反向 linear 360° 旋轉,效果會是啥樣?

CSS 代碼如下:

.rotate {
    animation: rotate 5s linear infinite;
}
.reverseRotate {
    animation: reverseRotate 5s linear infinite;
}
@keyframes rotate {
    100% {
        transform: rotate(360deg);
    }
}
@keyframes reverseRotate {
    100% {
        transform: rotate(-360deg);
    }
}

我們可以得到這樣一種動畫(註意,下圖是 GIF 不是 PNG):

神奇!因為一正一反的旋轉,且緩動函數一樣,所以整個 .content 看上去依然是靜止的!註意,這裡整個 .content 靜止的非常重要。

有讀者看到這裡就要罵人了,作者你個智障,靜止了不就沒動畫了嗎?哪來的動畫技巧?

別急!雖然看上去是靜止的,但是其實祖先兩個元素都是在旋轉的!這會看上去風平浪靜的效果底下其實是暗流涌動。用開發者工具選取最外層祖先元素是這樣的:

既然如此,我們繼續思考,如果我在其中旋轉的一個父元素上,添加一些別的動畫會是什麼效果?想想就很刺激。

首先,我們先給這幾個元素添加 CSS 3D 轉換:

div {
    transform-style: preserve-3d;
    perspective: 100px;
}

接著,嘗試修改上面的旋轉動畫,在內層旋轉上額外添加一個 rotateX:

@keyframes rotate {
    0% {
        transform: rotateX(0deg) rotateZ(0deg);
    }
    50% {
        transform: rotateX(40deg) rotateZ(180deg);
    }
    100% {
        transform: rotateX(0deg) rotateZ(360deg);
    }
}

效果如下:

Wow,這裡需要好好理解一下。由於內容 .content 層是靜止的但其實外層兩個圖層都在旋轉,通過設置額外的 rotateX(40deg),相當於疊加多了一個動畫,由於正反旋轉抵消了,所有整個動畫只能看到旋轉的 rotateX(40deg) 這個動畫,產生了上述的效果。

這樣,在沒有 JavaScript 介入的情況下,我們就模擬了題圖所示的 3D 效果。當然,僅僅是這樣,與用戶的聯動是不夠的,如果一定要結合滑鼠移動,我們就需要 JavaScript 的一些輔助了。

藉助 Javascript 實現滑鼠跟隨 3D 旋轉動效

我們的目標是實現這樣一個動畫效果:

這裡,我們其實有兩個核心元素:

  1. 滑鼠活動區域
  2. 旋轉物體本身

滑鼠在滑鼠活動區域內的移動,會影響旋轉物體本身的 3D 旋轉,而旋轉的方向其實可以被分解為 X 軸方向與 Y 軸方向。

我們來看一下,假設我們的 HTML 結構如下:

<body>
    <div id="element"></div>
</body>

得到這樣一個圖形:

這裡,body 的範圍就是整個滑鼠可活動區域,也是我們添加滑鼠的 mousemove 事件的宿主 target,而 #element 就是需要跟隨滑鼠一起轉動的旋轉物體本身。

因為整個效果是需要基於 CSS 3D 的,我們首先加上簡單的 CSS 3D 效果:

body {
    width: 100vw;
    height: 100vh;
    transform-style: preserve-3d;
    perspective: 500px;
}

div {
    width: 200px;
    height: 200px;
    background: #000;
    transform-style: preserve-3d;
}

效果如下:

沒有什麼不一樣。這是因為還沒有添加任何的 3D 變換,我們給元素添加 X、Y 兩個方向的 rotate() 試一下(註意,這裡預設的旋轉圓心即是元素中心):

div {
     transform: rotateX(15deg) rotateY(30deg);
}

效果如下,是有那麼點意思了:

好,接下來,我們的目標就是通過結合 mouseover 事件,讓元素動起來。

控制 X 方向的移動

當然,為了更加容易理解,我們把動畫拆分為 X、Y 兩個方向上的移動。首先看 X 方向上的移動:

gb3.gif

這裡,我們需要以元素的中心為界:

  1. 當滑鼠在中心右側連續移動,元素繞 Y 軸移動,並且值從 0 開始,越來越大,範圍為(0, +∞)deg
  2. 反之,當滑鼠在中心左側連續移動,元素繞 Y 軸移動,並且值從 0 開始,越來越小,範圍為(-∞, 0)deg

這樣,我們可以得到這樣一個公式:

rotateY = (滑鼠 x 坐標 - 元素左上角 x 坐標 - 元素寬度的一半)deg

通過綁定 onmousemove 事件,我們嘗試一下:

const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");

mouseOverContainer.onmousemove = function(e) {
  let box = element.getBoundingClientRect();
  let calcY = e.clientX - box.x - (box.width / 2);
    
  element.style.transform  = "rotateY(" + calcY + "deg) ";
}

效果如下:

gb4.gif

好吧,旋轉的太誇張了,因此,我們需要加一個倍數進行控制:

const multiple = 20;
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");

mouseOverContainer.onmousemove = function(e) {
  let box = element.getBoundingClientRect();
  let calcY = (e.clientX - box.x - (box.width / 2)) / multiple;
    
  element.style.transform  = "rotateY(" + calcY + "deg) ";
}

通過一個倍數約束後,效果好了不少:

控制 Y 方向的移動

同理,我們利用上述的方式,同樣可以控制 Y 方向上的移動:

const multiple = 20;
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");

mouseOverContainer.onmousemove = function(e) {
  let box = element.getBoundingClientRect();
  let calcX = (e.clientY - box.y - (box.height / 2)) / multiple;
    
  element.style.transform  = "rotateX(" + calcX + "deg) ";
};

效果如下:

當然,在這裡,我們會發現方向是元素運動的方向是反的,所以需要做一下取反處理,修改下 calcX 的值,乘以一個 -1 即可:

let calcX = (e.clientY - box.y - (box.height / 2)) / multiple * -1;

結合 X、Y 方向的移動

OK,到這裡,我們只需要把上述的結果合併一下即可,同時,上面我們使用的是 onmousemove 觸發每一次動畫移動。現代 Web 動畫中,我們更傾向於使用 requestAnimationFrame 去優化我們的動畫,確保每一幀渲染一次動畫即可。

完整的改造後的代碼如下:

const multiple = 20;
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");

function transformElement(x, y) {
  let box = element.getBoundingClientRect();
  let calcX = -(y - box.y - (box.height / 2)) / multiple;
  let calcY = (x - box.x - (box.width / 2)) / multiple;
  
  element.style.transform  = "rotateX("+ calcX +"deg) "
                        + "rotateY("+ calcY +"deg)";
}

mouseOverContainer.addEventListener('mousemove', (e) => {
  window.requestAnimationFrame(function(){
    transformElement(e.clientX, e.clientY);
  });
});

至此,我們就能簡單的實現題圖所示的滑鼠跟隨 3D 旋轉動效:

設置平滑出入

現在,還有最後一個問題,就是當我們的滑鼠離開活動區域時,元素的 transform 將停留在最後一幀,正確的表現應該是複原到原狀。因此,我們還需要添加一些事件監聽做到元素的平滑複位。

通過一個 mouseleave 事件配合元素的 transition 即可。

div {
    // 與上述保持一致...
    transition: all .2s;
}
mouseOverContainer.addEventListener('mouseleave', (e) => {
  window.requestAnimationFrame(function(){
    element.style.transform = "rotateX(0) rotateY(0)";
  });
});

至此,我們就可以完美的實現平滑出入,整體效果最終如下:

完整的代碼,你可以戳這裡:CodePen Demo -- CSS 3D Rotate With Mouse Move

最後

怎樣,其實也不是很難吧?好了,本文到此結束,希望本文對你有所幫助

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文介紹如何使用 SQL WHERE 子句指定搜索條件,過濾返回的數據。還介紹如何檢驗相等、不相等、大於、小於、值的範圍以及 NULL 值等。 一、使用 WHERE 子句 資料庫表一般包含大量的數據,很少需要檢索表中的所有行。通常只會根據特定操作或報告的需要提取表數據的子集。只檢索所需數據需要指定搜 ...
  • 為了更好地幫助開發者,官方文檔特意整理出“接入智慧生活App”專題。跟緊小編的步伐,趕緊來看看本次文檔更新內容~ ...
  • 你或許不知道它在什麼時候橫空出世,當你意識到的時候,它已如空氣環繞在你身邊。 截至2021年6月,我國即時通信用戶規模達到9.83億,以97%的網民使用占比,在用戶量級之巔一覽眾山小。今天就來聊聊這個“如空氣般存在”的能力——IM(Instant Messaging)即時消息。(數據來自中國互聯網路 ...
  • 微信小程式集成vant,大概的過程先通過npm 安裝vant包->微信小程式設置npm環境變數->將npm中的vant包導成miniprogram_npm 開發環境 macOS ,微信小程式模版【支持騰訊雲】 安裝vant包 cd miniprogram # 通過 npm 安裝 npm i @van ...
  • 4月25日,“共建新技術,開拓新領域”OpenAtom OpenHarmony(以下簡稱“OpenHarmony”)技術日在深圳順利召開。OpenHarmony 攜手各共建單位、生態伙伴分享技術創新、生態共建、教育發展等方面的最新進展和實踐成果。 ...
  • 想必大部分做頂部導航欄(position: fixed;)的都遇見過導航欄遮住鏈接鏈接對象部分內容這種情況吧,如下圖所示,我的頂部導航欄的高度為9vh,video元素是“本店快遞流程”(錨鏈接)跳轉的元素 當我點擊該鏈接時,video元素被遮去了9vh的高度,這是為什麼呢? 我查看了一下源代碼(vi ...
  • 其實複習一次的作用真實太大了,真的,自從上次ajax開始其實就開始i有點懵懵懂懂的感覺,一直拖想到了node在去回顧一遍,這一次回去複習,ajax已經很熟練了,node之前搞不懂那些原理也順清楚了好多,其實這次複習沒有什麼需要說的知識點,因為要說的前面都說過了,我來說一下這個做的一個大項目吧,這個項 ...
  • 一、使用writing-mode(推薦使用) writing-mode:翻譯過來是“寫字 — 模式”,文本在水平或垂直方向上如何排布 有以下幾個屬性值: horizontal-tb: 水平展示,也就是橫著展示文字,最平常預設的樣式 vertical-rl:垂直展示,也就是上面圖片上實現的樣式 ver ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...