diff --git a/Tests/LibWeb/Text/expected/css/attribute-selector-case-sensitivity.txt b/Tests/LibWeb/Text/expected/css/attribute-selector-case-sensitivity.txt
new file mode 100644
index 000000000000..1bfb3c1d2e5f
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/css/attribute-selector-case-sensitivity.txt
@@ -0,0 +1,4 @@
+The accept attribute is matched case insensitively in HTML documents true
+The accept attribute is matched case insensitively in XML documents false
+The accesskey attribute is matched case insensitively in HTML documents false
+The accesskey attribute is matched case insensitively in XML documents false
diff --git a/Tests/LibWeb/Text/input/css/attribute-selector-case-sensitivity.html b/Tests/LibWeb/Text/input/css/attribute-selector-case-sensitivity.html
new file mode 100644
index 000000000000..535d2ffabcd6
--- /dev/null
+++ b/Tests/LibWeb/Text/input/css/attribute-selector-case-sensitivity.html
@@ -0,0 +1,18 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
index 029dff9c8cf5..43492dccf039 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
@@ -77,56 +77,6 @@ class Parser {
[[nodiscard]] LengthOrCalculated parse_as_sizes_attribute();
- // https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors
- static constexpr Array case_insensitive_html_attributes = {
- "accept"sv,
- "accept-charset"sv,
- "align"sv,
- "alink"sv,
- "axis"sv,
- "bgcolor"sv,
- "charset"sv,
- "checked"sv,
- "clear"sv,
- "codetype"sv,
- "color"sv,
- "compact"sv,
- "declare"sv,
- "defer"sv,
- "dir"sv,
- "direction"sv,
- "disabled"sv,
- "enctype"sv,
- "face"sv,
- "frame"sv,
- "hreflang"sv,
- "http-equiv"sv,
- "lang"sv,
- "language"sv,
- "link"sv,
- "media"sv,
- "method"sv,
- "multiple"sv,
- "nohref"sv,
- "noresize"sv,
- "noshade"sv,
- "nowrap"sv,
- "readonly"sv,
- "rel"sv,
- "rev"sv,
- "rules"sv,
- "scope"sv,
- "scrolling"sv,
- "selected"sv,
- "shape"sv,
- "target"sv,
- "text"sv,
- "type"sv,
- "valign"sv,
- "valuetype"sv,
- "vlink"sv,
- };
-
private:
Parser(ParsingContext const&, Vector);
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp b/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp
index 15693ff8c79e..523a737b3475 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/SelectorParsing.cpp
@@ -260,15 +260,8 @@ Parser::ParseErrorOr Parser::parse_attribute_simple_se
.type = Selector::SimpleSelector::Type::Attribute,
.value = Selector::SimpleSelector::Attribute {
.match_type = Selector::SimpleSelector::Attribute::MatchType::HasAttribute,
- // FIXME: Case-sensitivity is defined by the document language.
- // HTML is insensitive with attribute names, and our code generally assumes
- // they are converted to lowercase, so we do that here too. If we want to be
- // correct with XML later, we'll need to keep the original case and then do
- // a case-insensitive compare later.
.qualified_name = qualified_name,
- .case_type = case_insensitive_html_attributes.contains_slow(qualified_name.name.lowercase_name)
- ? Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch
- : Selector::SimpleSelector::Attribute::CaseType::DefaultMatch,
+ .case_type = Selector::SimpleSelector::Attribute::CaseType::DefaultMatch,
}
};
diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
index efd95c882b74..8710ae3b6a3a 100644
--- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
+++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
@@ -213,10 +213,37 @@ static inline bool matches_attribute(CSS::Selector::SimpleSelector::Attribute co
if (!attr)
return false;
- auto const case_insensitive_match = (attribute.case_type == CSS::Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch);
- auto const case_sensitivity = case_insensitive_match
- ? CaseSensitivity::CaseInsensitive
- : CaseSensitivity::CaseSensitive;
+ auto case_sensitivity = [&](CSS::Selector::SimpleSelector::Attribute::CaseType case_type) {
+ switch (case_type) {
+ case CSS::Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch:
+ return CaseSensitivity::CaseInsensitive;
+ case CSS::Selector::SimpleSelector::Attribute::CaseType::CaseSensitiveMatch:
+ return CaseSensitivity::CaseSensitive;
+ case CSS::Selector::SimpleSelector::Attribute::CaseType::DefaultMatch:
+ // See: https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors
+ if (element.document().is_html_document()
+ && element.namespace_uri() == Namespace::HTML
+ && attribute_name.is_one_of(
+ HTML::AttributeNames::accept, HTML::AttributeNames::accept_charset, HTML::AttributeNames::align,
+ HTML::AttributeNames::alink, HTML::AttributeNames::axis, HTML::AttributeNames::bgcolor, HTML::AttributeNames::charset,
+ HTML::AttributeNames::checked, HTML::AttributeNames::clear, HTML::AttributeNames::codetype, HTML::AttributeNames::color,
+ HTML::AttributeNames::compact, HTML::AttributeNames::declare, HTML::AttributeNames::defer, HTML::AttributeNames::dir,
+ HTML::AttributeNames::direction, HTML::AttributeNames::disabled, HTML::AttributeNames::enctype, HTML::AttributeNames::face,
+ HTML::AttributeNames::frame, HTML::AttributeNames::hreflang, HTML::AttributeNames::http_equiv, HTML::AttributeNames::lang,
+ HTML::AttributeNames::language, HTML::AttributeNames::link, HTML::AttributeNames::media, HTML::AttributeNames::method,
+ HTML::AttributeNames::multiple, HTML::AttributeNames::nohref, HTML::AttributeNames::noresize, HTML::AttributeNames::noshade,
+ HTML::AttributeNames::nowrap, HTML::AttributeNames::readonly, HTML::AttributeNames::rel, HTML::AttributeNames::rev,
+ HTML::AttributeNames::rules, HTML::AttributeNames::scope, HTML::AttributeNames::scrolling, HTML::AttributeNames::selected,
+ HTML::AttributeNames::shape, HTML::AttributeNames::target, HTML::AttributeNames::text, HTML::AttributeNames::type,
+ HTML::AttributeNames::valign, HTML::AttributeNames::valuetype, HTML::AttributeNames::vlink)) {
+ return CaseSensitivity::CaseInsensitive;
+ }
+
+ return CaseSensitivity::CaseSensitive;
+ }
+ VERIFY_NOT_REACHED();
+ }(attribute.case_type);
+ auto case_insensitive_match = case_sensitivity == CaseSensitivity::CaseInsensitive;
switch (attribute.match_type) {
case CSS::Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch: