Closed Bug 1874042 Opened 11 months ago Closed 8 months ago

:is containing :has/:nth-child(of) may not invalidate correctly

Categories

(Core :: CSS Parsing and Computation, defect)

Firefox 121
defect

Tracking

()

RESOLVED FIXED
126 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox121 --- wontfix
firefox122 --- wontfix
firefox123 --- wontfix
firefox124 --- wontfix
firefox125 --- wontfix
firefox126 --- fixed

People

(Reporter: i3vg6j1f, Assigned: dshin)

References

(Blocks 1 open bug)

Details

Attachments

(4 files)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0

Steps to reproduce:

  1. Apply some styles under this selector: :is([data-pressed=true], :has(.stuff)).
  2. Use JS to toggle data-pressed.

See playground (press button): https://developer.mozilla.org/en-US/play?id=Q82Vp%2FpR%2Bzyvu9fwfTudUzpPjXseTppN65OFbz7Wh0C1YjAlMH86s4FVMPcf0%2BaqgpMz4d5UBodeRz8n

Actual results:

Selector is matched correctly on initial load, but not for future updates.

If :has(.stuff) is removed from the selector list, then it works correctly.

(Also works correctly in Blink and Webkit)

Expected results:

Selector should continue to match the correct state for both initial loads and future updates.

Side note: I'm not sure if there are performance concerns with using :has inside :is. If that is the case, it would be nice if devtools showed a 🐢warning, similar to how it does for unconstrained selectors like :has(*).

Component: Untriaged → CSS Parsing and Computation
Product: Firefox → Core

dshin, mind taking a look?

I do see a behavior difference between Firefox vs. WebKit/Chrome here; in the linked MDN playground, we keep the hotpink outline after the button is pressed whereas it disappears when "off" is showing (e.g. after 1 press) in WebKit/Chrome.

Blocks: has-issues
Severity: -- → S3
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(dshin)

Oh... Ouch.
We always return true for :has() in invalidation context because we're just marking for invalidation and we'll match later while styling.
So in this case we have :is(non-has-selector, has-selector), where non-has-selector initially matches, but then no longer does. Our invalidator examines now vs then matches for the element, only marking for invalidation if it changed. For the "then" match, non-has-selector matches, and for the "now" match, has-selector matches, so we don't end up marking the element for invalidation.

:nth-child(N of selector) has the same issue.

Flags: needinfo?(dshin)
Assignee: nobody → dshin

STR: Load the test case, wait 1 second
Expected: Purple square should disappear
Actual: Purple square does not disappear (Unless you force restyle by e.g. opening the inspector)

Summary: :is containing :has doesn't invalidate → :is containing :has/:nth-child(of) may not invalidate correctly

I was able to reproduce this issue with the test case from comment 4 on MacOS 13.2.1 using Fx 121.0.1, 122.0b9 and Nightly 123.0a1(2024-01-14). I noticed that the issue is not reproducible on Fx 120.0.1.

(Sorry - late reply) Ah, :has shipped on release 121.

Pushed by dshin@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/3b319cf7f343 Refactor KleeneValue for use in selector invalidation. r=firefox-style-system-reviewers,emilio https://hg.mozilla.org/integration/autoland/rev/068df8e3c3c6 Add support for unknown match result for invalidation by comparing now/then. r=firefox-style-system-reviewers,emilio
Created web-platform-tests PR https://github.com/web-platform-tests/wpt/pull/45482 for changes under testing/web-platform/tests
Status: NEW → RESOLVED
Closed: 8 months ago
Resolution: --- → FIXED
Target Milestone: --- → 126 Branch
Upstream PR merged by moz-wptsync-bot
QA Whiteboard: [qa-126b-p2]
Regressions: 1892727
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: