LibWeb: Inherit animated CSS property values separately

When starting transitions we compute the after-change style, for any
inherited properties this should include the non-animated value.

Previously we were only inheriting the animated value and treating it as
non-animated so were instead including the animated value.

This commit fixes that by inheriting both the animated and non-animated
values (with the former being stored in `m_animated_property_values`,
and the latter in `m_property_values`).

This gains us 12 new WPT passes.

This brings with it 252 new WPT fails from the various 'events' tests in
css/css-transitions/properties-value-inherit-001.html, however these
also fail in other browsers (Chrome, Edge and Firefox) and the behaviour
that causes these failures is specifically mentioned in the spec.
This commit is contained in:
Callum Law 2025-08-14 16:08:09 +12:00 committed by Sam Atkins
commit 9a8c6ff8c3
Notes: github-actions[bot] 2025-08-18 10:19:39 +00:00
5 changed files with 481 additions and 271 deletions

View file

@ -1678,7 +1678,21 @@ NonnullRefPtr<StyleValue const> StyleComputer::get_inherit_value(CSS::PropertyID
if (!parent_element || !parent_element->computed_properties())
return property_initial_value(property_id);
return parent_element->computed_properties()->property(property_id);
return parent_element->computed_properties()->property(property_id, CSS::ComputedProperties::WithAnimationsApplied::No);
}
Optional<NonnullRefPtr<StyleValue const>> StyleComputer::get_animated_inherit_value(CSS::PropertyID property_id, DOM::Element const* element, Optional<CSS::PseudoElement> pseudo_element)
{
auto parent_element = element ? element->element_to_inherit_style_from(pseudo_element) : nullptr;
if (!parent_element || !parent_element->computed_properties())
return {};
if (auto animated_value = parent_element->computed_properties()->animated_property_values().get(property_id); animated_value.has_value())
return *animated_value.value();
return {};
}
void StyleComputer::compute_defaulted_property_value(ComputedProperties& style, DOM::Element const* element, CSS::PropertyID property_id, Optional<CSS::PseudoElement> pseudo_element) const
@ -1686,6 +1700,8 @@ void StyleComputer::compute_defaulted_property_value(ComputedProperties& style,
auto& value_slot = style.m_property_values[to_underlying(property_id)];
if (!value_slot) {
if (is_inherited_property(property_id)) {
if (auto animated_inherit_value = get_animated_inherit_value(property_id, element, pseudo_element); animated_inherit_value.has_value())
style.set_animated_property(property_id, animated_inherit_value.value());
style.set_property(
property_id,
get_inherit_value(property_id, element, pseudo_element),
@ -1703,6 +1719,8 @@ void StyleComputer::compute_defaulted_property_value(ComputedProperties& style,
}
if (value_slot->is_inherit()) {
if (auto animated_inherit_value = get_animated_inherit_value(property_id, element, pseudo_element); animated_inherit_value.has_value())
style.set_animated_property(property_id, animated_inherit_value.value());
value_slot = get_inherit_value(property_id, element, pseudo_element);
style.set_property_inherited(property_id, ComputedProperties::Inherited::Yes);
return;
@ -1713,6 +1731,8 @@ void StyleComputer::compute_defaulted_property_value(ComputedProperties& style,
if (value_slot->is_unset()) {
if (is_inherited_property(property_id)) {
// then if it is an inherited property, this is treated as inherit,
if (auto animated_inherit_value = get_animated_inherit_value(property_id, element, pseudo_element); animated_inherit_value.has_value())
style.set_animated_property(property_id, animated_inherit_value.value());
value_slot = get_inherit_value(property_id, element, pseudo_element);
style.set_property_inherited(property_id, ComputedProperties::Inherited::Yes);
} else {
@ -2648,20 +2668,17 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::Element& elem
auto property_id = static_cast<CSS::PropertyID>(i);
auto value = cascaded_properties.property(property_id);
auto inherited = ComputedProperties::Inherited::No;
Optional<NonnullRefPtr<StyleValue const>> animated_value;
// NOTE: We've already handled font-size above.
if (property_id == PropertyID::FontSize && !value && new_font_size)
continue;
// FIXME: Logical properties should inherit from their parent's equivalent unmapped logical property.
if ((!value && is_inherited_property(property_id))
|| (value && value->is_inherit())) {
if (auto const inheritance_parent = element.element_to_inherit_style_from(pseudo_element)) {
value = inheritance_parent->computed_properties()->property(property_id);
inherited = ComputedProperties::Inherited::Yes;
} else {
value = property_initial_value(property_id);
}
if ((!value && is_inherited_property(property_id)) || (value && value->is_inherit())) {
value = get_inherit_value(property_id, &element, pseudo_element);
animated_value = get_animated_inherit_value(property_id, &element, pseudo_element);
inherited = ComputedProperties::Inherited::Yes;
}
if (!value || value->is_initial())
@ -2675,6 +2692,8 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::Element& elem
}
computed_style->set_property(property_id, value.release_nonnull(), inherited);
if (animated_value.has_value())
computed_style->set_animated_property(property_id, animated_value.value());
if (property_id == PropertyID::AnimationName) {
computed_style->set_animation_name_source(cascaded_properties.property_source(property_id));

View file

@ -133,6 +133,7 @@ class StyleComputer final : public GC::Cell {
public:
static void for_each_property_expanding_shorthands(PropertyID, StyleValue const&, Function<void(PropertyID, StyleValue const&)> const& set_longhand_property);
static NonnullRefPtr<StyleValue const> get_inherit_value(CSS::PropertyID, DOM::Element const*, Optional<CSS::PseudoElement> = {});
static Optional<NonnullRefPtr<StyleValue const>> get_animated_inherit_value(CSS::PropertyID, DOM::Element const*, Optional<CSS::PseudoElement> = {});
static Optional<String> user_agent_style_sheet_source(StringView name);

View file

@ -0,0 +1,12 @@
Harness status: OK
Found 6 tests
5 Pass
1 Fail
Pass Start .inner transition based on inherited after-change color from .outer (lime)
Pass Start .inner transition based on inherited after-change background-color from .outer (lime)
Pass Initial computed styles
Pass Start inner transitions based on inherited after-change color and word-spacing from two different ancestors
Pass @starting-style rules should not apply to after-change style
Fail @container rules apply to after-change style

View file

@ -2,410 +2,410 @@ Harness status: OK
Found 560 tests
544 Pass
16 Fail
300 Pass
260 Fail
Pass background-color color(rgba) / values
Pass background-color color(rgba) / events
Fail background-position-x length(pt) / values
Fail background-color color(rgba) / events
Pass background-position-x length(pt) / values
Fail background-position-x length(pt) / events
Fail background-position-x length(pc) / values
Pass background-position-x length(pc) / values
Fail background-position-x length(pc) / events
Pass background-position-x length(px) / values
Pass background-position-x length(px) / events
Fail background-position-x length(em) / values
Fail background-position-x length(px) / events
Pass background-position-x length(em) / values
Fail background-position-x length(em) / events
Fail background-position-x length(ex) / values
Pass background-position-x length(ex) / values
Fail background-position-x length(ex) / events
Fail background-position-x length(mm) / values
Pass background-position-x length(mm) / values
Fail background-position-x length(mm) / events
Fail background-position-x length(cm) / values
Pass background-position-x length(cm) / values
Fail background-position-x length(cm) / events
Fail background-position-x length(in) / values
Pass background-position-x length(in) / values
Fail background-position-x length(in) / events
Pass background-position-x percentage(%) / values
Pass background-position-x percentage(%) / events
Fail background-position-x percentage(%) / events
Pass border-top-width length(pt) / values
Pass border-top-width length(pt) / events
Fail border-top-width length(pt) / events
Pass border-top-width length(pc) / values
Pass border-top-width length(pc) / events
Fail border-top-width length(pc) / events
Pass border-top-width length(px) / values
Pass border-top-width length(px) / events
Fail border-top-width length(px) / events
Pass border-top-width length(em) / values
Pass border-top-width length(em) / events
Fail border-top-width length(em) / events
Pass border-top-width length(ex) / values
Pass border-top-width length(ex) / events
Fail border-top-width length(ex) / events
Pass border-top-width length(mm) / values
Pass border-top-width length(mm) / events
Fail border-top-width length(mm) / events
Pass border-top-width length(cm) / values
Pass border-top-width length(cm) / events
Fail border-top-width length(cm) / events
Pass border-top-width length(in) / values
Pass border-top-width length(in) / events
Fail border-top-width length(in) / events
Pass border-right-width length(pt) / values
Pass border-right-width length(pt) / events
Fail border-right-width length(pt) / events
Pass border-right-width length(pc) / values
Pass border-right-width length(pc) / events
Fail border-right-width length(pc) / events
Pass border-right-width length(px) / values
Pass border-right-width length(px) / events
Fail border-right-width length(px) / events
Pass border-right-width length(em) / values
Pass border-right-width length(em) / events
Fail border-right-width length(em) / events
Pass border-right-width length(ex) / values
Pass border-right-width length(ex) / events
Fail border-right-width length(ex) / events
Pass border-right-width length(mm) / values
Pass border-right-width length(mm) / events
Fail border-right-width length(mm) / events
Pass border-right-width length(cm) / values
Pass border-right-width length(cm) / events
Fail border-right-width length(cm) / events
Pass border-right-width length(in) / values
Pass border-right-width length(in) / events
Fail border-right-width length(in) / events
Pass border-bottom-width length(pt) / values
Pass border-bottom-width length(pt) / events
Fail border-bottom-width length(pt) / events
Pass border-bottom-width length(pc) / values
Pass border-bottom-width length(pc) / events
Fail border-bottom-width length(pc) / events
Pass border-bottom-width length(px) / values
Pass border-bottom-width length(px) / events
Fail border-bottom-width length(px) / events
Pass border-bottom-width length(em) / values
Pass border-bottom-width length(em) / events
Fail border-bottom-width length(em) / events
Pass border-bottom-width length(ex) / values
Pass border-bottom-width length(ex) / events
Fail border-bottom-width length(ex) / events
Pass border-bottom-width length(mm) / values
Pass border-bottom-width length(mm) / events
Fail border-bottom-width length(mm) / events
Pass border-bottom-width length(cm) / values
Pass border-bottom-width length(cm) / events
Fail border-bottom-width length(cm) / events
Pass border-bottom-width length(in) / values
Pass border-bottom-width length(in) / events
Fail border-bottom-width length(in) / events
Pass border-left-width length(pt) / values
Pass border-left-width length(pt) / events
Fail border-left-width length(pt) / events
Pass border-left-width length(pc) / values
Pass border-left-width length(pc) / events
Fail border-left-width length(pc) / events
Pass border-left-width length(px) / values
Pass border-left-width length(px) / events
Fail border-left-width length(px) / events
Pass border-left-width length(em) / values
Pass border-left-width length(em) / events
Fail border-left-width length(em) / events
Pass border-left-width length(ex) / values
Pass border-left-width length(ex) / events
Fail border-left-width length(ex) / events
Pass border-left-width length(mm) / values
Pass border-left-width length(mm) / events
Fail border-left-width length(mm) / events
Pass border-left-width length(cm) / values
Pass border-left-width length(cm) / events
Fail border-left-width length(cm) / events
Pass border-left-width length(in) / values
Pass border-left-width length(in) / events
Fail border-left-width length(in) / events
Pass border-top-color color(rgba) / values
Pass border-top-color color(rgba) / events
Fail border-top-color color(rgba) / events
Pass border-right-color color(rgba) / values
Pass border-right-color color(rgba) / events
Fail border-right-color color(rgba) / events
Pass border-bottom-color color(rgba) / values
Pass border-bottom-color color(rgba) / events
Fail border-bottom-color color(rgba) / events
Pass border-left-color color(rgba) / values
Pass border-left-color color(rgba) / events
Fail border-left-color color(rgba) / events
Pass padding-bottom length(pt) / values
Pass padding-bottom length(pt) / events
Fail padding-bottom length(pt) / events
Pass padding-bottom length(pc) / values
Pass padding-bottom length(pc) / events
Fail padding-bottom length(pc) / events
Pass padding-bottom length(px) / values
Pass padding-bottom length(px) / events
Fail padding-bottom length(px) / events
Pass padding-bottom length(em) / values
Pass padding-bottom length(em) / events
Fail padding-bottom length(em) / events
Pass padding-bottom length(ex) / values
Pass padding-bottom length(ex) / events
Fail padding-bottom length(ex) / events
Pass padding-bottom length(mm) / values
Pass padding-bottom length(mm) / events
Fail padding-bottom length(mm) / events
Pass padding-bottom length(cm) / values
Pass padding-bottom length(cm) / events
Fail padding-bottom length(cm) / events
Pass padding-bottom length(in) / values
Pass padding-bottom length(in) / events
Fail padding-bottom length(in) / events
Pass padding-left length(pt) / values
Pass padding-left length(pt) / events
Fail padding-left length(pt) / events
Pass padding-left length(pc) / values
Pass padding-left length(pc) / events
Fail padding-left length(pc) / events
Pass padding-left length(px) / values
Pass padding-left length(px) / events
Fail padding-left length(px) / events
Pass padding-left length(em) / values
Pass padding-left length(em) / events
Fail padding-left length(em) / events
Pass padding-left length(ex) / values
Pass padding-left length(ex) / events
Fail padding-left length(ex) / events
Pass padding-left length(mm) / values
Pass padding-left length(mm) / events
Fail padding-left length(mm) / events
Pass padding-left length(cm) / values
Pass padding-left length(cm) / events
Fail padding-left length(cm) / events
Pass padding-left length(in) / values
Pass padding-left length(in) / events
Fail padding-left length(in) / events
Pass padding-right length(pt) / values
Pass padding-right length(pt) / events
Fail padding-right length(pt) / events
Pass padding-right length(pc) / values
Pass padding-right length(pc) / events
Fail padding-right length(pc) / events
Pass padding-right length(px) / values
Pass padding-right length(px) / events
Fail padding-right length(px) / events
Pass padding-right length(em) / values
Pass padding-right length(em) / events
Fail padding-right length(em) / events
Pass padding-right length(ex) / values
Pass padding-right length(ex) / events
Fail padding-right length(ex) / events
Pass padding-right length(mm) / values
Pass padding-right length(mm) / events
Fail padding-right length(mm) / events
Pass padding-right length(cm) / values
Pass padding-right length(cm) / events
Fail padding-right length(cm) / events
Pass padding-right length(in) / values
Pass padding-right length(in) / events
Fail padding-right length(in) / events
Pass padding-top length(pt) / values
Pass padding-top length(pt) / events
Fail padding-top length(pt) / events
Pass padding-top length(pc) / values
Pass padding-top length(pc) / events
Fail padding-top length(pc) / events
Pass padding-top length(px) / values
Pass padding-top length(px) / events
Fail padding-top length(px) / events
Pass padding-top length(em) / values
Pass padding-top length(em) / events
Fail padding-top length(em) / events
Pass padding-top length(ex) / values
Pass padding-top length(ex) / events
Fail padding-top length(ex) / events
Pass padding-top length(mm) / values
Pass padding-top length(mm) / events
Fail padding-top length(mm) / events
Pass padding-top length(cm) / values
Pass padding-top length(cm) / events
Fail padding-top length(cm) / events
Pass padding-top length(in) / values
Pass padding-top length(in) / events
Fail padding-top length(in) / events
Pass margin-bottom length(pt) / values
Pass margin-bottom length(pt) / events
Fail margin-bottom length(pt) / events
Pass margin-bottom length(pc) / values
Pass margin-bottom length(pc) / events
Fail margin-bottom length(pc) / events
Pass margin-bottom length(px) / values
Pass margin-bottom length(px) / events
Fail margin-bottom length(px) / events
Pass margin-bottom length(em) / values
Pass margin-bottom length(em) / events
Fail margin-bottom length(em) / events
Pass margin-bottom length(ex) / values
Pass margin-bottom length(ex) / events
Fail margin-bottom length(ex) / events
Pass margin-bottom length(mm) / values
Pass margin-bottom length(mm) / events
Fail margin-bottom length(mm) / events
Pass margin-bottom length(cm) / values
Pass margin-bottom length(cm) / events
Fail margin-bottom length(cm) / events
Pass margin-bottom length(in) / values
Pass margin-bottom length(in) / events
Fail margin-bottom length(in) / events
Pass margin-left length(pt) / values
Pass margin-left length(pt) / events
Fail margin-left length(pt) / events
Pass margin-left length(pc) / values
Pass margin-left length(pc) / events
Fail margin-left length(pc) / events
Pass margin-left length(px) / values
Pass margin-left length(px) / events
Fail margin-left length(px) / events
Pass margin-left length(em) / values
Pass margin-left length(em) / events
Fail margin-left length(em) / events
Pass margin-left length(ex) / values
Pass margin-left length(ex) / events
Fail margin-left length(ex) / events
Pass margin-left length(mm) / values
Pass margin-left length(mm) / events
Fail margin-left length(mm) / events
Pass margin-left length(cm) / values
Pass margin-left length(cm) / events
Fail margin-left length(cm) / events
Pass margin-left length(in) / values
Pass margin-left length(in) / events
Fail margin-left length(in) / events
Pass margin-right length(pt) / values
Pass margin-right length(pt) / events
Fail margin-right length(pt) / events
Pass margin-right length(pc) / values
Pass margin-right length(pc) / events
Fail margin-right length(pc) / events
Pass margin-right length(px) / values
Pass margin-right length(px) / events
Fail margin-right length(px) / events
Pass margin-right length(em) / values
Pass margin-right length(em) / events
Fail margin-right length(em) / events
Pass margin-right length(ex) / values
Pass margin-right length(ex) / events
Fail margin-right length(ex) / events
Pass margin-right length(mm) / values
Pass margin-right length(mm) / events
Fail margin-right length(mm) / events
Pass margin-right length(cm) / values
Pass margin-right length(cm) / events
Fail margin-right length(cm) / events
Pass margin-right length(in) / values
Pass margin-right length(in) / events
Fail margin-right length(in) / events
Pass margin-top length(pt) / values
Pass margin-top length(pt) / events
Fail margin-top length(pt) / events
Pass margin-top length(pc) / values
Pass margin-top length(pc) / events
Fail margin-top length(pc) / events
Pass margin-top length(px) / values
Pass margin-top length(px) / events
Fail margin-top length(px) / events
Pass margin-top length(em) / values
Pass margin-top length(em) / events
Fail margin-top length(em) / events
Pass margin-top length(ex) / values
Pass margin-top length(ex) / events
Fail margin-top length(ex) / events
Pass margin-top length(mm) / values
Pass margin-top length(mm) / events
Fail margin-top length(mm) / events
Pass margin-top length(cm) / values
Pass margin-top length(cm) / events
Fail margin-top length(cm) / events
Pass margin-top length(in) / values
Pass margin-top length(in) / events
Fail margin-top length(in) / events
Pass height length(pt) / values
Pass height length(pt) / events
Fail height length(pt) / events
Pass height length(pc) / values
Pass height length(pc) / events
Fail height length(pc) / events
Pass height length(px) / values
Pass height length(px) / events
Fail height length(px) / events
Pass height length(em) / values
Pass height length(em) / events
Fail height length(em) / events
Pass height length(ex) / values
Pass height length(ex) / events
Fail height length(ex) / events
Pass height length(mm) / values
Pass height length(mm) / events
Fail height length(mm) / events
Pass height length(cm) / values
Pass height length(cm) / events
Fail height length(cm) / events
Pass height length(in) / values
Pass height length(in) / events
Fail height length(in) / events
Pass height percentage(%) / values
Pass height percentage(%) / events
Fail height percentage(%) / events
Pass width length(pt) / values
Pass width length(pt) / events
Fail width length(pt) / events
Pass width length(pc) / values
Pass width length(pc) / events
Fail width length(pc) / events
Pass width length(px) / values
Pass width length(px) / events
Fail width length(px) / events
Pass width length(em) / values
Pass width length(em) / events
Fail width length(em) / events
Pass width length(ex) / values
Pass width length(ex) / events
Fail width length(ex) / events
Pass width length(mm) / values
Pass width length(mm) / events
Fail width length(mm) / events
Pass width length(cm) / values
Pass width length(cm) / events
Fail width length(cm) / events
Pass width length(in) / values
Pass width length(in) / events
Fail width length(in) / events
Pass width percentage(%) / values
Pass width percentage(%) / events
Fail width percentage(%) / events
Pass min-height length(pt) / values
Pass min-height length(pt) / events
Fail min-height length(pt) / events
Pass min-height length(pc) / values
Pass min-height length(pc) / events
Fail min-height length(pc) / events
Pass min-height length(px) / values
Pass min-height length(px) / events
Fail min-height length(px) / events
Pass min-height length(em) / values
Pass min-height length(em) / events
Fail min-height length(em) / events
Pass min-height length(ex) / values
Pass min-height length(ex) / events
Fail min-height length(ex) / events
Pass min-height length(mm) / values
Pass min-height length(mm) / events
Fail min-height length(mm) / events
Pass min-height length(cm) / values
Pass min-height length(cm) / events
Fail min-height length(cm) / events
Pass min-height length(in) / values
Pass min-height length(in) / events
Fail min-height length(in) / events
Pass min-height percentage(%) / values
Pass min-height percentage(%) / events
Fail min-height percentage(%) / events
Pass min-width length(pt) / values
Pass min-width length(pt) / events
Fail min-width length(pt) / events
Pass min-width length(pc) / values
Pass min-width length(pc) / events
Fail min-width length(pc) / events
Pass min-width length(px) / values
Pass min-width length(px) / events
Fail min-width length(px) / events
Pass min-width length(em) / values
Pass min-width length(em) / events
Fail min-width length(em) / events
Pass min-width length(ex) / values
Pass min-width length(ex) / events
Fail min-width length(ex) / events
Pass min-width length(mm) / values
Pass min-width length(mm) / events
Fail min-width length(mm) / events
Pass min-width length(cm) / values
Pass min-width length(cm) / events
Fail min-width length(cm) / events
Pass min-width length(in) / values
Pass min-width length(in) / events
Fail min-width length(in) / events
Pass min-width percentage(%) / values
Pass min-width percentage(%) / events
Fail min-width percentage(%) / events
Pass max-height length(pt) / values
Pass max-height length(pt) / events
Fail max-height length(pt) / events
Pass max-height length(pc) / values
Pass max-height length(pc) / events
Fail max-height length(pc) / events
Pass max-height length(px) / values
Pass max-height length(px) / events
Fail max-height length(px) / events
Pass max-height length(em) / values
Pass max-height length(em) / events
Fail max-height length(em) / events
Pass max-height length(ex) / values
Pass max-height length(ex) / events
Fail max-height length(ex) / events
Pass max-height length(mm) / values
Pass max-height length(mm) / events
Fail max-height length(mm) / events
Pass max-height length(cm) / values
Pass max-height length(cm) / events
Fail max-height length(cm) / events
Pass max-height length(in) / values
Pass max-height length(in) / events
Fail max-height length(in) / events
Pass max-height percentage(%) / values
Pass max-height percentage(%) / events
Fail max-height percentage(%) / events
Pass max-width length(pt) / values
Pass max-width length(pt) / events
Fail max-width length(pt) / events
Pass max-width length(pc) / values
Pass max-width length(pc) / events
Fail max-width length(pc) / events
Pass max-width length(px) / values
Pass max-width length(px) / events
Fail max-width length(px) / events
Pass max-width length(em) / values
Pass max-width length(em) / events
Fail max-width length(em) / events
Pass max-width length(ex) / values
Pass max-width length(ex) / events
Fail max-width length(ex) / events
Pass max-width length(mm) / values
Pass max-width length(mm) / events
Fail max-width length(mm) / events
Pass max-width length(cm) / values
Pass max-width length(cm) / events
Fail max-width length(cm) / events
Pass max-width length(in) / values
Pass max-width length(in) / events
Fail max-width length(in) / events
Pass max-width percentage(%) / values
Pass max-width percentage(%) / events
Fail max-width percentage(%) / events
Pass top length(pt) / values
Pass top length(pt) / events
Fail top length(pt) / events
Pass top length(pc) / values
Pass top length(pc) / events
Fail top length(pc) / events
Pass top length(px) / values
Pass top length(px) / events
Fail top length(px) / events
Pass top length(em) / values
Pass top length(em) / events
Fail top length(em) / events
Pass top length(ex) / values
Pass top length(ex) / events
Fail top length(ex) / events
Pass top length(mm) / values
Pass top length(mm) / events
Fail top length(mm) / events
Pass top length(cm) / values
Pass top length(cm) / events
Fail top length(cm) / events
Pass top length(in) / values
Pass top length(in) / events
Fail top length(in) / events
Pass top percentage(%) / values
Pass top percentage(%) / events
Fail top percentage(%) / events
Pass right length(pt) / values
Pass right length(pt) / events
Fail right length(pt) / events
Pass right length(pc) / values
Pass right length(pc) / events
Fail right length(pc) / events
Pass right length(px) / values
Pass right length(px) / events
Fail right length(px) / events
Pass right length(em) / values
Pass right length(em) / events
Fail right length(em) / events
Pass right length(ex) / values
Pass right length(ex) / events
Fail right length(ex) / events
Pass right length(mm) / values
Pass right length(mm) / events
Fail right length(mm) / events
Pass right length(cm) / values
Pass right length(cm) / events
Fail right length(cm) / events
Pass right length(in) / values
Pass right length(in) / events
Fail right length(in) / events
Pass right percentage(%) / values
Pass right percentage(%) / events
Fail right percentage(%) / events
Pass bottom length(pt) / values
Pass bottom length(pt) / events
Fail bottom length(pt) / events
Pass bottom length(pc) / values
Pass bottom length(pc) / events
Fail bottom length(pc) / events
Pass bottom length(px) / values
Pass bottom length(px) / events
Fail bottom length(px) / events
Pass bottom length(em) / values
Pass bottom length(em) / events
Fail bottom length(em) / events
Pass bottom length(ex) / values
Pass bottom length(ex) / events
Fail bottom length(ex) / events
Pass bottom length(mm) / values
Pass bottom length(mm) / events
Fail bottom length(mm) / events
Pass bottom length(cm) / values
Pass bottom length(cm) / events
Fail bottom length(cm) / events
Pass bottom length(in) / values
Pass bottom length(in) / events
Fail bottom length(in) / events
Pass bottom percentage(%) / values
Pass bottom percentage(%) / events
Fail bottom percentage(%) / events
Pass left length(pt) / values
Pass left length(pt) / events
Fail left length(pt) / events
Pass left length(pc) / values
Pass left length(pc) / events
Fail left length(pc) / events
Pass left length(px) / values
Pass left length(px) / events
Fail left length(px) / events
Pass left length(em) / values
Pass left length(em) / events
Fail left length(em) / events
Pass left length(ex) / values
Pass left length(ex) / events
Fail left length(ex) / events
Pass left length(mm) / values
Pass left length(mm) / events
Fail left length(mm) / events
Pass left length(cm) / values
Pass left length(cm) / events
Fail left length(cm) / events
Pass left length(in) / values
Pass left length(in) / events
Fail left length(in) / events
Pass left percentage(%) / values
Pass left percentage(%) / events
Fail left percentage(%) / events
Pass color color(rgba) / values
Pass color color(rgba) / events
Fail color color(rgba) / events
Pass font-size length(pt) / values
Pass font-size length(pt) / events
Pass font-size length(pc) / values
@ -429,9 +429,9 @@ Pass font-weight font-weight(keyword) / events
Pass font-weight font-weight(numeric) / values
Pass font-weight font-weight(numeric) / events
Pass line-height number(integer) / values
Pass line-height number(integer) / events
Fail line-height number(integer) / events
Pass line-height number(decimal) / values
Pass line-height number(decimal) / events
Fail line-height number(decimal) / events
Pass line-height length(pt) / values
Pass line-height length(pt) / events
Pass line-height length(pc) / values
@ -451,116 +451,116 @@ Pass line-height length(in) / events
Pass line-height percentage(%) / values
Pass line-height percentage(%) / events
Pass letter-spacing length(pt) / values
Pass letter-spacing length(pt) / events
Fail letter-spacing length(pt) / events
Pass letter-spacing length(pc) / values
Pass letter-spacing length(pc) / events
Fail letter-spacing length(pc) / events
Pass letter-spacing length(px) / values
Pass letter-spacing length(px) / events
Fail letter-spacing length(px) / events
Pass letter-spacing length(em) / values
Pass letter-spacing length(em) / events
Fail letter-spacing length(em) / events
Pass letter-spacing length(ex) / values
Pass letter-spacing length(ex) / events
Fail letter-spacing length(ex) / events
Pass letter-spacing length(mm) / values
Pass letter-spacing length(mm) / events
Fail letter-spacing length(mm) / events
Pass letter-spacing length(cm) / values
Pass letter-spacing length(cm) / events
Fail letter-spacing length(cm) / events
Pass letter-spacing length(in) / values
Pass letter-spacing length(in) / events
Fail letter-spacing length(in) / events
Pass word-spacing length(pt) / values
Pass word-spacing length(pt) / events
Fail word-spacing length(pt) / events
Pass word-spacing length(pc) / values
Pass word-spacing length(pc) / events
Fail word-spacing length(pc) / events
Pass word-spacing length(px) / values
Pass word-spacing length(px) / events
Fail word-spacing length(px) / events
Pass word-spacing length(em) / values
Pass word-spacing length(em) / events
Fail word-spacing length(em) / events
Pass word-spacing length(ex) / values
Pass word-spacing length(ex) / events
Fail word-spacing length(ex) / events
Pass word-spacing length(mm) / values
Pass word-spacing length(mm) / events
Fail word-spacing length(mm) / events
Pass word-spacing length(cm) / values
Pass word-spacing length(cm) / events
Fail word-spacing length(cm) / events
Pass word-spacing length(in) / values
Pass word-spacing length(in) / events
Fail word-spacing length(in) / events
Pass word-spacing percentage(%) / values
Pass word-spacing percentage(%) / events
Fail word-spacing percentage(%) / events
Pass text-indent length(pt) / values
Pass text-indent length(pt) / events
Fail text-indent length(pt) / events
Pass text-indent length(pc) / values
Pass text-indent length(pc) / events
Fail text-indent length(pc) / events
Pass text-indent length(px) / values
Pass text-indent length(px) / events
Fail text-indent length(px) / events
Pass text-indent length(em) / values
Pass text-indent length(em) / events
Fail text-indent length(em) / events
Pass text-indent length(ex) / values
Pass text-indent length(ex) / events
Fail text-indent length(ex) / events
Pass text-indent length(mm) / values
Pass text-indent length(mm) / events
Fail text-indent length(mm) / events
Pass text-indent length(cm) / values
Pass text-indent length(cm) / events
Fail text-indent length(cm) / events
Pass text-indent length(in) / values
Pass text-indent length(in) / events
Fail text-indent length(in) / events
Pass text-indent percentage(%) / values
Pass text-indent percentage(%) / events
Fail text-shadow shadow(shadow) / values
Fail text-indent percentage(%) / events
Pass text-shadow shadow(shadow) / values
Fail text-shadow shadow(shadow) / events
Pass outline-color color(rgba) / values
Pass outline-color color(rgba) / events
Fail outline-color color(rgba) / events
Pass outline-offset length(pt) / values
Pass outline-offset length(pt) / events
Fail outline-offset length(pt) / events
Pass outline-offset length(pc) / values
Pass outline-offset length(pc) / events
Fail outline-offset length(pc) / events
Pass outline-offset length(px) / values
Pass outline-offset length(px) / events
Fail outline-offset length(px) / events
Pass outline-offset length(em) / values
Pass outline-offset length(em) / events
Fail outline-offset length(em) / events
Pass outline-offset length(ex) / values
Pass outline-offset length(ex) / events
Fail outline-offset length(ex) / events
Pass outline-offset length(mm) / values
Pass outline-offset length(mm) / events
Fail outline-offset length(mm) / events
Pass outline-offset length(cm) / values
Pass outline-offset length(cm) / events
Fail outline-offset length(cm) / events
Pass outline-offset length(in) / values
Pass outline-offset length(in) / events
Fail outline-offset length(in) / events
Pass outline-width length(pt) / values
Pass outline-width length(pt) / events
Fail outline-width length(pt) / events
Pass outline-width length(pc) / values
Pass outline-width length(pc) / events
Fail outline-width length(pc) / events
Pass outline-width length(px) / values
Pass outline-width length(px) / events
Fail outline-width length(px) / events
Pass outline-width length(em) / values
Pass outline-width length(em) / events
Fail outline-width length(em) / events
Pass outline-width length(ex) / values
Pass outline-width length(ex) / events
Fail outline-width length(ex) / events
Pass outline-width length(mm) / values
Pass outline-width length(mm) / events
Fail outline-width length(mm) / events
Pass outline-width length(cm) / values
Pass outline-width length(cm) / events
Fail outline-width length(cm) / events
Pass outline-width length(in) / values
Pass outline-width length(in) / events
Fail outline-width length(in) / events
Pass clip rectangle(rectangle) / values
Pass clip rectangle(rectangle) / events
Fail clip rectangle(rectangle) / events
Pass vertical-align length(pt) / values
Pass vertical-align length(pt) / events
Fail vertical-align length(pt) / events
Pass vertical-align length(pc) / values
Pass vertical-align length(pc) / events
Fail vertical-align length(pc) / events
Pass vertical-align length(px) / values
Pass vertical-align length(px) / events
Fail vertical-align length(px) / events
Pass vertical-align length(em) / values
Pass vertical-align length(em) / events
Fail vertical-align length(em) / events
Pass vertical-align length(ex) / values
Pass vertical-align length(ex) / events
Fail vertical-align length(ex) / events
Pass vertical-align length(mm) / values
Pass vertical-align length(mm) / events
Fail vertical-align length(mm) / events
Pass vertical-align length(cm) / values
Pass vertical-align length(cm) / events
Fail vertical-align length(cm) / events
Pass vertical-align length(in) / values
Pass vertical-align length(in) / events
Fail vertical-align length(in) / events
Pass vertical-align percentage(%) / values
Pass vertical-align percentage(%) / events
Fail vertical-align percentage(%) / events
Pass opacity number[0,1](zero-to-one) / values
Pass opacity number[0,1](zero-to-one) / events
Fail opacity number[0,1](zero-to-one) / events
Pass visibility visibility(keyword) / values
Pass visibility visibility(keyword) / events
Fail visibility visibility(keyword) / events
Pass z-index integer(integer) / values
Pass z-index integer(integer) / events
Fail z-index integer(integer) / events

View file

@ -0,0 +1,178 @@
<!DOCTYPE html>
<title>CSS Transitions Test: trigger transitions on inherited after-change styles</title>
<link rel="help" href="https://drafts.csswg.org/css-transitions-1/#after-change-style">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
#t1 :is(.outer, .inner) { transition: color 1000s steps(2, start); }
#t1 .outer { color: red; }
#t1 .inner { color: black; }
#t1 .outer.green { color: lime; }
#t1 .outer.green .inner { color: unset; }
</style>
<div id="t1">
<div class="outer">
<div>
<div class="inner"></div>
</div>
</div>
</div>
<script>
test(() => {
const outer = document.querySelector("#t1 .outer");
const inner = document.querySelector("#t1 .inner");
outer.offsetTop;
assert_equals(getComputedStyle(outer).color, "rgb(255, 0, 0)",
".outer initially red");
assert_equals(getComputedStyle(inner).color, "rgb(0, 0, 0)",
".inner initially black");
outer.classList.add("green");
assert_equals(getComputedStyle(outer).color, "rgb(128, 128, 0)",
".outer halfway between red and lime");
assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)",
".inner halfway between black and lime");
}, "Start .inner transition based on inherited after-change color from .outer (lime)");
</script>
<style>
#t2 :is(.outer, .inner) { transition: background-color 1000s steps(2, start); }
#t2 .outer { background-color: red; }
#t2 .inner { background-color: black; }
#t2 .outer.green { background-color: lime; }
#t2 .outer.green div { background-color: inherit; }
</style>
<div id="t2">
<div class="outer">
<div>
<div class="inner"></div>
</div>
</div>
</div>
<script>
test(() => {
const outer = document.querySelector("#t2 .outer");
const inner = document.querySelector("#t2 .inner");
outer.offsetTop;
assert_equals(getComputedStyle(outer).backgroundColor, "rgb(255, 0, 0)",
".outer initially red");
assert_equals(getComputedStyle(inner).backgroundColor, "rgb(0, 0, 0)",
".inner initially black");
outer.classList.add("green");
assert_equals(getComputedStyle(outer).backgroundColor, "rgb(128, 128, 0)",
".outer halfway between red and lime");
assert_equals(getComputedStyle(inner).backgroundColor, "rgb(0, 128, 0)",
".inner halfway between black and lime");
}, "Start .inner transition based on inherited after-change background-color from .outer (lime)");
</script>
<style>
#t3 .trans {
transition: 1000s steps(2, start);
transition-property: color, word-spacing;
}
#t3 .a2 { color: red; }
#t3 .a3 { color: black; }
#t3 .a2.green { color: lime; }
#t3 .a2.green .a3 { color: unset; }
#t3 .a1 { word-spacing: 17px; }
#t3 .a3 { word-spacing: 0px; }
#t3 .a1.wide { word-spacing: 100px; }
#t3 .a1.wide .a3 { word-spacing: unset; }
</style>
<div id="t3">
<div class="trans a1">
<div style="color:pink">
<div class="trans a2">
<div class="trans a3"></div>
</div>
</div>
</div>
</div>
</div>
<script>
const a1 = document.querySelector("#t3 .a1");
const a2 = document.querySelector("#t3 .a2");
const a3 = document.querySelector("#t3 .a3");
test(() => {
assert_equals(getComputedStyle(a3).color, "rgb(0, 0, 0)", ".a3 color initially black");
assert_equals(getComputedStyle(a3).wordSpacing, "0px", ".a3 word-spacing initially 0px");
}, "Initial computed styles");
test(() => {
a1.classList.add("wide");
a2.classList.add("green");
assert_equals(getComputedStyle(a3).color, "rgb(0, 128, 0)", ".a3 color transitioning between black and lime");
assert_equals(getComputedStyle(a3).wordSpacing, "50px", ".a3 word-spacing transitioning between 0px and 100px");
}, "Start inner transitions based on inherited after-change color and word-spacing from two different ancestors");
</script>
<style>
#t4 :is(.outer, .inner) { transition: color 1000s steps(2, start); }
#t4 .outer { color: red; }
#t4 .inner { color: black; }
#t4 .outer.green { color: lime; }
#t4 .outer.green .inner { color: unset; }
@starting-style {
#t4 .outer.green { color: pink; }
}
</style>
<div id="t4">
<div class="outer">
<div>
<div class="inner"></div>
</div>
</div>
</div>
<script>
test(() => {
const outer = document.querySelector("#t4 .outer");
const inner = document.querySelector("#t4 .inner");
outer.offsetTop;
assert_equals(getComputedStyle(outer).color, "rgb(255, 0, 0)",
".outer initially red");
assert_equals(getComputedStyle(inner).color, "rgb(0, 0, 0)",
".inner initially black");
outer.classList.add("green");
assert_equals(getComputedStyle(outer).color, "rgb(128, 128, 0)",
".outer halfway between red and lime");
assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)",
".inner halfway between black and lime");
}, "@starting-style rules should not apply to after-change style");
</script>
<style>
#t5 :is(.outer, .inner) { transition: color 1000s steps(2, start); }
#t5 .outer { color: red; }
#t5 .inner { color: black; }
#t5 .outer.green { color: lime; }
#t5 .container { container-type: inline-size; }
@container (width < 100000px) {
#t5 .outer.green .inner { color: unset; }
}
</style>
<div id="t5">
<div class="outer">
<div class="container">
<div class="inner"></div>
</div>
</div>
</div>
<script>
test(() => {
const outer = document.querySelector("#t5 .outer");
const inner = document.querySelector("#t5 .inner");
outer.offsetTop;
assert_equals(getComputedStyle(outer).color, "rgb(255, 0, 0)",
".outer initially red");
assert_equals(getComputedStyle(inner).color, "rgb(0, 0, 0)",
".inner initially black");
outer.classList.add("green");
assert_equals(getComputedStyle(outer).color, "rgb(128, 128, 0)",
".outer halfway between red and lime");
assert_equals(getComputedStyle(inner).color, "rgb(0, 128, 0)",
".inner halfway between black and lime");
}, "@container rules apply to after-change style");
</script>