阅读MDN发现的零碎知识笔记-Web开发基础-多媒体(二)

49 阅读27分钟

盗链(hotlinking)

大多数图片是有版权的。不要在你的网页上使用一张图片,除非:

  1. 你是图片版权所有者
  2. 你有图片版权所有者明确的、书面上的使用授权
  3. 你有充分的证据证明这张图片是公共领域内的

侵犯版权是违法并且不道德的。此外,在得到授权之前永远不要把你的src属性指向其他人网站上的图片。这被称为"盗链(hotlinking)"。同样,盗取其他人的带宽也是违法的。而且这会降低你的页面的加载速度,而且图片可能会在不受你控制的情况下被移走或用别的令人尴尬的东西替换掉。

<img><video> 这样的元素有时被称之为替换元素,因为这样的元素的内容和尺寸由外部资源(像是一个图片或视频文件)所定义,而不是元素自身。

为什么我们需要备选文本呢(alt)?

那么,为什么我们需要备选文本呢?它可以派上用场的原因有很多:

  • 用户有视力障碍,通过屏幕阅读器来浏览网页。事实上,给图片一个备选的描述文本对大多数用户都是很有用的。
  • 就像上面所说的,你也许会把图片的路径或文件名拼错。
  • 浏览器不支持该图片类型。某些用户仍在使用纯文本的浏览器,例如 Lynx,这些浏览器会把图片替换为描述文本。
  • 你会想提供一些文字描述来给搜索引擎使用,例如搜索引擎可能会将图片的文字描述和查询条件进行匹配。
  • 用户关闭的图片显示以减少数据的传输,这在手机上是十分普遍的,并且在一些国家带宽有限且昂贵。

你到底应该在 alt 里写点什么呢?这首先取决于为什么这张图片会在这儿,换句话说,如果这张图片没显示出来,会少了什么:

  • 装饰:如果图片只是用于装饰,而不是内容的一部分,可以写一个空的 alt=""。例如,屏幕阅读器不会浪费时间对用户读出不是核心需要的内容。实际上装饰性图片就不应该放在 HTML 文件里,CSS 背景图片才应该用于插入装饰图片,但如果这种情况无法避免,alt="" 会是最佳处理方案。
  • 内容:如果你的图片提供了重要的信息,就要在 alt 文本中简要的提供相同的信息,甚至更近一步,把这些信息写在主要的文本内容里,这样所有人都能看见。不要写冗余的备选文本(如果在主要文本中将所有的段落都重复两遍,对于没有失明的用户来说多烦啊!),如果在主要文本中已经对图片进行了充分的描述,写 alt="" 就好。
  • 链接:如果你把图片嵌套在 <a> 标签里,来把图片变成链接,那你还必须提供无障碍的链接文本。在这种情况下,你可以写在同一个 元素里,或者写在图片的 alt 属性里,随你喜欢。
  • 文本:你不应该将文本放到图像里。例如,如果你的主标题需要有阴影,你可以用 CSS 来达到这个目的,而不是把文本放到图片里。如果真的必须这么做,那就把文本也放到 alt 里。

本质上,关键在于在图片无法被看见时也提供一个可用的体验,这确保了所有人都不会错失一部分内容。尝试在浏览器中使图片不可见然后看看网页变成什么样了,你会很快意识到在图片无法显示时备选文本能帮上多大忙。

解说图片

有一个更好的做法是使用 HTML5 的 <figure><figcaption> 元素,它正是为此而被创造出来的:为图片提供一个语义容器,在标题和图片之间建立清晰的关联。我们之前的例子可以重写为:

<figure>
  <img
    src="https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg"
    alt="一只恐龙头部和躯干的骨架,它有一个巨大的头,长着锋利的牙齿。"
    width="400"
    height="341" />
  <figcaption>曼彻斯特大学博物馆展出的一只霸王龙的化石</figcaption>
</figure>

这个 <figcaption> 元素 告诉浏览器和其他辅助的技术工具这段说明文字描述了 <figure> 元素的内容。

备注: 从无障碍的角度来说,说明文字和 alt 文本扮演着不同的角色。看得见图片的人们同样可以受益于说明文字,而 alt 文字只有在图片无法显示时才这样。所以,说明文字和 alt 的内容不应该一样,因为当图片无法显示时,它们会同时出现。尝试让你的图片不显示,看看效果如何。

