diff --git a/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Libraries/LibWeb/CSS/SelectorEngine.cpp index cba4bbc397d..5eb13d3a89a 100644 --- a/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -549,8 +549,7 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla case CSS::PseudoClass::Focus: return element.is_focused(); case CSS::PseudoClass::FocusVisible: - // FIXME: We should only apply this when a visible focus is useful. Decide when that is! - return element.is_focused(); + return element.is_focused() && element.should_indicate_focus(); case CSS::PseudoClass::FocusWithin: { auto* focused_element = element.document().focused_element(); return focused_element && element.is_inclusive_ancestor_of(*focused_element); diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 4b83bd546c0..50f0f89bbed 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -3967,4 +3967,41 @@ void Element::play_or_cancel_animations_after_display_property_change() } } +// https://drafts.csswg.org/selectors/#indicate-focus +bool Element::should_indicate_focus() const +{ + // User agents can choose their own heuristics for when to indicate focus; however, the following (non-normative) + // suggestions can be used as a starting point for when to indicate focus on the currently focused element: + + // FIXME: * If the user has expressed a preference (such as via a system preference or a browser setting) to always see a + // visible focus indicator, indicate focus regardless of any other factors. (Another option may be for the user + // agent to show its own focus indicator regardless of author styles.) + + // * If the element which supports keyboard input (such as an input element, or any other element that would + // triggers a virtual keyboard to be shown on focus if a physical keyboard were not present), indicate focus. + if (is(this)) + return true; + + // * If the user interacts with the page via keyboard or some other non-pointing device, indicate focus. (This means + // keyboard usage may change whether this pseudo-class matches even if it doesn’t affect :focus). + if (document().last_focus_trigger() == HTML::FocusTrigger::Key) + return true; + + // FIXME: * If the user interacts with the page via a pointing device (mouse, touchscreen, etc.) and the focused element + // does not support keyboard input, don’t indicate focus. + + // * If the previously-focused element indicated focus, and a script causes focus to move elsewhere, indicate focus + // on the newly focused element. + // Conversely, if the previously-focused element did not indicate focus, and a script causes focus to move + // elsewhere, don’t indicate focus on the newly focused element. + // AD-HOC: Other browsers seem to always indicate focus on programmatically focused elements. + if (document().last_focus_trigger() == HTML::FocusTrigger::Script) + return true; + + // FIXME: * If a newly-displayed element automatically gains focus (such as an action button in a freshly opened dialog), + // that element should indicate focus. + + return false; +} + } diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index cd89143078f..5410d169fe6 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -272,6 +272,7 @@ public: virtual void did_receive_focus() { } virtual void did_lose_focus() { } + bool should_indicate_focus() const; static GC::Ptr create_layout_node_for_display_type(DOM::Document&, CSS::Display const&, GC::Ref, Element*);