# 鏈接標簽
鏈接(hyperlink)是互聯網的核心。它允許用戶在頁面上,從一個網址跳轉到另一個網址,從而把所有資源聯系在一起。
URL 是鏈接指向的地址。鏈接不僅可以指向另一個網頁,也可以指向文本、圖像、文件等資源。可以這樣說,所有互聯網上的資源,都可以通過鏈接訪問。
## `<a>`
鏈接通過`<a>`標簽表示,用戶點擊后,瀏覽器會跳轉到指定的網址。下面就是一個典型的鏈接。
```html
<a href="https://wikipedia.org/">維基百科</a>
```
上面代碼就定義了一個超級鏈接。瀏覽器顯示“維基百科”,文字下面默認會有下劃線,表示這是一個鏈接。用戶點擊后,瀏覽器跳轉到`href`屬性指定的網址。
`<a>`標簽內部不僅可以放置文字,也可以放置其他元素,比如段落、圖像、多媒體等等。
```html
<a href="https://www.example.com/">
<img src="https://www.example.com/foo.jpg">
</a>
```
上面代碼中,`<a>`標簽內部就是一個圖像。用戶點擊圖像,就會跳轉到指定網址。
`<a>`標簽有如下屬性。
**(1)href**
`href`屬性給出鏈接指向的網址。它的值應該是一個 URL 或者錨點。
上文已經給出了完整 URL 的例子,下面是錨點的例子。
```html
<a href="#demo">示例</a>
```
上面代碼中,`href`屬性的值是`#`加上錨點名稱。點擊后,瀏覽器會自動滾動,停在當前頁面里面`demo`錨點所在的位置。
**(2)hreflang**
`hreflang`屬性給出鏈接指向的網址所使用的語言,純粹是提示性的,沒有實際功能。
```html
<a
href="https://www.example.com"
hreflang="en"
>示例網址</a>
```
上面代碼表明,`href`屬性指向的網址的語言是英語。
該屬性的值跟通用屬性`lang`一樣,語言代碼可以參考《屬性》一章的`lang`屬性的介紹。
**(3)title**
`title`屬性給出鏈接的說明信息。鼠標懸停在鏈接上方時,瀏覽器會將這個屬性的值,以提示塊的形式顯示出來。
```html
<a
href="https://www.example.com/"
title="hello"
>示例</a>。
```
上面代碼中,用戶鼠標停留在鏈接上面,會出現文字提示`hello`。
**(4)target**
`target`屬性指定如何展示打開的鏈接。它可以是在指定的窗口打開,也可以在`<iframe>`里面打開。
```html
<p><a href="http://foo.com" target="test">foo</a></p>
<p><a href="http://bar.com" target="test">bar</a></p>
```
上面代碼中,兩個鏈接都在名叫`test`的窗口打開。首先點擊鏈接`foo`,瀏覽器發現沒有叫做`test`的窗口,就新建一個窗口,起名為`test`,在該窗口打開`foo.com`。然后,用戶又點擊鏈接`bar`,由于已經存在`test`窗口,瀏覽器就在該窗口打開`bar.com`,取代里面已經打開的`foo.com`。
`target`屬性的值也可以是以下四個關鍵字之一。
- `_self`:當前窗口打開,這是默認值。
- `_blank`:新窗口打開。
- `_parent`:上層窗口打開,這通常用于從父窗口打開的子窗口,或者`<iframe>`里面的鏈接。如果當前窗口沒有上層窗口,這個值等同于`_self`。
- `_top`:頂層窗口打開。如果當前窗口就是頂層窗口,這個值等同于`_self`。
```html
<a
href="https://www.example.com"
target="_blank"
>示例鏈接</a>
```
上面代碼點擊后,瀏覽器會新建一個窗口,在該窗口打開鏈接,并且新窗口沒有名字。
注意,使用`target`屬性的時候,最好跟`rel="noreferrer"`一起使用,這樣可以避免安全風險。
**(5)rel**
`rel`屬性說明鏈接與當前頁面的關系。
```html
<a href="help.html" rel="help">幫助</a>
```
上面代碼的`rel`屬性,說明鏈接是當前頁面的幫助文檔。
下面是一些常見的`rel`屬性的值。
- `alternate`:當前文檔的另一種形式,比如翻譯。
- `author`:作者鏈接。
- `bookmark`:用作書簽的永久地址。
- `external`:當前文檔的外部參考文檔。
- `help`:幫助鏈接。
- `license`:許可證鏈接。
- `next`:系列文檔的下一篇。
- `nofollow`:告訴搜索引擎忽略該鏈接,主要用于用戶提交的內容,防止有人企圖通過添加鏈接,提高該鏈接的搜索排名。
- `noreferrer`:告訴瀏覽器打開鏈接時,不要將當前網址作為 HTTP 頭信息的`Referer`字段發送出去,這樣可以隱藏點擊的來源。
- `noopener`:告訴瀏覽器打開鏈接時,不讓鏈接窗口通過 JavaScript 的`window.opener`屬性引用原始窗口,這樣就提高了安全性。
- `prev`:系列文檔的上一篇。
- `search`:文檔的搜索鏈接。
- `tag`:文檔的標簽鏈接。
**(6)referrerpolicy**
`referrerpolicy`屬性用于精確設定點擊鏈接時,瀏覽器發送 HTTP 頭信息的`Referer`字段的行為。
該屬性可以取下面八個值:`no-referrer`、`no-referrer-when-downgrade`、`origin`、`origin-when-cross-origin`、`unsafe-url`、`same-origin`、`strict-origin`、`strict-origin-when-cross-origin`。
其中,`no-referrer`表示不發送`Referer`字段,`same-origin`表示同源時才發送`Referer`字段,`origin`表示只發送源信息(協議+域名+端口)。其他幾項的解釋,請查閱 HTTP 文檔。
**(7)ping**
`ping`屬性指定一個網址,用戶點擊的時候,會向該網址發出一個 POST 請求,通常用于跟蹤用戶的行為。
**(8)type**
`type`屬性給出鏈接 URL 的 MIME 類型,比如到底是網頁,還是圖像或文件。它也是純粹提示性的屬性,沒有實際功能。
```html
<a
href="smile.jpg"
type="image/jpeg"
>示例圖片</a>
```
上面代碼中,`type`屬性提示這是一張圖片。
**(9)download**
`download`屬性表明當前鏈接用于下載,而不是跳轉到另一個 URL。
```html
<a href="demo.txt" download>下載</a>
```
上面代碼點擊后,會出現下載對話框。
注意,`download`屬性只在鏈接與網址同源時,才會生效。也就是說,鏈接應該與網址屬于同一個網站。
如果`download`屬性設置了值,那么這個值就是下載的文件名。
```html
<a
href="foo.exe"
download="bar.exe"
>點擊下載</a>
```
上面代碼中,下載文件的原始文件名是`foo.exe`。點擊后,下載對話框提示的文件名是`bar.exe`。
注意,如果鏈接點擊后,服務器的 HTTP 回應的頭信息設置了`Content-Disposition`字段,并且該字段的值與`download`屬性不一致,那么該字段優先,下載時將顯示其設置的文件名。
`download`屬性還有一個用途,就是有些地址不是真實網址,而是數據網址,比如`data:`開頭的網址。這時,`download`屬性可以為虛擬網址指定下載的文件名。
```html
<a href="data:,Hello%2C%20World!">點擊</a>
```
上面鏈接點擊后,會打開一個虛擬網頁,上面顯示`Hello World!`。
```html
<a
href="data:,Hello%2C%20World!"
download="hello.txt"
>點擊</a>
```
上面鏈接點擊后,下載的`hello.txt`文件內容就是“Hello, World!”。
## 郵件鏈接
鏈接也可以指向一個郵件地址,使用`mailto`協議。用戶點擊后,瀏覽器會打開本機默認的郵件程序,讓用戶向指定的地址發送郵件。
```html
<a href="mailto:contact@example.com">聯系我們</a>
```
上面代碼中,鏈接就指向郵件地址。點擊后,瀏覽器會打開一個郵件地址,讓你可以向`contact@example.com`發送郵件。
除了郵箱,郵件協議還允許指定其他幾個郵件要素。
- `subject`:主題
- `cc`:抄送
- `bcc`:密送
- `body`:郵件內容
使用方法是將這些郵件要素,以查詢字符串的方式,附加在郵箱地址后面。
```html
<a
href="mailto:foo@bar.com?cc=test@test.com&subject=The%20subject&body=The%20body"
>發送郵件</a>
```
上面代碼中,郵件鏈接里面不僅包含了郵箱地址,還包含了`cc`、`subject`、`body`等郵件要素。這些要素的值需要經過 URL 轉義,比如空格轉成`%20`。
不指定郵箱也是允許的,就像下面這樣。這時用戶自己在郵件程序里面,填寫想要發送的郵箱,通常用于郵件分享網頁。
```html
<a href="mailto:">告訴朋友</a>
```
## 電話鏈接
如果是手機瀏覽的頁面,還可以使用`tel`協議,創建電話鏈接。用戶點擊該鏈接,會喚起電話,可以進行撥號。
```html
<a href="tel:13312345678">13312345678</a>
```
上面代碼在手機中,點擊鏈接會喚起撥號界面,可以直接撥打指定號碼。
## `<link>`
### 基本用法
`<link>`標簽主要用于將當前網頁與相關的外部資源聯系起來,通常放在`<head>`元素里面。最常見的用途就是加載 CSS 樣式表。
```html
<link rel="stylesheet" type="text/css" href="theme.css">
```
上面代碼為網頁加載樣式表`theme.css`。
除了默認樣式表,網頁還可以加載替代樣式表,即默認不生效、需要用戶手動切換的樣式表。
```html
<link href="default.css" rel="stylesheet" title="Default Style">
<link href="fancy.css" rel="alternate stylesheet" title="Fancy">
<link href="basic.css" rel="alternate stylesheet" title="Basic">
```
上面代碼中,`default.css`是默認樣式表,默認就會生效。`fancy.css`和`basic.css`是替換樣式表(`rel="alternate stylesheet"`),默認不生效。`title`屬性在這里是必需的,用來在瀏覽器菜單里面列出這些樣式表的名字,供用戶選擇,以替代默認樣式表。
`<link>`還可以加載網站的 favicon 圖標文件。
```html
<link rel="icon" href="/favicon.ico" type="image/x-icon">
```
手機訪問時,網站通常需要提供不同分辨率的圖標文件。
```html
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="favicon114.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="favicon72.png">
```
上面代碼指定 iPhone 設備需要的114像素和72像素的圖標。
`<link>`也用于提供文檔的相關鏈接,比如下面是給出文檔的 RSS Feed 地址。
```html
<link rel="alternate" type="application/atom+xml" href="/blog/news/atom">
```
### rel 屬性
`rel`屬性表示外部資源與當前文檔之間的關系,是`<link>`標簽的必需屬性。它可以但不限于取以下值。
- `alternate`:文檔的另一種表現形式的鏈接,比如打印版。
- `author`:文檔作者的鏈接。
- `dns-prefetch`:要求瀏覽器提前執行指定網址的 DNS 查詢。
- `help`:幫助文檔的鏈接。
- `icon`:加載文檔的圖標文件。
- `license`:許可證鏈接。
- `next`:系列文檔下一篇的鏈接。
- `pingback`:接收當前文檔 pingback 請求的網址。
- `preconnect`:要求瀏覽器提前與給定服務器,建立 HTTP 連接。
- `prefetch`:要求瀏覽器提前下載并緩存指定資源,供下一個頁面使用。它的優先級較低,瀏覽器可以不下載。
- `preload`:要求瀏覽器提前下載并緩存指定資源,當前頁面稍后就會用到。它的優先級較高,瀏覽器必須立即下載。
- `prerender`:要求瀏覽器提前渲染指定鏈接。這樣的話,用戶稍后打開該鏈接,就會立刻顯示,感覺非常快。
- `prev`:表示當前文檔是系列文檔的一篇,這里給出上一篇文檔的鏈接。
- `search`:提供當前網頁的搜索鏈接。
- `stylesheet`:加載一張樣式表。
下面是一些示例。
```html
<!-- 作者信息 -->
<link rel="author" href="humans.txt">
<!-- 版權信息 -->
<link rel="license" href="copyright.html">
<!-- 另一個語言的版本 -->
<link rel="alternate" href="https://es.example.com/" hreflang="es">
<!-- 聯系方式 -->
<link rel="me" href="https://google.com/profiles/someone" type="text/html">
<link rel="me" href="mailto:name@example.com">
<link rel="me" href="sms:+15035550125">
<!-- 歷史資料 -->
<link rel="archives" href="http://example.com/archives/">
<!-- 目錄 -->
<link rel="index" href="http://example.com/article/">
<!-- 導航 -->
<link rel="first" href="http://example.com/article/">
<link rel="last" href="http://example.com/article/?page=42">
<link rel="prev" href="http://example.com/article/?page=1">
<link rel="next" href="http://example.com/article/?page=3">
```
### 資源的預加載
某些情況下,你需要瀏覽器預加載某些資源,也就是先把資源緩存下來,等到使用的時候,就不用再從網上下載了,立即就能使用。預處理指令可以做到這一點。
預加載主要有下面五種類型。
(1)`<link rel="preload">`
`<link rel="preload">`告訴瀏覽器盡快下載并緩存資源(如腳本或樣式表),該指令優先級較高,瀏覽器肯定會執行。當加載頁面幾秒鐘后需要該資源時,它會很有用。下載后,瀏覽器不會對資源執行任何操作,腳本未執行,樣式表未應用。它只是緩存,當其他東西需要它時,它立即可用。
```html
<link rel="preload" href="image.png" as="image">
```
`rel="preload"`除了優先級較高,還有兩個優點:一是允許指定預加載資源的類型,二是允許`onload`事件的回調函數。下面是`rel="preload"`配合`as`屬性,告訴瀏覽器預處理資源的類型,以便正確處理。
```html
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">
```
上面代碼要求瀏覽器提前下載并緩存`style.css`和`main.js`。
`as`屬性指定加載資源的類型,它的值一般有下面幾種。
- "script"
- "style"
- "image"
- "media"
- "document"
如果不指定`as`屬性,或者它的值是瀏覽器不認識的,那么瀏覽器會以較低的優先級下載這個資源。
有時還需要`type`屬性,進一步明確 MIME 類型。
```html
<link rel="preload" href="sintel-short.mp4" as="video" type="video/mp4">
```
上面代碼要求瀏覽器提前下載視頻文件,并且說明這是 MP4 編碼。
下面是預下載字體文件的例子。
```html
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
```
注意,所有預下載的資源,只是下載到瀏覽器的緩存,并沒有執行。如果希望資源預下載后立刻執行,可以參考下面的寫法。
```html
<link rel="preload" as="style" href="async_style.css" onload="this.rel='stylesheet'">
```
上面代碼中,`onload`指定的回調函數會在腳本下載完成后執行,立即插入頁面。
(2)`<link rel="prefetch">`
`<link rel="prefetch">`的使用場合是,如果后續的頁面需要某個資源,并且希望預加載該資源,以便加速頁面渲染。該指令不是強制性的,優先級較低,瀏覽器不一定會執行。這意味著,瀏覽器可以不下載該資源,比如連接速度很慢時。
```html
<link rel="prefetch" href="https://www.example.com/">
```
(3)`<link rel="preconnect">`
`<link rel="preconnect">`要求瀏覽器提前與某個域名建立 TCP 連接。當你知道,很快就會請求該域名時,這會很有幫助。
```html
<link rel="preconnect" href="https://www.example.com/">
```
(4)`<link rel="dns-prefetch">`
`<link rel="dns-prefetch">`要求瀏覽器提前執行某個域名的 DNS 解析。
```html
<link rel="dns-prefetch" href="//example.com/">
```
(5)`<link rel="prerender">`
`<link rel="prerender">`要求瀏覽器加載某個網頁,并且提前渲染它。用戶點擊指向該網頁的鏈接時,就會立即呈現該頁面。如果確定用戶下一步會訪問該頁面,這會很有幫助。
```html
<link rel="prerender" href="http://example.com/">
```
### media 屬性
`media`屬性給出外部資源生效的媒介條件。
```html
<link href="print.css" rel="stylesheet" media="print">
<link href="mobile.css" rel="stylesheet" media="screen and (max-width: 600px)">
```
上面代碼中,打印時加載`print.css`,移動設備訪問時(設備寬度小于600像素)加載`mobile.css`。
下面是使用`media`屬性實現條件加載的例子。
```html
<link rel="preload" as="image" href="map.png" media="(max-width: 600px)">
<link rel="preload" as="script" href="map.js" media="(min-width: 601px)">
```
上面代碼中,如果屏幕寬度在600像素以下,則只加載第一個資源,否則就加載第二個資源。
### 其他屬性
`<link>`標簽的其他屬性如下。
- `crossorigin`:加載外部資源的跨域設置。
- `href`:外部資源的網址。
- `referrerpolicy`:加載時`Referer`頭信息字段的處理方法。
- `as`:`rel="preload"`或`rel="prefetch"`時,設置外部資源的類型。
- `type`:外部資源的 MIME 類型,目前僅用于`rel="preload"`或`rel="prefetch"`的情況。
- `title`:加載樣式表時,用來標識樣式表的名稱。
- `sizes`:用來聲明圖標文件的尺寸,比如加載蘋果手機的圖標文件。
## `<script>`
`<script>`用于加載腳本代碼,目前主要是加載 JavaScript 代碼。
```html
<script>
console.log('hello world');
</script>
```
上面代碼嵌入網頁,會立即執行。
`<script>`也可以加載外部腳本,`src`屬性給出外部腳本的地址。
```html
<script src="javascript.js"></script>
```
上面代碼會加載`javascript.js`腳本文件,并執行。
`type`屬性給出腳本的類型,默認是 JavaScript 代碼,所以可省略。完整的寫法其實是下面這樣。
```html
<script type="text/javascript" src="javascript.js"></script>
```
`type`屬性也可以設成`module`,表示這是一個 ES6 模塊,不是傳統腳本。
```html
<script type="module" src="main.js"></script>
```
對于那些不支持 ES6 模塊的瀏覽器,可以設置`nomodule`屬性。支持 ES6 模塊的瀏覽器,會不加載指定的腳本。這個屬性通常與`type="module"`配合使用,作為老式瀏覽器的回退方案。
```html
<script type="module" src="main.js"></script>
<script nomodule src="fallback.js"></script>
```
`<script>`還有下面一些其他屬性,大部分跟 JavaScript 語言有關,可以參考相關的 JavaScript 教程。
- `async`:該屬性指定 JavaScript 代碼為異步執行,不是造成阻塞效果,JavaScript 代碼默認是同步執行。
- `defer`:該屬性指定 JavaScript 代碼不是立即執行,而是頁面解析完成后執行。
- `crossorigin`:如果采用這個屬性,就會采用跨域的方式加載外部腳本,即 HTTP 請求的頭信息會加上`origin`字段。
- `integrity`:給出外部腳本的哈希值,防止腳本被篡改。只有哈希值相符的外部腳本,才會執行。
- `nonce`:一個密碼隨機數,由服務器在 HTTP 頭信息里面給出,每次加載腳本都不一樣。它相當于給出了內嵌腳本的白名單,只有在白名單內的腳本才能執行。
- `referrerpolicy`:HTTP 請求的`Referer`字段的處理方法。
## `<noscript>`
`<noscript>`標簽用于瀏覽器不支持或關閉 JavaScript 時,所要顯示的內容。用戶關閉 JavaScript 可能是為了節省帶寬,以延長手機電池壽命,或者為了防止追蹤,保護隱私。
```html
<noscript>
您的瀏覽器不能執行 JavaScript 語言,頁面無法正常顯示。
</noscript>
```
上面這段代碼,只有瀏覽器不能執行 JavaScript 代碼時才會顯示,否則就不會顯示。
## 參考鏈接
- [A free guide to `<head>` elements](https://gethead.info/)