CSS only – O不OK?

2023-08-12
預估閱讀時間: 5 分鐘

我最近發現,許多人儘量排除不需要的 JavaScript,並盡可能多使用單純 CSS 來完成他們的網站。我自己也開始思考,如果這麼多東西可以用 CSS 單獨完成,也許這才是正確的方式?也許我們真的不需要 JavaScript 了?其實每次看我的網站的 PageSpeed 分數,都會陷入這種想法中。

在網路上可以找到許多關於如何使用單純的 CSS 製作漢堡菜單、彈跳窗或手風琴。就對我而言,當你可以用單純 CSS 讓東西有交互作用(例如模擬 click events ),我認為這種做法是很有趣的,但也可能會導致一些問題。在這篇文章當中,我會介紹這些不足之處。

那麼,我們首先來解釋一下 「CSS only」 到底是什麼意思呢?CSS only 指的是通常需要 JavaScript 的東西,像在前面提到的漢堡菜單、彈跳窗或手風琴,直接用單純的 CSS 來寫,保持正常功能與作用。這樣做的主要原因是為了減少網站加載時間,因為更多的 JavaScript 等於更多 CPU 的工作量,則這等於網站變慢。甚至更糟糕的是,更多的 JavaScript 等於更多 CPU 的工作量,則這等於 PageSpeed 得分變差 😛。

CSS only 的漢堡選單

讓我們以一個僅使用 CSS 的菜單作為例子。這樣的菜單使用 CSS 中所謂的「siblings selectors」來運作。其背後的想法非常簡單,你先創建一個checkbox,然後根據它的狀態,您可以在 CSS 中切換菜單的可見性。然後你的菜單需要在 DOM 中直接放在 checkbox 之後的位置,或者至少在 DOM 中的同一個 level。在這個例子當中,我們會使用 〜 的 CSS selector,因此你要把你的 checkbox 和菜單寫在 DOM 中的同一級就可以。

你可以參考以下的 HTML:


<input id="hamburger-toggle" type="checkbox">

<label for="hamburger-toggle" class="hamburger-menu">
  <span class="hamburger-line"></span> 
  <span class="hamburger-line"></span>
  <span class="hamburger-line"></span>
</label>

<nav id="menu">
  <ul>
    <li><a href="#">Menu 1</a></li>
    <li><a href="#">Menu 2</a></li>
  </ul>
</nav>

然後你的 CSS 可以這樣寫:


#hamburger-toggle,
#menu {
  display: none;
}

#hamburger-toggle:checked ~ #menu {
  display: block;
}

雖然這種 CSS only 的方式看起來是 OK 的,但這種菜單的主要問題在於它無法用鍵盤使用(你無法僅使用鍵盤來打開和關閉菜單),而且如果它的狀態由單純的 CSS 處理,你將無法切換 aria 屬性。 Aria 屬性很重要,因為 aria 可以告訴螢幕閱讀器隱藏的 HTML 元素需要切換可見。但是,你需不需要用 aria 可能要看你的需求,因為不是每個人的網站都需要達到 100% 無障礙性。

另一方面,我認為如果你想保持使用單純 CSS 並在無障礙性方面做一些進步,你應該至少執行鍵盤支援。這是可以做得到,只需要加一點 hacky 的 CSS。其實我發現也有不是殘障的人,也會僅使用鍵盤操作網站。

因此我們可以考慮不把 checkbox 的 display 屬性切換不可見,而是將其透明度設定為 0。然後在 checkbox 選中時,讓按鈕創建一個虛假的輪廓周圍。接下來你還需要把你的 checkbox 設定為絕對的 position。這是因為 opacity 雖然會讓他隱藏,但它還是會佔空間。


#hamburger-toggle {
  opacity: 0;
  position: absolute;
  left: -9999px;
}

#hamburger-toggle:focus ~ .hamburger-menu {
  outline: 2px solid white;
  outline: auto;
  outline-offset: 4px;
}

現在,因為 checkbox 已經不是 display none,而它的透明度為 0% 而已,所以還是可以使用鍵盤操作。這種 CSS 的 hack 可以提供基本的鍵盤支援。但我認為,如果你想要讓你的菜單更加無障礙性,你將需要再進一步。

使用 JavaScript 製作無障礙性的菜單

請不要誤會我的意思,我並不覺得只使用 CSS 的方式是完全錯的。因為就像我之前提到的,有些網站並不需要達到 100% 的無障礙性。有些網站可以直接加上面的 hacky 提供鍵盤支援,可能這樣就夠了。其實我在一些網站上還使用單純 CSS 的漢堡菜單,不過一些網站確實需要良好的無障礙支援。

那完全無障礙性菜單需要有什麼呢?我認為是這些步驟:

  • 鍵盤支援
  • 使用 aria 屬性
  • 使用恰當的 HTML5 的元素

事實上,在上面的例子當中,我們已經使用適當的 HTML5 的元素來建立菜單(nav),因此螢幕閱讀器可以知道它是一個菜單。儘管如此,我們還必須增加適當的 aria 屬性和更好的鍵盤支援。為了這些,我們可以將我們的 HTML 和 JavaScript 寫成這樣:


<button class="hamburger-menu" aria-expanded="false" aria-controls="menu">
    <span class="hamburger-line"></span> <span class="hamburger-line"></span><span class="hamburger-line"></span>
</button>

<nav id="menu" aria-label="Main Menu">
  <ul>
    <li><a href="#" title="Menu Item 1">Menu 1</a></li>
    <li><a href="#" title="Menu Item 2">Menu 2</a></li>
  </ul>
</nav>

const menu = document.getElementById('menu');
const hamburger = document.querySelector('.hamburger-menu');

if (menu && hamburger) {
  hamburger.addEventListener("click", () => {
    const isMenuVisible = menu.classList.toggle("active");
    hamburger.setAttribute('aria-expanded', isMenuVisible);
  });
}

以上的程式會在你點擊漢堡按鈕時切換 aria-expanded 的屬性,讓螢幕閱讀器知道菜單要呈現。另外,你可能已經發現了我們把 checkbox 換成 button的元素。因為在 HTML,按鈕具有鍵盤支持,並且可以與 JavaScript 一起運作。依我個人觀點,這種具有一點 JavaScript 的菜單對於螢幕閱讀器來說是更好的。我們也可以新增 aria-controls 的屬性,讓螢幕閱讀器知道我們的 button 和菜單的元素是連在一起的。

確定你的 aria-expanded 的屬性是用在 button 而不是菜單的元素。

如果你有任何想法,如何讓這個 menu 更好,或者任何其他建議,請在下面留言。

發佈留言