注意 <figure> 里不一定要是一张图片,只要是一个这样的独立内容单元:

  • 用简洁、易懂的方式表达意图。
  • 可以置于页面线性流的某处。
  • 为主要内容提供重要的补充说明。

<figure> 可以是几张图片、一段代码、音视频、方程、表格或别的。

那么为什么我们还要使用 HTML 图片呢?

你也可以使用 CSS 把图片嵌入网站中(JavaScript 也行,不过那是另外一个故事了),这个 CSS 属性 background-image 和另其他 background-* 属性是用来放置背景图片的。比如,为页面中的所有段落设置一个背景图片,你可以这样做:

p {
    background-image: url("images/dinosaur.jpg");
}

按理说,这种做法相对于 HTML 中插入图片的做法,可以更好地控制图片和设置图片的位置,那么为什么我们还要使用 HTML 图片呢?如上所述,CSS 背景图片只是为了装饰 — 如果你只是想要在你的页面上添加一些漂亮的东西,来提升视觉效果,那 CSS 的做法是可以的。但是这样插入的图片完全没有语义上的意义,它们不能有任何备选文本,也不能被屏幕阅读器识别。这就是 HTML 图片有用的地方了。

总而言之,如果图像对你的内容里有意义,则应使用 HTML 图像。如果图像纯粹是装饰,则应使用 CSS 背景图片。

使用多个播放源以提高兼容性

要使你的媒体文件在不同平台,不同设备的浏览器上都可观看,这需要多种编码器组合使用,但是这是一种非常麻烦的事,所以可以参考选择合适的容器来选择最适合的容器格式,同样地,参考选择视频编解码器选择音频编解码器 (en-US)选择编码格式

需要记住的另一件事:同一款浏览器,移动版与桌面版支持的格式可能会有不同。最重要的是,它们都可以减轻媒体播放的处理负担(对于所有媒体或仅针对其内部无法处理的特定类型)。这意味着设备的媒体支持还部分取决于用户安装了什么软件。

我们该怎么做呢?请看如下例子(你可以点击这里查看网页,或者点击这里查看源代码):

<video controls>
  <source src="rabbit320.mp4" type="video/mp4" />
  <source src="rabbit320.webm" type="video/webm" />
  <p>
    你的浏览器不支持 HTML5 视频。可点击<a href="rabbit320.mp4">此链接</a>观看
  </p>
</video>

现在我们将 src 属性从 <video> 标签中移除,转而将它放在几个单独的标签 <source> 当中。在这个例子当中,浏览器将会检查 <source> 标签,并且播放第一个与其自身 codec 相匹配的媒体。你的视频应当包括 WebM 和 MP4 两种格式,这两种在目前已经足够支持大多数平台和浏览器。

每个 <source> 标签页含有一个 type 属性,这个属性是可选的,但是建议你添加上这个属性 — 它包含了视频文件的 MIME types ,同时浏览器也会通过检查这个属性来迅速的跳过那些不支持的格式。如果你没有添加 type 属性,浏览器会尝试加载每一个文件,直到找到一个能正确播放的格式,这样会消耗掉大量的时间和资源。

其他 特性

<video
  controls
  width="400"
  height="400"
  autoplay
  loop
  muted
  poster="poster.png">
  <source src="rabbit320.mp4" type="video/mp4" />
  <source src="rabbit320.webm" type="video/webm" />
  <p>
    你的浏览器不支持 HTML5 视频。可点击<a href="rabbit320.mp4">此链接</a>观看
  </p>
</video>

新的特性:

widthheight

你可以用属性控制视频的尺寸,也可以用 CSS 来控制视频尺寸。无论使用哪种方式,视频都会保持它原始的长宽比 — 也叫做纵横比。如果你设置的尺寸没有保持视频原始长宽比,那么视频边框将会拉伸,而未被视频内容填充的部分,将会显示默认的背景颜色。

autoplay

这个属性会使音频和视频内容立即播放,即使页面的其他部分还没有加载完全。建议不要应用这个属性在你的网站上,因为用户们会比较反感自动播放的媒体文件。

loop

这个属性可以让音频或者视频文件循环播放。同样不建议使用,除非有必要。

