diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-nesting/top-level-parent-pseudo-specificity.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-nesting/top-level-parent-pseudo-specificity.txt index 0682c632752..4963c1d9ded 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-nesting/top-level-parent-pseudo-specificity.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-nesting/top-level-parent-pseudo-specificity.txt @@ -6,6 +6,6 @@ Rerun Found 1 tests -1 Fail +1 Pass Details -Result Test Name MessageFail CSS Nesting: Specificity of top-level '&' \ No newline at end of file +Result Test Name MessagePass CSS Nesting: Specificity of top-level '&' \ No newline at end of file diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleRule.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleRule.cpp index e7cfc437045..534f04f60d8 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleRule.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleRule.cpp @@ -177,28 +177,25 @@ SelectorList const& CSSStyleRule::absolutized_selectors() const // "When used in the selector of a nested style rule, the nesting selector represents the elements matched by the parent rule. // When used in any other context, it represents the same elements as :scope in that context (unless otherwise defined)." // https://drafts.csswg.org/css-nesting-1/#nest-selector - Selector::SimpleSelector parent_selector; if (auto const* parent_style_rule = this->parent_style_rule()) { // TODO: If there's only 1, we don't have to use `:is()` for it - parent_selector = { + Selector::SimpleSelector parent_selector = { .type = Selector::SimpleSelector::Type::PseudoClass, .value = Selector::SimpleSelector::PseudoClassSelector { .type = PseudoClass::Is, .argument_selector_list = parent_style_rule->absolutized_selectors(), }, }; + SelectorList absolutized_selectors; + for (auto const& selector : selectors()) + absolutized_selectors.append(selector->absolutized(parent_selector)); + m_cached_absolutized_selectors = move(absolutized_selectors); } else { - parent_selector = { - .type = Selector::SimpleSelector::Type::PseudoClass, - .value = Selector::SimpleSelector::PseudoClassSelector { .type = PseudoClass::Scope }, - }; + // NOTE: We can't actually replace & with :scope, because & has to have 0 specificity. + // So we leave it, and treat & like :scope during matching. + m_cached_absolutized_selectors = m_selectors; } - SelectorList absolutized_selectors; - for (auto const& selector : selectors()) - absolutized_selectors.append(selector->absolutized(parent_selector)); - - m_cached_absolutized_selectors = move(absolutized_selectors); return m_cached_absolutized_selectors.value(); } diff --git a/Userland/Libraries/LibWeb/CSS/Selector.cpp b/Userland/Libraries/LibWeb/CSS/Selector.cpp index 17cf972e91e..266391e4f8a 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.cpp +++ b/Userland/Libraries/LibWeb/CSS/Selector.cpp @@ -179,8 +179,11 @@ u32 Selector::specificity() const // ignore the universal selector break; case SimpleSelector::Type::Nesting: - // We should have replaced this already - VERIFY_NOT_REACHED(); + // "The specificity of the nesting selector is equal to the largest specificity among the complex selectors in the parent style rule’s selector list (identical to the behavior of :is()), or zero if no such selector list exists." + // - https://drafts.csswg.org/css-nesting/#ref-for-specificity + // The parented case is handled by replacing & with :is(). + // So if we got here, the specificity is 0. + break; } } } diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index eb537f59aa1..6802fa73cc1 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -760,8 +760,10 @@ static inline bool matches(CSS::Selector::SimpleSelector const& component, Optio // Pseudo-element matching/not-matching is handled in the top level matches(). return true; case CSS::Selector::SimpleSelector::Type::Nesting: - // We should only try to match selectors that have been absolutized! - VERIFY_NOT_REACHED(); + // Nesting either behaves like :is(), or like :scope. + // :is() is handled already, by us replacing it with :is() directly, so if we + // got here, it's :scope. + return matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClassSelector { .type = CSS::PseudoClass::Scope }, style_sheet_for_rule, element, shadow_host, scope, selector_kind); } VERIFY_NOT_REACHED(); }