# HTML 語言簡介
## 概述
HTML 是網頁使用的語言,定義了網頁的結構和內容。瀏覽器訪問網站,其實就是從服務器下載 HTML 代碼,然后渲染出網頁。
HTML 的全名是“超文本標記語言”(HyperText Markup Language),上個世紀90年代由歐洲核子研究中心的物理學家蒂姆·伯納斯-李(Tim Berners-Lee)發明。它的最大特點就是支持超鏈接,點擊鏈接就可以跳轉到其他網頁,從而構成了整個互聯網。
1999年,HTML 4.01 版發布,成為廣泛接受的 HTML 標準。2014年,HTML 5 發布,這是目前正在使用的版本。
瀏覽器的網頁開發,涉及三種技術:HTML、CSS 和 JavaScript。HTML 語言定義網頁的結構和內容,CSS 樣式表定義網頁的樣式,JavaScript 語言定義網頁與用戶的互動行為。HTML 語言是網頁開發的基礎,CSS 和 JavaScript 都是基于 HTML 才能生效,即使沒有這兩者,HTML 本身也能使用,可以完成基本的內容展示。本教程只介紹 HTML 語言。
下面就是一個簡單網頁的 HTML 源碼。
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>網頁標題</title>
</head>
<body>
<p>Hello World</p>
</body>
</html>
```
上面這段代碼,可以保存成文件`hello.html`。瀏覽器打開這個本地文件,就能看到文字“Hello World”。
瀏覽器右鍵菜單的“查看源碼”(View page source),可以展示當前網頁的 HTML 源碼。
## 網頁的基本概念
### 標簽
網頁的 HTML 代碼由許許多多不同的標簽(tag)構成。學習 HTML 語言,就是學習各種標簽的用法。
下面就是標簽的一個例子。
```html
<title>網頁標題</title>
```
上面代碼中,`<title>`和`</title>`就是一對標簽。
標簽用來告訴瀏覽器,如何處理這段代碼。標簽的內容就是瀏覽器所要渲染的、展示在網頁上的內容。
標簽放在一對尖括號里面(比如`<title>`),大多數標簽都是成對出現的,分成開始標簽和結束標簽,結束標簽在標簽名之前加斜杠(比如`</title>`)。但是,也有一些標簽不是成對使用,而是只有開始標簽,沒有結束標簽,比如上一節示例的`<meta>`標簽。
```html
<meta charset="utf-8">
```
上面代碼中,`<meta>`標簽就沒有結束標簽`</meta>`。
這種單獨使用的標簽,通常是因為標簽本身就足夠完成功能了,不需要標簽之間的內容。實際應用中,它們主要用來提示瀏覽器,做一些特別處理。
標簽可以嵌套。
```html
<div><p>hello world</p></div>
```
上面代碼中,`<div>`標簽內部包含了一個`<p>`標簽。
嵌套時,必須保證正確的閉合順序,不能跨層嵌套,否則會出現意想不到的渲染結果。
```html
<div><p>hello world</div></p>
```
上面代碼就是錯誤的嵌套,閉合順序不正確。
HTML 標簽名是大小寫不敏感,比如`<title>`和`<TITLE>`是同一個標簽。不過,一般習慣都是使用小寫。
另外,HTML 語言忽略縮進和換行。下面幾種寫法的渲染結果是一樣的。
```html
<title>網頁標題</title>
<title>
網頁標題
</title>
<title>網頁
標題</title>
```
進一步說,整個網頁的 HTML 代碼完全可以寫成一行,瀏覽器照樣解析,結果完全一樣。所以,正式發布網頁之前,開發者有時會把源碼壓縮成一行,以減少傳輸的字節數。
各種網頁的樣式效果,比如內容的縮進和換行,主要靠 CSS 來實現。
### 元素
瀏覽器渲染網頁時,會把 HTML 源碼解析成一個標簽樹,每個標簽都是樹的一個節點(node)。這種節點就稱為網頁元素(element)。所以,“標簽”和“元素”基本上是同義詞,只是使用的場合不一樣:標簽是從源碼角度來看,元素是從編程角度來看,比如`<p>`標簽對應網頁的`p`元素。
嵌套的標簽就構成了網頁元素的層級關系。
```html
<div><p>hello world</p></div>
```
上面代碼中,`div`元素內部包含了一個`p`元素。上層元素又稱為“父元素”,下層元素又稱為“子元素”,即`div`是`p`的父元素,`p`是`div`的子元素。
### 塊級元素,行內元素
所有元素可以分成兩大類:塊級元素(block)和行內元素(inline)。
塊級元素默認占據一個獨立的區域,在網頁上會自動另起一行,占據 100% 的寬度。
```html
<p>hello</p>
<p>world</p>
```
上面代碼中,`p`元素是塊級元素,因此瀏覽器會將內容分成兩行顯示。
行內元素默認與其他元素在同一行,不產生換行。比如,`span`就是行內元素,通常用來為某些文字指定特別的樣式。
```html
<span>hello</span>
<span>world</span>
```
上面代碼中,`span`元素是行內元素,因此瀏覽器會將兩行內容放在一行顯示。
### 屬性
屬性(attribute)是標簽的額外信息,使用空格與標簽名和其他屬性分隔。
```html
<img src="demo.jpg" width="500">
```
上面代碼中,`<img>`標簽有兩個屬性:`src`和`width`。
屬性可以用等號指定屬性值,比如上例的`demo.jpg`就是`src`的屬性值。屬性值一般放在雙引號里面,這不是必需的,但推薦總是使用雙引號。
注意,屬性名是大小寫不敏感的,`onclick`和`onClick`是同一個屬性。
HTML 提供大量屬性,用來定制標簽的行為,詳細介紹請看《元素的屬性》一章。
## 網頁的基本標簽
符合 HTML 語法標準的網頁,應該滿足下面的基本結構。
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
</body>
</html>
```
不管多么復雜的網頁,都是從上面這個基本結構衍生出來的。
前面說過,HTML 代碼的縮進和換行,對于瀏覽器不產生作用。所以,上面的代碼完全可以寫成一行,渲染結果不變。上面這樣分行寫,只是為了提高可讀性。
下面就依次介紹,這個基本結構的主要標簽。它們構成了網頁的骨架。
### `<!doctype>`
網頁的第一個標簽通常是`<!doctype>`,表示文檔類型,告訴瀏覽器如何解析網頁。
一般來說,只要像下面這樣,簡單聲明`doctype`為`html`即可。瀏覽器就會按照 HTML 5 的規則處理網頁。
```html
<!doctype html>
```
有時,該標簽采用完全大寫的形式,以便區別于正常的 HTML 標簽。因為`<!doctype>`本質上不是標簽,更像一個處理指令。
```html
<!DOCTYPE html>
```
### `<html>`
`<html>`標簽是網頁的頂層容器,即標簽樹結構的頂層節點,也稱為根元素(root element),其他元素都是它的子元素。一個網頁只能有一個`<html>`標簽。
該標簽的`lang`屬性,表示網頁內容默認的語言。
```html
<html lang="zh-CN">
```
上面代碼表示,網頁是中文內容。如果是英文內容,`zh-CN`要改成`en`。更詳細的介紹,參見《元素的屬性》一章。
### `<head>`
`<head>`標簽是一個容器標簽,用于放置網頁的元信息。它的內容不會出現在網頁上,而是為網頁渲染提供額外信息。
```html
<!doctype html>
<html>
<head>
<title>網頁標題</title>
</head>
</html>
```
`<head>`是`<html>`的第一個子元素。如果網頁不包含`<head>`,瀏覽器會自動創建一個。
`<head>`的子元素一般有下面七個,后文會一一介紹。
- `<meta>`:設置網頁的元數據。
- `<link>`:連接外部樣式表。
- `<title>`:設置網頁標題。
- `<style>`:放置內嵌的樣式表。
- `<script>`:引入腳本。
- `<noscript>`:瀏覽器不支持腳本時,所要顯示的內容。
- `<base>`:設置網頁內部相對 URL 的計算基準。
### `<meta>`
`<meta>`標簽用于設置或說明網頁的元數據,必須放在`<head>`里面。一個`<meta>`標簽就是一項元數據,網頁可以有多個`<meta>`。`<meta>`標簽約定放在`<head>`內容的最前面。
不管什么樣的網頁,一般都可以放置以下兩個`<meta>`標簽。
```html
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Title</title>
</head>
```
上面例子中,第一個`<meta>`標簽表示網頁采用 UTF-8 格式編碼,第二個`<meta>`標簽表示網頁在手機端可以自動縮放。
`<meta>`標簽有五個屬性,下面依次介紹。
**(1)charset 屬性**
`<meta>`標簽的`charset`屬性,用來指定網頁的編碼方式。該屬性非常重要,如果設置得不正確,瀏覽器可能無法正確解碼,就會顯示亂碼。
```html
<meta charset="utf-8">
```
上面代碼聲明,網頁為 UTF-8 編碼。雖然開發者可以使用其他的編碼方式,但正確的做法幾乎總是應該采用 UTF-8。
注意,這里聲明的編碼方式,應該與網頁實際的編碼方式一致,即聲明了`utf-8`,網頁就應該使用 UTF-8 編碼保存。如果這里聲明了`utf-8`,實際卻是使用另一種編碼(比如 GB2312),并不會導致瀏覽器的自動轉碼,網頁可能會顯示為亂碼。
**(2)name 屬性,content 屬性**
`<meta>`標簽的`name`屬性表示元數據的名字,`content`屬性表示元數據的值。它們合在一起使用,就可以為網頁指定一項元數據。
```html
<head>
<meta name="description" content="HTML 語言入門">
<meta name="keywords" content="HTML,教程">
<meta name="author" content="張三">
</head>
```
上面代碼包含了三個元數據:`description`是網頁內容的描述,`keywords`是網頁內容的關鍵字,`author`是網頁作者。
元數據有很多種,大部分涉及瀏覽器內部工作機制,或者特定的使用場景,這里就不一一介紹了。下面是一些例子。
```html
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="application-name" content="Application Name">
<meta name="generator" content="program">
<meta name="subject" content="your document's subject">
<meta name="referrer" content="no-referrer">
```
**(3)http-equiv 屬性,content 屬性**
`<meta>`標簽的`http-equiv`屬性用來覆蓋 HTTP 回應的頭信息字段,`content`屬性是對應的字段內容。這兩個屬性與 HTTP 協議相關,屬于高級用法,這里就不詳細介紹了。
```html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
```
上面代碼可以覆蓋 HTTP 回應的`Content-Security-Policy`字段。
下面是另一些例子。
```html
<meta http-equiv="Content-Type" content="Type=text/html; charset=utf-8">
<meta http-equiv="refresh" content="30">
<meta http-equiv="refresh" content="30;URL='http://website.com'">
```
### `<title>`
`<title>`標簽用于指定網頁的標題,會顯示在瀏覽器窗口的標題欄。
```html
<head>
<title>網頁標題</title>
</head>
```
搜索引擎根據這個標簽,顯示每個網頁的標題。它對于網頁在搜索引擎的排序,有很大的影響,應該精心安排,反映網頁的主題。
`<title>`標簽的內部,不能再放置其他標簽,只能放置無格式的純文本。
### `<body>`
`<body>`標簽是一個容器標簽,用于放置網頁的主體內容。瀏覽器顯示的頁面內容,都放置在它的內部。它是`<html>`的第二個子元素,緊跟在`<head>`后面。
```html
<html>
<head>
<title>網頁標題</title>
</head>
<body>
<p>hello world</p>
</body>
</html>
```
## 空格和換行
HTML 語言有自己的空格處理規則。標簽內容的頭部和尾部的空格,一律忽略不計。
```html
<p> hello world </p>
```
上面代碼中,`hello`前面的空格和`world`后面的空格,瀏覽器一律忽略不計。
標簽內容里面的多個連續空格(包含制表符`\t`),會被瀏覽器合并成一個。
```html
<p>hello world</p>
```
上面代碼中,`hello`與`world`之間有多個連續空格,瀏覽器會將它們合并成一個。網頁渲染的結果是,`hello`與`world`之間只有一個空格。
瀏覽器還會將文本里面的換行符(`\n`)和回車符(`\r`),替換成空格。
```html
<p>hello
world
</p>
```
上面代碼中,`hello`與`world`之間有多個換行,瀏覽器會將它們替換成空格,然后再將多個空格合并成一個。網頁渲染的結果是,`hello`與`world`之間有一個空格。
這意味著,HTML 源碼里面的換行,不會產生換行效果。
## 注釋
HTML 代碼可以包含注釋,瀏覽器會自動忽略注釋。注釋以`<!--`開頭,以`-->`結尾,下面就是一個注釋的例子。
```html
<!-- 這是一個注釋 -->
```
注釋可以是多行的,并且內部的 HTML 都不再生效了。
```html
<!--
<p>hello world</p>
-->
```
上面代碼是一個注釋的區塊,內部的代碼都是無效的,瀏覽器不會解析,更不會渲染它們。
注釋有助于理解代碼的含義,復雜的代碼塊前面最好加上注釋。