Cover image for 認識 HTML
Profile picture of Canis

Canis

2024-03-12

約 26 分鐘

認識 HTML

前言

這篇開始,我們要先了解網站開發的一些知識、技術,以及一些術語等。了解這些東西,對我們在開發網站的時候非常有幫助,它可以幫我們理解官方文檔或是其他地方的資源是在說什麼。

引言

一直以來 HTML 的標準都是由 W3C1 制定,直到 2019 年 05 月 28 日,W3C 與 WHATWG2 合作開發 HTML 和 DOM3 的規範(詳見參考資料)。

什麼是 HTML

HTML4 是一種標記語言(Markup Language)。常聽到的 HTML5 是於 2014 年發佈的最新版本的 HTML 技術,它的前身 HTML4 已於 1999 年 12 月進行了最後一次更新,這個版本簡化了許多語法,讓編寫程式變得更加容易且方便。

<!DOCTYPE html>
<html lang="zh-Hant">
    <head>
        <title>範例頁面</title>
    </head>
    <body>
        <h1>範例標題</h1>
        <p>這是一個範例頁面,它有一個<a href="https://iistw.com/">連結</a>的標籤。</p>
        <!-- 這是一個註解 -->
    </body>
</html>

根據上方的 HTML 程式片段可以清晰的了解到 HTML 是由元素和文字組成的樹狀結構,每一個元素都是由開始標記為起始以及結束標記為結束表示。(在某些情況下可略,並由其它標記暗示,詳見參考資料第 3 點)

嵌套關係

元素與元素可以是嵌套關係,但是不能是只重疊一部分的關係,如下面的例子:

<p>這是<em>一個<strong>錯誤</em>的例子</strong></p>
<p>這是<em>一個<strong>正確</strong>的例子</em></p>

元素屬性

元素可以擁有屬性(Attribute),讓元素能夠有不同的工作方式,或者是改變其代表的意義,例如說下面的例子是一個超連結,它擁有一個 href 屬性:

<a href="https://iistw.com/">連結</a>

規則

