mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb: Add support for the 'all' CSS property
The "longhands" array is populated in the code generator to avoid the overhead of manually maintaining the list in Properties.json There is one subtest that still fails in 'cssstyledeclaration-csstext-all-shorthand', this is related to us not maintaining the relative order of CSS declarations for custom vs non-custom properties.
This commit is contained in:
parent
0762d57f65
commit
d31a58a7d6
Notes:
github-actions[bot]
2025-06-12 14:26:43 +00:00
Author: https://github.com/Calme1709
Commit: d31a58a7d6
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5039
Reviewed-by: https://github.com/AtkinsSJ ✅
16 changed files with 199 additions and 82 deletions
|
@ -408,6 +408,11 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue const>> Parser::parse_css_value
|
||||||
|
|
||||||
// Special-case property handling
|
// Special-case property handling
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
|
case PropertyID::All:
|
||||||
|
// NOTE: The 'all' property, unlike some other shorthands, doesn't support directly listing sub-property
|
||||||
|
// values, only the CSS-wide keywords - this is handled above, and thus, if we have gotten to here, there
|
||||||
|
// is an invalid value which is a syntax error.
|
||||||
|
return ParseError::SyntaxError;
|
||||||
case PropertyID::AspectRatio:
|
case PropertyID::AspectRatio:
|
||||||
if (auto parsed_value = parse_aspect_ratio_value(tokens); parsed_value && !tokens.has_next_token())
|
if (auto parsed_value = parse_aspect_ratio_value(tokens); parsed_value && !tokens.has_next_token())
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
|
|
|
@ -183,6 +183,14 @@
|
||||||
"align-self"
|
"align-self"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"all": {
|
||||||
|
"affects-layout": true,
|
||||||
|
"affects-stacking-context": true,
|
||||||
|
"inherited": false,
|
||||||
|
"initial": "initial",
|
||||||
|
"longhands": [],
|
||||||
|
"_comment": "The 'longhands' array is populated in the code generator to avoid having to maintain it manually"
|
||||||
|
},
|
||||||
"animation": {
|
"animation": {
|
||||||
"affects-layout": false,
|
"affects-layout": false,
|
||||||
"inherited": false,
|
"inherited": false,
|
||||||
|
|
|
@ -996,57 +996,6 @@ void StyleComputer::for_each_property_expanding_shorthands(PropertyID property_i
|
||||||
set_longhand_property(property_id, value);
|
set_longhand_property(property_id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleComputer::set_property_expanding_shorthands(
|
|
||||||
CascadedProperties& cascaded_properties,
|
|
||||||
PropertyID property_id,
|
|
||||||
CSSStyleValue const& value,
|
|
||||||
GC::Ptr<CSSStyleDeclaration const> declaration,
|
|
||||||
CascadeOrigin cascade_origin,
|
|
||||||
Important important,
|
|
||||||
Optional<FlyString> layer_name)
|
|
||||||
{
|
|
||||||
for_each_property_expanding_shorthands(property_id, value, [&](PropertyID longhand_id, CSSStyleValue const& longhand_value) {
|
|
||||||
if (longhand_value.is_revert()) {
|
|
||||||
cascaded_properties.revert_property(longhand_id, important, cascade_origin);
|
|
||||||
} else if (longhand_value.is_revert_layer()) {
|
|
||||||
cascaded_properties.revert_layer_property(longhand_id, important, layer_name);
|
|
||||||
} else {
|
|
||||||
cascaded_properties.set_property(longhand_id, longhand_value, important, cascade_origin, layer_name, declaration);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void StyleComputer::set_all_properties(
|
|
||||||
CascadedProperties& cascaded_properties,
|
|
||||||
DOM::Element& element,
|
|
||||||
Optional<PseudoElement> pseudo_element,
|
|
||||||
CSSStyleValue const& value,
|
|
||||||
DOM::Document& document,
|
|
||||||
GC::Ptr<CSSStyleDeclaration const> declaration,
|
|
||||||
CascadeOrigin cascade_origin,
|
|
||||||
Important important,
|
|
||||||
Optional<FlyString> layer_name) const
|
|
||||||
{
|
|
||||||
for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) {
|
|
||||||
auto property_id = (CSS::PropertyID)i;
|
|
||||||
|
|
||||||
if (value.is_revert()) {
|
|
||||||
cascaded_properties.revert_property(property_id, important, cascade_origin);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.is_revert_layer()) {
|
|
||||||
cascaded_properties.revert_layer_property(property_id, important, layer_name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullRefPtr<CSSStyleValue const> property_value = value;
|
|
||||||
if (property_value->is_unresolved())
|
|
||||||
property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { document }, element, pseudo_element, property_id, property_value->as_unresolved());
|
|
||||||
set_property_expanding_shorthands(cascaded_properties, property_id, property_value, declaration, cascade_origin, important, layer_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StyleComputer::cascade_declarations(
|
void StyleComputer::cascade_declarations(
|
||||||
CascadedProperties& cascaded_properties,
|
CascadedProperties& cascaded_properties,
|
||||||
DOM::Element& element,
|
DOM::Element& element,
|
||||||
|
@ -1091,12 +1040,6 @@ void StyleComputer::cascade_declarations(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property.property_id == PropertyID::All) {
|
|
||||||
set_all_properties(cascaded_properties, element, pseudo_element, property_value, m_document, &declaration, cascade_origin, important, layer_name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This is a duplicate of set_property_expanding_shorthands() with some extra checks.
|
|
||||||
for_each_property_expanding_shorthands(property.property_id, property_value, [&](PropertyID longhand_id, CSSStyleValue const& longhand_value) {
|
for_each_property_expanding_shorthands(property.property_id, property_value, [&](PropertyID longhand_id, CSSStyleValue const& longhand_value) {
|
||||||
// If we're a PSV that's already been seen, that should mean that our shorthand already got
|
// If we're a PSV that's already been seen, that should mean that our shorthand already got
|
||||||
// resolved and gave us a value, so we don't want to overwrite it with a PSV.
|
// resolved and gave us a value, so we don't want to overwrite it with a PSV.
|
||||||
|
|
|
@ -129,14 +129,6 @@ class FontLoader;
|
||||||
class StyleComputer {
|
class StyleComputer {
|
||||||
public:
|
public:
|
||||||
static void for_each_property_expanding_shorthands(PropertyID, CSSStyleValue const&, Function<void(PropertyID, CSSStyleValue const&)> const& set_longhand_property);
|
static void for_each_property_expanding_shorthands(PropertyID, CSSStyleValue const&, Function<void(PropertyID, CSSStyleValue const&)> const& set_longhand_property);
|
||||||
static void set_property_expanding_shorthands(
|
|
||||||
CascadedProperties&,
|
|
||||||
PropertyID,
|
|
||||||
CSSStyleValue const&,
|
|
||||||
GC::Ptr<CSSStyleDeclaration const>,
|
|
||||||
CascadeOrigin,
|
|
||||||
Important,
|
|
||||||
Optional<FlyString> layer_name);
|
|
||||||
static NonnullRefPtr<CSSStyleValue const> get_inherit_value(CSS::PropertyID, DOM::Element const*, Optional<CSS::PseudoElement> = {});
|
static NonnullRefPtr<CSSStyleValue const> get_inherit_value(CSS::PropertyID, DOM::Element const*, Optional<CSS::PseudoElement> = {});
|
||||||
|
|
||||||
static Optional<String> user_agent_style_sheet_source(StringView name);
|
static Optional<String> user_agent_style_sheet_source(StringView name);
|
||||||
|
@ -222,17 +214,6 @@ private:
|
||||||
|
|
||||||
void compute_defaulted_property_value(ComputedProperties&, DOM::Element const*, CSS::PropertyID, Optional<CSS::PseudoElement>) const;
|
void compute_defaulted_property_value(ComputedProperties&, DOM::Element const*, CSS::PropertyID, Optional<CSS::PseudoElement>) const;
|
||||||
|
|
||||||
void set_all_properties(
|
|
||||||
CascadedProperties&,
|
|
||||||
DOM::Element&,
|
|
||||||
Optional<PseudoElement>,
|
|
||||||
CSSStyleValue const&,
|
|
||||||
DOM::Document&,
|
|
||||||
GC::Ptr<CSSStyleDeclaration const>,
|
|
||||||
CascadeOrigin,
|
|
||||||
Important,
|
|
||||||
Optional<FlyString> layer_name) const;
|
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_stylesheet(CascadeOrigin, Callback) const;
|
void for_each_stylesheet(CascadeOrigin, Callback) const;
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,11 @@ String ShorthandStyleValue::to_string(SerializationMode mode) const
|
||||||
|
|
||||||
// Then special cases
|
// Then special cases
|
||||||
switch (m_properties.shorthand_property) {
|
switch (m_properties.shorthand_property) {
|
||||||
|
case PropertyID::All: {
|
||||||
|
// NOTE: 'all' can only be serialized in the case all sub-properties share the same CSS-wide keyword, this is
|
||||||
|
// handled above, thus, if we get to here that mustn't be the case and we should return the empty string.
|
||||||
|
return ""_string;
|
||||||
|
}
|
||||||
case PropertyID::Background: {
|
case PropertyID::Background: {
|
||||||
auto color = longhand(PropertyID::BackgroundColor);
|
auto color = longhand(PropertyID::BackgroundColor);
|
||||||
auto image = longhand(PropertyID::BackgroundImage);
|
auto image = longhand(PropertyID::BackgroundImage);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <LibMain/Main.h>
|
#include <LibMain/Main.h>
|
||||||
|
|
||||||
void replace_logical_aliases(JsonObject& properties);
|
void replace_logical_aliases(JsonObject& properties);
|
||||||
|
void populate_all_property_longhands(JsonObject& properties);
|
||||||
ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file);
|
ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file);
|
||||||
ErrorOr<void> generate_implementation_file(JsonObject& properties, Core::File& file);
|
ErrorOr<void> generate_implementation_file(JsonObject& properties, Core::File& file);
|
||||||
void generate_bounds_checking_function(JsonObject& properties, SourceGenerator& parent_generator, StringView css_type_name, StringView type_name, Optional<StringView> default_unit_name = {}, Optional<StringView> value_getter = {});
|
void generate_bounds_checking_function(JsonObject& properties, SourceGenerator& parent_generator, StringView css_type_name, StringView type_name, Optional<StringView> default_unit_name = {}, Optional<StringView> value_getter = {});
|
||||||
|
@ -81,6 +82,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
});
|
});
|
||||||
|
|
||||||
replace_logical_aliases(properties);
|
replace_logical_aliases(properties);
|
||||||
|
populate_all_property_longhands(properties);
|
||||||
|
|
||||||
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
|
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
|
||||||
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
|
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
|
||||||
|
@ -123,6 +125,20 @@ void replace_logical_aliases(JsonObject& properties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void populate_all_property_longhands(JsonObject& properties)
|
||||||
|
{
|
||||||
|
auto all_entry = properties.get_object("all"sv);
|
||||||
|
|
||||||
|
VERIFY(all_entry.has_value());
|
||||||
|
|
||||||
|
properties.for_each_member([&](auto name, auto value) {
|
||||||
|
if (value.as_object().has_array("longhands"sv) || value.as_object().has_array("logical-alias-for"sv) || value.as_object().has_string("legacy-alias-for"sv) || name == "direction" || name == "unicode-bidi")
|
||||||
|
return;
|
||||||
|
|
||||||
|
MUST(all_entry->get_array("longhands"sv)->append(JsonValue { name }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file)
|
ErrorOr<void> generate_header_file(JsonObject& properties, Core::File& file)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
@ -142,7 +158,6 @@ namespace Web::CSS {
|
||||||
enum class PropertyID : @property_id_underlying_type@ {
|
enum class PropertyID : @property_id_underlying_type@ {
|
||||||
Invalid,
|
Invalid,
|
||||||
Custom,
|
Custom,
|
||||||
All,
|
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
Vector<String> inherited_shorthand_property_ids;
|
Vector<String> inherited_shorthand_property_ids;
|
||||||
|
@ -448,8 +463,6 @@ Optional<PropertyID> property_id_from_string(StringView string)
|
||||||
if (is_a_custom_property_name_string(string))
|
if (is_a_custom_property_name_string(string))
|
||||||
return PropertyID::Custom;
|
return PropertyID::Custom;
|
||||||
|
|
||||||
if (string.equals_ignoring_ascii_case("all"sv))
|
|
||||||
return PropertyID::All;
|
|
||||||
)~~~");
|
)~~~");
|
||||||
|
|
||||||
properties.for_each_member([&](auto& name, auto& value) {
|
properties.for_each_member([&](auto& name, auto& value) {
|
||||||
|
|
|
@ -152,6 +152,7 @@ All supported properties and their default values exposed from CSSStylePropertie
|
||||||
'align-items': 'normal'
|
'align-items': 'normal'
|
||||||
'alignSelf': 'auto'
|
'alignSelf': 'auto'
|
||||||
'align-self': 'auto'
|
'align-self': 'auto'
|
||||||
|
'all': ''
|
||||||
'animation': 'none'
|
'animation': 'none'
|
||||||
'animationDelay': '0s'
|
'animationDelay': '0s'
|
||||||
'animation-delay': '0s'
|
'animation-delay': '0s'
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
div { }
|
|
@ -0,0 +1,11 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 6 tests
|
||||||
|
|
||||||
|
6 Pass
|
||||||
|
Pass getPropertyValue('all') returns empty string
|
||||||
|
Pass getPropertyValue('all') returns css-wide keyword if possible
|
||||||
|
Pass getPropertyValue('all') returns empty string when single property overriden
|
||||||
|
Pass setProperty('all') sets all property values
|
||||||
|
Pass removeProperty('all') removes all declarations affected by 'all'
|
||||||
|
Pass removeProperty('all') removes an 'all' declaration
|
|
@ -0,0 +1,12 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 6 tests
|
||||||
|
|
||||||
|
5 Pass
|
||||||
|
1 Fail
|
||||||
|
Pass 'all' shorthand alone
|
||||||
|
Pass 'all' shorthand with 'width' and 'height'
|
||||||
|
Pass 'all' shorthand with 'direction' and 'unicode-bidi'
|
||||||
|
Fail 'all' shorthand with 'width', 'height' and custom properties
|
||||||
|
Pass 'all' shorthand with all longhands
|
||||||
|
Pass all:initial should not exclude custom from cssText
|
|
@ -0,0 +1,6 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Pass CSSStyleDeclaration.removeProperty("all")
|
|
@ -2,7 +2,6 @@ Harness status: OK
|
||||||
|
|
||||||
Found 2 tests
|
Found 2 tests
|
||||||
|
|
||||||
1 Pass
|
2 Pass
|
||||||
1 Fail
|
Pass Specified style
|
||||||
Fail Specified style
|
|
||||||
Pass Computed style
|
Pass Computed style
|
14
Tests/LibWeb/Text/input/css/all-with-invalid-value.html
Normal file
14
Tests/LibWeb/Text/input/css/all-with-invalid-value.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
all: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
println(document.styleSheets[0].cssRules[0].cssText);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSSOM Test: Passing "all" shorthand to property methods</title>
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-cascade/#all-shorthand">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-removeproperty">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
const style = document.createElement("div").style;
|
||||||
|
|
||||||
|
test((t) => {
|
||||||
|
t.add_cleanup(() => { style.cssText = ""; } );
|
||||||
|
style.cssText = "width: 50px";
|
||||||
|
assert_equals(style.getPropertyValue("all"), "");
|
||||||
|
}, "getPropertyValue('all') returns empty string");
|
||||||
|
|
||||||
|
test((t) => {
|
||||||
|
t.add_cleanup(() => { style.cssText = ""; } );
|
||||||
|
style.cssText = "all: revert";
|
||||||
|
assert_equals(style.getPropertyValue("all"), "revert");
|
||||||
|
}, "getPropertyValue('all') returns css-wide keyword if possible");
|
||||||
|
|
||||||
|
test((t) => {
|
||||||
|
t.add_cleanup(() => { style.cssText = ""; } );
|
||||||
|
style.cssText = "all: revert; width: 50px";
|
||||||
|
assert_equals(style.getPropertyValue("all"), "");
|
||||||
|
}, "getPropertyValue('all') returns empty string when single property overriden");
|
||||||
|
|
||||||
|
test((t) => {
|
||||||
|
t.add_cleanup(() => { style.cssText = ""; } );
|
||||||
|
style.setProperty("all", "revert");
|
||||||
|
assert_equals(style.getPropertyValue("width"), "revert");
|
||||||
|
assert_equals(style.getPropertyValue("color"), "revert");
|
||||||
|
}, "setProperty('all') sets all property values");
|
||||||
|
|
||||||
|
test((t) => {
|
||||||
|
t.add_cleanup(() => { style.cssText = ""; } );
|
||||||
|
style.cssText = "width: 50px; color: green; direction: rtl";
|
||||||
|
assert_equals(style.getPropertyValue("width"), "50px");
|
||||||
|
assert_equals(style.getPropertyValue("color"), "green");
|
||||||
|
assert_equals(style.getPropertyValue("direction"), "rtl");
|
||||||
|
style.removeProperty("all");
|
||||||
|
assert_equals(style.getPropertyValue("width"), "");
|
||||||
|
assert_equals(style.getPropertyValue("color"), "");
|
||||||
|
assert_equals(style.getPropertyValue("direction"), "rtl");
|
||||||
|
}, "removeProperty('all') removes all declarations affected by 'all'");
|
||||||
|
|
||||||
|
test((t) => {
|
||||||
|
t.add_cleanup(() => { style.cssText = ""; } );
|
||||||
|
style.cssText = "all: revert";
|
||||||
|
style.removeProperty("all");
|
||||||
|
assert_equals(style.getPropertyValue("all"), "");
|
||||||
|
}, "removeProperty('all') removes an 'all' declaration");
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSSOM test: serialization of the 'all' shorthand in cssText</title>
|
||||||
|
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/cssom-1/#dom-cssstyledeclaration-csstext">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
const style = document.createElement("div").style;
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
style.cssText = "all: inherit";
|
||||||
|
assert_equals(style.cssText, "all: inherit;");
|
||||||
|
}, "'all' shorthand alone");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
style.cssText = "width: 100px; all: inherit; height: inherit";
|
||||||
|
assert_equals(style.cssText, "all: inherit;");
|
||||||
|
}, "'all' shorthand with 'width' and 'height'");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
style.cssText = "direction: ltr; all: inherit; unicode-bidi: plaintext";
|
||||||
|
assert_equals(style.cssText, "direction: ltr; all: inherit; unicode-bidi: plaintext;");
|
||||||
|
}, "'all' shorthand with 'direction' and 'unicode-bidi'");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
style.cssText = "width: 100px; --a: a; all: inherit; --b: b; height: inherit";
|
||||||
|
assert_equals(style.cssText, "--a: a; all: inherit; --b: b;");
|
||||||
|
}, "'all' shorthand with 'width', 'height' and custom properties");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
let cssText = "all: inherit; ";
|
||||||
|
for (let longhand of getComputedStyle(document.documentElement)) {
|
||||||
|
cssText += longhand + ": inherit; ";
|
||||||
|
}
|
||||||
|
style.cssText = cssText;
|
||||||
|
if (CSS.supports("interactivity:inert")) {
|
||||||
|
assert_equals(style.cssText, "all: inherit; direction: inherit; interactivity: inherit; unicode-bidi: inherit;");
|
||||||
|
} else {
|
||||||
|
assert_equals(style.cssText, "all: inherit; direction: inherit; unicode-bidi: inherit;");
|
||||||
|
}
|
||||||
|
}, "'all' shorthand with all longhands");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
style.cssText = "--foo: bar; all: initial";
|
||||||
|
assert_true(style.cssText.includes("--foo: bar"), "cssText serialization includes custom property");
|
||||||
|
}, "all:initial should not exclude custom from cssText");
|
||||||
|
</script>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSSStyleDeclaration.removeProperty("all")</title>
|
||||||
|
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/cssom-1/#dom-cssstyledeclaration-removeproperty">
|
||||||
|
<script src="../../resources/testharness.js"></script>
|
||||||
|
<script src="../../resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
let style = document.createElement("div").style;
|
||||||
|
style.width = "40px";
|
||||||
|
assert_equals(style.length, 1, "setter should work as expected");
|
||||||
|
style.removeProperty("all");
|
||||||
|
assert_equals(style.length, 0, "all is a shorthand of all properties, so should remove the property");
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue