從 object 到 iframe — 通用嵌入技術

開發者通常認為將影像、影片和音訊等多媒體嵌入到網頁中。在本文中,我們將另闢蹊徑,探討一些允許您將各種內容型別嵌入到網頁中的元素:<iframe><embed><object> 元素。<iframe> 用於嵌入其他網頁,而另外兩個元素允許您嵌入外部資源,例如 PDF 檔案。

預備知識 已安裝基本軟體,瞭解檔案操作基礎知識,熟悉 HTML 基礎知識
目標 瞭解如何使用 <object><embed><iframe> 將專案(例如 PDF 文件和其他網頁)嵌入到網頁中。

嵌入簡史

很久以前,在全球資訊網上,使用框架(frames)來建立網站很流行——網站的小部分儲存在單獨的 HTML 頁面中。這些頁面嵌入在一個稱為框架集(frameset)的主文件中,您可以透過框架集指定每個框架在螢幕上佔據的區域,就像調整表格的列和行大小一樣。在 90 年代中後期,這些被認為是酷炫的巔峰,並且有證據表明,將網頁分成這樣的小塊對下載速度更有利——尤其是在當時的網速如此緩慢的情況下。然而,它們確實存在許多問題,隨著網速的加快,這些問題遠遠超過了任何優點,所以你現在已經看不到它們被使用了。

稍後(90 年代末,2000 年代初),外掛技術變得非常流行,例如 Java AppletFlash——這些技術允許 Web 開發人員將影片和動畫等富內容嵌入到網頁中,而這些內容僅透過 HTML 是無法實現的。嵌入這些技術是透過 <object> 元素和較少使用的 <embed> 元素實現的,它們在當時非常有用。由於可訪問性、安全性、檔案大小等諸多問題,它們此後已不再流行。如今,主流瀏覽器已停止支援 Flash 等外掛。

最後,<iframe> 元素出現了(以及其他嵌入內容的方式,例如 <canvas><video> 等)。它提供了一種將整個 Web 文件嵌入到另一個文件中的方法,就好像它是一個 <img> 或其他類似元素一樣,並且如今仍被經常使用。

歷史課到此為止,讓我們繼續看看如何使用其中一些。

使用經典嵌入功能

在本文中,我們將直接進入一個練習,讓您立即瞭解嵌入技術有什麼用。線上世界對 YouTube 非常熟悉,但許多人不知道它擁有的一些共享功能。

  1. 首先,開啟 MDN Playground
  2. 現在我們將瞭解 YouTube 如何允許我們使用 <iframe> 將影片嵌入到我們喜歡的任何頁面中。
    1. 前往 YouTube,找到您喜歡的影片。
    2. 在影片下方,您會找到一個“分享”按鈕——選擇此按鈕以顯示分享選項。
    3. 選擇“嵌入”按鈕,您將獲得一些 <iframe> 程式碼——複製此程式碼。
    4. 將其貼上到 Playground 中的 HTML 面板中,並檢視輸出結果。
  3. 作為額外加分項,您還可以嘗試在 Playground 中嵌入 Google 地圖
    1. 前往 Google 地圖,找到您喜歡的地圖。
    2. 單擊 UI 左上角的“漢堡包選單”(三條水平線)。
    3. 選擇“分享或嵌入地圖”選項。
    4. 選擇“嵌入地圖”選項,這將為您提供一些 <iframe> 程式碼——複製它。
    5. 將其貼上到 Playground 中的 HTML 面板中,並檢視輸出結果。

如果您犯了錯誤,您可以隨時使用 Playground 中的“重置”按鈕將其重置。

iframe 詳解

所以,這既簡單又有趣,對吧?<iframe> 元素旨在允許您將其他 Web 文件嵌入到當前文件中。這對於將您可能無法直接控制且不想自己實現第三方內容(例如線上影片提供商的影片、Disqus 等評論系統、線上地圖提供商的地圖、廣告橫幅等)整合到您的網站中非常有用。甚至您在本課程中使用的即時可編輯示例也是使用 <iframe> 實現的。

在深入使用 <iframe> 元素之前,需要注意一些安全問題。假設您想使用 <iframe> 元素在您的一個網頁中包含 MDN 詞彙表,您可能會嘗試類似以下程式碼示例。如果您將以下程式碼新增到您的一個頁面中,您可能會驚訝地看到錯誤訊息而不是詞彙表頁面。

html
<iframe
  src="https://mdn.club.tw/en-US/docs/Glossary"
  width="100%"
  height="500"
  allowfullscreen
  sandbox>
  <p>
    <a href="/en-US/docs/Glossary">
      Fallback link for browsers that don't support iframes
    </a>
  </p>
</iframe>
css
iframe {
  border: none;
}

如果您檢視瀏覽器的控制檯,您會看到如下錯誤訊息:

Refused to display 'https://mdn.club.tw/' in a frame because it set 'X-Frame-Options' to 'deny'.

下面的安全部分將詳細說明您看到此錯誤的原因,但首先,讓我們看看我們的程式碼正在做什麼。

該示例包含了使用 <iframe> 所需的基本要素:

邊框:無

如果使用,<iframe> 將不帶邊框顯示。否則,預設情況下,瀏覽器會顯示帶邊框的 <iframe>(這通常是不需要的)。

allowfullscreen

如果設定,<iframe> 可以使用 Fullscreen API 進入全屏模式(這超出了本文的範圍)。

src

此屬性與 <video>/<img> 一樣,包含指向要嵌入文件 URL 的路徑。

widthheight

這些屬性指定了您希望 iframe 的寬度和高度。

sandbox

此屬性在比其他 <iframe> 功能稍新的瀏覽器(例如 IE 10 及更高版本)中起作用,它要求提高安全設定;我們將在下一節中詳細介紹。

注意:為了提高速度,最好在主內容載入完成後使用 JavaScript 設定 iframe 的 src 屬性。這可以使您的頁面更快可用,並減少您的官方頁面載入時間(一個重要的 SEO 指標)。

安全問題

前面我們提到了安全問題——現在讓我們更詳細地探討一下。我們不期望您第一次就完全理解所有這些內容;我們只是想讓您意識到這個問題,並提供一個參考,以便您在變得更有經驗並開始在實驗和工作中考慮使用 <iframe> 時可以回顧。另外,沒有必要害怕而不使用 <iframe>——您只需要小心謹慎。請繼續閱讀……

瀏覽器製造商和 Web 開發人員已經透過慘痛的教訓認識到,iframe 是 Web 上不法分子(通常稱為駭客,或更準確地說,破解者)進行攻擊的常見目標(官方術語:攻擊向量),如果他們試圖惡意修改您的網頁,或者誘騙人們做他們不想做的事情,例如洩露使用者名稱和密碼等敏感資訊。正因為如此,規範工程師和瀏覽器開發人員為使 <iframe> 更安全開發了各種安全機制,並且還有一些最佳實踐需要考慮——我們將在下面介紹其中一些。

注意:點選劫持是一種常見的 iframe 攻擊,駭客將一個不可見的 iframe 嵌入到您的文件中(或者將您的文件嵌入到他們自己的惡意網站中),並利用它來捕獲使用者的互動。這是一種誤導使用者或竊取敏感資料的常見方式。

不過,首先舉一個簡單的例子——嘗試在您的瀏覽器中載入我們前面展示的那個例子——您可以在 GitHub 上找到它的線上版本也可檢視原始碼)。您可能會看到一些類似於“我無法開啟此頁面”的錯誤訊息,而不是您期望的頁面,如果您檢視瀏覽器開發者工具中的控制檯,您會看到一條訊息告訴您原因。在 Firefox 中,您會收到類似“載入 ‘https://mdn.club.tw/en-US/docs/Glossary’ 的框架被 'X-Frame-Options' 指令設定為 'DENY' 拒絕”的訊息。這是因為構建 MDN 的開發者在提供網站頁面的伺服器上包含了一個設定,禁止將它們嵌入到 <iframe> 中(參見下面的配置 CSP 指令)。這是有道理的——除非您想做一些事情,例如將它們嵌入到您的網站並聲稱是您自己的——或嘗試透過點選劫持竊取資料,否則將整個 MDN 頁面嵌入到其他頁面中並沒有真正的意義,這些都是非常糟糕的事情。此外,如果每個人都開始這樣做,所有額外的頻寬將開始讓 Mozilla 花費大量資金。

僅在必要時嵌入

有時嵌入第三方內容(例如 YouTube 影片和地圖)是有意義的,但如果您只在完全必要時才嵌入第三方內容,可以省去很多麻煩。一個好的網路安全規則是:“你永遠不能過於謹慎。如果你自己製作了它,無論如何都要仔細檢查。如果是別人製作的,則在證明它無害之前,假定它是危險的。”

除了安全問題,您還應該注意智慧財產權問題。大多數內容都受版權保護,無論是離線還是線上,甚至您可能不期望的內容(例如,維基共享資源上的大多數圖片)。除非您擁有該內容或所有者已明確書面許可,否則切勿在您的網頁上顯示內容。侵犯版權的處罰是嚴厲的。再次強調,您永遠不能過於謹慎。

如果內容已獲得許可,您必須遵守許可條款。例如,MDN 上的內容根據 CC-BY-SA 許可。這意味著,當您引用我們的內容時,即使您進行了實質性更改,也必須正確註明出處

使用 HTTPS

HTTPSHTTP 的加密版本。您應該儘可能使用 HTTPS 提供您的網站服務。

  1. HTTPS 降低了遠端內容在傳輸過程中被篡改的可能性。
  2. HTTPS 阻止嵌入內容訪問父文件中的內容,反之亦然。

啟用 HTTPS 需要安裝特殊的安全證書。許多託管服務提供商提供 HTTPS 託管,您無需自行設定證書。但是,如果您確實需要自行設定網站的 HTTPS 支援,Let's Encrypt 提供工具和說明,您可以用於自動建立和安裝必要的證書——內建支援最廣泛使用的 Web 伺服器,包括 Apache Web 伺服器、Nginx 等。Let's Encrypt 工具旨在使過程儘可能簡單,因此確實沒有充分的理由避免使用它或其他可用方式來啟用您的網站 HTTPS。

注意:GitHub Pages 預設透過 HTTPS 提供內容。如果您使用不同的託管服務提供商,您應該檢查他們對透過 HTTPS 提供內容的支援情況。

始終使用 sandbox 屬性

您希望儘可能減少攻擊者在您網站上作惡的能力,因此您應該只給予嵌入內容完成其工作所需的許可權。當然,這也適用於您自己的內容。一個可以適當地使用程式碼——或用於測試——但不會對程式碼庫的其餘部分造成任何損害(無論是意外還是惡意)的程式碼容器被稱為沙盒

未沙盒化的內容可能能夠執行 JavaScript、提交表單、觸發彈出視窗等。預設情況下,您應該透過使用不帶引數的 sandbox 屬性來施加所有可用限制,如我們之前的示例所示。

如果絕對需要,您可以逐個新增許可權(在 sandbox="" 屬性值內)——有關所有可用選項,請參閱 sandbox 參考條目。一個重要的注意事項是,您永遠不應同時向 sandbox 屬性新增 allow-scriptsallow-same-origin——在這種情況下,嵌入內容可以繞過阻止站點執行指令碼的同源策略,並使用 JavaScript 完全關閉沙盒。

注意:如果攻擊者能夠誘騙人們直接訪問惡意內容(在 iframe 之外),沙盒將無法提供保護。如果某些內容(例如使用者生成的內容)有任何惡意可能性,請務必從與您主站點不同的提供服務。

配置 CSP 指令

CSP 代表內容安全策略,它提供一組 HTTP 頭(當您的網頁從 Web 伺服器提供時,與網頁一起傳送的元資料),旨在提高 HTML 文件的安全性。在保護 <iframe> 方面,您可以配置您的伺服器傳送適當的 X-Frame-Options 頭。這可以防止其他網站在他們的網頁中嵌入您的內容(這將啟用點選劫持和許多其他攻擊),這正是 MDN 開發人員所做的,正如我們之前所見。

注意:您可以閱讀 Frederik Braun 的文章 關於 X-Frame-Options 安全頭,以獲取更多有關此主題的背景資訊。顯然,本文無法對此進行全面解釋。

<embed><object> 元素

<embed><object> 元素的功能與 <iframe> 不同——這些元素是用於嵌入外部內容(如 PDF)的通用嵌入工具。

然而,您不太可能經常使用這些元素。如果您需要顯示 PDF,通常最好連結到它們,而不是將它們嵌入到頁面中。

從歷史上看,這些元素也曾用於嵌入由瀏覽器外掛(如 Adobe Flash)處理的內容,但這項技術現在已經過時,並且不受現代瀏覽器支援。

如果您發現自己需要嵌入外掛內容,那麼您至少需要以下資訊:

<embed> <object>
URL 指向嵌入內容 src data
嵌入內容的準確媒體型別 type type
由外掛控制的框的高度和寬度(以 CSS 畫素為單位) height
width
height
width
作為不可用資源的備用獨立 HTML 內容 不支援(<noembed> 已過時) 包含在 <object> 的開始和結束標籤之間

讓我們看一個嵌入 PDF 到頁面中的 <object> 示例(參見即時示例原始碼

html
<object data="my-pdf.pdf" type="application/pdf" width="800" height="1200">
  <p>
    You don't have a PDF plugin, but you can
    <a href="my-pdf.pdf">download the PDF file. </a>
  </p>
</object>

PDF 曾是紙質文件和數字文件之間必不可少的過渡,但它們帶來了許多可訪問性挑戰,並且在小螢幕上可能難以閱讀。它們在某些圈子中仍然很受歡迎,但最好是連結到它們,以便可以在單獨的頁面上下載或閱讀,而不是將它們嵌入到網頁中。

總結

在網頁文件中嵌入其他內容這個話題很快就會變得非常複雜,因此在本文中,我們試圖以一種簡單、熟悉的方式介紹它,使其立即顯得相關,同時仍暗示了所涉及技術的一些更高階功能。一開始,您不太可能將嵌入用於除了在頁面中包含地圖和影片等第三方內容之外的任何其他用途。然而,隨著您經驗的增長,您可能會發現它們有更多的用途。

除了我們在這裡討論的技術之外,還有許多其他涉及嵌入外部內容的技術。我們在前面的文章中看到了一些,例如 <video><audio><img>,但還有其他一些可以發現,例如用於 JavaScript 生成的 2D 和 3D 圖形的 <canvas>,以及用於嵌入向量圖形的 <svg>