停止手动编写 Srcset:Symfony 的终极图像解决方案
Source: Dev.to

解决 Symfony 中的图片问题:认识 PGI
Images are the heaviest part of the modern web. They cause slow page loads, frustrating Cumulative Layout Shift (CLS), and a nightmare developer experience when trying to implement truly responsive designs. If you’ve ever wrestled with complex “ tags or manually calculated srcset values for different breakpoints, you know the pain.
Enter PGI (Progressive Image Bundle) — the new standard for image handling in Symfony 6.4 and newer.
引子:为何 Core Web Vitals 改变了一切
Google 的 Core Web Vitals——尤其是 Largest Contentful Paint (LCP) 和 Cumulative Layout Shift (CLS)——已经彻底改变了我们构建网站的方式。仅仅“展示一张图片”已经不够了。你需要:
- 快速展示。
- 确保当图片最终出现时布局不会跳动。
对于许多 Symfony 开发者来说,在保持代码整洁的同时实现完美的 100/100 PageSpeed 分数似乎是一种权衡。要么花费数小时编写自定义响应式逻辑,要么妥协为“够用”的性能。PGI 的诞生就是为了解除这种权衡。
代码展示:从凌乱到精妙
传统 Twig
[Image: Hero image] }})
这仅仅是针对 一种 长宽比而言。
使用 PGI(受 Tailwind‑inspired 语法)
真实案例:6slov.sk
要看到 PGI 的实际效果,让我们以 6slov.sk 为例,观察它在不同设备上如何处理同一张图片。
不同设备上的表现
| 设备 | 行为 |
|---|---|
| 移动端 (sm) | 加载一个 正方形 (1:1) 裁剪,占据容器的全部宽度。 ![]() |
| 平板/桌面 (md+) | 自动切换为 横向 (16:9) 裁剪,占据网格的一半(6/12 列)。 ![]() |
渲染后的 HTML(干净且语义化)
PGI 生成一个单一的、已优化的 HTML 块,处理所有繁重的工作,包括 模糊占位符:

这里发生了什么?
| 语法 | 含义 |
|---|---|
sm:12@square | 在小屏幕上全宽,自动裁剪为 1:1。 |
md:6@landscape | 从中等断点起占半宽(6/12 列),自动裁剪为 16:9。 |
xl:[430x370] | 自定义布局的任意尺寸——PGI 直接在 sizes 属性中接受显式尺寸。 |
preload | PGI 将 注入,立即提升您的 LCP 分数。 |
PGI 中的“渐进式”:模糊预览体验
对用户而言,最令人满意的功能之一是内置的 Blurhash 支持。PGI 不会显示空白区域或通用的加载指示器,而是立即渲染出一张美观、超轻量的模糊图像版本。
这种 blur‑up 技术显著提升了 perceived performance:即使在慢速网络下,用户也能立刻看到布局和图像的上下文,而高分辨率版本则在后台加载。待加载完成后,高分辨率图像会平滑淡入,呈现出精致的使用体验。
技术深度解析:零 CLS 与 CSS 魔法
PGI 如何防止布局偏移?这不仅仅是添加 width 和 height 属性。PGI 利用现代 CSS aspect-ratio 和 CSS 变量。
当组件渲染时,它会根据你的 sizes 定义计算宽高比。随后,它会将图像包裹在一个容器中,预留出恰好的空间。即使图像是懒加载或加载缓慢,也不会出现内容跳动。
为引擎提供动力:LiipImagine 集成
PGI 并没有重新发明图像处理的轮子。相反,它站在巨人的肩膀上:LiipImagineBundle。默认情况下,PGI 可以将尺寸调整和过滤的繁重工作委托给 LiipImagine,让你充分利用其完整生态系统。
这种协同的最强大功能之一是 自动转换为 WebP 等现代格式。只需几行配置,即可确保 PGI 提供的每张图片不仅尺寸恰到好处,而且压缩效果最佳。
示例配置
# config/packages/liip_imagine.yaml
liip_imagine:
default_filter_set_settings:
format: webp
webp:
generate: true
# config/packages/progressive_image.yaml
progressive_image:
image_configs:
quality: 75
post_processors:
cwebp: { q: 30 }
通过使用 liip_imagine 装饰器,PGI 会自动将图片请求路由到 LiipImagine 的过滤系统。这意味着你可以继续使用所有已有的 Liip 过滤器,同时受益于 PGI 更强大的 Twig 语法和 Zero CLS 特性。
Source: …
底层揭秘:使其成为可能的配置
PGI 最受赞誉的特点之一是其灵活性。虽然开箱即用,但真正的威力在于配置。下面我们拆解 progressive_image.yaml 中最重要的部分:
# config/packages/progressive_image.yaml
progressive_image:
# 1. Responsive Strategy
responsive_strategy:
grid:
framework: tailwind # or bootstrap, or custom
ratios:
landscape: "16/9"
square: "1/1"
hero: "21/9"
# 2. Resolvers (Where are your images?)
resolvers:
public_files:
type: "filesystem"
roots: [ '%kernel.project_dir%/public' ]
assets:
type: "asset_mapper"
# 3. Transparent HTML Caching
image_cache_enabled: true
image_cache_service: "cache.app"
1. 响应式策略
这是 PGI 的“大脑”。通过告诉 Bundle 你使用 Tailwind 或 Bootstrap,它会自动知道每个断点的容器宽度。当你写 md:6 时,PGI 会查找 md 容器宽度,将其除以 2(6/12 列),并生成所需的精确图片尺寸。
2. 解析器:文件自由度
无论你把图片放在 public/ 目录,还是使用现代的 Symfony AssetMapper,PGI 都能找到它们。你甚至可以定义一个 chain 解析器,在多个位置搜索。这对正在迁移到新 Symfony 功能的项目来说是救星。
3. 性能优先:HTML 缓存
生成 Blurhash 和读取元数据需要 CPU 资源。PGI 通过 透明的 HTML 缓存 解决了这个问题。组件渲染一次后,最终的 HTML 会存入缓存。下次有人访问页面时,PGI 直接返回缓存的 HTML,省去所有 PHP 逻辑,瞬间响应。
兴趣点 (PoI) 裁剪
最酷的功能之一是“智能裁剪”。与其盲目从中心裁剪,你可以定义一个兴趣点:
这确保了图像中最重要的部分(例如人物的面部)始终保留在画面中,无论裁剪为方形、纵向还是横向比例。
为什么 PGI 应该出现在你的下一个项目中
PGI 不仅仅是一个包装器;它是 Symfony 的完整生态系统:
- 零配置: 安装后即可在 Bootstrap 或 Tailwind 中直接使用。
- 自动生成: 实时生成所有所需尺寸并进行缓存。
- LiipImagine 集成: 如需自定义过滤器时,可与现有工具良好协作。
- 透明缓存: 缓存生成的 HTML,避免在每次请求时重新计算元数据。
如果你正在构建现代 Symfony 应用,并且在乎 SEO、用户体验以及作为开发者的自我安宁,PGI 正是缺失的那块拼图。它已经为像 6slov.sk 这样的高性能站点提供动力,帮助它们实现近乎完美的 PageSpeed 分数。
准备提升你的 PageSpeed 吗?
在 GitHub 上查看 PGI 并加入向更快、更稳定的网络迈进的行列。



