對話容器 (Chat Container)

  • 新提案
  • 封閉測試
  • 公開測試
  • 已穩定
成熟度說明
  • 新提案:未完成開發、請勿使用。
  • 封閉測試:開發暫時性完成,可使用。可能仍有親和力或其他使用上問題待透過實測發現。
  • 公開測試:開發暫時性完成,歡迎使用。具有完整親和力報告。
  • 已穩定:開發完成、歡迎使用。應無任何親和力或使用上問題。

靜態對話

與客服助理的對話

你好,我想申請戶籍謄本,需要準備哪些文件? 您好!臨櫃申請戶籍謄本需攜帶國民身分證正本;若委託他人代辦,另需委託書與受託人身分證件。 可以線上申請嗎? 可以,您可使用自然人憑證至內政部戶政司全球資訊網線上申辦電子戶籍謄本。 規費怎麼計算? 臨櫃申請每份新臺幣 15 元;線上申辦電子戶籍謄本免費。 好的,謝謝說明。 不客氣,若還有其他問題歡迎隨時詢問。
HTML
<!-- 即時宣告元件:全站僅需一個,供訊息氣泡的複製等操作播報使用 -->
<live-announcer></live-announcer>

<h2 id="chat-log-heading">與客服助理的對話</h2>
<!-- 外層需建立定位環境(如 position: relative),供下方「捲到最新訊息」按鈕絕對定位 -->
<div style="position: relative;">
  <div
    class="chat-container"
    role="log"
    aria-labelledby="chat-log-heading"
    tabindex="0"
    data-chat-container
  >
    <message-bubble variant="user">你好,我想申請戶籍謄本,需要準備哪些文件?</message-bubble>
    <message-bubble variant="ai">您好!臨櫃申請戶籍謄本需攜帶國民身分證正本;若委託他人代辦,另需委託書與受託人身分證件。</message-bubble>
  </div>
  <button type="button" class="chat-container__jump-latest" hidden data-jump-latest>
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="18"
      height="18"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      aria-hidden="true"
      focusable="false"
    >
      <line x1="12" y1="5" x2="12" y2="19"/>
      <polyline points="19 12 12 19 5 12"/>
    </svg>
    <span>捲到最新訊息</span>
  </button>
</div>
  • 容器使用 role="log",新加入的訊息由螢幕閱讀器自動朗讀(polite),無需設定 aria-live
  • 未使用螢幕閱讀器時,Tab 聚焦容器後可用方向鍵、PageUp/PageDown、Home/End 捲動;螢幕閱讀器使用者請以閱讀游標瀏覽訊息。
  • 本頁 demo 使用簡潔形式 <message-bubble variant="…">文字</message-bubble>(由 JS 建構完整結構);正式使用建議伺服器渲染完整結構,以保留無 JS 降級與可見角色標題,寫法參照訊息氣泡說明頁。

動態訊息與捲動策略

與客服助理的對話

你好,想詢問地價稅的繳納期限。 您好!地價稅開徵期間為每年 11 月 1 日至 11 月 30 日。
HTML
<h2 id="chat-log-heading-dynamic">與客服助理的對話</h2>
<!-- 外層需建立定位環境(如 position: relative),供下方「捲到最新訊息」按鈕絕對定位 -->
<div style="position: relative;">
  <div
    class="chat-container"
    role="log"
    aria-labelledby="chat-log-heading-dynamic"
    tabindex="0"
    data-chat-container
  >
    <message-bubble variant="user">你好,想詢問地價稅的繳納期限。</message-bubble>
    <message-bubble variant="ai">您好!地價稅開徵期間為每年 11 月 1 日至 11 月 30 日。</message-bubble>
  </div>
  <button type="button" class="chat-container__jump-latest" hidden data-jump-latest>
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="18"
      height="18"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      aria-hidden="true"
      focusable="false"
    >
      <line x1="12" y1="5" x2="12" y2="19"/>
      <polyline points="19 12 12 19 5 12"/>
    </svg>
    <span>捲到最新訊息</span>
  </button>
</div>
  • 捲動位置在底部時,新訊息自動捲到底;上捲閱讀歷史時不打斷,改顯示「捲到最新訊息」按鈕。
  • 「模擬新訊息」按鈕僅供文件示範。

使用方式

const container = document.querySelector('[data-chat-container]');
container.chatContainer.appendMessage(node); // 將訊息節點加入末端並依捲動策略處理

CSS

  • .chat-container:對話容器本體;訊息子節點可為任意元素,示範使用訊息氣泡
  • .chat-container__jump-latest:「捲到最新訊息」按鈕,需放在 log 元素外。

親和力

  • log 需有可及名稱:aria-labelledby 指向可見標題。
  • 新訊息永不搶焦點;視覺捲動與鍵盤焦點分離。
  • 容器 tabindex="0" 讓鍵盤使用者可聚焦捲動,聚焦時有可見 focus ring。
  • 訊息的角色標示(「你」「客服助理」)由訊息氣泡元件以可見文字提供,角色區分不僅依賴視覺。

JavaScript

元件以 ES module 撰寫,載入必須加 type="module"。(若因架構需要跨網域載入,伺服器須提供 CORS 標頭,否則會靜默失敗。)路徑請依實際部署位置調整。

<script type="module" src="js/components/chat-container.js"></script>
  • 使用 chat-container.js,自動初始化所有 [data-chat-container]
  • 自動初始化僅涵蓋腳本載入當時已存在的 [data-*] 節點;動態插入的情境請先於 DOM 備妥節點再載入腳本。
  • 無 JS 時:靜態訊息仍可讀、容器聚焦後仍可鍵盤捲動;「捲到最新訊息」按鈕不會出現。

參考