Skip to content

fix(core): size gallery images to their grid cell, not the viewport - #3103

Merged
ascorbic merged 1 commit into
emdash-cms:mainfrom
dchaudhari7177:fix/2930-gallery-sizes
Sep 14, 2026
Merged

ascorbic merged 1 commit into
emdash-cms:mainfrom
dchaudhari7177:fix/2930-gallery-sizes

Conversation

@dchaudhari7177

Copy link
Copy Markdown
Contributor

What does this PR do?

Gallery.astro told browsers each image fills the viewport. Provider images got sizes="(min-width: Wpx) Wpx, 100vw", and locally stored images with dimensions go through <Image layout="constrained">, whose default is the same estimate. But the gallery lays images out in repeat(var(--columns, 3), 1fr) with a 1rem gap, and two columns at 640px and below. So the browser sizes the slot at roughly three times the rendered cell and picks a correspondingly large srcset candidate. The local path's srcset runs up to 3200w for a 1600px image, so on DPR 2 screens this means downloading far more than each cell shows.

  • gallerySizes(columns) in media/responsive.ts builds the cell estimate from the gallery's own CSS:
    (max-width: 640px) calc((100vw - 1rem) / 2), calc((100vw - 2rem) / 3) for three columns. One column gives 100vw above the breakpoint. A missing, zero or non-integer count falls back to three, the count Gallery.astro already defaults to.
  • Gallery.astro uses it for both the provider <img> and the AstroImage path.
  • A new optional sizes prop overrides it. This is the issue's second direction, for galleries rendered in a container narrower than the viewport, where a viewport-based estimate is still too large. Both directions from the issue are covered: an accurate default and a consumer override.

Closes #2930

Type of change

  • Bug fix

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes: not run as tsgo (not installed here). tsc --noEmit -p packages/core reports no errors.
  • pnpm lint passes: oxlint on the touched files
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run: oxfmt (via stdin on the LF content) and prettier for the .astro file, no changes
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation: n/a, no admin strings
  • I have added and reviewed the user-facing changeset
  • New features link to an approved Discussion: n/a, bug fix. The sizes prop is the override the issue proposes alongside it.
  • I have included screenshots below if this PR changes the UI: n/a, the change is an attribute value, shown below

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 5 (Claude Code)

Screenshots / test output

tests/repro/gallery-sizes.render.test.ts (new) renders Gallery through the Astro container, with a mock provider injected via __emdashTestMediaProviders:

  • provider images in a default gallery get the three-column cell estimate, and their srcset is still provider-generated
  • columns: 4 gives calc((100vw - 3rem) / 4)
  • a local image with width/height (data-astro-image="constrained") gets the same estimate
  • a sizes prop wins

With main's Gallery.astro and responsive.ts:

× provider images are sized to one of three default columns
× the slot follows the block's column count
× locally stored images with dimensions get the same cell estimate
× a consumer-provided sizes wins
Tests  4 failed (4)

With this branch: 4 passed. tests/unit/media/responsive.test.ts gains gallerySizes cases (column counts, one column, the fallback for undefined/0/2.5/NaN): 21 passed. The existing image-render and focal-point-render repro suites still pass (23 tests across the three files).

Gallery.astro gave provider images sizes="(min-width: Wpx) Wpx, 100vw"
and left locally stored images on Astro's constrained default, the same
estimate. Each image renders in one of columns cells (two at 640px and
below), so browsers picked srcset candidates several times wider than
the cell.

sizes now comes from gallerySizes(columns), which mirrors the gallery CSS
including its 1rem gap, and applies to both the provider img and the
AstroImage path. A new sizes prop overrides it for galleries rendered in
a narrower container.

Closes emdash-cms#2930
@changeset-bot

changeset-bot Bot commented Sep 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a101b69

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/plugin-test Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
create-emdash Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/release-service Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added area/core size/M review/needs-review No maintainer or bot review yet labels Sep 14, 2026

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach judgment

This is the right change, solving the right problem, in the right place. The bug is real: Gallery.astro was telling browsers each image fills the viewport, so multi-column galleries downloaded oversized srcset candidates. Moving the sizes computation into a shared gallerySizes(columns) helper in media/responsive.ts keeps the responsive-image logic centralized and testable, and the new sizes prop addresses the issue's second direction (galleries inside narrower containers). The implementation mirrors the CSS grid rules, handles invalid column counts safely, and applies the override to both the provider <img> and Astro Image paths.

What I checked

  • Full diff and the changed files (Gallery.astro, media/responsive.ts, the new repro test, and the updated unit tests).
  • Call sites and siblings: Image.astro, provider-loader.ts, existing image-render.render.test.ts, and focal-point-render.render.test.ts to confirm the __emdashTestMediaProviders pattern and provider rendering expectations.
  • AGENTS.md conventions for comments, changesets, and test quality.
  • .changeset/README.md against the submitted changeset.

Headline conclusion

The code is sound, the tests reproduce the bug and verify the fix behaviorally, and the changeset is useful. I found only one minor AGENTS.md convention item in the new test file.

Findings

  1. packages/core/tests/repro/gallery-sizes.render.test.ts (suggestion): the header comment references issue #2930. Per AGENTS.md comment discipline, issue/PR references should not live in code comments — that context belongs in the commit message and PR description. Keep the explanatory prose about the bug; just drop the issue number.

Comment on lines +1 to +7
/**
* The gallery's `sizes` must describe a grid cell, not the viewport: each
* image renders in one of `columns` cells (two at 640px and below), and a
* `100vw` estimate lets the browser pick a far larger srcset candidate than
* the cell needs (#2930).
*/
import { experimental_AstroContainer as AstroContainer } from "astro/container";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] The test header comment references issue #2930. Per AGENTS.md comment discipline, issue/PR references should not live in code comments — they become stale narrative once the change merges; that context belongs in the commit message and PR description.

Keep the explanatory prose about what the test reproduces; just remove the issue number.

Suggested change
/**
* The gallery's `sizes` must describe a grid cell, not the viewport: each
* image renders in one of `columns` cells (two at 640px and below), and a
* `100vw` estimate lets the browser pick a far larger srcset candidate than
* the cell needs (#2930).
*/
import { experimental_AstroContainer as AstroContainer } from "astro/container";
/**
* The gallery's `sizes` must describe a grid cell, not the viewport: each
* image renders in one of `columns` cells (two at 640px and below), and a
* `100vw` estimate lets the browser pick a far larger srcset candidate than
* the cell needs.
*/

@pkg-pr-new

pkg-pr-new Bot commented Sep 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@3103

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@3103

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@3103

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@3103

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@3103

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@3103

emdash

npm i https://pkg.pr.new/emdash@3103

create-emdash

npm i https://pkg.pr.new/create-emdash@3103

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@3103

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@3103

@emdash-cms/plugin-test

npm i https://pkg.pr.new/@emdash-cms/plugin-test@3103

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@3103

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@3103

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@3103

@emdash-cms/registry-moderation

npm i https://pkg.pr.new/@emdash-cms/registry-moderation@3103

@emdash-cms/registry-verification

npm i https://pkg.pr.new/@emdash-cms/registry-verification@3103

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@3103

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@3103

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@3103

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@3103

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@3103

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@3103

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@3103

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@3103

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@3103

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@3103

commit: a101b69

@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-review No maintainer or bot review yet labels Sep 14, 2026

@ascorbic ascorbic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@ascorbic
ascorbic merged commit fea6beb into emdash-cms:main Sep 14, 2026
60 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core review/awaiting-author Reviewed; waiting on the author to respond size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gallery renderer uses full viewport in sizes for multi-column images

2 participants