muted

这个属性会导致媒体播放时,默认关闭声音。

poster

这个属性指向了一个图像的 URL,这个图像会在视频播放前显示。通常用于粗略的预览或者广告。

preload

这个属性被用来缓冲较大的文件,有 3 个值可选:

  • "none" :不缓冲
  • "auto" :页面加载后缓存媒体文件
  • "metadata" :仅缓冲文件的元数据

你可以点击这里查看以上的例子,也可以点击这里查看源代码。注意我们并没有使用 autoplay 属性在这个版本的例子中 — 如果当页面一加载就开始播放视频的话,就不会看到 poster 属性的效果了。

显示音轨文本 WebVTT

现在,我们将讨论一个略微先进的概念,这个概念将会十分的有用。许多人不想(或者不能)听到 Web 上的音频/视频内容,至少在某些情况下是这样的,比如:

  • 许多人患有听觉障碍(通常来说是很难听清声音的人,或者聋人),所以他们不能听见音频中的声音。
  • 另外的情况可能是由于人们并不能听音频,可能是因为他们在一个非常嘈杂的环境当中(比如在一个拥挤的酒吧内恰好赶上了球赛),也可能是由于他们并不想打扰到其他人(比如在一个十分安静的地方,例如图书馆)。
  • 有一些人他们不说音频当中的语言,所以他们听不懂,因此他们想要一个副本或者是翻译来帮助他们理解媒体内容。

给那些听不懂音频语言的人们提供一个音频内容的副本岂不是一件很棒的事情吗?所以,感谢 HTML5 <video> 使之成为可能,有了 WebVTT (en-US) 格式,你可以使用 <track> 标签。

备注: “副本”的意思是指,用文本记录下音频的内容。

WebVTT 是一个格式,用来编写文本文件,这个文本文件包含了众多的字符串,这些字符串会带有一些元数据,它们可以用来描述这个字符串将会在视频中显示的时间,甚至可以用来描述这些字符串的样式以及定位信息。这些字符串叫做 cues ,你可以根据不同的需求来显示不同的样式,最常见的如下:

subtitles

通过添加翻译字幕,来帮助那些听不懂外国语言的人们理解音频当中的内容。

captions

同步翻译对白,或是描述一些有重要信息的声音,来帮助那些不能听音频的人们理解音频中的内容。

timed descriptions

将文字转换为音频,用于服务那些有视觉障碍的人。

一个典型的 WebVTT 文件如下:

WEBVTT

1
00:00:22.230 --> 00:00:24.606
第一段字幕

2
00:00:30.739 --> 00:00:34.074
第二段

  ...

让其与 HTML 媒体一起显示,你需要做如下工作:

  1. 以 .vtt 后缀名保存文件。
  2. <track> 标签链接 .vtt 文件, <track> 标签需放在 <audio><video> 标签当中,同时需要放在所有 <source> 标签之后。使用 kind 属性来指明是哪一种类型,如 subtitles、captions、descriptions。然后,使用 srclang 来告诉浏览器你是用什么语言来编写的 subtitles。

如下:

HTMLCopy to Clipboard

<video controls>
  <source src="example.mp4" type="video/mp4" />
  <source src="example.webm" type="video/webm" />
  <track kind="subtitles" src="subtitles_en.vtt" srclang="en" />
</video>

上面这串代码会显示一段带有字幕的视频,如下:

如果你想了解更多细节,你可以阅读 Adding captions and subtitles to HTML5 video。在 Github 上你可以找到与本文相关的样例,他们由 Ian Devlin 编写,点击这里可以查看该样例,或者点击这里查看源代码。这个样例使用了 JavaScript 代码,它使得用户可以选择不同的字幕。注意,若想要显示字幕,你需要点击 "CC" 按钮,并且选择一种语言 — English, Deutsch, 或 Español。

文本轨道会使你的网站更容易被搜索引擎抓取到(SEO),由于搜索引擎的文本抓取能力非常强大,使用文本轨道甚至可以让搜索引擎通过视频的内容直接链接。

嵌入类型的使用

大家都非常熟悉 Bilibili,但很多人不了解它所提供的一些分享功能。让我们来看看 Bilibili 如何让我们通过 <iframe> 在页面中嵌入喜欢的视频。

  1. 首先,去 Bilibili 找一个喜欢的视频。
  2. 在视频下方,你会看到一个分享按钮(样式为一个向右箭头),鼠标停留在那个按钮上,可以看到一些分享选项。
  3. 选择“嵌入代码”选项,会出现“成功复制到剪贴板”的提示。
  4. 将复制的代码粘贴到下面的输入框里,看看输出结果是什么。

此外,你还可以试试在示例中嵌入 Bing 地图

  1. 去 Bing 地图找一个喜欢的地图。
  2. 鼠标移动到 UI 上方的“更多”处。
  3. 选择嵌入地图选项。
  4. 在新打开的网页中,指定你喜欢的地图大小、类型、风格和链接,点击“生成代码”按钮,代码会复制到剪贴板中。
  5. 将复制的代码粘贴到下面的输入框,看看输出结果是什么。

Iframe 详解

<iframe> 基本要素:

allowfullscreen

如果设置,<iframe>则可以通过全屏 API 设置为全屏模式(稍微超出本文的范围)。

frameborder

如果设置为 1,则会告诉浏览器在此框架和其他框架之间绘制边框,这是默认行为。0 删除边框。不推荐这样设置,因为在 CSS 中可以更好地实现相同的效果。border``: none;

src

该属性与 <video> / 元素表示文档中的图像。<img>一样包含指向要嵌入文档的 URL 路径。

widthheight

这些属性指定你想要的 iframe 的宽度和高度。

备选内容

<video> 等其他类似元素相同,你可以在 <iframe></iframe> 标签之间包含备选内容,如果浏览器不支持 <iframe>,将会显示备选内容,这种情况下,我们已经添加了一个到该页面的链接。现在你几乎不可能遇到任何不支持 <iframe> 的浏览器。

sandbox

该属性需要在已经支持其他 <iframe> 功能(例如 IE 10 及更高版本)但稍微更现代的浏览器上才能工作,该属性可以提高安全性设置;我们将在下一节中更加详细地谈到。

为了提高速度,在主内容完成加载后,使用 JavaScript 设置 iframe 的 src 属性是个好主意。这使你的页面可以更快地被使用,并减少你的官方页面加载时间(重要的 SEO 指标)。

安全隐患

以上我们提到了安全问题——现在我们来详细介绍一下这一点。我们并不期望你第一次就能完全理解所有内容; 我们只想让你意识到这一问题,在你更有经验并开始考虑在你的实验和工作中使用 <iframe> 时为你提供参考。此外,没有必要害怕和不使用 <iframe>——你只需要谨慎一点。继续看下去吧...

浏览器制造商和 Web 开发人员了解到网络上的坏人(通常被称为黑客,或更准确地说是破解者),如果他们试图恶意修改你的网页或欺骗人们进行不想做的事情时常把 iframe 作为共同的攻击目标(官方术语:攻击向量),例如显示用户名和密码等敏感信息。因此,规范工程师和浏览器开发人员已经开发了各种安全机制,使<iframe>更加安全,这有些最佳方案值得我们考虑——我们将在下面介绍其中的一些。

备注: 单击劫持是一种常见的 iframe 攻击,黑客将隐藏的 iframe 嵌入到你的文档中(或将你的文档嵌入到他们自己的恶意网站),并使用它来捕获用户的交互。这是误导用户或窃取敏感数据的常见方式。

一个快速的例子——尝试在浏览器中加载上面的例子——你也可以 在 Github 上找到它参见源代码)。你将不会看到任何内容,但如果你点击浏览器开发者工具中的控制台,你会看到一条消息,告诉你为什么没有显示内容。在 Firefox 中,你会被告知:“X-Frame-Options 拒绝加载 https://developer.mozilla.org/zh-CN/docs/Glossary。这是因为构建 MDN 的开发人员已经在网站页面的服务器上设置了一个不允许被嵌入到<iframe>的设置(请参阅配置 CSP 指令)这是有必要的——整个 MDN 页面被嵌入在其他页面中没有多大意义,除非你想要将其嵌入到你的网站上并将其声称为自己的内容,或尝试通过单击劫持来窃取数据,这都是非常糟糕的事情。此外,如果每个人都这样做,所有额外的带宽将花费 Mozilla 很多资金。

