Skip to content
This page has been auto-translated and may contain errors.View in English

图片和媒体

docs.scrimba.com

网页的内容不仅仅是文字。照片、图表、插图、视频和音频也都是内容,HTML 对每种都有相应的元素。本章介绍的是将媒体放在网页上的标记:如何指向一个图片文件,如何为看不到图片的人描述它,以及如何为不同的屏幕提供正确的文件而不浪费用户的流量。

图片元素

你可以用**图片元素**(写作 <img>)在网页上放一张图片。它没有内容,也没有关闭标签。相反,你通过属性告诉它两件事:显示哪个文件,以及图片是什么。

html
<img src="golden-retriever.jpg" alt="一只金毛寻回犬坐在高草地里">

src 是源:图片文件的路径或网址。alt 是替代文本:用词语简要描述图片。如果图片无法加载,或者有人用屏幕阅读器听网页而不是看,他们会得到 alt 文本。所以写得就像你在电话里向朋友描述这张图片一样。

<img> 元素将一个外部文件拉到页面中。它是一个空元素,所以没有关闭标签;它需要的一切都在属性中。有两个是必需的:

html
<img src="/images/team-photo.jpg" alt="设计团队的五名成员在各自的办公桌前">

src 是文件的路径,相对于页面或一个绝对 URL。alt 是**替代文本**,当图片不显示或无法看到时代替图片的文字。

alt 写对是人们容易跳过而不应该跳过的部分。描述图片的内容和用途,而不是它的文件细节。"条形图显示销售额在2023年和2024年之间翻倍"告诉读者图表说的是什么;"chart.png"则什么都没说。保持在一句话以内,不要以"图片"开头,浏览器已经会说这是一个图片。

<img> 是一个空元素,默认情况下加载外部资源并将其内联放置于文本中。两个属性做真正的工作:src(资源 URL)和 alt(文本替代)。本节其余部分讲的是 alt,因为这是图片的可访问性和正确性真正所在的地方。

alt 属性不是标题,也不是文件的描述。它是替代:当图片不存在时浏览器在图片位置渲染的文本,以及**屏幕阅读器**(为看不到网页的人朗读网页的软件)读出来的文本而不是图片。测试是功能等价性。如果你删除了图片,并把 alt 文本放进了文本流,句子是否仍然有意义并传达相同的信息?好的 alt 通过这个测试;"photo1"不行。

由此衍生出两条规则。首先,描述用途,不描述像素:搜索按钮内的放大镜图标的 alt="搜索",而不是 alt="放大镜",因为它在页面上的工作是动作,不是画图。其次,装饰性图片使用空 alt。当图片不增加信息时,一个背景装饰或分割线,写 alt="" 引号之间什么都不写。这和省略 alt 不一样。空的 alt 告诉辅助技术"跳过这个,它没有意义",而缺少的 alt 让屏幕阅读器退而求其次读文件名,这比什么都没有还糟。

html
<!-- 有意义的:描述它传达的是什么 -->
<img src="revenue-2024.png" alt="2024年全年收入从120万增长到240万">

<!-- 装饰性的:空alt,所以辅助技术跳过它 -->
<img src="corner-flourish.svg" alt="">
Juno图片元素 一张图片需要两样东西:src,即要显示的文件,和 alt,用词语描述图片。写 alt 就像你在电话里告诉某人照片里有什么。这是最容易被跳过的部分,也是最重要的部分。
Juno图片元素<img> 是一个空元素:没有关闭标签,一切都在属性里。描述图片说的是什么,而不是文件,永远不要以 Image of 开头,浏览器已经知道它是一个图片。图表的 alt 应该告诉某人这个图表在说什么数字。
Juno图片元素 好的 alt 是替代,不是标题:把它放进句子里意思应该保存下来。描述工作,不是画图,所以搜索图标读作 搜索。而且 alt="" 用于装饰性图片是真实的选择,它告诉屏幕阅读器跳过,而缺少 alt 会让它大声读出文件名。

响应式图片

一张在笔记本电脑上看起来很清晰的照片对手机来说可能大得多。把那个完整尺寸的文件发送到小屏幕会浪费访客的流量并拖慢页面。HTML 让你可以提供浏览器同一张图片的几个版本,让它选择合适的。

你一开始不需要为每张图片都这样做。一个带有合理文件的 <img> 就很好。但知道这个想法存在是有帮助的:同一张照片可以有多种尺寸,浏览器来选择。

html
<img src="beach-800.jpg" alt="海浪卷上安静的沙滩,夕阳西下">

**响应式图片**让浏览器根据屏幕选择文件。与其硬编码一个源,你可以用 srcset 列出多个,并用 sizes 描述图片会显示多宽。浏览器会计算并下载最佳匹配。

html
<img
  src="beach-800.jpg"
  srcset="beach-400.jpg 400w, beach-800.jpg 800w, beach-1600.jpg 1600w"
  sizes="(max-width: 600px) 100vw, 50vw"
  alt="海浪卷上安静的沙滩,夕阳西下">

srcset 中,每一项将一个文件与其实际像素宽度配对(400w 表示文件宽 400 像素)。在 sizes 中,你告诉浏览器图片会占多少空间:这里在屏幕宽度不超过 600 像素时它填满整个视口宽度(100vw),否则填一半宽度(50vw)。src 保留作为旧浏览器的后备。注意 alt 写一次,适用于每个源,因为它们都是同一张图片。

当你需要的不仅仅是大小交换时,求助于 <picture>。它包装几个 <source> 元素和一个 <img>,浏览器使用第一个匹配的 <source>。这处理艺术指导,在不同宽度下提供裁剪不同的图片,以及现代文件格式:

html
<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="两个骑手在破晓时分爬上山路">
</picture>

浏览器从上到下读,选择第一个它能理解的格式,如果没有匹配则回到普通 <img><img> 在里面是必需的;它是实际渲染的东西,也是 alt 所在的地方。

响应式图片解决分辨率切换问题:同一张图片,不同像素尺寸用于不同显示,由浏览器在下载前选择,所以没人会为看不到的像素付费。有两个工具,它们回答不同的问题。

srcsetsizes 回答"哪个分辨率?"。你给浏览器一组候选文件,每个用 w 描述符标记其固有宽度(像素),还有一个 sizes 值告诉它图片在各种断点会渲染多宽。断点是布局改变的屏幕宽度阈值。浏览器将你的 sizes 提示与设备的像素密度结合,选择最小的仍然看起来清晰的文件。

html
<img
  src="product-800.jpg"
  srcset="product-400.jpg 400w, product-800.jpg 800w, product-1200.jpg 1200w"
  sizes="(max-width: 700px) 100vw, 350px"
  alt="从正面展示的皮质背包">

<picture> 元素回答一个不同的问题:"完全用哪个源?"。它用于文件本身应该改变的情况,而不仅仅是其缩放。两个常见原因。艺术指导,其中宽横幅在窄屏幕上裁剪为高竖幅以保持主体可见,需要不同的图像文件,而不是一个文件缩小。还有格式协商,其中你提供现代格式和后备,需要浏览器按其能否解码来选择。

html
<picture>
  <source media="(max-width: 600px)" srcset="hero-portrait.avif" type="image/avif">
  <source media="(max-width: 600px)" srcset="hero-portrait.jpg">
  <source srcset="hero-wide.avif" type="image/avif">
  <img src="hero-wide.jpg" alt="厨师在繁忙的厨房里装盘">
</picture>

顺序很重要:浏览器取第一个满足其 mediatype<source>,所以把你最偏好和最受限的选项放在前面。尾部的 <img> 是强制的,是页面实际渲染的元素;源上的 srcsetsizes 供给它,但 altwidthheight 和加载行为都属于内部那个 <img>

Juno响应式图片 同一张照片可以有几个尺寸,浏览器可以选择合适屏幕的那个,这样手机就不会下载笔记本电脑大小的文件。你在第一天不需要这个;一个普通的 <img> 就很好。当页面在移动设备上开始变得沉重时,这个选项就在那里。
Juno响应式图片 当你想让浏览器选择大小时使用 srcsetsizes,当你想交换文件本身时使用 <picture>,用于不同的裁剪或现代格式。<picture> 内的 <img> 是必需的,也是 alt 所在的地方。写一次 alt;每个源都是同一张图片。
Juno响应式图片 两个不同的工作:srcsetsizes 选择分辨率,<picture> 为艺术指导或格式协商选择一个完整的源。源从上到下读,第一个匹配赢,所以最受限的放在前面。所有渲染的东西仍然挂在内部 <img> 上,所以那是 alt 和大小所在的地方。

