Skip to content

Editor: order viewport breakpoints only against a comparable base - #12948

Open
jigneshbhavani wants to merge 1 commit into
WordPress:trunkfrom
jigneshbhavani:fix/65833-viewport-breakpoint-unit-ordering
Open

Editor: order viewport breakpoints only against a comparable base#12948
jigneshbhavani wants to merge 1 commit into
WordPress:trunkfrom
jigneshbhavani:fix/65833-viewport-breakpoint-unit-ordering

Conversation

@jigneshbhavani

@jigneshbhavani jigneshbhavani commented Aug 9, 2026

Copy link
Copy Markdown

WP_Theme_JSON::sanitize_viewport_settings() proves that tablet is larger than mobile using values normalized at a hardcoded 16px, but get_viewport_media_queries() emits the authored units. A media query resolves em and rem against the initial font size rather than anything set on the page, so the ordering proven at 16px does not transfer to the browser when the two breakpoints are measured against different bases.

With mobile: 30em, tablet: 500px the guard passes because 30 x 16 = 480 < 500, and core emits @media (30em < width <= 500px). Above a 16px base that range is empty, and @media (width <= 30em) and @media (width > 500px) begin to overlap instead, so two viewport states apply at once.

em and rem share a base in a media query, so they can be ordered against each other. A px length and a font-relative one cannot, at any base. This adds get_viewport_breakpoint_base() and keeps tablet only when both breakpoints are measured against the same base, dropping it in the mixed case exactly as it is already dropped when it is not larger than mobile.

No new string, so it is available after hard string freeze. settings.viewport is new in 7.1 and unreleased, so no existing theme depends on the current behavior.

Approach agreed with wildworks in comment:3. The warning message requested there is a follow-up rather than part of this change, since it needs a translatable string.

Gutenberg mirrors this logic in packages/global-styles-engine/src/utils/viewport.ts and lib/class-wp-theme-json-gutenberg.php, so the editor preview needs the same change upstream. Not part of this PR.

Testing instructions

In a theme's theme.json:

{ "version": 3, "settings": { "viewport": { "mobile": "30em", "tablet": "500px" } } }

Add a paragraph with block visibility set to hide on tablet, then view the post. Before this change the page emits @media (30em < width <= 500px). After it, tablet is not a configured breakpoint and only the mobile query is emitted. mobile: 30em, tablet: 40rem keeps both breakpoints, since those share a base.

Trac ticket: https://core.trac.wordpress.org/ticket/65833

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Investigation, browser measurements, drafting the change and the tests. I
reviewed, tested and take responsibility for everything in this pull request.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props bejignesh.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

Media queries resolve em and rem against the initial font size, so a px
breakpoint cannot be ordered against a font-relative one. Keep tablet only when
both breakpoints share a base, matching how it is already dropped when it is not
larger than mobile.

See #65833.
@jigneshbhavani
jigneshbhavani force-pushed the fix/65833-viewport-breakpoint-unit-ordering branch from 68578bd to 75d766d Compare August 9, 2026 18:09

@irozum irozum left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This correctly fixes the ordering bug from #65833: sanitize_viewport_settings() was proving tablet > mobile at a hardcoded 16px base while get_viewport_media_queries() emitted the authored units, so a px/em mix could pass the guard but produce a media query that never matches (or overlaps) in the browser. Keeping tablet only when both breakpoints share a base (px vs. font-relative) is exactly the approach agreed with wildworks in ticket comment:3, and correctly treats em/rem as comparable to each other since both resolve against the initial font size.

I checked out the branch, ran the full Tests_Theme_wpThemeJson suite (295 tests, all green), PHPStan, and PHPCS against both touched files — all clean. Traced the single-breakpoint and default-breakpoint (480px/782px) paths by hand; neither goes through the new base check, so existing behavior for themes using only one breakpoint or the defaults is unaffected. str_ends_with() is polyfilled in compat.php for the PHP 7.4 floor, so no compat concern there. Since settings.viewport is unreleased in 7.1, there's no BC surface to worry about, and the docblock updates on both changed methods are accurate.

No blocking issues. Nice, tightly-scoped fix with good test coverage across the px/em, px/rem, and em/rem-mixed cases plus a settings-level integration test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants