图片
图片会对应用的性能产生很大影响。为了获得最佳效果,你应该通过执行以下操作来优化它们:
¥Images can have a big impact on your app’s performance. For best results, you should optimize them by doing the following:
生成最佳格式,如
.avif
和.webp
¥generate optimal formats like
.avif
and.webp
为不同的屏幕创建不同的尺寸
¥create different sizes for different screens
确保资源可以有效地缓存
¥ensure that assets can be cached effectively
手动执行此操作很繁琐。你可以使用多种技术,具体取决于你的需求和偏好。
¥Doing this manually is tedious. There are a variety of techniques you can use, depending on your needs and preferences.
Vite 的内置处理(Vite’s built-in handling)
¥Vite’s built-in handling
Vite 将自动处理导入的资源 用于提高性能。这包括通过 CSS url()
函数引用的资源。文件名将添加哈希值,以便可以缓存它们,并且小于 assetsInlineLimit
的资源将被内联。Vite 的资源处理最常用于图片,但也可用于视频、音频等。
¥Vite will automatically process imported assets for improved performance. This includes assets referenced via the CSS url()
function. Hashes will be added to the filenames so that they can be cached, and assets smaller than assetsInlineLimit
will be inlined. Vite’s asset handling is most often used for images, but is also useful for video, audio, etc.
<script>
import logo from '$lib/assets/logo.png';
</script>
<img alt="The project logo" src={logo} />
@sveltejs/enhanced-img
@sveltejs/enhanced-img
是在 Vite 内置资源处理之上提供的插件。它提供即插即用图片处理,可为较小的文件格式(如 avif
或 webp
)提供服务,自动设置图片的内在 width
和 height
以避免布局偏移,为各种设备创建多种尺寸的图片,并剥离 EXIF 数据以保护隐私。它将在任何基于 Vite 的项目中工作,包括但不限于 SvelteKit 项目。
¥@sveltejs/enhanced-img
is a plugin offered on top of Vite’s built-in asset handling. It provides plug and play image processing that serves smaller file formats like avif
or webp
, automatically sets the intrinsic width
and height
of the image to avoid layout shift, creates images of multiple sizes for various devices, and strips EXIF data for privacy. It will work in any Vite-based project including, but not limited to, SvelteKit projects.
作为构建插件,
@sveltejs/enhanced-img
只能在构建过程中优化位于你机器上的文件。如果你的图片位于其他地方(例如从数据库、CMS 或后端提供的路径),请阅读有关 从 CDN 动态加载图片 的信息。¥[!NOTE] As a build plugin,
@sveltejs/enhanced-img
can only optimize files located on your machine during the build process. If you have an image located elsewhere (such as a path served from your database, CMS, or backend), please read about loading images dynamically from a CDN.WARNING:
@sveltejs/enhanced-img
包是实验性的。它使用 1.0 之前的版本,并且可能会在每次小版本发布时引入重大更改。¥WARNING: The
@sveltejs/enhanced-img
package is experimental. It uses pre-1.0 versioning and may introduce breaking changes with every minor version release.
设置(Setup)
¥Setup
安装:
¥Install:
npm install --save-dev @sveltejs/enhanced-img
调整 vite.config.js
:
¥Adjust vite.config.js
:
import { function sveltekit(): Promise<Plugin<any>[]>
Returns the SvelteKit Vite plugins.
sveltekit } from '@sveltejs/kit/vite';
import { function enhancedImages(): Promise<Plugin[]>
enhancedImages } from '@sveltejs/enhanced-img';
import { function defineConfig(config: UserConfig): UserConfig (+3 overloads)
Type helper to make it easier to use vite.config.ts
accepts a direct
{@link
UserConfig
}
object, or a function that returns it.
The function receives a
{@link
ConfigEnv
}
object.
defineConfig } from 'vite';
export default function defineConfig(config: UserConfig): UserConfig (+3 overloads)
Type helper to make it easier to use vite.config.ts
accepts a direct
{@link
UserConfig
}
object, or a function that returns it.
The function receives a
{@link
ConfigEnv
}
object.
defineConfig({
UserConfig.plugins?: PluginOption[] | undefined
Array of vite plugins to use.
plugins: [
function enhancedImages(): Promise<Plugin[]>
enhancedImages(),
function sveltekit(): Promise<Plugin<any>[]>
Returns the SvelteKit Vite plugins.
sveltekit()
]
});
由于转换图片的计算成本,首次构建将花费更长时间。但是,构建输出将缓存在 ./node_modules/.cache/imagetools
中,以便后续构建速度更快。
¥Building will take longer on the first build due to the computational expense of transforming images. However, the build output will be cached in ./node_modules/.cache/imagetools
so that subsequent builds will be fast.
基本用法(Basic usage)
¥Basic usage
在你的 .svelte
组件中使用 <enhanced:img>
而不是 <img>
并使用 Vite 资源导入 路径引用图片文件:
¥Use in your .svelte
components by using <enhanced:img>
rather than <img>
and referencing the image file with a Vite asset import path:
<enhanced:img src="./path/to/your/image.jpg" alt="An alt text" />
在构建时,你的 <enhanced:img>
标签将被替换为由 <picture>
封装的 <img>
,提供多种图片类型和大小。只能在不损失质量的情况下缩小图片,这意味着你应该提供所需的最高分辨率图片 - 将为可能请求图片的各种设备类型生成较小的版本。
¥At build time, your <enhanced:img>
tag will be replaced with an <img>
wrapped by a <picture>
providing multiple image types and sizes. It’s only possible to downscale images without losing quality, which means that you should provide the highest resolution image that you need — smaller versions will be generated for the various device types that may request an image.
你应该以 2 倍分辨率为 HiDPI 显示器(又名视网膜显示器)提供图片。<enhanced:img>
将自动负责为较小的设备提供较小的版本。
¥You should provide your image at 2x resolution for HiDPI displays (a.k.a. retina displays). <enhanced:img>
will automatically take care of serving smaller versions to smaller devices.
如果你希望将样式添加到 <enhanced:img>
,则应添加 class
并以此为目标。
¥If you wish to add styles to your <enhanced:img>
, you should add a class
and target that.
动态选择图片(Dynamically choosing an image)
¥Dynamically choosing an image
你还可以手动导入图片资源并将其传递给 <enhanced:img>
。当你拥有一组静态图片并希望动态选择其中一个或 对它们进行迭代 时,这将非常有用。在这种情况下,你需要更新 import
语句和 <img>
元素,如下所示,以表明你希望处理它们。
¥You can also manually import an image asset and pass it to an <enhanced:img>
. This is useful when you have a collection of static images and would like to dynamically choose one or iterate over them. In this case you will need to update both the import
statement and <img>
element as shown below to indicate you’d like process them.
<script>
import MyImage from './path/to/your/image.jpg?enhanced';
</script>
<enhanced:img src={MyImage} alt="some alt text" />
你还可以使用 Vite 的 import.meta.glob
。请注意,你必须通过 自定义查询 指定 enhanced
:
¥You can also use Vite’s import.meta.glob
. Note that you will have to specify enhanced
via a custom query:
<script>
const imageModules = import.meta.glob(
'/path/to/assets/*.{avif,gif,heif,jpeg,jpg,png,tiff,webp,svg}',
{
eager: true,
query: {
enhanced: true
}
}
)
</script>
{#each Object.entries(imageModules) as [_path, module]}
<enhanced:img src={module.default} alt="some alt text" />
{/each}
内在维度(Intrinsic Dimensions)
¥Intrinsic Dimensions
width
和 height
是可选的,因为它们可以从源图片中推断出来,并且在预处理 <enhanced:img>
标签时会自动添加。使用这些属性,浏览器可以保留正确的空间量,从而防止 布局移位。如果你想使用不同的 width
和 height
,你可以使用 CSS 设置图片样式。由于预处理器为你添加了 width
和 height
,如果你希望自动计算其中一个维度,则需要指定:
¥width
and height
are optional as they can be inferred from the source image and will be automatically added when the <enhanced:img>
tag is preprocessed. With these attributes, the browser can reserve the correct amount of space, preventing layout shift. If you’d like to use a different width
and height
you can style the image with CSS. Because the preprocessor adds a width
and height
for you, if you’d like one of the dimensions to be automatically calculated then you will need to specify that:
<style>
.hero-image img {
width: var(--size);
height: auto;
}
</style>
srcset 和 sizes(srcset and sizes)
¥srcset
and sizes
如果你有一个大图片,例如占据设计宽度的英雄图片,你应该指定 sizes
,以便在较小的设备上请求较小的版本。例如如果你有一个 1280px 的图片,你可能需要指定类似以下内容:
¥If you have a large image, such as a hero image taking the width of the design, you should specify sizes
so that smaller versions are requested on smaller devices. E.g. if you have a 1280px image you may want to specify something like:
<enhanced:img src="./image.png" sizes="min(1280px, 100vw)"/>
如果指定了 sizes
,<enhanced:img>
将为较小的设备生成小图片并填充 srcset
属性。
¥If sizes
is specified, <enhanced:img>
will generate small images for smaller devices and populate the srcset
attribute.
自动生成的最小图片宽度为 540px。如果你想要更小的图片或想要指定自定义宽度,可以使用 w
查询参数执行此操作:
¥The smallest picture generated automatically will have a width of 540px. If you’d like smaller images or would otherwise like to specify custom widths, you can do that with the w
query parameter:
<enhanced:img
src="./image.png?w=1280;640;400"
sizes="(min-width:1920px) 1280px, (min-width:1080px) 640px, (min-width:768px) 400px"
/>
如果没有提供 sizes
,则会生成 HiDPI / Retina 图片和标准分辨率图片。你提供的图片应该是你希望显示的分辨率的 2 倍,以便浏览器可以在具有高 设备像素比 的设备上显示该图片。
¥If sizes
is not provided, then a HiDPI/Retina image and a standard resolution image will be generated. The image you provide should be 2x the resolution you wish to display so that the browser can display that image on devices with a high device pixel ratio.
每个图片转换(Per-image transforms)
¥Per-image transforms
默认情况下,增强图片将转换为更高效的格式。但是,你可能希望应用其他转换,例如模糊、质量、展平或旋转操作。你可以通过附加查询字符串来运行每个图片的转换:
¥By default, enhanced images will be transformed to more efficient formats. However, you may wish to apply other transforms such as a blur, quality, flatten, or rotate operation. You can run per-image transforms by appending a query string:
<enhanced:img src="./path/to/your/image.jpg?blur=15" alt="An alt text" />
查看 imagetools repo 以获取完整的指令列表。
¥See the imagetools repo for the full list of directives.
从 CDN 动态加载图片(Loading images dynamically from a CDN)
¥Loading images dynamically from a CDN
在某些情况下,图片在构建时可能无法访问 - 例如,它们可能位于内容管理系统或其他地方。
¥In some cases, the images may not be accessible at build time — e.g. they may live inside a content management system or elsewhere.
使用内容分发网络 (CDN) 可以让你动态优化这些图片,并在大小方面提供更大的灵活性,但它可能涉及一些设置开销和使用成本。根据缓存策略,浏览器可能无法使用资源的缓存副本,直到从 CDN 收到 304 响应。构建 HTML 以目标 CDN 允许使用 <img>
标签,因为 CDN 可以根据 User-Agent
标头提供适当的格式,而构建时优化必须生成具有多个来源的 <picture>
标签。最后,一些 CDN 可能会延迟生成图片,这可能会对流量低且图片频繁更改的站点产生负面性能影响。
¥Using a content delivery network (CDN) can allow you to optimize these images dynamically, and provides more flexibility with regards to sizes, but it may involve some setup overhead and usage costs. Depending on caching strategy, the browser may not be able to use a cached copy of the asset until a 304 response is received from the CDN. Building HTML to target CDNs allows using an <img>
tag since the CDN can serve the appropriate format based on the User-Agent
header, whereas build-time optimizations must produce <picture>
tags with multiple sources. Finally, some CDNs may generate images lazily, which could have a negative performance impact for sites with low traffic and frequently changing images.
CDN 通常可以在不需要任何库的情况下使用。但是,有许多支持 Svelte 的库可以简化这一过程。@unpic/svelte
是一个与 CDN 无关的库,支持大量提供商。你还可能会发现特定的 CDN(如 Cloudinary)具有 Svelte 支持。最后,一些支持 Svelte 的内容管理系统 (CMS)(例如 Contentful、Storyblok 和 Contentstack)内置了对图片处理的支持。
¥CDNs can generally be used without any need for a library. However, there are a number of libraries with Svelte support that make it easier. @unpic/svelte
is a CDN-agnostic library with support for a large number of providers. You may also find that specific CDNs like Cloudinary have Svelte support. Finally, some content management systems (CMS) which support Svelte (such as Contentful, Storyblok, and Contentstack) have built-in support for image handling.
图标(Icons)
¥Icons
使用图标的好方法是纯粹在 CSS 中定义它们。Iconify 提供了大量图标 可通过以下方式获得 CSS。
¥A great way to use icons is to define them purely in CSS. Iconify offers a huge set of icons available via CSS.
对于在 .svelte
文件中定义的图标,建议避免使用为每个图标提供 .svelte
文件的库。这些库可以有数千个 .svelte
文件,这确实会减慢 Vite 的依赖优化速度。如果通过伞形导入和子路径导入 如 vite-plugin-svelte
FAQ 中所述 导入图标,这可能会变得特别病态。
¥For icons defined in .svelte
files, it is recommended to avoid libraries that provide a .svelte
file per icon. These libraries can have thousands of .svelte
files which really slow down Vite’s dependency optimization. This can become especially pathological if the icons are imported both via an umbrella import and subpath import as described in the vite-plugin-svelte
FAQ.
最佳实践(Best practices)
¥Best practices
对于每种图片类型,请使用上面讨论的解决方案中的适当解决方案。你可以在一个项目中混合搭配所有三种解决方案。例如,你可以使用 Vite 的内置处理为
<meta>
标签提供图片,使用@sveltejs/enhanced-img
在你的主页上显示图片,并以动态方式显示用户提交的内容。¥For each image type, use the appropriate solution from those discussed above. You can mix and match all three solutions in one project. For example, you may use Vite’s built-in handling to provide images for
<meta>
tags, display images on your homepage with@sveltejs/enhanced-img
, and display user-submitted content with a dynamic approach.无论你使用哪种图片优化类型,都考虑通过 CDN 提供所有图片。CDN 通过在全球范围内分发静态资源的副本来减少延迟。
¥Consider serving all images via CDN regardless of the image optimization types you use. CDNs reduce latency by distributing copies of static assets globally.
你的原始图片应具有良好的质量/分辨率,并且应具有 2 倍的显示宽度,以服务于 HiDPI 设备。图片处理可以在服务较小的屏幕时缩小图片尺寸以节省带宽,但发明像素来放大图片尺寸会浪费带宽。
¥Your original images should have a good quality/resolution and should have 2x the width it will be displayed at to serve HiDPI devices. Image processing can size images down to save bandwidth when serving smaller screens, but it would be a waste of bandwidth to invent pixels to size images up.
对于比移动设备宽度大得多的图片(大约 400px),例如占据页面设计宽度的英雄图片,请指定
sizes
,以便在较小的设备上提供较小的图片。¥For images which are much larger than the width of a mobile device (roughly 400px), such as a hero image taking the width of the page design, specify
sizes
so that smaller images can be served on smaller devices.对于重要的图片,例如 最大内容绘制 (LCP) 图片,请设置
fetchpriority="high"
并避免使用loading="lazy"
以尽早优先加载。¥For important images, such as the largest contentful paint (LCP) image, set
fetchpriority="high"
and avoidloading="lazy"
to prioritize loading as early as possible.为图片提供容器或样式,使其受到约束,并且在页面加载时不会跳来跳去,从而影响你的 累积布局偏移 (CLS)。
width
和height
帮助浏览器在图片仍在加载时保留空间,因此@sveltejs/enhanced-img
将为你添加width
和height
。¥Give the image a container or styling so that it is constrained and does not jump around while the page is loading affecting your cumulative layout shift (CLS).
width
andheight
help the browser to reserve space while the image is still loading, so@sveltejs/enhanced-img
will add awidth
andheight
for you.始终提供良好的
alt
文本。如果你不这样做,Svelte 编译器会警告你。¥Always provide a good
alt
text. The Svelte compiler will warn you if you don’t do this.不要在
sizes
中使用em
或rem
,并更改这些度量的默认大小。当在sizes
或@media
查询中使用时,em
和rem
都被定义为用户的默认font-size
。对于像sizes="(min-width: 768px) min(100vw, 108rem), 64rem"
这样的sizes
声明,如果 CSS 更改,控制图片在页面上的布局方式的实际em
或rem
可能会有所不同。例如,不要执行类似html { font-size: 62.5%; }
的操作,因为浏览器预加载器保留的插槽现在最终会大于创建 CSS 对象模型后的实际插槽。¥Do not use
em
orrem
insizes
and change the default size of these measures. When used insizes
or@media
queries,em
andrem
are both defined to mean the user’s defaultfont-size
. For asizes
declaration likesizes="(min-width: 768px) min(100vw, 108rem), 64rem"
, the actualem
orrem
that controls how the image is laid out on the page can be different if changed by CSS. For example, do not do something likehtml { font-size: 62.5%; }
as the slot reserved by the browser preloader will now end up being larger than the actual slot of the CSS object model once it has been created.