视频和音频

HTML 可以不需要任何插件就播放视频和音频。对于视频,你使用 <video> 元素;对于音频,使用 <audio>。添加 controls 属性,浏览器就免费给你一个播放按钮、时间轴和音量控制。

html
<video src="tutorial.mp4" controls></video>

<audio src="podcast-episode.mp3" controls></audio>

与图片不同,这些有关闭标签,因为你可以在开启标签和关闭标签之间放置后备文本或额外设置。最重要的是记住早期的一件事:始终包括 controls,否则访客无法按播放。

<video><audio> 元素在页面中嵌入原生媒体播放器。controls 属性显示浏览器的内置播放、暂停、查找和音量界面;没有它,根本没有控制。

html
<video src="product-demo.mp4" controls width="640" poster="demo-cover.jpg"></video>

一些属性值得占用位置。poster 设置视频播放前显示的静止图像,所以播放器不是一个黑框。width 预留播放器的大小。你也可以添加 autoplayloopmuted,尽管大多数浏览器只在视频也被 muted 时才允许 autoplay,所以这两个一起出现。

要提供一个以上的文件格式,放下 src 并改为在内部列出 <source> 元素。浏览器播放第一个它能播放的:

html
<video controls width="640" poster="demo-cover.jpg">
  <source src="product-demo.webm" type="video/webm">
  <source src="product-demo.mp4" type="video/mp4">
  您的浏览器无法播放此视频。
</video>

源之后的文本是后备内容,只在浏览器无法播放其中任何一个时才显示。<audio> 工作方式相同,具有相同的 controls<source> 模式,减去 posterwidth 等视觉属性。

<video><audio> 嵌入浏览器的原生媒体管道,解码、缓冲和内置播放器 UI,无需第三方插件。两者都接受 controls(显示原生 UI),两者都接受多个 <source> 子元素,所以你可以提供几个编码器(视频或音频文件压缩的格式)并让浏览器选择第一个它能解码的。

html
<video controls width="640" height="360" poster="demo-cover.jpg" preload="metadata">
  <source src="demo.webm" type="video/webm">
  <source src="demo.mp4" type="video/mp4">
  <track kind="captions" src="demo-captions.en.vtt" srclang="en" label="English" default>
  您的浏览器无法播放此视频。
</video>

两个生产问题主导这里。第一是可访问性,让看不到或听不到的人能使用媒体。这就是 <track> 的用途:它附加一个定时文本文件(通常是 WebVTT 格式,一种纯文本字幕格式,文件以 .vtt 结尾)到媒体。kind="captions" 为聋子或无声环境下的观众提供言语和重要声音的文本版本,这是大多数在公共场所浏览的人。kind="subtitles" 将对话翻译成另一种语言。default 属性打开一个轨道而不让用户去寻找。没有字幕的视频会排除你的真实观众,字幕也帮助搜索引擎,它无法观看视频但可以阅读副本。

第二个问题是带宽。preload 控制浏览器在播放前如何急切地获取媒体:preload="none" 在用户按播放前不下载任何东西,preload="metadata" 只抓取时长和尺寸,preload="auto" 可能拉下整个文件。对于视口下方的任何东西,默认为 metadatanone,因为自动加载视频是页面能悄悄做的最重的事情之一。而同样的 autoplay 警告成立:浏览器阻止有声自动播放,所以自动播放的视频必须被 muted,这是字幕重要的另一个原因。

Juno视频和音频<video> 播放视频片段,<audio> 播放音频,不需要插件。添加 controls 否则没有播放按钮,访客会卡住。两者都有关闭标签,因为你可以在里面放设置和后备文本,不像图片。
Juno视频和音频 总是添加 controls,设置一个 poster 这样播放器不是一个黑矩形,并列出 <source> 元素以提供一个以上的格式。autoplay 只在视频是 muted 时才触发,所以这两个一起出现。音频是相同的模式但没有视觉属性。
Juno视频和音频 添加一个 <track> 带字幕;大多数人静音观看,搜索引擎读它们无法观看的文本。保持 preloadmetadatanone 用于视口下方的任何东西,自动加载视频是使页面沉重的最安静的方式之一。而有声自动播放被阻止,所以自动播放意味着静音,这是再一个添加字幕的理由。