只有在必要时嵌入

有时嵌入第三方内容(例如 YouTube 视频和地图)是有意义的,但如果你只在完全需要时嵌入第三方内容,你可以省去很多麻烦。网络安全的一个很好的经验法则是“你怎么谨慎都不为过,如果你决定要做这件事,多检查一遍;如果是别人做的,在被证明是安全的之前,都假设这是危险的。

除了安全问题,你还应该意识到知识产权问题。无论在线内容还是离线内容,绝大部分内容都是有版权的,甚至是一些你没想到有版权的内容(例如,Wikimedia Commons 上的大多数图片)。不要在网页上展示一些不属于你的内容,除非你是所有者或所有者给了你明确的、书面的许可。对于侵犯版权的惩罚是严厉的。再说一次,你再小心也不为过。

如果内容获得许可,你必须遵守许可条款。例如,MDN 上的内容是在 CC-BY-SA 下许可的,这意味着,如果你要引用我们的内容,就必须用适当的方式注明来源,即使你对内容做了实质性的修改。

使用 HTTPS

HTTPSHTTP 的加密版本。你应该尽可能使用 HTTPS 为你的网站提供服务:

  1. HTTPS 减少了远程内容在传输过程中被篡改的机会,
  2. HTTPS 防止嵌入式内容访问你的父文档中的内容,反之亦然。

使用 HTTPS 需要一个安全证书,这可能是昂贵的(尽管 Let's Encrypt 让这件事变得更容易),如果你没有,可以使用 HTTP 来为你的父文档提供服务。但是,由于 HTTPS 的第二个好处,无论成本如何,你绝对不能使用 HTTP 嵌入第三方内容(在最好的情况下,你的用户的 Web 浏览器会给他们一个可怕的警告)。所有有声望的公司,例如 Google Maps 或 Youtube,当你嵌入内容时,<iframe> 将通过 HTTPS 提供——查看 <iframe> src 属性内的 URL。

备注: Github 页面允许默认情况下通过 HTTPS 提供内容,因此对托管内容很有用。如果你正在使用不同的托管,并且不确定,请向你的托管服务商询问。

始终使用 sandbox 属性

想尽可能减少攻击者在你的网站上做坏事的机会,那么你应该给嵌入的内容仅能完成自己工作的权限。当然,这也适用于你自己的内容。一个允许包含在其里的代码以适当的方式执行或者用于测试,但不能对其他代码库(意外或恶意)造成任何损害的容器称为沙盒

未沙盒化(Unsandboxed)内容可以做得太多(执行 JavaScript,提交表单,弹出窗口等)默认情况下,你应该使用没有参数的 sandbox 属性来强制执行所有可用的限制,如我们前面的示例所示。

如果绝对需要,你可以逐个添加权限(sandbox=""属性值内)——请参阅 sandbox 所有可用选项的参考条目。其中重要的一点是,你永远不应该同时添加 allow-scriptsallow-same-origin 到你的 sandbox 属性中——在这种情况下,嵌入式内容可以绕过阻止站点执行脚本的同源安全策略,并使用 JavaScript 完全关闭沙盒。

备注: 如果攻击者可以欺骗人们直接访问恶意内容(在 iframe 之外),则沙盒无法提供保护。如果某些内容可能是恶意的(例如,用户生成的内容),请保证其是从不同的向你的主站点提供的。

配置 CSP 指令

CSP 代表 内容安全策略,它提供一组 HTTP 标头(由 web 服务器发送时与元数据一起发送的元数据),旨在提高 HTML 文档的安全性。在 <iframe> 的安全性方面,你可以*将服务器配置为发送适当的 X-Frame-Options 标题*。这样做可以防止其他网站在其网页中嵌入你的内容(这将导致点击劫持和一系列其他攻击),正如我们之前看到的那样,MDN 开发人员已经做了这些工作。

备注: 你可以阅读 Frederik Braun 的帖子在 X-Frame-Options 安全性标头上来获取有关此主题的更多背景信息。显然,在这篇文章中已经解释得很清楚了。

PDF 嵌入

现在来看一个 <object> 将 PDF 嵌入一个页面的例子(参见实例源代码):

HTMLCopy to Clipboard

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

PDF 是纸与数据之间重要的阶梯,但它们在无障碍上有些问题,并且可能难以在小屏幕上阅读。它们在一些圈子中仍然受欢迎,我们最好是用链接指向它们,而不是将其嵌入到网页中,以便它们可以在单独的页面上被下载或被阅读。

SVG 是什么?

SVG 是用于描述矢量图像的XML语言。它基本上是像 HTML 一样的标记,只是你有许多不同的元素来定义要显示在图像中的形状,以及要应用于这些形状的效果。SVG 用于标记图形,而不是内容。非常简单,你有一些元素来创建简单图形,如<circle><rect>。更高级的 SVG 功能包括 <feColorMatrix>(使用变换矩阵转换颜色)<animate> (矢量图形的动画部分)和 <mask>(在图像顶部应用模板)

<svg
  version="1.1"
  baseProfile="full"
  width="300"
  height="200"
  xmlns="http://www.w3.org/2000/svg">
  <rect width="100%" height="100%" fill="black" />
  <circle cx="150" cy="100" r="90" fill="blue" />
</svg>

SVG 很容易手工编码。是的,你可以在文本编辑器中手动编写简单的 SVG,但是对于复杂的图像,这很快就开始变得非常困难。为了创建 SVG 图像,大多数人使用矢量图形编辑器,如 InkscapeIllustrator。这些软件包允许你使用各种图形工具创建各种插图,并创建照片的近似值(例如 Inkscape 的跟踪位图功能)。

SVG 除了迄今为止所描述的以外还有其他优点:

  • 矢量图像中的文本仍然可访问(这也有利于 SEO)。
  • SVG 可以很好地适应样式/脚本,因为图像的每个组件都是可以通过 CSS 或通过 JavaScript 编写的样式的元素。

那么为什么会有人想使用光栅图形而不是 SVG?其实 SVG 确实有一些缺点:

  • SVG 非常容易变得复杂,这意味着文件大小会增加; 复杂的 SVG 也会在浏览器中占用很长的处理时间。
  • SVG 可能比栅格图像更难创建,具体取决于你尝试创建哪种图像。
  • 旧版浏览器不支持 SVG,因此如果你需要在网站上支持旧版本的 IE,则可能不适合(SVG 从 IE9 开始得到支持)。

由于上述原因,光栅图形更适合照片那样复杂精密的图像。

SVG**跨浏览器支持**

对于不支持 SVG(IE 8 及更低版本,Android 2.3 及更低版本)的浏览器,你可以从src属性引用 PNG 或 JPG,并使用srcset属性 只有最近的浏览器才能识别)来引用 SVG。在这种情况下,仅支持浏览器将加载 SVG - 较旧的浏览器将加载 PNG:

