TadNav v1.5.0

現代化、零依賴、符合 WCAG 2.2 的無障礙導覽選單套件,以純 JavaScript 取代 SmartMenus jQuery。

零依賴 WCAG 2.2 多層巢狀 Hover & Click hoverClose Spacer 靠右 CSS 變數主題 MIT License

📁 一、檔案結構

tadnav/
├── tadnav.css      ← 套件樣式(CSS 變數主題系統)
├── tadnav.js       ← 套件核心邏輯
└── index.html      ← 本說明文件 & 互動展示頁

套件本身僅需 tadnav.css 與 tadnav.js 兩個檔案。 Font Awesome 為選用依賴,僅用於箭頭與圖示顯示。

🚀 二、快速開始

步驟 1:引入檔案

<!-- Font Awesome(選用,用於箭頭圖示)-->
<link rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">

<!-- TadNav 樣式 -->
<link rel="stylesheet" href="tadnav.css">

<!-- TadNav 核心(放在 </body> 前)-->
<script src="tadnav.js"></script>

步驟 2:建立 HTML 結構

<nav class="tadnav-wrapper" aria-label="導覽工具列">
  <div class="tadnav-inner">

    <!-- 品牌名稱(選用)-->
    <div class="tadnav-brand">網站名稱</div>

    <!-- 漢堡按鈕(手機版)-->
    <button class="tadnav-toggle"
            aria-expanded="false"
            aria-controls="my-menu"
            aria-label="切換選單顯示狀態">
      <span class="bar" aria-hidden="true"></span>
      <span class="bar" aria-hidden="true"></span>
      <span class="bar" aria-hidden="true"></span>
    </button>

    <!-- 主選單 -->
    <ul id="my-menu" class="tadnav-menu" role="menubar" aria-label="主選單">

      <!-- 一般連結 -->
      <li role="none">
        <a href="/home" role="menuitem">首頁</a>
      </li>

      <!-- 有子選單的項目 -->
      <li role="none">
        <button class="tadnav-submenu-toggle" role="menuitem"
                aria-haspopup="true" aria-expanded="false">
          服務 <span class="tadnav-arrow" aria-hidden="true"></span>
        </button>
        <ul class="tadnav-submenu" role="menu" aria-label="服務">
          <li role="none"><a href="/svc1" role="menuitem">服務一</a></li>
          <li role="none"><a href="/svc2" role="menuitem">服務二</a></li>
        </ul>
      </li>

      <!-- Spacer:其後項目靠右 -->
      <li class="tadnav-spacer" role="none" aria-hidden="true"></li>

      <!-- 靠右項目(JS 自動標記,無需手寫 style)-->
      <li role="none">
        <a href="/login" role="menuitem">登入</a>
      </li>

    </ul>
  </div>
</nav>

步驟 3:初始化

document.addEventListener('DOMContentLoaded', function () {

  var nav = new TadNav('#my-menu', {

    // 展開方式
    trigger:    'hover',   // 'hover'(預設)| 'click'
    hoverClose: true,      // hover 模式下滑走是否收合

    // 主題色彩(全部選用,未設定則使用 CSS 預設值)
    theme: {
      navBg:           '#2c3e50',
      itemColor:       '#ffffff',
      itemHoverBg:     'rgba(255,255,255,0.15)',
      itemFontSize:    '0.95rem',
      subBg:           '#ffffff',
      subItemColor:    '#2c3e50',
      subItemHoverBg:  '#f0f4f8',
      subItemFontSize: '0.9rem',
      subShadow:       '0 4px 16px rgba(0,0,0,0.12)',
      innerMaxWidth:   '1200px',
    }

  });

});

🏗️ 三、HTML 結構規則

TadNav 依賴特定的 class 與 ARIA 屬性組合,請嚴格遵守以下規則:

元素必要 Class必要屬性說明
<nav>.tadnav-wrapperaria-label最外層容器,CSS 變數寫入此元素
<div>.tadnav-inner—flex 排版容器,寬度由 innerMaxWidth 控制
<div>.tadnav-brand—品牌名稱區塊(選用)
<button>.tadnav-togglearia-expanded aria-controls aria-label漢堡按鈕,手機版顯示
<ul>.tadnav-menurole="menubar" aria-label頂層選單根節點,id 需對應 aria-controls
<li>—role="none"所有 <li> 皆須加此屬性
<a>—role="menuitem"一般連結項目
<button>.tadnav-submenu-togglerole="menuitem" aria-haspopup="true" aria-expanded="false"子選單觸發按鈕
<span>.tadnav-arrowaria-hidden="true"箭頭指示器(Font Awesome 自動套用)
<ul>.tadnav-submenurole="menu" aria-label子選單,必須緊接在 toggle 按鈕之後
<li>.tadnav-spacerrole="none" aria-hidden="true"靠右分隔點,其後項目自動靠右展開
巢狀子選單:子選單內可再放置 .tadnav-submenu-toggle + .tadnav-submenu,支援無限層巢狀,JS 會自動處理所有 ARIA 屬性。