大小调整、延迟加载和性能

当图片加载时,它可以推动页面其余部分移动。你在读一个段落,一张照片完成了上面的加载,突然文本跳了下去。这种跳动很烦人,你可以阻止它:用 widthheight 提前告诉浏览器图片的大小。

html
<img src="team-lunch.jpg" alt="团队在办公室阳台上一起共进午餐"
     width="800" height="600">

有了这些数字,浏览器在图片到达前预留正确的空间,所以图片到达时没有任何东西会跳。你给出文件的真实像素尺寸,CSS 仍然可以在屏幕上调整大小。

图片影响你作为用户感受的两件事:页面加载时的移动程度,以及它拉多少数据。HTML 给你两个属性。

设置 widthheight 防止**布局移位**,当图片加载时内容周围跳动。当你声明尺寸时,浏览器立即预留那个空间,而不是把图片折叠到零然后在文件到达一旦它的真实高度已知就展开它。

html
<img src="article-header.jpg" alt="一个繁忙新闻编辑室的俯视图"
     width="1200" height="675" loading="lazy">

loading="lazy" 属性告诉浏览器在读者即将滚动它进入视图之前不要下载图片。对于长页面中靠下的图片,那节省数据并加快首次绘制。一条规则:不要延迟加载访客首先看到的图片,在页面顶部。那个你想尽快加载,所以将 loading 保留在它之外(或设置 loading="eager")。

媒体通常是页面最重的部分,所以控制其加载的属性是性能控制,不是装饰。有三个重要的。

首先,累积布局移位,一个衡量页面加载时可见内容移动多少的度量。通常的原因是一个没有声明大小的图片:浏览器给它零高度,排列其下方的一切,然后一旦文件到达并其真实高度已知,就重排整个列。你通过提前给浏览器宽高比来防止这种情况。将 widthheight 设置为文件的真实像素尺寸,浏览器计算比率并预留正确的框,即使 CSS 调整显示:

html
<img src="feature.jpg" alt="横跨绿色田地的太阳能电池板"
     width="1600" height="900" loading="lazy" decoding="async">

你可以用 CSS 的 aspect-ratio 属性表达相同的意图;重点是比率必须在像素下载前可知。

其次,loading="lazy" 延迟离屏图片的下载直到读者接近它们,在长页面上减少初始有效载荷。关键的例外是你的 LCP 元素(最大内容绘制,不滚动就可见的最大图片或块,以及浏览器和搜索排名关注的度量)。延迟加载该图片延迟了指标实际测量的东西,所以视口上方的英雄应该急切加载。

第三,decoding="async" 让浏览器在主线程外解码图片,所以将压缩字节变成像素不会阻止其他渲染。对于不是屏幕上第一件事的图片,这是一个小的、安全的胜利。

格式是另一个杠杆。WebPAVIF 是现代图片格式,在相同视觉质量下压缩的远小于 JPEG 或 PNG;AVIF 通常在文件大小上赢,WebP 在浏览器支持和编码速度上赢。权衡是兼容性和工具,这正是用 type 源的 <picture> 被构建来管理的:首先提供 AVIF,其次 WebP,最后 JPEG 或 PNG 后备,每个浏览器得到它实际能解码的最好文件。

Juno大小调整、延迟加载和性能 给每张图片一个 widthheight,页面在照片加载时会停止跳动。使用文件的真实像素大小;CSS 仍然可以在屏幕上缩小它。这个习惯修复了最烦人的加载故障。
Juno大小调整、延迟加载和性能widthheight 预留空间所以当图片加载时什么都不移,loading="lazy" 延迟下载图片直到它们即将滚动进视图。不要延迟加载的那张图片是页面上的第一张;那张应该立即加载。
Juno大小调整、延迟加载和性能 声明 widthheight(或设置 aspect-ratio)所以浏览器预留框并布局停止跳动;比率只需在像素到达前可知。延迟加载除了视口上方的英雄外的一切,因为延迟加载你最大的可见图片会减慢监视它的指标。并通过带 JPEG 后备的 <picture> 提供 AVIF 或 WebP 所以每个浏览器都得到它能解码的最小文件。