<img
  src="equilateral.png"
  alt="triangle with equal sides"
  srcset="equilateral.svg" />

你还可以使用 SVG 作为 CSS 背景图像,如下所示。在下面的代码中,旧版浏览器会坚持他们理解的 PNG,而较新的浏览器将加载 SVG:

CSSCopy to Clipboard

background: url("fallback.png") no-repeat center;
background-image: url("image.svg");
background-size: contain;

像上面描述的<img>方法一样,使用 CSS 背景图像插入 SVG 意味着它不能被 JavaScript 操作,并且也受到相同的 CSS 限制。

如果 SVG 根本没有显示,可能是因为你的服务器设置不正确。如果是这个问题,这篇文章将告诉你正确方向。

HTML 中引入 SVG 代码

优点

  • 将 SVG 内联减少 HTTP 请求,可以减少加载时间。
  • 你可以为 SVG 元素分配classid,并使用 CSS 修改样式,无论是在 SVG 中,还是 HTML 文档中的 CSS 样式规则。实际上,你可以使用任何 SVG 外观属性 作为 CSS 属性。
  • 内联 SVG 是唯一可以让你在 SVG 图像上使用 CSS 交互(如:focus)和 CSS 动画的方法(即使在常规样式表中)。
  • 你可以通过将 SVG 标记包在<a>元素中,使其成为超链接。

