點點動畫~畫出懂你的3D魔方
作者: ofollow,noindex">首席填坑官∙蘇南
來源:@IT·平頭哥聯盟
前言
最近在寫《 點點動畫系列 》文章,上一期分享了 < 手把手教你如何繪製一輛會跑的車 > ,本期給大家帶來是結合CSS3畫出來的一個 立體3d魔方
,結合了 js
讓你隨心所欲想怎麼轉,就怎麼轉,這裡是 @IT·平頭哥聯盟 ,我是 首席填坑官
∙ 蘇南 (South·Su),我們先來看看效果,然後再分解它的實現過程吧

繪製過程:
好吧,gif圖看著好像有點不是很清晰,想線上預覽的同學,可點選 線上預覽 :point_left: ,廢話不多扯了,先來分析一下,看如何實現這個功能吧。
∙ API預熱 :
- 本次示例是一個立體的正方形,既然有立體效果,肯定少不了CSS3中的
-webkit-perspective
-透視、preserve-3d
-三維空間,這個兩個是重點哦,當然還有transform-origin
、transition
、transform
等,先來回故一下 API 怎麼是講的吧:
perspective 取值 :
- none :不指定透視 ;
- length :指定觀察者與「z=0」平面的距離,使具有三維位置變換的元素產生
透視效果
。「z>0」的三維元素比正常大,而「z<0」時則比正常小,大小程度由該屬性的值決定,不允許負值。
transform-style 取值 :
- flat :指定子元素位於此元素所在平面內;
- preserve-3d :指定子元素定位在三維空間內,當該屬性值為
preserve-3
d時,元素將會建立區域性堆疊上下文;
小結:決定一個變換元素看起來是處在三維空間還是平面內,需要該元素的父元素上定義 <' transform-style '> 屬性,也就是說想某元素有三維效果,需要設定它的父級有 preserve-3d
。
transform-origin 取值 :
- percentage:用百分比指定座標值。可以為負值;
- length:用長度值指定座標值。可以為負值;
- left:指定原點的橫座標為left;
- center①:指定原點的橫座標為center;
- right:指定原點的橫座標為right;
- top:指定原點的縱座標為top;
- center②:指定原點的縱座標為center;
- bottom:指定原點的縱座標為bottom;
transform、transition等,就不介紹了
/* perspective 使用示例:*/ div{ -webkit-perspective:600px; perspective:600px; } /*transform-style 使用示例:*/ .preserve{ transform-style:preserve-3d; -webkit-transform-style:preserve-3d; } /*transform-origin 使用示例:*/ .preserve{ -webkit-transform-origin:50% 50% -100px; or -webkit-transform-origin:bottom; or -webkit-transform-origin:top; ………… } 複製程式碼
∙ 繪製6個面 :
- 是的,我沒有說錯,就是6個面:上、正面、下、背面、左、右,
- 上面API講了這麼多,來實踐試一下吧,寫6個div,結構大概是這樣的,也是接下來的魔方需要的結構:
<div class="cube"> <div class="cube-inner running"> <p class="single-side s1"><span>最</span></p> <p class="single-side s2"><span>懂</span></p> <p class="single-side s3"><span>你</span></p> <p class="single-side s4"><span>的</span></p> <p class="single-side s5"><span>魔</span></p> <p class="single-side s6"><span>方</span></p> </div> </div> 複製程式碼


rotate

.cube{ width:200px; height:200px; margin:10px auto; padding:260px; position:relative; -webkit-perspective:600px; perspective:600px; transition: .5s ; } .cube-inner{ width:200px; height:200px; position:relative; -webkit-transform-style:preserve-3d; transition:.3s; -webkit-transform-origin:50% 50% -100px; transform: rotateX(45deg); } .cube:hover{ /*滑鼠經過時,把 perspective 過渡到100 */ -webkit-perspective:100px; perspective:100px; } 複製程式碼
- 既然API有效,那麼拉下來我們就畫出6個面吧,按:上、正面、下、背面、左、右,這個順序來設定吧;
- 首先,我們要指定它們是在三維空間內的
preserve-3d
,也就是6個面的父級要設定transform-style
樣式; - 以上都設定好後,再來看看6個面吧,為了便於區分,給它們每個都設定了不同顏色(用了css3的漸變
radial-gradient
)——不想手寫的同學推薦一個網站可線上設定你要的效果,複製樣式即可,先來一睹風采,為了便於觀察,整體角度旋轉了10deg:

