# HTML 語言簡介
## 1.概述
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 語言。
下面就是一個簡單網頁的 HTML 源碼。
~~~html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>網頁標題</title>
</head>
<body>
<p>Hello World</p>
</body>
</html>
~~~
上面這段代碼,可以保存成文件`hello.html`。瀏覽器打開這個本地文件,就能看到文字“Hello World”。
## 2.網頁的概念
### 2.1 標簽
HTML 代碼由許許多多不同的標簽(tag)構成。
~~~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>
~~~
上面代碼就是錯誤的嵌套,閉合順序不正確。
標簽名是大小寫不敏感,比如`<title>`和`<TITLE>`是同一個標簽。不過,一般習慣都是使用小寫。
另外,HTML 語言忽略縮進和換行。也就是說,下面的寫法與一行的寫法效果是一樣的。
~~~html
<title>
網頁標題
</title>
~~~
進一步說,整個網頁的 HTML 代碼完全可以寫成一行,瀏覽器照樣解析,結果完全一樣。有時,正式發布網頁之前,開發者會把源碼壓縮成一行,以減少傳輸的字節數。網頁內容的縮進和換行,主要靠 CSS 樣式來實現。
### 2.2 元素
瀏覽器渲染網頁的時候,會把 HTML 源碼解析成一個標簽樹,每個標簽都是一個節點(node),稱為網頁元素(element)。所以,“標簽”和“元素”基本上是同義詞,只是使用的場合不一樣:標簽是源碼角度來看,元素是從編程角度來看,比如`<p>`標簽對應網頁的`p`元素。
嵌套的標簽就構成了網頁元素的層級關系。
~~~html
<div><p>hello world</p></div>
~~~
上面代碼中,`div`元素內部包含了一個`p`元素。上層元素又稱為“父元素”,下層元素又稱為“子元素”,即`div`是`p`的父元素,`p`是`div`的子元素。
所有元素可以分成兩大類:塊級元素(block)和行內元素(inline)。塊級元素默認占據一個獨立的區域,在網頁上會自動另起一行,占據 100% 的寬度。
~~~
<p>hello</p>
<p>world</p>
~~~
上面代碼中,`p`元素是塊級元素,因此瀏覽器會將內容分成兩行顯示。
行內元素默認與其他元素在同一行,不產生換行。比如,`span`就是行內元素,通常用來為某些文字指定特別的樣式。
~~~
<span>hello</span>
<span>world</span>
~~~
上面代碼中,`span`元素是行內元素,因此瀏覽器會將兩行內容放在一行顯示。
### 2.3 屬性
屬性(attribute)是標簽的額外信息,使用空格與標簽名和其他屬性分隔。
~~~html
<img src="demo.jpg" width="500">
~~~
上面代碼中,`<img>`標簽有兩個屬性:`src`和`width`。
屬性可以用等號指定屬性值,比如上例的`demo.jpg`就是`src`的屬性值。屬性值一般放在雙引號里面,這不是必需的,但推薦總是使用雙引號。
注意,屬性名是大小寫不敏感的,`onclick`和`onClick`是同一個屬性。
## 3.網頁的基本標簽
符合語法標準的網頁,應該滿足下面的基本結構。
~~~html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>文檔標題</title>
</head>
<body>
</body>
</html>
~~~
不管多么復雜的網頁,都是從上面這個基本結構衍生出來的。
注意,HTML 代碼的縮進和換行,對于瀏覽器不產生作用。所以,上面的代碼完全可以寫成一行,渲染結果不變。上面這樣分行寫,只是為了提高可讀性。
下面介紹,這個基本結構的主要標簽,它們構成網頁的骨架。
### 3.1 `<!DOCTYPE>`
網頁的第一個標簽通常是`<!doctype>`,表示文檔類型,告訴瀏覽器如何解析網頁。
一般來說,只要像下面這樣,簡單聲明`doctype`為`html`即可。瀏覽器就會按照 HTML5 的規則處理網頁。
~~~html
<!doctype html>
~~~
有時,該標簽采用完全大寫的形式,以便區別于正常的 HTML 標簽。因為`<!doctype>`本質上不是標簽,更像一個處理指令。
~~~html
<!DOCTYPE html>
~~~
### 3.2 `<html>`
`<html>`標簽是網頁的頂層容器,也稱為根元素(root element),其他元素都是它的子元素。一個網頁只能有一個`<html>`標簽。
該標簽的`lang`屬性,表示網頁內容默認的語言。
~~~html
<html lang="en">
~~~
上面代碼表示,網頁的語言是英語。
### 3.3 `<head>`
`<head>`標簽是一個容器標簽,用于放置網頁的元信息。它的內容不會出現在網頁上,而是為網頁渲染做準備。
~~~html
<!doctype html>
<html>
<head>
<title>網頁標題</title>
</head>
</html>
~~~
`<head>`是`<html>`的第一個子元素。如果網頁不包含`<head>`,瀏覽器會自動創建一個。
`<head>`的子元素一般有下面七個,后文會一一介紹。
* `<meta>`:設置網頁的元數據。
* `<link>`:連接外部樣式表。
* `<title>`:設置網頁標題。
* `<style>`:放置內嵌的樣式表。
* `<script>`:引入腳本。
* `<noscript>`:瀏覽器不支持腳本時,所要顯示的內容。
* `<base>`:設置網頁內部相對 URL 的計算基準。
### 3.4 `<meta>`
`<meta>`標簽用于設置或說明網頁的元數據,必須放在`<head>`里面。一個`<meta>`標簽就是一項元數據,網頁可以有多個`<meta>`。
一般來說,網頁至少應該具有以下兩個`<meta>`標簽,而且必須在`<head>`的最前面。
~~~
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>網頁標題</title>
</head>
~~~
- **charset 屬性**
`<meta>`有一個`charset`屬性,指定網頁的編碼方式,該屬性非常重要。如果設置得不正確,瀏覽器可能無法正確解碼,就會出現亂碼。
~~~html
<meta charset="utf-8">
~~~
上面代碼聲明,網頁為`utf-8`編碼。雖然可以使用其他的編碼方式,但幾乎總是應該采用 UTF-8。注意,聲明的編碼方式,應該與網頁實際的編碼方式一致,即聲明了`utf-8`,網頁就應該使用 UTF-8 編碼保存。
- **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">
~~~
- **http-equiv 屬性,content 屬性**
`http-equiv`屬性用來覆蓋 HTTP 回應的頭信息字段,`content`屬性是該字段的內容。
~~~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'">
~~~
### 3.5 `<title>`
`<title>`標簽用于指定網頁的標題,會顯示在瀏覽器窗口的標題欄。
~~~html
<head>
<title>網頁標題</title>
</head>
~~~
搜索引擎根據這個標簽,顯示每個網頁的標題。它對于網頁在搜索引擎的排序,有很大的影響,應該精心安排,反映網頁的主題。
`<title>`標簽的內部,不能再放置其他標簽,只能放置無格式的純文本。
### 3.6 `<body>`
`<body>`標簽是一個容器標簽,用于放置網頁的主體內容。瀏覽器顯示的頁面內容,都是放置在它的內部。它是`<html>`的第二個子元素,緊跟在`<head>`后面。
~~~html
<html>
<head>
<title>網頁標題</title>
</head>
<body>
<p>hello world</p>
</body>
</html>
~~~
## 4.空格和換行
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 源碼里面的換行,不會產生換行效果。
## 5.注釋
HTML 代碼可以包含注釋,瀏覽器會自動忽略注釋。注釋以`<!--`開頭,以`-->`結尾,下面就是一個注釋的例子。
~~~html
<!-- 這是一個注釋 -->
~~~
注釋可以是多行的,并且內部的 HTML 都不再生效了。
~~~html
<!--
<p>hello world</p>
-->
~~~
上面代碼是一個注釋的區塊,內部的代碼都是無效的,瀏覽器不會解析,更不會渲染它們。
注釋有助于理解代碼的含義,復雜的代碼塊前面最好加上注釋。