web-dev-assignment

響應式網頁設計

本專案用於學習響應式網頁設計 (Responsive Web Design, RWD),以下紀錄開發過程中,比較重要的技術細節。

如何實作導覽列

導覽列的 CSS 選擇器如下,階層以及名稱如下

  1. navbar: 導覽列
  2. navbar__toggler: 導覽列切換器
  3. navbar__nav: 所有導覽路徑
  4. nav__item: 導覽路徑

     navbar
      ├─ navbar__toggler
      └─ navbar__nav
          └─ nav__item
    

導覽列基本資訊

  1. 給一般使用者

    圖 1、展開所有 Menu items 且不需要折疊
  2. 給移動裝置,在使用者未進行操作

    圖 2、摺疊所有 Menu items 且顯示選單 icon
  3. 給移動裝置,使用者點擊選單 icon

    圖 3、向下展開所有 Menu items 且顯示選單 icon

導覽列實作

  1. 先寫 HTML 架構如下

    • navbar 為最外層 div
    • navbar__toggler 做為顯示或隱藏選單的 div
    • navbar__toggler 裡面包含一個 img,使用 hamberger 作為 icon
    • navbar__toggler 在被點擊的時候,呼叫函式 handleNavbarTogglerClick,並傳入 element
    • navbar__nav 所有導覽路徑的外層 div,包含四個導覽路徑 Item 1 ~ Item 4
    • nav__item 導覽路徑的名稱顯示或外層,通常會在裡面包含 <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>
    
  2. 所有導覽路徑水平排列,作為一般使用者的導覽列

     .navbar {
       align-items: center;
       display: flex;
       flex-wrap: wrap;
     }
    
     .navbar__nav {
       display: flex;
       flex-direction: row;
       list-style: none;
     }
    
  3. 設定導覽路徑邊寬,讓路徑間不要太擁擠

     .nav__item {
       cursor: pointer;
       padding-left: 0.5em;
       padding-right: 0.5em;
     }
    
  4. 設定導覽列切換器,在一般使用者下隱藏,完成一般使用者導覽列 (如圖 1)

     .navbar__toggler {
       cursor: pointer;
       display: none;
     }
    
  5. 設定移動裝置使用者屬性,完成移動裝置導覽列 (如圖 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;
       }
     }
    
  6. 導覽列切換器被點擊,切換 display: flex 或預設值 (display: none),完成移動裝置導覽列 (如圖 3)

    • 傳進來的 element 是 navbar__toggler
    • 父節點是 navbar,在 navbar 底下搜尋子節點 navbar__nav
     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 = "";
       }
     }
    

CSS 命名規則之一 BEM

Block Element Modifier (BEM) 是一種為了讓 CSS 類別更好維護的命名方式

  1. Block 區塊 .block {}
  2. Element 元素 .block__element
  3. Modifier 修飾器 .block__element--modifier

Block 區塊

主要負責描述大範圍功能,例如 headercontainernavbar

Element 元素

區塊的小部分,區塊可以不包含元素,但元素一定要包含在區塊,用於表達目的,中間用雙底線連結

例如 list__itemnavbar__toggler

Modifier 修飾器

區塊或元素的狀態,同一個區塊或元素可能有多種狀態,使用修飾器表達,中間用雙中線連結

例如 nav__item--activestar--activestar--inactive

BEM 觀念

  1. 當有重複使用的選擇器時,需要拉出來成為新的選擇器做調用,相當於 has-a 的功用
  2. 利用區塊元素,表達選擇器的階層關係,由於 CSS 沒有作用域,所以利用 BEM 避免命名重複
  3. 利用修飾器表達不同狀態
  4. 當區塊裡的元素,又有向下階層時,不希望一直下底線連結,只需要元素底線元素或區塊底線元素

    • 例如: menu__list__item__link 可以寫成 menu__link,代表 link 不一定要在 list 或 item 之下
  5. 使用抽象畫命名,例如顏色可以 text-blue 改為 text-primaryasidecontent 可以改為 col-3col-9

BEM 參考資料

網格系統的應用

長寬比的區塊 (aspect ratio)

參考資料:

中心裁剪 (center cropped)

參考資料:

彈性成長係數 (flex-grow)

不透明度 (opacity)

圖層概念 (z-index)

