- Published on
JS30 - 05 Flex Panels Image Gallery
透過 Flexbox 製作一個圖片展示頁面,每張圖片在點擊時會有動畫效果,並展開圖片並顯示更多文字內容
flex
屬性來設定圖片的排列方式和點擊後的展開效果
CSS:Flexbox
在這個挑戰中,使用 Flexbox 讓 .panel
(圖片區塊)能夠並排顯示,並且點擊時可以透過 flex
動態調整大小,產生展開效果
1️⃣ 設定 Flex 容器
在 .panels
上設定 display: flex
,讓 .panel
元素變成 Flexbox 的子項目(flex items),並透過 flex
屬性控制其大小
.panels {
display: flex;
}
2️⃣ 設定 Flex 子項目
在 .panel
上設定 flex: 1
,讓每個 .panel
元素平均分配剩餘空間,並且透過 flex
屬性來設定展開效果。 透過 flex-direction: column
來設定 .panel
元素的排列方向為垂直,並透過 justify-content: center
來讓內容置中
.panel {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
Main-axis 和 Cross-axis
flex-direction
屬性用來設定 Main-axis 的方向,預設為row
(水平)justify-content
屬性用來設定 Main-axis 上的對齊方式align-items
屬性用來設定 Cross-axis 上的對齊方式
當 flex-direction
設定為 row
時,Main-axis 為橫向,Cross-axis 為縱向
────────── Main Axis ───────────→
│ ┌────────┬────────┬────────┐
│ │ Item 1 │ Item 2 │ Item 3 │
│ └────────┴────────┴────────┘
│ Cross Axis
↓
當 flex-direction
設定為 column
時,Main-axis 為縱向,Cross-axis 為橫向
│ Main Axis
│
│ ┌────────┐
│ │ Item 1 │
│ ├────────┤
│ │ Item 2 │
│ ├────────┤
│ │ Item 3 │
│ └────────┘
│
↓ ── Cross Axis ──→
3️⃣ 控制項目大小(flex)
flex
屬性是 flex-grow
、flex-shrink
和 flex-basis
的簡寫,用來設定彈性盒子的伸縮比例、收縮比例和基準值
flex-grow
:當有多餘空間時,項目擴展的比例(預設 0)flex-shrink
:當空間不足時,項目收縮的比例(預設 1)flex-basis
:設定項目的初始大小(預設 auto)
在這個挑戰中,要讓 panel 初始時等寬,點擊時可以展開,因此設定為:
.panel {
flex: 1;
}
.panel.open {
flex: 2;
}
JavaScript
1️⃣ 取得 DOM 元素並監聽事件
因為要做點擊 panel 後的展開效果,所以要取得 panels 元素,並監聽 click
事件
const panelsContainer = document.querySelector('.panels')
panelsContainer.addEventListener('click', togglePanel)
panelsContainer.addEventListener('transitionend', toggleActive)
- 因為所有
.panel
都是.panels
的子元素,可以在.panels
上監聽click
,透過事件冒泡來處理點擊事件,這樣不需要對每個.panel
單獨監聽,提高效能
2️⃣ 展開 panel
透過 classList.toggle('open')
來切換 panel 的展開狀態
function togglePanel(e) {
const panel = e.target.closest('.panel')
if (!panel) return
panel.classList.toggle('open')
}
closest()
方法用來取得最接近的.panel
,也就是點擊的 panelclassList.toggle('open')
用來切換open
類別,如果有open
類別則移除;沒有open
類別則添加
3️⃣ 文字效果
透過 transitionend
事件監聽,當 flex 屬性動畫結束時,切換 .open-active
類別
function toggleActive(e) {
if (e.target.classList.contains('panel') && e.propertyName.includes('flex')) {
e.target.classList.toggle('open-active')
}
}
propertyName
可能在不同瀏覽器中回傳flex
或flex-grow
,所以用includes("flex")
來確保兼容性