- 說到漸變,偶然之間發現了一個有意思的東西
hue-rotate
,它能在你初始的顏色基礎上旋轉元素的色調及其內容,從而達到不同的效果。瞭解更多
hue-rotate: The hue-rotate() CSS function rotates the hue of an element and its contents. Its result is a .

- 上 - "
最
":
.cube-inner .single-side.s1{ /*s1頂部*/ left:0;top:-200px; background: radial-gradient(circle, rgba(255,255,255,.88), #00adff); background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #00adff); transform-origin:bottom; -webkit-transform-origin:bottom; transform:rotateX(90deg); -webkit-transform:rotateX(90deg); } 複製程式碼

-
正面- "
懂
":- 下面就是預設的,什麼都不用設定,所以就不展示了 ;
-
下面- "
你
":- 即底部,底部的設定,正好跟頂部它是相反的,一個origin 以 bottom為基準為座標,一個以top為基準為座標;
.cube-inner .single-side.s3{ /*s3底部*/ left:0;top:200px; background: radial-gradient(circle, rgba(255,255,255,.88), #100067); background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #100067); transform-origin:top; -webkit-transform-origin:top; transform:rotateX(-90deg); -webkit-transform:rotateX(-90deg); } 複製程式碼

- 背面 - "
的
":- 即正面的後邊,整體旋轉了 135deg,讓背面更直觀能看到;
- translateZ 、rotateX 同時移動,形成透視的關係,讓它看起來,在正面面的後面;
- 下圖二,把預設的正面,設定了透明度,可以看出,背面的透視效果;
.cube-inner .single-side.s4{ /*s4背部*/ z-index:2; left:0;top:0; background: radial-gradient(circle, rgba(255,255,255,.88), #F0C); background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #F0C); transform:translateZ(-200px) rotateX(180deg) ; -webkit-transform:translateZ(-200px) rotateX(180deg) ; /*rotateZ(-180deg) 左右旋轉的時候,Z軸旋轉180°,因為字是倒著的*/ } 複製程式碼


- 左側面 - "
魔
":- origin以right為基準,left負元素的寬度,rotateY軸旋轉90deg;
.cube-inner .single-side.s5{ /*s5左側*/ left:-200px;top:0; background: radial-gradient(circle, rgba(255,255,255,.88),rgba(33,33,33,1)); background: -webkit-radial-gradient(circle, rgba(255,255,255,.88),rgba(33,33,33,1)); transform-origin:right; -webkit-transform-origin:right; transform:rotateY(-90deg) -webkit-transform:rotateY(-90deg) } 複製程式碼

- 右側面 - "
方
":- 同理右側,與左側正好相反;
.cube-inner .single-side.s6{ /*s6右側*/ right:-200px;top:0; transform-origin:left; -webkit-transform-origin:left; background: radial-gradient(circle, rgba(255,255,255,.88), #f00); background: -webkit-radial-gradient(circle, rgba(255,255,255,.88), #f00); transform:rotateY(90deg); -webkit-transform:rotateY(90deg); } 複製程式碼

小結: 嗯,以上魔方的6個面的繪製過程,基本已經完成,主要在在於 transform-origin
、 rotate
、 translate
等屬性的應用,但為了讓它更炫酷一些,我們還要給邊角加一些光感。
∙ 新增高光 :
- 細心的寶寶,前面的佈局應該已經發現了,每一行佈局的
p
標籤裡,都多套了一層span
,就是為高光光感,埋下的伏筆,一個平面正方形有四個邊,after、before只有兩,那麼肯定要再套一層,當然方法很多,比如直接用border也是可以的,但比較麻煩,我就選擇了現在要講的這種: - after、before設定1px的邊框,設定一個線性漸變,中間是白色,兩斷是過渡到透明的,這樣高光就有了,來看一組圖吧:


∙ CSS 360°旋轉 :
animation keyframes
.cube .cube-inner{ /*-webkit-transform:rotateX(180deg) rotateY(0deg) ;*/ animation: elfCube 10s infinite ease-in-out; -webkit-animation: elfCube 10s infinite ease alternate; } @keyframes elfCube { 0% { transform: rotateX(0deg) rotateY(0deg); } 50% { transform: rotateX(360deg) rotateY(360deg); } 100% { transform: rotateX(0deg) rotateY(0deg); } } @-webkit-keyframes elfCube { 0% { -webkit-transform: rotateX(0deg) rotateY(0deg); } 50% { -webkit-transform: rotateX(360deg) rotateY(360deg); } 100% { transform: rotateX(0deg) rotateY(0deg); } } 複製程式碼

∙ 跟隨滑鼠旋轉 :
- 說好的隨著滑鼠旋轉呢??
- 別慌,接下來就是帶你裝逼,帶你飛的時候,
- 首先我們要了解,滑鼠在容器內所在的位置,X = e.pageX - ele.offsetLeft, Y = e.pageY - ele.offsetTop;
- 同時要知道元素內的中心點:centerX = width/2,centerY =height/2;
- 然後得出值:axisX = X - centerX,axisY = Y - centerY;
- PS : 開始嘗試想的是滑鼠從哪個方向進入,得到它的角度,但發現旋轉效果不明顯 ,有興趣的同學可以嘗試一下:(((Math.atan2(Y, X) * (180 / Math.PI)) + 180) / 90),參考司徒大神的 JS判斷滑鼠從什麼方向進入一個容器 ;
- 最後,給容器綁上事件:
mouseover
、mousemove
、mouseout
,滑鼠進入時,暫停css的動畫,不然會相互打架哦!

…… getAxisX(e){ let left = this.cubeEle.offsetLeft; return e.pageX - left - (this.cubeW/2) * (this.cubeW>this.cubeH ? this.cubeH/this.cubeW : 1); } getAxisY(e){ let top = this.cubeEle.offsetTop; return e.pageY - top - (this.cubeH/2) * (this.cubeH>this.cubeW ? this.cubeW/this.cubeH : 1); } ………… 複製程式碼
………… run(){ this.cubeEle.addEventListener('mouseover',(e)=>this.hoverOut(e),false); this.cubeEle.addEventListener('mousemove',(e)=>this.move(e),false); this.cubeEle.addEventListener('mouseout',(e)=>this.hoverOut(e),false); } hoverOut(e){ //進入/離開 e.preventDefault(); this.axisX = this.getAxisX(e), this.axisY = this.getAxisY(e); if(e.type == 'mouseout'){ //離開 this.axisX=0; this.axisY = 0; console.log("離開") this.cubeInner.className="cube-inner running"; }else{ this.cubeInner.className="cube-inner"; console.log("進入") }; let rotate = `rotateX(${-this.axisY}deg) rotateY(${-this.axisX}deg)`; this.cubeInner.style.WebkitTransform = this.cubeInner.style.transform = rotate; } …… 複製程式碼
結尾:
- -webkit-perspective,
- -webkit-transform-style,
- -webkit-transform-origin,
- radial-gradient、linear-gradient,
- transform:rotate、translate、scale,
- transition,
- animation;
- 以上就是今天為大家帶來的分享,以及使用到的知識點的API,如文章中有不對之處,煩請各位大神斧正,
- 文章原始碼獲取-> blog-resource :point_left:
- 想直接線上預覽 :point_left:
作者:蘇南 - 首席填坑官
來源:@IT·平頭哥聯盟
連結: honeybadger8.github.io/blog/
交流群:912594095[ 資源獲取/交流群
]、386485473(前端) 、260282062(測試)
本文原創,著作權歸作者所有。商業轉載請聯絡 @IT·平頭哥聯盟
獲得授權,非商業轉載請註明原連結及出處。