📌 四、Spacer 自動靠右機制

在頂層 <ul> 中放置一個 .tadnav-spacer, TadNav 初始化時會自動掃描並將其後所有 <li> 標記 is-right, 子選單自動靠右展開。完全不需手寫任何 style 屬性。

運作原理

<!-- spacer 之前:靠左展開(預設)-->
<li role="none">...</li>
<li role="none">...</li>

<!-- ★ Spacer -->
<li class="tadnav-spacer" role="none" aria-hidden="true"></li>

<!-- spacer 之後:JS 自動加上 is-right,子選單靠右展開 -->
<li role="none">...</li>   <!-- → <li class="is-right"> -->

巢狀子選單方向

  • 靠左項目的巢狀子選單:向右展開(left: 100%)
  • 靠右項目(is-right)的巢狀子選單:向左展開(right: 100%),避免超出視窗
動態更新:若動態新增或移除選單項目後,呼叫 nav.refresh() 即可重新掃描並更新 is-right 標記。

⚙️ 五、完整 API 參數

var nav = new TadNav('#my-menu', {

  // ── 展開觸發 ──────────────────────────────
  trigger:             'hover',   // 'hover'(預設)| 'click'
  hoverClose:          true,      // hover 模式:滑走是否收合(預設 true)
  hoverDelay:          200,       // 滑入後延遲展開 ms
  hideDelay:           300,       // 滑出後延遲收合 ms(hoverClose:true 時有效)

  // ── 響應式 ────────────────────────────────
  breakpoint:          768,       // 切換漢堡選單的視窗寬度斷點 px

  // ── 行為 ──────────────────────────────────
  collisionDetection:  true,      // 子選單超出視窗時自動翻轉
  closeOnOutsideClick: true,      // 點擊外部關閉
  closeOnEsc:          true,      // Esc 鍵關閉

  // ── 主題色彩(見第六節)──────────────────
  theme: { ... },

  // ── 事件回呼 ──────────────────────────────
  onInit:             null,       // (instance) => {}
  onOpen:             null,       // (submenu, triggerEl) => {}
  onClose:            null,       // (submenu, triggerEl) => {}
  onBreakpointChange: null,       // (isMobile) => {}
  onDestroy:          null,       // () => {}

});
參數類型預設值說明
triggerstring'hover'展開觸發方式:'hover' 或 'click'
hoverClosebooleantruehover 模式下,滑鼠移出是否自動收合
hoverDelaynumber200滑鼠移入後延遲展開毫秒數
hideDelaynumber300滑鼠移出後延遲收合毫秒數
breakpointnumber768視窗寬度 ≤ 此值時切換為漢堡模式
collisionDetectionbooleantrue子選單超出視窗邊界時自動翻轉方向
closeOnOutsideClickbooleantrue點擊選單外部時關閉所有子選單
closeOnEscbooleantrue按 Esc 鍵時關閉所有子選單
themeObject{}主題色彩物件,見第六節
onInitFunctionnull初始化完成後觸發,參數:(instance)
onOpenFunctionnull子選單展開時觸發,參數:(submenu, triggerEl)
onCloseFunctionnull子選單收合時觸發,參數:(submenu, triggerEl)
onBreakpointChangeFunctionnull桌機 ↔ 手機切換時觸發,參數:(isMobile)
onDestroyFunctionnulldestroy() 完成後觸發

🎨 六、主題色彩系統

TadNav 使用 CSS 自訂屬性(Custom Properties)管理所有顏色與尺寸。 tadnav.css 的 :root 定義預設值; JS 初始化時若傳入 theme 物件,會將對應值寫入 .tadnav-wrapper 的 inline style, 覆寫預設值,支援同頁多個導覽列各自獨立主題。

theme 參數完整列表

📐 版面

theme 屬性CSS 變數預設值說明
innerMaxWidth v1.5--tadnav-inner-max-width100%導覽列內容最大寬度,設 '1200px' 可置中限寬

🟦 導覽列

theme 屬性CSS 變數預設值說明
navBg--tadnav-nav-bg藍色漸層導覽列背景,支援純色、漸層、圖片
navShadow--tadnav-nav-shadow淡陰影導覽列底部陰影
brandColor--tadnav-brand-color#ffffff品牌文字顏色

