使用现代图像格式:AVIF 和 WebP
已发表: 2022-03-10我们最近出版了 Addy 的图像优化一书,其中包含您需要了解的有关图像、如何压缩、提供和维护图像的所有信息。 现在,随附由 Addy 签名的手写个人信息。 跳转到目录并立即获取这本书。
图片是网络上最流行的资源类型,并且通常是最大的。 用户欣赏高质量的视觉效果,但需要注意尽可能高效地传递这些英雄图像、产品照片和猫表情包。
如果您正在针对 Web Vitals 进行优化,您可能有兴趣听到图像占网站最大内容绘制元素的约 42%。 以用户为中心的关键指标通常取决于页面上图像的大小、数量、布局和加载优先级。 这就是为什么我们的很多性能指南都在谈论图像优化。
一个 tl;dr 的建议可以在下面找到。
tl;博士
- 如果有损、低保真压缩是可以接受的并且节省带宽是第一要务,那么 AVIF 是一个可靠的首选。 假设编码/解码速度满足您的需求。
- WebP 得到更广泛的支持,可用于渲染不需要广色域或文本覆盖等高级功能的常规图像。
- AVIF 可能无法压缩非摄影图像以及 PNG 或无损 WebP。 对于高保真有损压缩,WebP 的压缩节省可能低于 JPEG。
- 如果 AVIF 和 WebP 都不可行,请考虑评估 MozJPEG(优化 JPEG 图像)、OxiPNG(非摄影图像)或 JPEG 2000(有损或无损摄影图像)。
- 通过
<picture>
的渐进式增强让浏览器按优先顺序选择第一个支持的格式。 当使用接受标头和内容协商(例如自动格式和质量)可以提供最佳图像的图像 CDN 时,此实现大大简化。
为什么我们需要现代格式?
在网络上渲染图像时,我们有相当广泛的图像格式可供选择。 图像格式的本质区别在于用于编码或解码每种图像类型的图像编解码器是不同的。 图像编解码器表示用于将图像压缩和编码为特定文件类型并将其解码以显示在屏幕上的算法。
评估编解码器
您可以根据不同的参数评估哪种图像格式适合您。
- 压缩
编解码器的效率主要可以通过它可以实现多少压缩来衡量。 实现的压缩是相关的,因为压缩越高,文件大小越小,并且在网络上传输图像所需的数据越少。 较小的文件大小直接影响页面的最大内容绘制 (LCP) 指标,因为页面所需的图像资源加载速度更快。 - 质量
理想情况下,压缩不应导致图像数据丢失; 它应该是无损的。 导致图像数据丢失,从而降低图像质量的压缩格式被称为有损压缩格式。 您可以使用 DSSIM 或 ssimulacra 等工具来测量图像之间的结构相似性并判断质量损失是否可以接受。 - 编码/解码速度
复杂的压缩算法可能需要更高的处理能力来编码/解码图像。 这可能会因编码是提前(静态/构建)还是即时(按需)完成而变得复杂。 虽然在静态图像的情况下编码可能是一次性的,但浏览器仍然必须在渲染图像之前对其进行解码。 复杂的解码过程会减慢图像的渲染速度。
压缩程度、图像质量和解码速度是比较 Web 图像性能时要考虑的关键因素。 特定用例可能需要支持其他功能的图像格式,例如:
- 软件支持:一种图像格式可能表现得非常好,但如果浏览器、CDN 和其他图像处理工具无法识别它,它就毫无用处。
- Web 上的某些图像(例如,GIF)可能需要动画支持。 但是,理想情况下,您应该用视频替换此类图像。
- Alpha 透明度:使用 Alpha 通道创建具有不同不透明度级别的图像的能力。 (例如,具有透明背景的 PNG 图像)
- 它应该支持高动态范围(HDR)成像和宽色域。
- 渐进式解码以逐渐加载图像允许用户在图像被细化之前获得图像的合理预览。
- 深度图可让您将效果应用到图像的前景或背景。
- 具有多个重叠图层的图像,例如文本叠加层、边框等。
提示:在评估现代格式的质量、压缩和微调时,Squoosh.app 执行视觉并排比较的能力很有帮助。 放大可以让您更好地了解格式在哪里表现出块状或边缘伪影以进行权衡。
老卫士:JPEG和PNG
25 年来,JPEG 一直是最广泛支持的图像格式。 经典的 JPEG 编码器导致相对较弱的压缩,而更现代的 JPEG 编码工作(如 MozJPEG)改善了压缩,但不如现代格式优化。 JPEG 也是一种有损压缩格式。 虽然 JPEG 的解码速度非常出色,但它缺乏现代、引人注目的网站上图像所需的其他理想功能。 它不支持图像、动画、深度图或叠加层的透明度。
JPEG 最适用于照片,而 PNG 则适用于其他静止图像。 PNG 是一种无损格式,可以支持 alpha 透明度,但实现的压缩(尤其是对于照片)相当低。 根据所需的图像类型,JPEG 和 PNG 都被广泛使用。
因此,现代图像格式的目标是通过提供更好的压缩和灵活性来支持前面讨论的其他功能,从而克服 JPEG 和 PNG 的限制。 有了这个背景,让我们看看 AVIF 和 WebP 必须提供什么。
AVIF
AV1 图像文件格式 (AVIF) 是一种用于存储静止图像和动画图像的开源图像格式。 它于 2019 年 2 月由开放媒体联盟 (AOMedia) 发布。 AVIF 是流行的 AV1 视频格式的图像版本。 目标是开发一种新的开源视频编码格式,它既是最先进的又是免版税的。
AVIF 福利
AVIF 支持非常有效的有损和无损压缩,以在压缩后生成高质量的图像 AVIF 的压缩效果比当今网络上大多数流行的格式(JPEG、WebP、JPEG 2000 等)要好得多。 图像最多可以比具有相似视觉质量的 JPEG 小十倍。 一些测试表明,与具有相似感知质量的 JPEG 相比,AVIF 可节省 50% 的文件大小。 请注意,在某些情况下,WebP 无损可能比 AVIF 无损更好,因此请务必手动评估。
在这里,您可以看到 JPEG 图像与其使用 Squoosh 应用程序转换的相应(有损)AVIF 图像之间的大小比较:
除了卓越的压缩,AVIF 还提供以下功能:
- AVIF 通过存储在图像序列中的多层图像支持动画、实时照片等。
- 它为 JPEG 有限制的图形元素、徽标和信息图表提供了更好的支持。
- 它提供比 JPEG 更好的无损压缩。
- 它支持 12 位色深,可实现高动态范围 (HDR) 和宽色域 (WCG) 图像,具有更好的明暗色调和更广的亮度范围。
- 它包括对单色图像和多通道图像的支持,包括使用 alpha 通道的透明图像。
比较格式
为了更好地了解不同格式在质量和压缩方面的差异,我们可以直观地比较图像并评估差异。
评估质量和压缩
我们将使用 Squoosh 对每种格式的默认高质量输出设置开始对 JPEG、WebP 和 AVIF 的质量评估——故意不调整以模仿新用户的使用体验。 提醒一下,您应该旨在评估最适合您需求的质量配置和格式。 如果您的时间不够,图像 CDN 会自动执行其中的一些操作。
在第一个测试中,对一张 560KB 的日落照片(具有许多纹理)进行编码会生成一张在视觉和感知上都非常相似的图像。 输出大小为 289KB (JPEG@q75)、206KB (WebP@q75) 和 101KB (AVIF@q30) — 压缩节省高达 81%。
很棒的东西,但让我们更深入地挖掘。
存在用于比较不同图像格式(例如,DSSIM、simulacra)之间差异的各种工具。 使用这些工具,您可以在评估 JPEG 到 WebP 或 WebP 到 AVIF 时近似比较质量设置。 下面是相同质量的编码图像,以 JPEG 的 70% 质量为目标。 输出为 323KB (JPEG)、214KB (WebP@q75) 和 117KB (AVIF@60) — 大小比信任默认值稍大,但压缩效果仍然显着。
我们还可以查看每种格式的较低质量,这确实是 WebP 和 AVIF 的亮点。 这是 JPEG@q10 (35KB)、WebP@q1 (35KB)、AVIF@q17 (36KB) — 与 JPEG 相比,WebP 的块状伪影明显更少,而 AVIF 的块状伪影更少,图像中的关键细节更清晰.
注意:这张日落是更高分辨率的图像 ( 2400
× 1595
),在 2 倍屏幕上,质量可能会低得多,但仍然看起来很清晰,这取决于用户与图像的交互方式(例如,他们捏合和缩放的程度)。
有关 JPEG 和 AVIF 之间差异的更极端示例,我们可以查看 Kodak 数据集(由 Netflix 评估)中的一个示例,将 20KB 的 JPEG (4:4:4) 与 AVIF (4:4:4) 进行比较19.8KB。 请注意 JPEG 如何在天空和屋顶上有可见的块状伪影。 AVIF 明显更好,包含更少的块状伪影。 然而,屋顶上有一定程度的纹理损失和一些模糊。 考虑到整体压缩系数为 59 倍,它仍然令人印象深刻。
接下来,让我们评估具有许多精细细节、纹理和云中低对比度区域的海滩图像的质量。 我们将原始文件(482KB)与 JPEG、WebP 和 AVIF 在文件大小限制为 45KB(没有高级调整)的情况下可以生成的文件进行比较——使用 Squoosh; 这适用于 JPEG (MozJPEG) 质量为 50%、WebP 为 54% 和 AVIF 为 36%。
JPEG 在云层和水中具有块状伪影和可见的色带,而 WebP 和 AVIF 的这种块状可观察到的明显较少。 在我看来,AVIF 提供了三者中最流畅的体验。
说到纹理,我们还可以对 Netflix 的《巫师》海报(目标为 36KB)进行类似的低质量评估。 请注意 JPEG 的云中的块状和 WebP 的红色文本周围的一些模糊(仅支持 4:2:0 色度子采样,没有变通方法)。 AVIF 看起来最好,其次是 WebP。
最后,让我们看一张比以前的图像包含更多文本元素的照片——海报。 当我们降低质量并以相当小的尺寸(25KB)为目标时,我们可以观察到 JPEG 在文本周围有很强的色带和光晕。 边缘有明显的块状伪影。 WebP 避免了一定程度的阻塞,看起来越来越好。 与 JPEG 或 WebP 相比,AVIF 保留了锐利的边缘,从而产生了平滑的图像。
额外的格式与质量比较可用于摄影和插图。
AVIF 工具和支持
自 2019 年发布以来,对 AVIF 的支持大幅增加。 虽然之前没有直接的方法来创建或查看 AVIF 文件,但您现在可以使用可用的开源实用程序轻松地做到这一点。
浏览器中的 AVIF 图像
AVIF 于 2020 年 8 月在 Chrome 85 的桌面版 Chrome 中引入。它还支持适用于 Android 的 Chrome、适用于桌面的 Opera 和 Firefox,以及适用于 Android 的 Opera。
要在页面中包含 AVIF 图像,您可以将其添加为图像元素。 但是,不支持 AVIF 的浏览器无法呈现此图像。
<img src="/images/sky.avif" width="360" height="240" alt="a beautiful sky">
确保向所有浏览器提供至少一种受支持的图像格式的解决方法是将 AVIF 作为渐进增强应用。 有两种方法可以做到这一点。
渐进增强
- 使用
<picture>
元素
由于<picture>
允许浏览器跳过它们无法识别的图像,因此您可以按照您的偏好顺序包含图像。 浏览器选择它支持的第一个。
<picture> <source type="image/avif"> <source type="image/webp"> <img src="img/photo.jpg" alt="Description" width="360" height="240"> </picture>
- 使用内容协商
内容协商允许服务器根据浏览器支持的内容提供不同的资源格式。 支持特定格式的浏览器可以通过将格式添加到其接受请求标头来宣布它。 例如,Chrome 中图片的 Accept Request Header 是:
Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8
检查 fetch 事件处理程序是否支持 AVIF 的代码如下所示:
const hdrAccept = event.request.headers.get("accept");
const sendAVIF = /image\/avif/.test(hdrAccept);
您可以使用此值向客户端提供 AVIF 或任何其他默认格式。
为渐进增强创建标记可能令人生畏。 Image CDN 提供自动提供适合客户的最佳格式的选项。 但是,如果您不使用图像 CDN,则可以考虑使用 just-gimme-an-img 之类的工具。 此工具可以为具有不同格式和宽度的给定图像生成图片元素的标记。 它还使用 Squoosh 完全在客户端创建与标记相对应的图像。 注意:编码多种格式可能需要一段时间,所以你可能想在等待的时候喝杯咖啡。
注意:本文中多次提到图像 CDN。 CDN 服务器通常比原始服务器更靠近用户,并且可以具有更短的往返时间 (RTT),从而改善网络延迟。 也就是说,从不同来源提供服务可以增加往返次数并影响性能提升。 如果 CDN 服务于其他站点内容,这可能没问题,但如果有疑问,请进行试验和测量。
编码和解码 AVIF 文件
几个开源项目提供了不同的方法来编码/解码 AVIF 文件:
- 图书馆
Libaom 是由 AVIF 的创建者 AOMedia 维护的开源编码器和解码器。 该库不断更新新的优化,旨在降低编码 AVIF 的成本,特别是对于频繁加载或高优先级的图像。 Libavif 是用于 AVIF 的开源复用器和解析器,用于 Chrome 中用于解码 AVIF 图像。 您可以将 libavif 与 libaom 结合使用,从原始未压缩图像创建 AVIF 文件或从其他格式对其进行转码。 还有 Libheif,一种流行的 AVIF/HEIF 编码器/解码器和 Cavif。 感谢 Ben Morss,libgd 支持 AVIF,并且将于 11 月加入 PHP。 - Web 应用程序和桌面应用程序
Squoosh 是一款可让您使用不同图像压缩器的网络应用程序,它还支持 AVIF,使在线转换和创建.avif
文件变得相对简单。 在桌面上,GIMP 支持 AVIF 导出。 ImageMagick 和 Paint.net 也支持 AVIF,而 AVIF 的 Photoshop 社区插件也可用。 - JavaScript 库
- AVIF.js 是一个 AVIF polyfill,适用于尚不支持 AVIF 的浏览器。 它使用 Service Worker API 来拦截 fetch 事件并解码 AVIF 文件。
- Avif.io 是另一个 Web 实用程序,可以在客户端将文件从不同图像类型转换为 AVIF。 它使用 WebWorker 在浏览器中调用 Rust 代码。 转换器库使用 wasm-pack 编译为 WASM。
- Sharp 是一个 Node.js 模块,可以将标准格式的大图像转换为更小的 Web 友好图像,包括 AVIF 图像。
- 实用程序
图像转换或转换实用程序支持 AVIF 格式。 您可以使用 MP4Box 创建和解码 AVIF 文件。 - 在代码中
go-avif
使用libaom
为 Go 实现了一个 AVIF 编码器。 它带有一个名为avif
的实用程序,可以将 JPEG 或 PNG 文件编码为 AVIF。
任何有兴趣学习如何使用 Squoosh 创建 AVIF 图像或构建命令行编码器avifenc
的人都可以在提供 AVIF 文件的 codelab 中进行。
AVIF 和性能
由于更好的压缩,AVIF 可以减小图像的文件大小。 因此,AVIF 文件下载速度更快,占用的带宽更低。 这可以通过减少加载图像的时间来潜在地提高性能。
Lighthouse-best practice 审核现在认为 AVIF 图像压缩可以带来显着的改进。 它收集页面上的所有 BMP、JPEG 和 PNG 图像,将它们转换为 WebP 并估计 AVIF 文件大小。 该估计有助于 Lighthouse 在“以下一代格式提供图像”部分下报告潜在的节省。
Tim Vereecke 报告说,在将网站上的 1400 万张图像转换为使用真实用户监控 (RUM) 测量的 AVIF 后,节省了 25% 的字节并对 LCP(与 JPEG 相比)产生了积极影响。
AVIF 陷阱
目前AVIF最大的缺点是缺乏跨浏览器的统一支持。 将 AVIF 作为渐进增强引入有助于克服这一问题。 AVIF 不符合现代文件格式的理想标准的其他一些方面。
- 现代版本的 Chrome (Chrome 94+) 支持 AVIF 渐进式渲染,而旧版本不支持。 虽然在撰写本文时还没有可以轻松制作这些图像的编码器,但希望这种情况会有所改变。
- AVIF 图像需要更长的时间来编码和创建。 对于动态创建图像文件的站点来说,这可能是个问题。 但是,AVIF 团队正在努力提高编码速度。 Google 的 AVIF 贡献者也报告了一些不错的性能提升。 自 2021 年 1 月 1 日以来,AVIF 编码的转码时间提高了约 47%(这是速度 6,libavif 的当前默认值),并且在整个日历年中提高了 73%。 自 7 月以来,速度 9(动态编码)的转码时间也提高了 72%。
- 为显示解码 AVIF 图像也可能比其他编解码器占用更多的 CPU 功率,尽管较小的文件大小可以弥补这一点。
- 一些 CDN 默认不支持 AVIF 的自动格式模式,因为在第一次请求时生成它的速度仍然较慢。
WebP
我们已经多次提到 WebP,但让我们简要介绍一下它的历史。 谷歌在 2011 年创建了 WebP 格式,作为一种有助于加快网络速度的图像格式。 多年来,它已被广泛接受和采用,因为它能够将图像压缩到比 JPEG 和 PNG 更小的文件大小。 WebP 以可接受的视觉质量提供无损和有损压缩,并支持 alpha 通道透明度和动画。
有损 WebP 压缩基于 VP8 视频编解码器,并使用预测编码对图像进行编码。 它使用相邻像素块中的值来预测块中的值并仅对差异进行编码。 无损 WebP 图像是通过对图像应用多种转换技术进行压缩来生成的。
WebP 的好处
WebP 无损图像通常比 PNG 小 26%,WebP 有损图像比类似质量的 JPEG 图像小 25-34%。 动画支持也使它们成为 GIF 图像的绝佳替代品。 下图左侧为透明 PNG 图片,右侧为 Squoosh 应用生成的相应 WebP 图片,尺寸缩小 26%。
此外,WebP 还提供其他好处,例如:
- 透明度
WebP 有一个无损的 8 位透明通道,其字节数仅比 PNG 多 22%。 它还支持有损 RGB 透明度,这是 WebP 独有的功能。 - 元数据
WebP 文件格式支持 EXIF 照片元数据和可扩展元数据平台 (XMP) 数字文档元数据。 它还可能包含 ICC 颜色配置文件。 - 动画
WebP 支持真彩色动画图像。
注意:在上述透明的、类似矢量的图像的情况下,与光栅格式相比,优化的 SVG 最终可能会提供更清晰、更小的文件。
WebP 工具和支持
多年来,Google 以外的生态系统都采用了 WebP,并且有许多工具可用于创建、查看和加载 WebP 文件。
提供和查看 WebP 文件
当今几乎所有主流浏览器的最新版本都支持 WebP。
如果开发人员希望将来在其他浏览器上提供 WebP,他们可以使用<picture>
元素或请求标头来实现,如 AVIF 部分所示。
图像内容交付网络 (CDN) 还支持响应式图像,根据浏览器支持自动选择 WebP 或 AVIF 中的图像格式。 WebP 插件可用于其他流行的堆栈,如 WordPress、Joomla、Drupal 等。从 WordPress 5.8 开始,WordPress 核心也提供了对 WebP 的初始支持。
您可以通过在支持 WebP 的浏览器中打开它们来轻松查看它们。 此外,您还可以使用附加组件在 Windows 和 macOS 上预览它们。 安装 WebP 的 Quick Look 插件 ( qlImageSize
) 将允许您使用 Quick Look 实用程序预览 WebP 文件。 WebP 团队已经为 Windows、macOS 和 Linux 的 WebP 编解码器发布了预编译的库和实用程序。 在 Windows 上使用这些可以让您在文件资源管理器或 Windows 照片查看器中预览 WebP 图像。
将图像转换为 WebP
除了 WebP 团队提供的库之外,还有一些免费、开源和商业的图像编辑工具支持 WebP。
实用程序:
与 AVIF 一样,Squoosh 也可以在线将文件转换为 WebP,如上一节所示。 XnConvert 是一个实用程序,您可以安装在桌面上以转换不同的图像格式,包括 WebP。 XnConvert 还可以帮助剥离和编辑元数据、裁剪和调整大小、亮度和对比度、自定义颜色深度、模糊和锐化、蒙版和水印以及其他转换。
Node.js 模块:
Imagemin 是一个流行的图像缩小模块,带有一个用于将图像转换为 WebP (imagemin-webp) 的附加组件。 该插件支持有损和无损 WebP 模式。
其他:
一些用于图像转换和处理的应用程序支持 WebP 格式。 其中包括 Sketch、GIMP、ImageMagick 等。WebP 的 Photoshop 插件也可用。
WebP 生产使用
由于其优于 JPEG 和 PNG 的压缩优势,许多大公司在生产中使用 WebP 来降低成本并减少网页加载时间。 谷歌报告说,使用 WebP 比其他有损压缩方案节省 30-35%,每天处理 430 亿个图像请求,其中 26% 是无损压缩。
为了在数据价格昂贵的新兴市场获得庞大的用户群,Facebook 开始向 Android 用户提供 WebP 图像。 他们观察到,“与 JPG 相比,可节省 25% 到 35% 的数据,与 PNG 相比可节省 80%”。
WebP 陷阱
在早期,WebP 的一个重大缺点是缺乏浏览器和工具支持。 考虑到现代格式应理想支持的所有功能时,与 WebP 的权衡仍然很少。
- WebP 仅限于 8 位颜色精度。 因此,它无法支持 HDR/广色域图像。
- WebP 不支持没有色度二次采样的有损图像。 有损 WebP 仅适用于 8 位 YCbCr 4:2:0,而无损 WebP 则适用于 RGBA 格式。 这会影响具有精细细节、色彩纹理或彩色文本的图像。 请参阅下面的示例。
- 它不支持渐进式解码,但支持增量式解码。 这可以在一定程度上弥补这一点,但对渲染的影响可能会有所不同。
理想情况下,您应该从可用的最佳质量源文件生成 WebP 文件。 将不合格的 JPEG 转换为 WebP 的效率不是很高,因为您会损失两次质量。
概括
总结关于 JPEG、PNG、AVIF 和 WebP 四种格式的所有信息,并比较和量化上一节中介绍的优缺点,我们得出了下表。
注意:星数基于一般意见,可能因特定用例而异。
以下是参考此表时要考虑的一些关键点。
- 根据图像的保真度(质量),摄影和非摄影图像的压缩可能会进一步不同。 我们在此标出了总分。
- 您应该根据图像的用途选择质量和色度二次采样设置。 在网络上的大多数场景中,例如新闻、社交媒体和电子商务,中低保真度的图像可能是可以接受的。 图像档案、电影或摄影网站需要高保真图像。 在转换为另一种格式之前,您应该测试由于高保真压缩导致的实际节省。
- 缺乏渐进式解码支持和速度可能是编码/解码 AVIF 文件的问题。 对于具有平均大小图像的网站,由于压缩而节省的字节可以补偿速度和由于图像快速下载而缺少渐进式解码。
- 比较图像格式提供的压缩率时,请比较相同 DSSIM 下的文件大小。
- 编码时使用的质量设置对于不同的格式不必相同以产生相同质量的图像。 正如本文所建议的,以 60 质量设置编码的 JPEG 可能类似于质量设置为 50 的 AVIF 和质量设置为 65 的 WebP。
- 在比较格式时,仍需要进行广泛的研究来衡量对 LCP 的实际影响。
- 在此比较中,我们没有包括其他格式,例如 JPEG XL 和 HEIC。 JPEG XL 仍处于相对初级阶段,只有 Apple 设备支持 HEIC(而 Safari 不支持)。 版税和许可费使对 HEIC 的支持进一步复杂化。
AVIF 确实检查了大多数框,与 JPEG 或 PNG 相比,WebP 具有更好的支持并提供更好的压缩。 因此,在优化网站上的图像时,您无疑应该考虑 WebP 支持。 评估 AVIF 是否满足您的要求并将其作为渐进增强引入可以提供价值,因为该格式被不同的浏览器和平台采用。 通过质量比较工具和使用 AVIF 提高编码速度最终会变得更容易。
感谢 Leena Sohoni-Kasture 对本文的大力投入,以及 Patrick Meenan、Frank Galligan 和 Yoav Weiss 的评论。
一个惊人的笔记
今年早些时候,我们与 Addy 一起出版了一本全新的书,介绍了优化压缩、服务和维护图像的方式所需了解的所有内容,从而提高了性能。 我们在全球范围内免费运送这些书籍,如果您现在拿到这本书,您还将收到一张 Addy手写的明信片,上面有个人信息。
- 跳转到详情↓
- 下载免费 PDF 样本 (12MB)
- 印刷书籍的全球免费航空邮寄。
- 马上拿书。
打印 + 电子书
$ 44 .00质量精装。 全球免费送货。 100 天退款保证。
电子书
当然,无 DRM 。 ePUB、Kindle、PDF。
包含在 Smashing 会员资格中。
下载 PDF、ePUB、Kindle。
谢谢你砸! ️