Responsive Grid & Ratios
Progressive Image Bundle uses a breakpoint-first approach: instead of storing fixed image sizes, it calculates the exact pixel width needed at each breakpoint from your CSS grid, and generates (or requests) exactly that.
Grid frameworks
progressive_image:
responsive_strategy:
grid:
framework: bootstrap # or 'tailwind', or 'custom'bootstrap— 12 columns, breakpointsxs/sm/md/lg/xl/xxlwith Bootstrap's realmin_viewport/max_containervalues (e.g.lg: 992px viewport / 960px container).tailwind— 12 columns, breakpointsxs/sm/md/lg/xl/2xlwith Tailwind's real breakpoints (e.g.lg: 1024px).custom(default) — define your owncolumns,gutter, andlayouts.
Any key you set explicitly under grid (e.g. a custom layouts.lg.max_container) wins over the framework preset — the preset only fills in what you didn't specify.
Custom grid
progressive_image:
responsive_strategy:
grid:
framework: custom
columns: 12
gutter: 24
layouts:
xl: { min_viewport: 1200, max_container: 1140 }
md: { min_viewport: 768, max_container: 720 }
sm: { min_viewport: 0, max_container: null } # null = 100vw (fluid)max_container: null means the breakpoint is fluid — its effective width is 100vw (capped by responsive_strategy.fluid_max_width when estimating a concrete pixel value).
Aspect ratios
progressive_image:
responsive_strategy:
ratios:
landscape: '16/9'
portrait: '3/4'
square: '1/1'
hero: '21/9'Reference these by name in sizes (md:6@landscape) or as a component-level default via the ratio prop — see Sizes syntax.
Generating the CSS
responsive_strategy.grid also drives the CSS custom properties that lock in each breakpoint's width/aspect ratio client-side, avoiding layout shift:
php bin/console progressive-image:generate-custom-cssEmits @layer vendor { .progressive-image-container { ... } } rules with per-breakpoint media queries, using --img-width-<bp> / --img-aspect-<bp> custom properties (with var() fallback chains). Re-run it whenever breakpoints change, and import the generated file from your JS entry point. Bootstrap/Tailwind users can instead import the pre-built assets/styles/progressive-image-{tailwind,bootstrap}.css shipped with the bundle.
Upscaling protection
The bundle never generates (or requests) an image wider than its own source. If a breakpoint's computed target width exceeds the original image's width, that srcset candidate is capped at the original width instead of being upscaled — so the browser never downloads an artificially enlarged, blurry image, and no storage/CPU is wasted generating one.
Zero CLS
Source dimensions are read via PHP streams (no full image load needed) and written into --img-width / --img-aspect CSS custom properties on the wrapping <div> before the <img> itself is even requested — the browser reserves the correct space up front, so nothing jumps when the image finishes loading.