從 KKBOX 到 CSS,選擇器命名規則

剛開始寫 CSS 時,我們都知道要有意義的命名,但即使命名都有自己的意義, 卻發現選擇器之間有很多重複的屬性,完成第一份作業後,就有問彭彭老師,老師 就提到選擇器的命名規則是滿值得討論的議題,並讓我查詢「css bem naming」, 我就開始調查,CSS 怎麼樣才是好命名,並查學習一些常見網頁的命名方式。

重要的命名觀念

  1. 抽象化命名,例如: left 就只能放在左邊,改為 aside 就可以放在左右
  2. 避免針對性命名,例如: 作業的歡迎橫幅 welcome,可以改為 banner 內容就不一定是歡迎
  3. 狀態命名,例如: 導航欄連結在當前頁面狀態 menu-item 加上 is-active,其他頁面則只有 menu-item

BEM

Block Element Modifier (BEM) 是一種為了讓 CSS 類別更好維護的命名方式

  1. Block 區塊 .block {}

    主要負責描述大範圍功能,例如 headercontainer

  2. Element 元素 .block__element {}

    區塊的小部分,區塊可以不包含元素,但元素一定要包含在區塊,用於表達目的,中間用雙底線連結 例如 list__itemnavbar__toggler

  3. Modifier 修飾器 .block__element--modifier {}

    區塊或元素的狀態,同一個區塊或元素可能有多種狀態,使用修飾器表達,中間用雙中線連結 例如 nav__item--activestar--activestar--inactive

KKBOX 的導覽列分解

  1. KKBOX 導覽列分為兩個選擇器,並在寬度 1024 切換

      Mobile Desktop
    0 ~ 1024 display: flex display: none
    1024 ~ display: none display: flex
     pm-header
     ├─ pm-mobile-header
     └─ pm-desktop-header
    

    | | | :-: | | pm-header | | 圖1 pm-header | | pm-desktop-header | | 圖2 pm-desktop-header | | pm-mobile-header | | 圖3 pm-mobile-header |

  2. 桌面版本裡面的 pm-container 有兩個區塊,位於旁邊的 pm-header-aside,和位於另一端的 pm-header-menu

     pm-header
     ├─ pm-mobile-header
     └─ pm-desktop-header
        └─ pm-container*
           ├─ pm-header-aside*
           └─ pm-header-menu*
    
     
    pm-container
    圖4 pm-container
    pm-header-aside
    圖5 pm-header-aside
    pm-header-menu
    圖6 pm-header-menu
  3. 在旁邊的 pm-header-aside 裡面只有一個 pm-logo

     pm-header
     ├─ pm-mobile-header
     └─ pm-desktop-header
        └─ pm-container-menu
           ├─ pm-header-aside
           |  └─ pm-logo*
           └─ pm-header-menu
    
     
    pm-logo
    圖7 pm-logo
  4. 而 pm-header-menu 包含的東西就比要多,有 pm-drop-down、pm-search-button 和普通的 a

    • 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*
    
     
    pm-drop-down
    圖8 pm-drop-down
    pm-search-button
    圖9 pm-search-button
    pm-normal pm-download
    圖10 普通的 a
  5. 利用狀態顯示顏色,像是搜尋按鈕和下載都是藍色,使用選擇器 pm-highlight

     
    pm-search-button
    圖11 帶有 pm-highlight 的 pm-search-button
    pm-download
    圖12 帶有 pm-highlight 的 a
  6. 接下來介紹 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
    
     
    pm-menu-icon
    圖13 pm-menu-icon
    pm-search-icon
    圖14 pm-search-icon
    pm-logo-m
    圖15 pm-logo
  7. 最後,當 pm-menu-icon 和 pm-search-icon 被點擊都會展開左或右側的菜單,所以他們都有狀態 pm-active, 這個狀態將背景圖片都改為叉叉,複寫原本的選單或放大鏡

     
    pm-menu-icon-active
    圖16 帶有 pm-active 的 pm-menu-icon
    pm-search-icon-active
    圖17 帶有 pm-active 的 pm-search-icon

KKBOX 的導覽列總結

用 BEM 角度看 KKBOX 的導覽列,從中看到 Block 中都是可被單一重複使用,Element 需要依賴在特定 Block 之下,Modifier 則可以直接附加在 Block 或 Element

參考資料