本專案用於學習響應式網頁設計 (Responsive Web Design, RWD),以下紀錄開發過程中,比較重要的技術細節。
導覽列的 CSS 選擇器如下,階層以及名稱如下
nav__item: 導覽路徑
navbar
├─ navbar__toggler
└─ navbar__nav
└─ nav__item
給一般使用者
給移動裝置,在使用者未進行操作
給移動裝置,使用者點擊選單 icon
先寫 HTML 架構如下
div
<a>
作為連結 <div class="navbar">
<div class="navbar__toggler" onclick='handleNavbarTogglerClick(this)'>
<img src="icon/hamberger.svg">
</div>
<div class="navbar__nav">
<li class="nav__item">Item 1</li>
<li class="nav__item">Item 2</li>
<li class="nav__item">Item 3</li>
<li class="nav__item">Item 4</li>
</div>
</div>
將所有導覽路徑水平排列,作為一般使用者的導覽列
.navbar {
align-items: center;
display: flex;
flex-wrap: wrap;
}
.navbar__nav {
display: flex;
flex-direction: row;
list-style: none;
}
設定導覽路徑邊寬,讓路徑間不要太擁擠
.nav__item {
cursor: pointer;
padding-left: 0.5em;
padding-right: 0.5em;
}
設定導覽列切換器,在一般使用者下隱藏,完成一般使用者導覽列 (如圖 1)
.navbar__toggler {
cursor: pointer;
display: none;
}
設定移動裝置使用者屬性,完成移動裝置導覽列 (如圖 2)
@media screen and (max-width: 600px) {
.navbar__toggler {
display: block;
}
.navbar__nav {
display: none;
flex-direction: column;
width: 100%;
}
.nav__item {
padding-top: 0.25em;
padding-bottom: 0.25em;
padding-left: 0;
padding-right: 0;
}
}
當導覽列切換器被點擊,切換 display: flex
或預設值 (display: none
),完成移動裝置導覽列 (如圖 3)
function handleNavbarTogglerClick(element) {
const parent = element.parentElement;
element = parent.querySelector('.navbar__nav');
if (element.style.display !== "flex") {
element.style.display = "flex";
} else {
element.style.display = "";
}
}
Block Element Modifier (BEM) 是一種為了讓 CSS 類別更好維護的命名方式
.block {}
.block__element
.block__element--modifier
主要負責描述大範圍功能,例如 header
、container
或 navbar
區塊的小部分,區塊可以不包含元素,但元素一定要包含在區塊,用於表達目的,中間用雙底線連結
例如 list__item
或 navbar__toggler
區塊或元素的狀態,同一個區塊或元素可能有多種狀態,使用修飾器表達,中間用雙中線連結
例如 nav__item--active
、star--active
或 star--inactive
當區塊裡的元素,又有向下階層時,不希望一直下底線連結,只需要元素底線元素或區塊底線元素
menu__list__item__link
可以寫成 menu__link
,代表 link 不一定要在 list 或 item 之下text-blue
改為 text-primary
,aside
和 content
可以改為 col-3
和 col-9
display: grid
和 grid-template-columns
grid-template-columns: repeat(4, 1fr)
,當需要不同數量為二時可以修改為 repeat(2, 1fr)
間距: 透過 column-gap: 1em
和 row-gap: 1em
可以設定上下左右的間距都是 1em,並且間距設定不包含邊緣,若有需求要用 margin
或 padding
container
和內層 media
position: absolute
,該屬性會往上層找層級最接近的 position:relative
,並以它作為絕對座標範例: 16:9 如下,4:3 則設定為 3/4 = 0.75,3:2 則設定為 2/3 = 0.6667
.container {
position: relative;
width: 100%;
padding-top: 56.25%; /* 16:9 Aspect Ratio */
}
.media {
position: absolute;
top: 0;
}
參考資料:
用途: 將影像中心裁剪到符合長寬需求
.center-cropped {
object-fit: cover;
object-position: center;
}
範例:
<div style="width: 250px; height: 250px">
<img style="width: 100%; height: 100%" src="...">
</div>
<div style="width: 250px; height: 250px">
<img style="width: 100%; height: 100%; object-fit: cover; object-position: center;" src="...">
</div>
參考資料:
flex-direction: colume
或垂直 flex-direction: row
的剩餘空間flex-grow: 1
,數字代表權重範例: 尚未加上 flow-grow 前,因為同一列高度不一樣,有些區塊下方仍未填滿,在區塊下方的元素加上 flow-grow: 1
,則將剩餘空間都給該元素
opacity: 25
,設定不透明度 25z-index: 1
,設定為圖層 1,只要其他 z-index 大於該數字且重疊,較大者會在上面剛開始寫 CSS 時,我們都知道要有意義的命名,但即使命名都有自己的意義, 卻發現選擇器之間有很多重複的屬性,完成第一份作業後,就有問彭彭老師,老師 就提到選擇器的命名規則是滿值得討論的議題,並讓我查詢「css bem naming」, 我就開始調查,CSS 怎麼樣才是好命名,並查學習一些常見網頁的命名方式。
left
就只能放在左邊,改為 aside
就可以放在左右welcome
,可以改為 banner
內容就不一定是歡迎menu-item
加上 is-active
,其他頁面則只有 menu-item
Block Element Modifier (BEM) 是一種為了讓 CSS 類別更好維護的命名方式
Block 區塊 .block {}
主要負責描述大範圍功能,例如 header
或 container
Element 元素 .block__element {}
區塊的小部分,區塊可以不包含元素,但元素一定要包含在區塊,用於表達目的,中間用雙底線連結
例如 list__item
或 navbar__toggler
Modifier 修飾器 .block__element--modifier {}
區塊或元素的狀態,同一個區塊或元素可能有多種狀態,使用修飾器表達,中間用雙中線連結
例如 nav__item--active
、star--active
或 star--inactive
KKBOX 導覽列分為兩個選擇器,並在寬度 1024 切換
Mobile | Desktop | |
---|---|---|
0 ~ 1024 | display: flex |
display: none |
1024 ~ | display: none |
display: flex |
pm-header
├─ pm-mobile-header
└─ pm-desktop-header
| | | :-: | | | | 圖1 pm-header | | | | 圖2 pm-desktop-header | | | | 圖3 pm-mobile-header |
桌面版本裡面的 pm-container 有兩個區塊,位於旁邊的 pm-header-aside,和位於另一端的 pm-header-menu
pm-header
├─ pm-mobile-header
└─ pm-desktop-header
└─ pm-container*
├─ pm-header-aside*
└─ pm-header-menu*
圖4 pm-container |
圖5 pm-header-aside |
圖6 pm-header-menu |
在旁邊的 pm-header-aside 裡面只有一個 pm-logo
pm-header
├─ pm-mobile-header
└─ pm-desktop-header
└─ pm-container-menu
├─ pm-header-aside
| └─ pm-logo*
└─ pm-header-menu
圖7 pm-logo |
而 pm-header-menu 包含的東西就比要多,有 pm-drop-down、pm-search-button 和普通的 a
pm-header
├─ pm-mobile-header
└─ pm-desktop-header
└─ pm-container-menu
├─ pm-header-aside
| └─ pm-logo
└─ pm-header-menu
├─ pm-drop-down*
├─ pm-search-button*
└─ a*
圖8 pm-drop-down |
圖9 pm-search-button |
圖10 普通的 a |
利用狀態顯示顏色,像是搜尋按鈕和下載都是藍色,使用選擇器 pm-highlight
圖11 帶有 pm-highlight 的 pm-search-button |
圖12 帶有 pm-highlight 的 a |
接下來介紹 pm-mobile-header,裡面都是圖片 pm-menu-icon、pm-search-icon、pm-logo 其中 pm-logo 和 pm-search-icon (被包含在 pm-search-button 底下) desktop 共用選擇器
pm-header
├─ pm-mobile-header
| ├─ pm-menu-icon*
| ├─ pm-search-icon*
| └─ pm-logo*
└─ pm-desktop-header
└─ pm-container-menu
├─ pm-header-aside
| └─ pm-logo
└─ pm-header-menu
├─ pm-drop-down
├─ pm-search-button
└─ a
圖13 pm-menu-icon |
圖14 pm-search-icon |
圖15 pm-logo |
最後,當 pm-menu-icon 和 pm-search-icon 被點擊都會展開左或右側的菜單,所以他們都有狀態 pm-active, 這個狀態將背景圖片都改為叉叉,複寫原本的選單或放大鏡
圖16 帶有 pm-active 的 pm-menu-icon |
圖17 帶有 pm-active 的 pm-search-icon |
用 BEM 角度看 KKBOX 的導覽列,從中看到 Block 中都是可被單一重複使用,Element 需要依賴在特定 Block 之下,Modifier 則可以直接附加在 Block 或 Element