缺点

  • 这种方法只适用于在一个地方使用的 SVG。多次使用会导致资源密集型维护(resource-intensive maintenance)。
  • 额外的 SVG 代码会增加 HTML 文件的大小。
  • 浏览器不能像缓存普通图片一样缓存内联 SVG。
  • 你可能会在<foreignObject> 元素中包含回退,但支持 SVG 的浏览器仍然会下载任何后备图像。你需要考虑仅仅为支持过时的浏览器,而增加额外开销是否真的值得。

<iframe> 嵌入 SVG

你可以在浏览器中打开 SVG 图像,就像网页一样。因此,使用<iframe>嵌入 SVG 文档就像我们在 从对象到 iframe - 其他嵌入技术 中进行研究一样。

这绝对不是最好的方法:

缺点

  • 如你所知, iframe有一个回退机制,如果浏览器不支持iframe,则只会显示回退。
  • 此外,除非 SVG 和你当前的网页具有相同的 origin,否则你不能在主页面上使用 JavaScript 来操纵 SVG。

HTML 的响应式图片

developer.mozilla.org/zh-CN/docs/…

在 HTML 文件中的 <head> 标签里,你将会找到这一行代码 <meta name="viewport" content="width=device-width">:这行代码会强制让手机浏览器采用它们真实可视窗口的宽度来加载网页(有些手机浏览器会提供不真实的可视窗口宽度,用比真实视口更大的宽度加载网页,然后再缩小加载的页面,这样的做法对响应式图片或其他响应式设计,没有任何帮助)。

美术设计

美术设计问题涉及到更改显示的图像以适应不同的显示尺寸。例如,如果在桌面浏览器上的一个网站上显示一张大的、横向的照片,照片中央有个人,然后当在移动端浏览器上浏览这个网站时,照片会缩小,这时照片上的人会变得非常小,看起来会很糟糕。这种情况可能在移动端显示一个更小的、聚焦到这个人的肖像图会更好。<picture> 元素允许我们这样实现。

回到我们最初的例子 not-responsive.html,我们有一张图片需要进行美术设计:

HTMLCopy to Clipboard

<img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva" />

让我们改用 <picture>!就像 <video> 和 <audio><picture> 元素包含了一些 <source> 元素,它使浏览器在不同资源间做出选择,紧跟着的是最重要的 <img> 元素。responsive.html 的代码如下:

HTMLCopy to Clipboard

<picture>
  <source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg" />
  <source media="(min-width: 800px)" srcset="elva-800w.jpg" />
  <img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva" />
</picture>
  • <source> 元素包含一个 media 属性,这一属性包含一个媒体条件——就像第一个 srcset 例子,这些条件来决定哪张图片会显示——第一个条件返回真,那么就会显示这张图片。在上述示例中,如果视窗的宽度为 799px 或更少,第一个 <source> 元素的图片就会显示。如果视窗的宽度是 800px 或更大,就显示第二张图片。
  • srcset 属性包含要显示图片的路径。请注意,正如我们在 <img> 上面看到的那样,<source> 可以使用引用多个图像的 srcset 属性,还有 sizes 属性。所以你可以通过一个 <picture> 元素提供多个图片,不过也可以给每个图片提供多分辨率的图片。实际上,你可能不想经常做这样的事情。
  • 在任何情况下,你都必须在 </picture> 之前正确提供一个 <img> 元素以及它的 srcalt 属性,否则不会有图片显示。当媒体条件都不返回真的时候(你可以在这个例子中删除第二个 <source> 元素),它会显示默认图片;如果浏览器不支持 <picture> 元素时,它可以作为后备方案。

这样的代码允许我们在宽屏和窄屏上都能显示合适的图片,如下所示:

备注: 你应该仅仅当在需要美术设计的场景中使用 media 属性;当你使用 media 时,不要在 sizes 属性中也提供媒体条件。

为什么我们不用 CSS 或 JavaScript 来实现?

当浏览器开始加载一个页面,它会在主解析器开始加载和解析页面的 CSS 和 JavaScript 之前先下载(预加载)任意的图片。这种有用的机制总体上会减少页面加载时间,但是它对响应式图片没有帮助,所以需要类似 srcset 的实现方法。因为你不能先加载好 <img> 元素后,再用 JavaScript 检测可视窗口的宽度,如果觉得大小不合适,再动态地加载小的图片替换已经加载好的图片,这样的话,原始的图像已经被加载了,然后你又加载了小的图像,这反而更不“响应”了。