Bootstrap上有個navbar的功能,裡面提供了一個External content的功能讓我們可以將內容先隱藏起來,等到使用者點擊按鈕觸發後才會以動畫的方式拉開內容,這樣的動畫呈現是使用了Bootstrap它自己的Collapse元件,但是Collapse只提供上下的展開,並沒有左右伸縮的功能,這讓我很苦惱,因為需求是要做從左邊展開的導覽列,自己刻一個是沒有問題,但既然Bootstrap都有提供Collapse以及跟按鈕的整合了,不用一下說不過去,這篇就來看看要怎麼使用Bootstrap做出一個可以有轉換動畫做隱藏及顯示的左清單列吧。
2018-02-08: add new content: 使用transform的轉場動畫
Navbar external content
先來做個一般的隱藏內容。
新增一個隱藏內容的元素:
1 | <div class="collapse" id="navbarToggleExternalContent"> |
class要加上collaspe。
新增一個觸發按鈕:
1 | <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggleExternalContent"> |
data-toggle要設為collapse。data-target設定選擇器,指向你要隱藏的元素(這裡是#navbarToggleExternalContent)。
這樣我們就完成了一個簡單的隱藏/顯示內容的功能了,下面是完整的程式碼:
See the Pen bootstrap 4 simple collapse with navbar by Peter Chen (@peterhpchen) on CodePen.
Collapse
要動手前我們要先知道關於Collapse這個元件的用法,它是一個可以讓對象在動作時有慢慢展開的效果,主要是由下面三個class來控制:
collapse: 初始化時設定的class,會將元素隱藏。collapsing: 觸發展開/縮回時開始到完成前會有的class,這上面設定了轉換時的動畫。collapse.show: 展開後的元素會多一個show的class,將元素顯示出來。
小小的原碼探險
我們由文件知道了上面三個類別會做的動作,從我們的需求上看,collapsing是我們應該深入的地方,因為這裡是在處理動畫呈現的部分,現在來看Bootstrap是怎麼實作出來的,我們可以看到_transitions.scss這個檔案,把焦點聚在Collapsing這邊:
1 | /* _transitions.scss */ |
我們可以注意到transition-property是設定height,所以Collapse是不會有橫向的動畫的,所以之後再覆寫時應該要改動這個設置。
上面collapsing的樣式會看到它將height設為0,而transition會在height改變的時候動作,所以一定有個地方改變了元素的height,接著找到了collapse.js:
1 | ... |
這邊有兩個重點:
_getDimension()會決定要抓的是Width還是Height,如果有設定Width類別的話就會抓Width。- 展開的大小是由scrollwidth(scrollHeight)決定。
這樣就萬事具備了,接著我們來試著開發吧。
將隱藏內容由左邊展開
接著進入本篇的重點,我們想要把隱藏的內容由左邊展開。
加上width類別讓_getDimension()取到的是Width:
1 | <div class="collapse width" id="navbarToggleExternalContent"> |
覆寫.collapsing:
1 | .collapsing { |
覆寫的原因說明在下面:
width設為0: 起始寬度設置。transition-property設為width: 轉換的目標變為width。height設為100%: 因高度不再是轉換的目標,所以原本的height: 0要改為原來的高度,要不然會因為長寬都是0造成在轉換期間會看不到元素的錯誤。
下面是依照上面設置後的演示:
See the Pen bootstrap 4 simple collapse with navbar(have scrollWidth Problem) by Peter Chen (@peterhpchen) on CodePen.
上面這樣成功讓隱藏內容由右邊展開了,但有兩個問題:
- 展開後的元素會擠掉其他元素。
- 在展開過程中內文的文字會依照目前的寬度折行。
第一個問題可以用position:fixed的設置來解決,我們用Bootstrap的position-fixed類別來實作。
1 | <div class="collapse width position-fixed" id="navbarToggleExternalContent"> |
第二個問題可以white-space設為nowrap來實現(參考自StackOverflow)。
解決這兩個問題後,現在會像是下面這樣。
See the Pen bootstrap 4 left navbar(have scrollWidth Problem) by Peter Chen (@peterhpchen) on CodePen.
如果觸發的話我們又會看到另一個問題,在轉換的最後會突然的顯示一節,有不平滑的感覺。
經過觀察發現scrollwidth的長度並不是真正的長度,它並不包含right padding,從這篇StackOverflow我們可以知道將padding改為用margin實作就好,因此我們將內容改為下面這樣:
1 | <div class="bg-dark py-4"> |
程式如下:
See the Pen bootstrap v4 left menu bar(not height 100%) by Peter Chen (@peterhpchen) on CodePen.
使用transform的轉場動畫
上面的例子所使用的轉場對象是width,看到的是清單內容慢慢隱沒的效果,還有另一種是直接把內容向左推,推動的是整個區塊,我們來看兩者的效果差別:

上面的比較圖我們可以看到左邊的是我們目前使用width做轉換的版本,可以看到它會慢慢的把內容文字從又變捲掉,而右邊會是整個區塊往左推,所以可以看到是從左邊的內容開始消失。
兩種不同的版本會因設計需求不同而被採用,現在來示範用translate的方式實作。
首先因為bootstrap的collapse是對長度(寬度或高度)做轉換,而translate的效果是不需要動到長度的,因此我們先把原本設定寬度dimension的width類別拿掉:
1 | <div class="bg-dark collapse position-fixed" id="navbarToggleExternalContent">...</div> |
拿掉width後,bootstrap變回抓預設的dimension: Height了,所以我們現在要固定高度:
1 | #navbarToggleExternalContent{ |
在固定高度後,就要來修改動畫的部分,前面有說因為collapse是以長度為動畫依據,所以全部的預設動畫都沒有用處了,我們需要自己加上動畫。
為此我們需要定義一個class,在show的時候加到元素上,藉這個class來設定開啟時候的狀態,為了達到這個目的我們用bootstrap提供的js事件來實作:
1 | const $menu = $('#navbarToggleExternalContent'); |
使用menu-show class,在show的時候加上,在hidden的時候清掉,現在我們在show的時候元素上會有menu-show這個類別了。
最後我們來加上動畫吧,在初始的狀態下我們是要隱藏menu的,所以我們用translateX(-100%)來隱藏清單:
1 | #navbarToggleExternalContent{ |
接著在顯示的狀態下,清單的起始位置應該要在0px(靠左)的地方:
1 | #navbarToggleExternalContent.menu-show{ |
如此一來,我們就可以得到一個translate的左導覽列了:
See the Pen bootstrap v4 left menu transform bar by Peter Chen (@peterhpchen) on CodePen.
結語
Bootstrap是個很易用的元件庫,我們可以用它來節省不少的時間及精力,像這次的覆寫也是因為Bootstrap本身就已經有開好入口讓我們可以輕鬆地修改,會卡住的應該就是對Transition還不太了解的人(就是我),理解CSS的Transition後就很簡單了。
備註
- 本文使用的是Bootstrap 4。