最近,有群里在群里發了這麼一個非常有意思的卡片 Hover 動效,來源於此網站 -- key-drop,效果如下: 非常有意思酷炫的效果。而本文,我們不會完全還原此效果,而是基於此效果,嘗試去製作這麼一個類似的卡片交互效果: 該效果的幾個核心點: 卡片的 3D 旋轉跟隨滑鼠移動效果 如何讓卡片在 H ...
最近,有群里在群里發了這麼一個非常有意思的卡片 Hover 動效,來源於此網站 -- key-drop,效果如下:
非常有意思酷炫的效果。而本文,我們不會完全還原此效果,而是基於此效果,嘗試去製作這麼一個類似的卡片交互效果:
該效果的幾個核心點:
- 卡片的 3D 旋轉跟隨滑鼠移動效果
- 如何讓卡片在 Hover 狀態,有不同的光澤變化
- 如何讓卡片在 Hover 狀態,有 Blink,Blink 的星星閃爍效果
當然,要做到卡片的 3D 旋轉跟隨滑鼠移動效果需要一定程度的藉助 JavaScript,因此,最終的效果是 CSS 配合 JavaScript 以及一些動態效果的 Gif 共同實現。
好,下麵就讓我們一步一步一起來實現這個效果。
卡片的 3D 旋轉跟隨效果
OK,接下來,如何實現 3D 卡片效果呢?
這個效果之前在 讓交互更加生動!有意思的滑鼠跟隨 3D 旋轉動效 實現過一次,我們複習一下。
這個交互效果主要有兩個核心:
- 藉助了 CSS 3D 的能力
- 元素的旋轉需要和滑鼠的移動相結合
我們的目標是實現這樣一個動畫效果:
這裡,我們其實有兩個核心元素:
- 滑鼠活動區域
- 旋轉物體本身
滑鼠在滑鼠活動區域內的移動,會影響旋轉物體本身的 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 方向上的移動:
這裡,我們需要以元素的中心為界:
- 當滑鼠在中心右側連續移動,元素繞 Y 軸移動,並且值從 0 開始,越來越大,範圍為(0, +∞)deg
- 反之,當滑鼠在中心左側連續移動,元素繞 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) ";
}
效果如下:
好吧,旋轉的太誇張了,因此,我們需要加一個倍數進行控制:
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
Hover 狀態下的光澤變化
好,有了上述鋪墊之後,我們就可以將黑色背景圖,替換成實際的圖片,得到這麼一個初步效果:
接下來,我們需要讓卡片能夠變得有光澤,並且也能基於滑鼠 Hover 的坐標不同,展現出不一樣的效果,像是這樣:
怎麼實現呢?看似複雜,其實只需要簡單的利用混合模式即可。其中本質就是圖片疊加上黑白相間的漸變,再調整混合模式,就能實現上述的高光效果。
代碼如下:
<div></div>
div {
position: relative;
background: url('image.png');
&::before {
content: "";
position: absolute;
inset: 0;
background:
linear-gradient(
115deg,
transparent 0%,
rgba(255, 255, 255, 0.5 30%),
rgba(0, 0, 0, .5) 55%),
rgba(255, 255, 255, .5) 80%),
transparent 100%
);
mix-blend-mode: color-dodge;
}
}
這裡,我們利用 div 元素的背景展示了圖片,利用元素的偽元素展示了黑白漸變效果,最終再疊加上混合模式 mix-blend-mode: color-dodge
,示意圖如下:
但是,此時,只有卡片是有 3D 效果的,疊加的黑白漸變層是不會隨著 Hover 效果進行變化的:
為瞭解決這個問題,我們需要讓漸變圖層也能受到 Hover 的動態影響,這個好做,我們額外引入一個 CSS 變數,基於滑鼠當前 Hover 卡片時,距離卡片最左側的橫向距離,設置動態的 CSS 變數。
改造一下代碼:
<div id="g-img"></div>
div {
--per: 30%;
position: relative;
// ...
&::before {
content: "";
position: absolute;
inset: 0;
background:
linear-gradient(
115deg,
transparent 0%,
rgba(255, 255, 255, 0.5) var(--per),
rgba(0, 0, 0, .5) calc(var(--per) + 25%),
rgba(255, 255, 255, .5) calc(var(--per) + 50%),
transparent 100%
);
mix-blend-mode: color-dodge;
}
}
const multiple = 15;
const mouseOverContainer = document.getElementsByTagName("body")[0];
const element = document.getElementById("element");
const img = document.getElementById("g-img");
function transformElement(x, y) {
let box = element.getBoundingClientRect();
const calcX = -(y - box.y - box.height / 2) / multiple;
const calcY = (x - box.x - box.width / 2) / multiple;
const percentage = parseInt((x - box.x) / box.width * 1000) / 10;
element.style.transform = "rotateX(" + calcX + "deg) " + "rotateY(" + calcY + "deg)";
// 額外增加一個控制 --per 的變數寫入
img.style = `--per: ${percentage}%`;
}
mouseOverContainer.addEventListener("mousemove", (e) => {
window.requestAnimationFrame(function () {
transformElement(e.clientX, e.clientY);
});
});
簡單解釋一下,上述代碼最核心的部分就是引入了 --per
CSS 變數,其應用在漸變代碼中。
我們通過計算當前滑鼠距離卡片左側的橫向距離,除以卡片整體的寬度,得到 --per
實際表示的百分比,再賦值給 --per
,以此實現 Hover 時候的光效變化:
疊加星星閃爍效果
好,效果已經非常接近了。當然,總感覺缺少什麼,我們可以在這一步,繼續疊加上另外一層星星閃爍的效果。
這裡,我們可以用現成的 GIF 圖,像是這樣(圖片來源於 Pokemon Card Holo Effect):
這樣,我們的整個效果,其實就變成了這種疊加狀態:
我們再簡單改造一下代碼:
#g-img {
--per: 30%;
position: relative;
background: url('image.png');
&::after {
content: "";
display: none;
position: absolute;
inset: 0;
background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/13471/sparkles.gif");
mix-blend-mode: color-dodge;
}
&::before {
content: "";
display: none;
position: absolute;
background:
linear-gradient(
115deg,
transparent 0%,
rgba(255, 255, 255, 0.7) var(--per),
rgba(0, 0, 0, .6) calc(var(--per) + 25%),
rgba(255, 255, 255, .5) calc(var(--per) + 50%),
transparent 100%
);
mix-blend-mode: color-dodge;
}
&:hover::after,
&:hover::before {
display: block;
}
}
當 Hover 狀態下,才展示漸變背景與星星 Gif 圖的疊加效果,最終,我們就實現了最開頭的效果:
完整的代碼,你可以戳這裡 CodePen Demo -- CSS 3D Rotate With Mouse Move
嘗試不同漸變背景與不同混合模式
瞭解上述製作方式的全過程後,我們就可以改變疊加的混合模式與漸變背景,以創造更多不一樣的效果。
像是這樣:
完整的代碼,你可以戳這裡 CodePen Demo -- CSS 3D Rotate With Mouse Move2
或者是這樣:
完整的代碼,你可以戳這裡 CodePen Demo -- CSS 3D Rotate With Mouse Move3
最後
怎樣,學會了嗎。通過不同的混合模式與不同的漸變背景,可以排列組合出非常多種有趣有意思的效果。感興趣的,一定動手試試!
好了,本文到此結束,希望本文對你有所幫助