CSS3 的 transform
和 transition
讓開發者可以輕鬆實現轉場、過渡的動畫效果,但這並不代表誰可以做出一個流暢、清晰的動畫效果。
在這篇文章裡,我嘗試在 Fantastic-admin 後臺框架裡去增加一些錦上添花的動畫效果,並會分享我的設計思路。
本文觀點為作者主觀看法,有不同見解歡迎友好討論。
準備工作
首先動效是屬於設計的活,對於開發來說,其實是不擅長的,包括我也一樣。那怎麼辦呢?一種就是請教設計大佬,但這種機會比較少,我的辦法就是參考大廠出的一些設計規範,而我這次參考的就是幾年前的 Material Design 。
然後就是參考同類產品,看看他們在那些地方都加了動效,並以使用者的角度去感受動效是否合理,是否會破壞使用者的操作體驗。
最後關於動效執行時間,在簡單閱讀了 Material Design 後,我大致理解為,移動端長動畫大約在 300ms 到 400ms ,短動畫大約在 150ms 到 200ms ,而桌面端動畫大約在 150ms 到 200ms ,可以看到所有動畫執行時長都不會超過 400ms ,設定大部分都會控制在 300ms 以內,因為過長的動畫會讓人感覺遲鈍,相反,過短的動畫也會讓人覺得難以看明白。
所以我最終確定的整體思路就是,頁面中儘量避免元素突然出現或消失,也就是說動態載入和動態刪除的元素儘量通過動效進行緩進和緩出,然後頁面上的固定元素如果需要位移或者變更尺寸等操作,則必須使用動效進行過渡。而動畫執行時長控制在 150ms 到 300ms 之間,因為有些大區域的動畫使用 200ms 會顯得太短,甚至看不出有動畫效果。
接下來就是依次改造了。
吸頂層
這是一個很常見的場景,通過 position: fixed;
固定在頂部的模組不會隨著頁面滾動而移動,因為固定在內容區的上方,所以使用 box-shadow
模擬出懸浮的效果,然後再配合 js 動態計算頁面 scrollTop 的距離,從而動態增加陰影效果。
部分程式碼:
.breadcrumb-container {
transition: box-shadow 0.2s;
box-shadow: 0 10px 10px -10px #ccc;
}
麵包屑導航
麵包屑導航用來展示當前頁面所在的層級,所以當路由切換時,麵包屑導航也會隨之變化。這裡我沒有使用淡入淡出的效果,而是從右側做了一個位移的效果,同時配合文字的傾斜,給使用者傳遞“進入頁面”的意思。
你會發現,這裡其實是沒有移出動畫的,只做了進入的效果。因為使用者操作的時候視覺是跟隨滑鼠的,而麵包屑導航的變化一般是在點選側邊欄導航進行路由切換時才會變化,使用者並不太會注意到麵包屑導航,加上本身又是個短動畫,要控制好執行時長,一出一進顯得有點拖沓,所以就把移出動畫去掉了,當然最終效果還是可以接受的。
部分程式碼:
.breadcrumb-enter-active {
transition: all 0.2s;
}
.breadcrumb-enter,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(30px) skewX(-50deg);
}
標籤欄
標籤欄是參考了 chrome 瀏覽器的介面,新增和關閉的動畫從原本橫向展開的形式,改成了上下升降的形式。
有人會問,這裡為什麼又有移出的動畫了?其實還是上面說的那個思路,使用者操作的時候視覺是跟隨滑鼠的,而標籤欄上操作的相對比較頻繁的,因為會在多個標籤頁面之間切換,所以這塊移出動畫不可少。同時升降的形式也避免了標籤元素在執行各自動畫時的重疊。
部分程式碼:
.tab-animate {
display: inline-block;
transition: transform 0.2s ease, opacity 0.2s ease;
}
.tabbar-enter,
.tabbar-leave-to {
opacity: 0;
transform: translateY(30px);
}
.tabbar-leave-active {
position: absolute;
}
主題
主題切換需要注意的就是動畫執行時間,因為使用的是 ElementUI 裡的 Menu 元件,它自帶了 transition
的設定,並且時長是 300ms ,所以為了統一,導航的動畫時長我都調整成了 300ms ,這樣在切換主題的時候,過渡效果就顯得比較整體,不然就會出現這樣的情況:
導航欄
導航欄摺疊的效果難點其實和上面的一樣,就是注意動畫執行時長,與 ElementUI 的 Menu 元件保持一致。
內容區
內容區也就是業務頁面,過渡沒用使用 transform
處理,因為考慮到內容區裡的元素不可控,而 transform
會導致 position: fixed;
定位失效。
同時將 <transition>
元件的 mode 設定為 mode="out-in"
,因為不設定的話,進來的元素和出去的元素動畫是同時執行的,就會出現動畫執行時它倆是一上一下的位置,知道上面的元素完全移出後,下面的元素突然被頂了上來,效果不理想,除非進入的元素設定成 position: absolute;
,將其覆蓋在移出元素上方,但脫離文件裡就會有太多不可控的因素。
所以最終內容區的動效我採用 margin-left
進行處理,並且模式是先出後進,為了避免兩個動效執行總時長過長,移出的動畫為 200ms ,進入的動畫為 150ms ,總時長控制在 400ms 以內,因為不能使用 transform
所以也就不能進行 GPU 加速,過短的時長偶爾會出現掉幀的情況。
部分程式碼:
.main-enter-active {
transition: all 0.2s;
}
.main-leave-active {
transition: all 0.15s;
}
.main-enter {
opacity: 0;
margin-left: -20px;
}
.main-leave-to {
opacity: 0;
margin-left: 20px;
}
最後
這就是整體的一個效果演示了。
當然如果你感興趣,你可以去 Fantastic-admin 實際操作體驗一下,這是我寫的一箇中後臺系統框架,基於 Vue 和 ElementUI 。