🔤 頂層項目

theme 屬性CSS 變數預設值說明
itemColor--tadnav-item-color#ffffff頂層項目文字顏色
itemBg--tadnav-item-bgtransparent頂層項目背景
itemFontSize v1.5--tadnav-item-font-size0.9rem頂層項目文字大小
itemHoverBg--tadnav-item-hover-bg白色半透明頂層項目 Hover / Active 背景
itemHoverColor--tadnav-item-hover-color#ffffff頂層項目 Hover / Active 文字顏色
itemAccent--tadnav-item-accent白色半透明頂層項目 Hover 底線強調色

📋 子選單面板

theme 屬性CSS 變數預設值說明
subBg--tadnav-sub-bg#ffffff子選單面板背景
subShadow v1.5--tadnav-sub-shadow淡陰影子選單陰影,傳入 'none' 可完全關閉
subBorder--tadnav-sub-border#2e86c1子選單頂部 / 側邊強調線顏色
subDivider--tadnav-sub-divider#f0f4f8子選單項目間分隔線顏色

🔤 子選單項目

theme 屬性CSS 變數預設值說明
subItemColor--tadnav-sub-item-color#1a3a5c子選單項目文字顏色
subItemBg--tadnav-sub-item-bgtransparent子選單項目背景
subItemFontSize v1.5--tadnav-sub-item-font-size0.88rem子選單項目文字大小
subItemHoverBg--tadnav-sub-item-hover-bg#eaf4fd子選單項目 Hover 背景
subItemHoverColor--tadnav-sub-item-hover-color#1a5276子選單項目 Hover 文字顏色

📱 漢堡按鈕 & 手機版

theme 屬性CSS 變數預設值說明
toggleColor--tadnav-toggle-color#ffffff漢堡按鈕線條顏色
toggleHoverBg--tadnav-toggle-hover-bg白色半透明漢堡按鈕 Hover 背景
mobileSubBg--tadnav-mobile-sub-bg黑色半透明手機版子選單背景
mobileSubBorder--tadnav-mobile-sub-border白色半透明手機版子選單左側邊框
mobileSubColor--tadnav-mobile-sub-color白色半透明手機版子選單文字顏色
mobileItemBorder--tadnav-mobile-item-border白色半透明手機版項目分隔線顏色

動態更換主題

// 部分更新(合併)
nav.setTheme({
  navBg:      '#2c3e50',
  itemColor:  '#ecf0f1',
});

// 完全取代(先清除所有舊設定)
nav.setTheme({
  navBg:           '#ffffff',
  itemColor:       '#333333',
  itemHoverBg:     '#f0f0f0',
  itemHoverColor:  '#000000',
}, false);

// 重設回 CSS 預設值
nav.resetTheme();

// 取得目前主題
var current = nav.getTheme();
console.log(current);

🖌️ 七、主題互動展示

以下控制項可即時調整上方導覽列的外觀,所有變更都透過 nav.setTheme() 套用。

預設主題

導覽列背景與文字

頂層項目

子選單面板

子選單項目

版面寬度

🖱️ 八、trigger 模式

控制子選單的展開觸發方式,可在初始化時設定,也可執行期間動態切換。

模式展開方式適用情境
'hover'(預設)滑鼠移入後延遲展開一般網站導覽、桌機為主
'click'點擊 toggle 按鈕展開應用程式介面、觸控裝置、無障礙優先
// 初始化時設定
var nav = new TadNav('#my-menu', { trigger: 'click' });

// 執行期間動態切換
nav.setTrigger('click');
nav.setTrigger('hover');
目前:hover

🔒 九、hoverClose 控制

hoverClose 控制 hover 模式下,滑鼠離開後是否自動收合子選單。 在 trigger: 'click' 模式下此參數無作用。

值行為適用情境
true(預設)滑走後自動收合一般網站導覽
false滑走不收合,需點擊外部或按 Esc 關閉複雜多層選單、需仔細閱讀選項時
// 滑入展開,滑走不收合
var nav = new TadNav('#my-menu', {
  trigger:    'hover',
  hoverClose: false
});

// 執行期間動態切換
nav.setHoverClose(false);  // 關閉自動收合
nav.setHoverClose(true);   // 恢復自動收合
注意:使用 hoverClose: false 時,請確保 closeOnOutsideClick: true(預設已開啟), 否則使用者將難以關閉展開的子選單。
目前:true

🔧 十、公開方法

方法參數說明
open(submenu)HTMLElement手動展開指定子選單
close(submenu)HTMLElement手動收合指