屬性會在起始的標記內,由名稱、值組成,並以 = 作為分隔。如果屬性值不包含:

  • ASCII 空格(詳見參考資料第 4 點)
  • 雙引號(")
  • 單引號(')
  • 反引號(`)
  • 等於(=)
  • 小於(<)
  • 大於(>)

則屬性值可以不用以引號(單、雙皆可)包起來。如果值是空字串,可以省略值以及 =。下面是一些例子:

<!-- 正確 -->
<button type=button>按鈕</button>
<button type="button">按鈕</button>
<button type='button'>按鈕</button>
<button type=`button`>按鈕</button>
<button type="button" disabled>按鈕</button>
<button type="button" disabled="">按鈕</button>
<!-- 錯誤 -->
<button type="button" class=primary flex>按鈕</button>
<button type="button" title=不可以這樣用<喔>按鈕</button>
<button type="button" title=不可以這樣用>喔>按鈕</button>
<button type='button">按鈕</button>

枚舉屬性

枚舉屬性(Enumeration Attributes)是HTML中一類特殊的屬性,它們的值被限定在一個特定的列表之中。這些屬性值代表了不同的選項或設定,開發者可以從這個列表中選擇一個值來設定元素的某種行為或樣式。其特點是:

  • 限定的值:屬性值被限制在一個明確定義的列表中,不能隨意填寫。
  • 行為明確:每個值都有預定的行為或樣式效果,便於開發者使用。
  • 可讀性高:由於值是預定義的,因此枚舉屬性的使用增加了代碼的可讀性和維護性。

使用枚舉屬性時,選擇不在列表中的值可能導致默認行為或無效果,具體取決於瀏覽器的處理方式。因此,正確理解和使用這些屬性對於開發可靠且功能正確的網頁應用至關重要。

全局屬性

既然都已經提到了屬性的概念,那麼就要提一下全局屬性了。全局屬性是所有 HTML 元素共有的屬性,即使可能對某些元素不起作用。接下來就介紹一下有哪些比較常見的全局屬性(其餘的可以參考一下參考資料第 6 點):

  1. class

    class 的值是一個類名列表,列表裡面的每一項用空格隔開,具體如何使用,在講 CSS 和 JavaScript 時會說到。

    <div class="badge rounded"></div>
  2. id

    這個屬性定義了在整個 HTML 文件裡面唯一的識別碼(就像身份證字號),使用方法在講 CSS 和 JavaScript 時會說到。

    <input type="text" id="username" />
  3. style

    這個是用來定義元素樣式使用的,一般稱為行內樣式(Inline Style)。定義樣式的方法非常多,而 style 優先級是最高的,使用方法在講 CSS 和 JavaScript 時會說到。

    <p style="color: #1f1f1f;">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</p>
  4. title

    這個屬性 MDN 給的解釋是「包含代表與它所屬的元素有關的諮詢訊息的文字」,但是我覺得好像沒有那麼的準確,或是說有點難以理解?它有幾個作用(使用場景):

    1. 如果元素是 iframetitle 屬性可以提供有關嵌入內容的說明,幫助一些輔助技術(如閱讀器)更好地理解內容。

    2. 如果在 table 中使用像是 input 這類元素,將 title 屬性加在 input 上可以提供額外的說明,增加可訪問性。

    3. title 也能為樣式表提供一個識別碼,讓那個樣式表成為一個替代樣式表,這樣說可能有些難懂,先看看下面的例子:

      <link rel="stylesheet" href="default-style.css">
      <link rel="alternate stylesheet" title="Dark Theme" href="dark-theme.css">

      在這個例子裡面,default-style.css 是被自動套用的樣式表(默認樣式表),而 dark-theme.css 帶有 title 屬性且 rel 屬性被加上了 alternate5,使用者就能透過擴充功能或是開發者提供的方法改變套用的 CSS。

    4. 當元素是 abbr6 時,title 扮演了一個非常重要的角色。它可以為其提供一種方式來說明縮寫的完整含義,例如下面的例子。但是儘管這個屬性很方便,但還是建議在首次出現縮寫時,就以純文本形式提供全稱。

      <p>網頁標記語言通常被稱為 <abbr title="Hyper Text Markup Language">HTML</abbr>。</p>
  5. tabindex

    這個屬性用於指定一個元素在鍵盤([[Tab]] 鍵)導航時的順序。它可以加在任何的 HTML 元素,雖然一般用於不自動支持鍵盤聚焦的元素。它會有三種情況:

    說明
    0將元素加入到鍵盤導航的順序中,會按照當前 DOM 的結構來決定順序。
    -1允許元素通過程式(如 JavaScript)設定獲得焦點,但它不會通過鍵盤導航([[Tab]] 鍵)進入焦點順序。
    大於 0表示元素可聚焦,並根據數值的大小來決定聚焦順序。根據我自己的測試,在所有 tabindex 大於 0 的元素被聚焦完後,才會開始其它可聚焦元素的聚焦。而因為它會改變鍵盤導航的自然流程,也會因為很多原因7導致與預期結果不符,建議非必要不要使用,免得和我一樣,光是為了測試效果就一直出現預期之外的結果。
    <p tabindex="0">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</p>
    <p tabindex="-1">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</p>
    <p tabindex="1">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</p>
  6. translate

    他是一個枚舉屬性,只接受以下的值:

    說明
    空或 yes表示網頁在進行翻譯的時候被翻譯。
    no表示網頁在進行翻譯的時候不會被翻譯。
    <p><span translate>Markdown</span> 是一種輕量級標記式語言。</p> <!-- 會被翻譯 -->
    <p><span translate="yes">Markdown</span> 是一種輕量級標記式語言。</p> <!-- 會被翻譯 -->
    <p><span translate="no">Markdown</span> 是一種輕量級標記式語言。</p> <!-- 不會被翻譯 -->

    可能有人會好奇,既然是用 yesno 來作為值,可不可以使用 truefalse?答案是建議不要。因為它的列表只有 yesno,所以一般來說,瀏覽器可能不會如預期般理解和執行。

  7. contenteditable

    也是一個枚舉屬性,表示元素是否可以被使用者編輯,只接受以下的值:

    說明
    空或 true可編輯狀態。
    false不可編輯狀態。
    plaintext-only可編輯,但是富文本格式8會被禁用,具體效果可以複製下方程式碼試試看(建議按 [[F12]] 開啓開發人員工具查看變化)。
    <div contenteditable>Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</div>
    <div contenteditable="true">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</div>
    <div contenteditable="false">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</div>
    <div contenteditable="plaintext-only">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</div>
  8. data-*

    這個屬性非常特別且好用,它會構成一組稱為「自訂 data 屬性」的屬性。它的作用就像是便利貼,能夠對元素貼標籤,讓開發者比較簡單的做一些事情。下面直接舉例:

    <div id="one" data-mode="dark" data-theme-color="blue">
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</p>
    </div>
    <div id="two" data-mode="light" data-theme-color="orange">
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis, odit!</p>
    </div>

    由上面的例子可以發現,我為他貼了一些標籤,而要存取 data 屬性也很容易,我分別以 CSS 和 JavaScript 兩種方式來舉例(之後有遇到再詳細說明):

    [data-mode="dark"] {
        background-color: black; /* 背景顏色為黑色 */
        color: white; /* 文字顏色為白色 */
    }
     
    [data-mode="light"] {
        background-color: white; /* 背景顏色為白色 */
        color: black; /* 文字顏色為白色 */
    }
     
    [data-theme-color="blue"] {
        border: 1px solid blue; /* 邊框寬度為 1px 的藍色實線 */
    }
     
    [data-theme-color="orange"] {
        border: 1px solid orange; /* 邊框寬度為 1px 的橘色實線 */
    }
    // 方式一
    const oneModeWay1 = document.getElementById('one').dataset.mode; // dark
    const oneThemeWay1 = document.getElementById('one').dataset.themeColor; // blue
    const twoModeWay1 = document.getElementById('two').dataset.mode; // light
    const twoThemeWay1 = document.getElementById('two').dataset.themeColor; // orange
     
    console.log('方法一', oneModeWay1, oneThemeWay1, twoModeWay1, twoThemeWay1); // 方法一 dark blue light orange
     
    // 方式二
    const oneModeWay2 = document.getElementById('one').dataset["mode"]; // dark
    const oneThemeWay2 = document.getElementById('one').dataset["themeColor"]; // blue
    const twoModeWay2 = document.getElementById('two').dataset["mode"]; // light
    const twoThemeWay2 = document.getElementById('two').dataset["themeColor"]; // orange
     
    console.log('方法二', oneModeWay2, oneThemeWay2, twoModeWay2, twoThemeWay2); // 方法二 dark blue light orange

    不過它也有一些限制——命名規則

    • 名字絕對不能以 xml 起頭,無論是否用於 xml
    • 名字絕對不能包含分號(U+003A)
    • 名字絕對不能包含大寫 A 到大小 Z 的拉丁字母
  9. autocapitalize

    枚舉屬性,控制使用者在輸入或編輯文字是所輸入的文字是否要自動大寫,以及如何自動大寫,以下是可接受的值:

    說明
    offnone不會自動大寫(默認小寫)。
    onsentence每一句的首字母默認大寫,其餘默認小寫。
    words每個單詞的首字母默認大寫,其餘默認小寫。
    characters所有字母默認大寫。

    雖然是這樣,但是也是有限制的。在實體鍵盤輸入的時候,這個屬性起作用。只有在虛擬鍵盤或語音輸入的時候才會起作用。另外,這個屬性永遠不會在 input 元素帶有 type 屬性,且值為 urlemailpassword 時起作用。

  10. spellcheck

    枚舉屬性,定義是否檢查拼寫錯誤,它具有以下的值:

    說明
    true會檢查元素內的拼寫錯誤。
    false不會檢查元素內的拼寫錯誤。

    如果沒有設定這個屬性,默認會由元素自身類型和瀏覽器設定決定。有關瀏覽器默認的設定和元素依賴,可以查看:spellcheck - HTML(超文本标记语言) | MDN(只有簡中版本有特別列出來)。

  11. inputmode

    枚舉屬性,提供使用者在編輯元素或其內容時可能輸入的類型提示。它可能會是以下值:

    說明
    none將不會有虛擬鍵盤,在網站有提供屬於自己的輸入控件時很有用。
    text(默認)會開啓使用者的標準輸入鍵盤。
    decimal會開啓使用者有數字以及小數分隔符(通常是 [[.]] 或 [[,]])的鍵盤。
    numeric會開啓使用者有數字的鍵盤。
    tel開啓包含數位 0 到 9、星號 (*) 和井號 (#) 的鍵盤。如果需要使用者輸入電話號碼,通常會使用 typetelinput 元素。
    search開啓針對搜索輸入進行了優化的虛擬鍵盤。例如,返回或提交鍵可能被標記為**搜索等。通常會使用 typesearchinput 元素。
    email開啓為輸入電子郵件地址而優化的虛擬鍵盤。通常包括 @ 字元。通常會使用 typeemailinput 元素。
    url開啓為輸入 URL 而優化的鍵盤。例如,特別顯示 / 字元。通常會使用 typeurlinput 元素。
    <fieldset>
        <legend>none</legend>
        <input type="text" inputmode="" id="inputmodeAttr" />
        <label for="inputmodeAttr">(inputmode 版本)</label>
    </fieldset>
    <fieldset>
        <legend>text</legend>
        <input type="text" inputmode="text" id="inputmodeAttrText" />
        <label for="inputmodeAttrText">(inputmode 版本)</label>
    </fieldset>
    <fieldset>
        <legend>decimal</legend>
        <input type="text" inputmode="decimal" id="inputmodeAttrDecimal" />
        <label for="inputmodeAttrDecimal">(inputmode 版本)</label>
    </fieldset>
    <fieldset>
        <legend>numeric</legend>
        <input type="text" inputmode="numeric" id="inputmodeAttrNumeric" />
        <label for="inputmodeAttrNumeric">(inputmode 版本)</label>
    </fieldset>
    <fieldset>
        <legend>tel</legend>
        <input type="text" inputmode="tel" id="inputmodeAttrTel" />
        <label for="inputmodeAttrTel">(inputmode 版本)</label>
        <br />
        <input type="tel" id="notInputmodeAttrTel" />
        <label for="notInputmodeAttrTel">(非 inputmode)</label>
    </fieldset>
    <fieldset>
        <legend>search</legend>
        <input type="text" inputmode="search" id="inputmodeAttrSearch" />
        <label for="inputmodeAttrSearch">(inputmode 版本)</label>
        <br />
        <input type="search" id="notInputmodeAttrSearch" />
        <label for="notInputmodeAttrSearch">(非 inputmode)</label>
    </fieldset>
    <fieldset>
        <legend>email</legend>
        <input type="text" inputmode="email" id="inputmodeAttrEmail" />
        <label for="inputmodeAttrEmail">(inputmode 版本)</label>
        <br />
        <input type="email" id="notInputmodeAttrEmail" />
        <label for="notInputmodeAttrEmail">(非 inputmode)</label>
    </fieldset>
    <fieldset>
        <legend>url</legend>
        <input type="text" inputmode="url" id="inputmodeAttrUrl" />
        <label for="inputmodeAttrUrl">(inputmode 版本)</label>
        <br />
        <input type="url" id="notInputmodeAttrUrl" />
        <label for="notInputmodeAttrUrl">(非 inputmode)</label>
    </fieldset>
  12. autofocus

    是一個布林屬性,表示元素應該在頁面載入時或是所屬的 dialog 元素顯示時被聚焦。在 HTML 檔案或是 dialog 元素中,最多只能有一個元素擁有這個屬性,畢竟超過一個元素有的話,具體是要聚焦哪個?但是如果你真的有多個元素有這個屬性的話,只有第一個元素會起作用。

    <input type="text" autofocus />
  13. lang

    幫助元素定義內容所使用的語言。主要分為兩種情況:

    1. 不可編輯的元素:它告訴瀏覽器和輔助技術這些內容是用哪種語言書寫的。這有助於正確顯示語言特定的字元,並為使用屏幕閱讀器的使用者提供正確的語音合成。
    2. 可編輯的元素:比如在一個表單的輸入欄位中,它指示使用者應當使用什麼語言進行輸入(非強制性的)。這對於實現語言特定的輸入法或校對工具特別有用。

    而寫法分為三種:

    類型說明
    語言子標籤(Language Subtag)必填。定義基本語言的 2 或 3 個字元的代碼,通常以全部小寫形式編寫。
    腳本子標籤(Script Subtag)自選。定義了用於語言的書寫系統,長度始終為 4 個字元,首字母大寫。
    區域子標籤(Region Subtag)自選。定義來自特定位置的基本語言的方言,並且是 ALLCAPS9 中與國家地區代碼匹配 2 個字母,或與非國家地區匹配 3 個數字。

    具體的值在可參考 BCP47 中的 RFC 5646

  14. draggable

    枚舉屬性,用於指定元素是否可以使用瀏覽器原生行為或使用 HTML 的拖放 API 拖動元素(之後講 JavaScript 的時候會講,如果記得的話)。它可以有以下值:

    說明
    true表示元素可以被拖動。
    false表示元素不可以被拖動。

    如果沒有加 draggable 屬性,預設會是 auto,表示使用預設的行為。

  15. popover

    這是一個很新的屬性(我寫這部分的時候是 2023-03-11),是用來指定一個元素為彈出式的元素(Popover Element)。這個元素通過設定 CSS display 屬性為 none 隱藏,打開的話,透過帶有 popovertarget 屬性控制元素(如 button 元素或 typebuttoninput 元素)或 JavaScript 的 HTMLElement.showPopover() API 打開。

    <button popovertarget="popoverTarget">Button 開啓或關閉</button>
    <input type="button" popovertarget="popoverTarget" value="Input 開啓或關閉">
    <button id="openBtn">js 開啓</button>
    <button id="closeBtn">js 關閉</button>
    <div popover id="popoverTarget">Popover 元素</div>
    const openBtn = document.getElementById('openBtn');
    const closeBtn = document.getElementById('closeBtn');
    const popoverTarget = document.getElementById('popoverTarget');
     
    openBtn.addEventListener('click', () => {
      popoverTarget.showPopover();
    });
     
    closeBtn.addEventListener('click', () => {
      popoverTarget.hidePopover();
    });
  16. accesskey

    為元素提供一個快捷鍵,且要是可列印字元。這個屬性有點一言難盡,它可能會因為瀏覽器或鍵盤產生一些問題,所以建議不要使用。

    Windows Linux Mac
    Firefox Alt + Shift + [key] Firefox 57(或更新)Control + Option + [key]Control + Alt + [key]
    Firefox 14(或更新)Control + Alt + [key]
    Firefox 13(或更舊)Control + [key]
    Internet Explorer Alt + [key] N/A
    Google Chrome Alt + [key] Control + Alt + [key]
    Safari Alt + [key] N/A Control + Alt + [key]
    Opera 15+ Alt + [key] Control + Alt + [key]
    Opera 12 Shift + Esc 開啓可訪問的清單,然後按 [key]

    Firefox 可以通過使用者偏好改變修飾鍵。

  17. dir

    枚舉屬性,是用來指定元素中文字的方向。它具有以下值:

    說明
    ltr從左到右,例如中文、英文。
    rtl從右到左,例如阿拉伯語。
    auto使用者代理(User Agent)10做出決定。它使用基本演算法來解析元素內的字元,直到找到具有強方向性的字元,然後將該方向性應用於整個元素。

    如果 CSS 的 directionunicode-bidi 屬性和 dir 屬性同時被設定,CSS 優先程度比較高,因此建議盡可能使用 dir 而不是相關的 CSS 屬性。這樣,即使在不支援 CSS 或停用 CSS 的瀏覽器上,文字也能正確顯示。

結語

終於寫完了,這篇寫了有點久。其實我在開始介紹 HTML 的時候一直在思考那些要先講、那些要晚一點,後來就想說總得先知道 HTML 的屬性吧?於是先後順序就變成這樣了。這篇先簡單的介紹了一下 HTML 是什麼、屬性的規則、類型,下一篇講一下 HTML 的結構與元素。

參考資料

  1. HTML Standard: [https://html.spec.whatwg.org/multipage/
  2. W3C and WHATWG to work together to advance the open Web platform | 2019 | Blog | W3C: https://www.w3.org/blog/2019/w3c-and-whatwg-to-work-together-to-advance-the-open-web-platform/
  3. HTML Standard, Edition for Web Developers: https://html.spec.whatwg.org/dev/syntax.html#syntax-tag-omission
  4. Infra Standard: https://infra.spec.whatwg.org/#ascii-whitespace
  5. 學習 HTML :指南與教學 - 學習該如何開發 Web | MDN:https://developer.mozilla.org/zh-TW/docs/Learn/HTML
  6. Global attributes - HTML: HyperText Markup Language | MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes
  7. HTML Standard - Attributes: https://html.spec.whatwg.org/multipage/indices.html#attributes-3

Footnotes

  1. W3C(World Wide Web Consortium,全球資訊網協會)成立於 1994 年,為半自治非政府組織。

  2. WHATWG(Web Hypertext Application Technology Working Group,網頁超文字應用技術工作小組)成立於 2004 年,是一個以推動網路HTML標準為目的而成立的組織。

  3. DOM(Document Object Model,文件物件模型)是 Web 文件的程式設計介面,它將文件表示為節點和物件,以便程式可以更改文件結構、樣式和內容。

  4. HTML 全稱為 Hyper Text Markup Language,中文為超文本標記語言。

  5. rel 加上 alternate 時,表示這個樣式表是可選的、非自動套用的。當 relalternate 時,title 為必要且不能為空的。

  6. abbr 的全稱是 abbreviation 也就是「縮寫」。

  7. 瀏覽器緩存或腳本影響、CSS、HTML 結構、瀏覽器特定行為、擴充應用程式等都有可能導致與預期結果不符。

  8. 富文本格式(Rich Text Format),通常指的是除了純文字之外,還包含了其他類型的格式設定或特殊元素的文字內容。如粗體、斜體、下劃線、顏色變化、圖片、連結、列表、表格等多種視覺效果和佈局調整,使得文字內容的表達更加多元和豐富。

  9. ALLCAPS 指的是全部大寫字母的拼寫方式。

  10. 使用者代理(User Agent)是一種軟體,通常是網頁瀏覽器,它在使用者與網站之間充當了一個傳遞訊息的角色。

網站開發學習前端入門HTML
Canis

Canis

一個能設計 UI/UX 的前端工程師。平時有想法的時候,會坐到電腦前開始把想法慢慢地實現出來。白話文就是「喜歡沒事找事來折磨自己」。