diff --git a/__tests__/spelling-ignore.yml b/__tests__/spelling-ignore.yml index 5fe2885729f..bc8caa654b4 100644 --- a/__tests__/spelling-ignore.yml +++ b/__tests__/spelling-ignore.yml @@ -10,6 +10,7 @@ - https - wai-aria - validator +- 8lzn42 # Tag(s) - svg # `aria-query` dom tags does not list `svg` @@ -88,6 +89,7 @@ - rfc - webauthn - customizable +- ua #lowercase needed in reference list # spell checker checks against strict casing & hence some repeated words here - Autocomplete @@ -136,7 +138,7 @@ - ozplayer - GitHub -# Test case anamolies +# Test case anomalies - brewitt-taylor - level2-frame1 - level1-frame2 @@ -210,6 +212,11 @@ - dom-meta-content - showModal +# Javascript identifiers +- clientRects +- getBoundingClientRect +- getClientRects + # Unsure why the dictionary does not have these words - programmatically - personalization @@ -238,6 +245,7 @@ - focusability - unitless - luminance +- checkboxes # this seems to be the correct plural - disambiguated - superclass - grey @@ -273,11 +281,21 @@ - 10px - 15px - 16px +- 17px +- 18px - 20px - 24px - 25px - 30px - 32px +- 35px +- 40px +- 41px +- 44px +- 45px +- 48px +- 50px +- 54px # Language codes - da diff --git a/_rules/target-size-enhanced-gi8qkf.md b/_rules/target-size-enhanced-gi8qkf.md new file mode 100644 index 00000000000..ee44ebc4db2 --- /dev/null +++ b/_rules/target-size-enhanced-gi8qkf.md @@ -0,0 +1,847 @@ +--- +id: gi8qkf +name: Interactive component has enhanced size +rule_type: atomic +description: | + This rule checks that elements that can receive pointer events have a size of at least 44×44 pixels, unless they are inline, are user agent controlled, or have essential size. +accessibility_requirements: + wcag21:2.5.5: # Target size (enhanced) (AAA) + forConformance: true + failed: not satisfied + passed: further testing needed + inapplicable: further testing needed + wcag22:2.5.8: # Target Size (Minimum) (AA) + secondary: 'This success criterion is **less strict** than this rule. This is because this criterion has a lower size requirement. Some of the failed examples may satisfy this success criterion.' +input_aspects: + - DOM Tree + - CSS Styling +acknowledgments: + authors: + - Jean-Yves Moyen + test_assets: Map Image designed by Freepik; Zoom-out icon and Zoom in icon created by Rizki Ahmad Fauzi - Flaticon +--- + +## Applicability + +This rule applies to any [HTML element][namespaced element] which is [observed as a pointer events target][], except when one of the following is true: + +- the element has an [always empty clickable area][]; or +- the element is [in a block of text][]; or +- the element is [User Agent controlled][user agent controlled component]; or +- the element has [essential size][]. + +## Expectation + +For each target element, at least one of the following is true: + +- the element can be brought into viewport though scrolling with a [clickable area][] containing an [aligned rectangle][] with width and height of at least 44 CSS pixels; or +- there is an [instrument][] to achieve an equivalent goal as the target element on the same page, and through scrolling this [instrument][] can be brought into viewport with a [clickable area][] containing an [aligned rectangle][] with width and height of at least 44 CSS pixels. + +## Background + +While the rule, and [Success Criterion 2.5.5 Target Size (enhanced)][sc255], apply targets of any shape, the test cases mostly focus on targets whose [clickable area][] is itself an [aligned rectangle][]. This acknowledges the fact that the [border box][] of an element can easily be queried by automated tools (e.g., through the `getBoundingClientRect` function), and therefore it is expected that most automated tools will perform better on such elements. For elements with irregular clickable shapes, including `area` elements, nested targets, or elements that have been rotated or clipped, the actual [clickable area][] is much harder to determine and may be much smaller than the [border box][]. These elements could fail the rule while their [border box][] contains a large enough [aligned rectangle][]. In order to allow automated tools to have a consistent implementation of this rule, it does not contain such test cases, notably all Failed test cases have a [border box][] which is too small. + +### Assumptions + +- This rule assumes that [focusable][] `widget` are effectively clickable. If a widget is [focusable][] without being clickable, it may fail this rule while [Success Criterion 2.5.5 Target Size (enhanced)][sc255] is satisfied. + +### Accessibility Support + +Hit testing isn't properly defined, and this has been an [issue in the CSS specification](https://github.com/w3c/csswg-drafts/issues/2325) for years. Therefore, different User Agents may perform it differently, resulting in different [clickable areas][clickable area] for the same element. As of February 2025, the ACT rules Community Group is not aware of actual cases resulting in significantly different [clickable areas][clickable area]. + +### Bibliography + +- [Understanding Success Criterion 2.5.5: Target Size (enhanced)](https://www.w3.org/WAI/WCAG22/Understanding/target-size-enhanced.html) + +## Test Cases + +> **Note:** Several examples draw borders around some of the elements or texts. This is purely for aesthetic purpose and to clearly show the [clickable areas][clickable area] that are not obvious. These borders are solid green when showing good cases, or relevant areas; and dashed red when showing bad cases, or irrelevant areas. + +> **Note:** Several examples illustrate overlapping and partially obscured content with fully transparent `div` (with a dashed red border), in order to still show the underlying target. This often results in very "artificial" examples where in real page the overlapping element would not be transparent and would actually hide the target. + +### Passed + +#### Passed Example 1 + +This `link` has a [clickable area][] of approximately 210×55 pixels. + +```html + +ACT rules +``` + +#### Passed Example 2 + +This button has a [clickable area][] of exactly 44×44 pixels. + +```html + + +``` + +#### Passed Example 3 + +This `input` element, combined with its [implicit label][] and its padding, has a [clickable area][] containing a rectangle of approximately 81×48px. Note that this rectangle has to intersect both the `input` element itself, and the text of the label (within the solid green border), as none of the individual components are enough. + +```html + + Passed Example 3 + + + + + + + +``` + +#### Passed Example 4 + +This `input` element, combined with its [explicit label][] and its padding, has a [clickable area][] containing a rectangle of approximately 81×45px. Note that this rectangle has to intersect both the `input` element itself, and the text of the label (within the solid green border), as none of the individual components are enough. + +```html + + Passed Example 4 + + + + + + + + +``` + +#### Passed Example 5 + +This button has a clickable area of approximately 212×54px due to the overflowing text being clickable. The `div` element is only here to visually display the clickable area of the text. + +```html + + Passed Example 5 + + + + + + + + + +``` + +#### Passed Example 6 + +This button, together with its padding and border, has a [clickable area][] of more than 44×44px. The solid green border shows the [clickable area][] while the dashed red one shows the inner text (without sizing nor padding). + +```html + + Passed Example 6 + + + + + +
Hi
+ + +``` + +#### Passed Example 7 + +The `#small` button has a [clickable area][] of only 35×35px, but there is an [instrument][] to achieve the same function with a 44×44px [clickable area][] (namely, the `#large` button). + +```html + + + +``` + +#### Passed Example 8 + +This button has a [clickable area][] containing a 44×44px rectangle. Even though it is partially obscured by the dashed red `div`, its remaining [clickable area][] contains a 44×44px rectangle delimited by prolonging the solid green lines. + +```html + + Passed Example 9 + + + + + + +
+
+
+ +``` + +#### Passed Example 9 + +This button has a [clickable area][] of roughly 73×50px. The `div` element with a dashed red border does not obscure it because of its `pointer-events: none` CSS property that let the clicks go through. + +```html + + Passed Example 10 + + + + + + +
+ +``` + +#### Passed Example 10 + +This button has a 50×50px [clickable area][]. The `div` with a dashed red border is not obscuring it because it can be scrolled out of the way. The solid green lines hint at a 44×44px area inside the button. + +```html + + Passed Example 12 + + + + +
+
+
+
+ + +
+
+ +``` + +#### Passed Example 11 + +The [clickable area][] of this button contains a 44×44px [aligned rectangle][]. Note that the actual [border box][] has to be much larger to account for the rounded corners. + +```html + + +``` + +#### Passed Example 12 + +This button has been clipped, leaving a [clickable area][] containing a 45×45px [aligned rectangle][]. + +```html + + Failed Example + + + + +
+ Hello +
+ +``` + +### Failed + +#### Failed Example 1 + +This `button` has a [clickable area][] of only 35×35 pixels. + +```html + + +``` + +#### Failed Example 2 + +This link only has a [clickable area][] of approximately 66×18 pixels, as shown by its border. + +```html + + Failed Example 2 + + + + + ACT rules + +``` + +#### Failed Example 3 + +This custom button has a [clickable area][] of approximately 18×20px, as shown by its dashed red border. + +```html + + Failed Example 3 + + + + Hi + +``` + +#### Failed Example 4 + +This input, together with its [implicit label][] and its padding has a [clickable area][] whose height is below 41px. + +```html + +``` + +#### Failed Example 5 + +The `#small` button has a [clickable area][] of only 35×35px. The `#large` button has a [clickable area][] of 44×44px, but it does not achieve the same objective. + +```html + + + +``` + +#### Failed Example 6 + +These links are have a [clickable area][] of approximately 184×17px and 267×17px. There ancestor [block box][] is created by the `li` elements which contain no other [text node][] (except for the `::marker` pseudo-element), hence they are not [in a block of text][]. + +```html +

Useful links for the ACT rules group:

+ +``` + +#### Failed Example 7 + +This button only has a [clickable area][] of approximately 20×45px, because it is obscured by the `div` with a dashed red border. The solid green lines hint at how a 44×44px area would fit inside the button, but not inside the non-obscured part. + +```html + + Failed Example 6 + + + + + + +
+
+
+ +``` + +#### Failed Example 8 + +This button only has a [clickable area][] of approximately 20×45px, because it is obscured by the `div` with a dashed red border. Even though the `div` is scrollable, it is not scrollable fully out of the way and always obscures the button. The solid green lines hint at how a 44×44px area would fit inside the button, but not inside the never obscured part. + +```html + + Failed Example 7 + + + + +
+
+
+
+ + +
+
+ +``` + +#### Failed Example 9 + +These radio buttons have their size modified by the author and are therefore not [User Agent controlled components][user agent controlled component]. Their [clickable area][] is too small. + +```html + +
+ Pick a color (required) + + +
+``` + +#### Failed Example 10 + +The zoom buttons do not have [essential size][]; they are too small. The pin (red square) on this map has [essential size][]. + +```html + + +Location of ACT rules headquarters: +
+ + +``` + +#### Failed Example 11 + +The [clickable area][] of this button does not contain a 44×44px [aligned rectangle][]. + +```html + + +``` + +#### Failed Example 12 + +The [clickable area][] of this button does not contain a 44×44px [aligned rectangle][]. + +```html + + +``` + +#### Failed Example 13 + +The [clickable area][] of this button only contains a 25×45px [aligned rectangle][]. + +```html + + Failed Example + + + + +
+ Hi +
+ +``` + +### Inapplicable + +#### Inapplicable Example 1 + +These `input` elements and `button` are `disabled` and therefore not [focusable][]. + +```html +
+
+
+ +
+``` + +#### Inapplicable Example 2 + +This button is not [observed as a pointer events target][] because it is entirely covered by the `div` element with a dashed red border. + +```html + + Inapplicable Example + + + + + + +
+ +``` + +#### Inapplicable Example 3 + +This button has an [always empty clickable area][] because it is moved off-screen and cannot be scrolled to. + +```html + + +``` + +#### Inapplicable Example 4 + +These links are [in a block of text][]. + +```html +

+ The size of the target for + pointer inputs is at least 44 by 44 + CSS pixels. +

+``` + +#### Inapplicable Example 5 + +These links are [in a block of text][] + +```html +

Useful links for the ACT rules group:

+ +``` + +#### Inapplicable Example 6 + +This checkbox is an [User Agent controlled component][]. + +```html +

+ + I agree with the terms and conditions. +

+``` + +#### Inapplicable Example 7 + +The pin (red square) on this map has [essential size][] because it is important to pinpoint the exact location. + +```html + + +Location of ACT rules headquarters: +
+ +``` + +[aligned rectangle]: #aligned-rectangle 'Definition of Aligned Rectangle' +[always empty clickable area]: #clickable-area:empty 'Definition of Always Empty Clickable Area' +[block box]: https://drafts.csswg.org/css-display/#block-box 'CSS definition of a Block Box' +[border box]: https://www.w3.org/TR/css-box-3/#border-box 'CSS definition of Border Box' +[clickable area]: #clickable-area 'Definition of Clickable Area' +[essential size]: #essential-target-size 'Definition of Essential Target Size' +[explicit label]: #programmatic-label:explicit 'Definition of Explicit Label' +[focusable]: #focusable 'Definition of Focusable' +[implicit label]: #programmatic-label:implicit 'Definition of Implicit Label' +[in a block of text]: #in-a-block-of-text 'Definition of In a Block of Text' +[instrument]: #instrument-to-achieve-an-objective 'Definition of Instrument to Achieve an Objective' +[namespaced element]: #namespaced-element 'Definition of Namespaced Element' +[observed as a pointer events target]: #observed-as-pointer-events-target 'Definition of Observed as a Pointer Events Target' +[sc255]: https://www.w3.org/TR/WCAG22/#target-size-enhanced 'Success Criterion 2.5.5 Target Size (enhanced)' +[text node]: https://dom.spec.whatwg.org/#text 'DOM Definition of Text Node' +[user agent controlled component]: #user-agent-controlled-component 'Definition of UI Controlled Component' diff --git a/pages/examples/programmatic-label.md b/pages/examples/programmatic-label.md index 37fbc0b445d..b0987010457 100644 --- a/pages/examples/programmatic-label.md +++ b/pages/examples/programmatic-label.md @@ -56,13 +56,13 @@ The `div` element is not [labelable][]. Therefore, it is not a [labeled control]
My name is Bond. James Bond.
``` -## aria-labelledby on div +## aria-labelledby on aside -The `span` element is referenced by the `aria-labelledby` attribute on the `div` element. Therefore, the `span` element is a programmatic label of the `div` element. Note that the `aria-labelledby` attribute works on any element, not just on the [labelable][] elements. +The `span` element is referenced by the `aria-labelledby` attribute on the `aside` element. Therefore, the `span` element is a programmatic label of the `aside` element. Note that the `aria-labelledby` attribute works on any element, not just on the [labelable][] elements. ```html Full name: -
My name is Bond. James Bond.
+ ``` [programmatic label]: /glossary/#programmatic-label diff --git a/pages/glossary/aligned-rectangle.md b/pages/glossary/aligned-rectangle.md new file mode 100644 index 00000000000..df826efbb4a --- /dev/null +++ b/pages/glossary/aligned-rectangle.md @@ -0,0 +1,13 @@ +--- +title: Aligned rectangle +key: aligned-rectangle +unambiguous: true +objective: true +input_aspects: +--- + +A set of coordinates R is an _aligned rectangle_ if there exist a coordinate _(x, y)_ and numbers _w_ and _h_ such that all coordinates _(a, b)_ with _x ⩽ a ⩽ x+w_ and _y ⩽ b ⩽ y+h_ are part of R, and reciprocally all coordinates _(a, b)_ in R verify _x ⩽ a ⩽ x+w_ and _y ⩽ b ⩽ y+h_. + +R is then said to have corner _(x, y)_, width _w_, and height _h_. + +Note that the rectangle is "aligned" in the sense that its sides align with the axis of the coordinate system. diff --git a/pages/glossary/clickable-area.md b/pages/glossary/clickable-area.md new file mode 100644 index 00000000000..18c268b602e --- /dev/null +++ b/pages/glossary/clickable-area.md @@ -0,0 +1,51 @@ +--- +title: Clickable area +key: clickable-area +unambiguous: true +objective: false +input_aspects: + - CSS styling + - DOM tree +--- + +The directly clickable area of an element is the set of all viewport coordinates for which the element is the [topmost event target][] + +The _clickable area_ of an element is the union of its _directly clickable area_ and that of its [implicit][implicit label] or [explicit label][]. Clickable areas may contain several disconnected parts. + +An element has an always empty clickable area if its clickable area is empty and cannot be made non-empty through scrolling. + +#### Examples of totally empty clickable areas + +This `button` has a totally empty clickable area because it is moved off-screen and cannot be brought into the viewport through scrolling. + +```html + + +``` + +This `button` does not have a totally empty clickable area; its clickable area can be made non-empty through vertical scrolling. + +```html + + +``` + +[explicit label]: #programmatic-label:explicit 'Definition of Explicit Label' +[implicit label]: #programmatic-label:implicit 'Definition of Implicit Label' +[topmost event target]: https://w3c.github.io/uievents/#topmost-event-target 'CSS definition of Topmost Event Target' diff --git a/pages/glossary/essential-target-size.md b/pages/glossary/essential-target-size.md new file mode 100644 index 00000000000..95fa6da2565 --- /dev/null +++ b/pages/glossary/essential-target-size.md @@ -0,0 +1,13 @@ +--- +title: Essential Target Size +key: essential-target-size +unambiguous: true +objective: false +--- + +An element which is [observed as a pointer events target][] has _essential target size_ if at least one of the following is true: + +- the element is a pin on a map, indicating a precise position, and larger size would create confusion regarding this position; or +- the element is part of a graphical representation of data (e.g., a graph), indicating a precise value, and larger size would create confusion regarding this value. + +[observed as a pointer events target]: #observed-as-pointer-events-target 'Definition of Observed as a Pointer Events Target' diff --git a/pages/glossary/in-a-block-of-text.md b/pages/glossary/in-a-block-of-text.md new file mode 100644 index 00000000000..864ffd73224 --- /dev/null +++ b/pages/glossary/in-a-block-of-text.md @@ -0,0 +1,19 @@ +--- +title: In a Block of Text +key: in-a-block-of-text +unambiguous: true +objective: true +input_aspects: + - CSS styling + - DOM tree +--- + +An element E is _in a block of text_ if its closest [inclusive ancestor][] which creates a [block box][] contains at least one non-whitespace [text node][] descendant (other than a `::marker` pseudo-element) that is not also a descendant of E. + +[block box]: https://drafts.csswg.org/css-display/#block-box 'CSS definition of a Block Box' +[inclusive ancestor]: https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor 'DOM Definition of Inclusive Ancestor' +[text node]: https://dom.spec.whatwg.org/#text 'DOM Definition of Text Node' + +``` + +``` diff --git a/pages/glossary/observed-as-pointer-events-target.md b/pages/glossary/observed-as-pointer-events-target.md new file mode 100644 index 00000000000..28764c20f0d --- /dev/null +++ b/pages/glossary/observed-as-pointer-events-target.md @@ -0,0 +1,37 @@ +--- +title: Observed as a pointer events target +key: observed-as-pointer-events-target +unambiguous: true +objective: true +input_aspects: + - CSS styling + - DOM tree +--- + +An element is _observed as a pointer events target_ when all the following conditions are true: + +- the element is a [semantic `widget`][semantic role]; and +- the element is [focusable][]; and +- the element [computed value][] of the `pointer-events` CSS property is `auto`; and +- through scrolling, it is possible to have parts of the element's [border box][] which intersect the viewport but do not intersect by the [border boxes][] any element that appears later in the [painting order][] and has a [computed][computed value] `pointer-events` of `auto`. + +#### Background + +This definition tries to capture which HTML elements can actually respond to pointer events. It is not possible to have an exact definition of these for two reasons: + +- Sometimes, the element that handles the event is not the element that appears to react to it, but an ancestor (or descendant) capturing the event during propagation or bubbling. In the most extreme case, the `body` element of a page could be the only one with an event handler, acting differently depending on where the event actually occurred. In such a case, a button would be perceived by users as something that can be targeted by a pointer event, while technically it is the `body` element which is targeted. +- It is not possible to query the list of event listeners on a given element. Some User Agents offer ways to monitor events fired at a given element, but none offer a way to query for event listeners. Additionally, an event listener might ultimately do nothing and thus, for users, the corresponding element wouldn't look like it could be targeted by pointer events (since it effectively wouldn't react to them). + +As a consequence, this definition has these two known limitations: + +- Not all HTML elements that can actually be targeted by a pointer event match this definition. For example, an author may build custom buttons without giving them an appropriate role or making them [focusable][]; or content overflowing the [border box][] of an element is clickable, but that element might not match the definition if the [border box][] is off-screen. Elements that can actually be targeted by pointer events but do not match this definition likely fail either [Success Criterion 4.1.2 Name, Role, Value][sc412] or [Success Criterion 2.1.1 Keyboard][sc211]. +- Not all HTML elements that match this definition can actually be targeted by a pointer event. For example, when the actual clickable area does not cover the full [border box][] and is entirely covered by other elements, or when the element has an event handler that does nothing. Elements that match this definition but cannot actually be targeted by pointer events likely fail [Success Criterion 2.5.6 Concurrent Input Mechanisms][sc256]. + +[border box]: https://www.w3.org/TR/css-box-3/#border-box 'CSS definition of Border Box' +[computed value]: https://www.w3.org/TR/css-cascade-3/#computed 'CSS definition of Computed Value' +[focusable]: #focusable 'Definition of Focusable' +[painting order]: https://drafts.csswg.org/css2/#painting-order 'CSS definition of Painting Order' +[sc211]: https://www.w3.org/TR/WCAG22/#keyboard 'Success Criterion 2.1.1 Keyboard' +[sc256]: https://www.w3.org/TR/WCAG22/#concurrent-input-mechanisms 'Success Criterion 2.5.6 Concurrent Input Mechanisms' +[sc412]: https://www.w3.org/TR/WCAG22/#name-role-value 'Success Criterion 4.1.2 Name, Role, Value' +[semantic role]: #semantic-role 'Definition of Semantic Role' diff --git a/pages/glossary/programmatic-label.md b/pages/glossary/programmatic-label.md index 83af78845a6..0fb8a926c43 100755 --- a/pages/glossary/programmatic-label.md +++ b/pages/glossary/programmatic-label.md @@ -16,5 +16,9 @@ For more details, see [examples of programmatic label][]. **Note**: a given element may have more than one programmatic label. +The label L of a [labeled control][] T is its explicit label if L has a `for` attribute referencing T's `id` attribute. + +The label L of a [labeled control][] T is its implicit label if L has no `for` attribute and is an ancestor of T in the DOM tree. Note that explicit labels take precedence over implicit label, and that [labeled controls][labeled control] do not cross shadow boundaries nor content documents. + [labeled control]: https://html.spec.whatwg.org/multipage/forms.html#labeled-control 'Definition of labeled control' [examples of programmatic label]: https://act-rules.github.io/pages/examples/programmatic-label/ diff --git a/pages/glossary/user-agent-controlled-component.md b/pages/glossary/user-agent-controlled-component.md new file mode 100644 index 00000000000..74213ebfd5d --- /dev/null +++ b/pages/glossary/user-agent-controlled-component.md @@ -0,0 +1,31 @@ +--- +title: User-Agent Controlled Component +key: user-agent-controlled-component +unambiguous: true +objective: true +input_aspects: + - CSS styling + - DOM tree +--- + +A _User-Agent Controlled Component_ is an [HTML element][namespace element] for which all the following are true: + +- the element has an [implicit role][] which is a [semantic `widget`][semantic role]; and +- the [computed values][] of the element's `height` and `width` CSS properties do not depend on content provided by the author; and +- the [computed values][] of the element's `height` and `width` CSS properties do not depend on any CSS property with a [cascaded value][] with "Author" [origin][]. + +#### Examples of User-Agent Controlled Components + +Typically, radio buttons or checkboxes are User-Agent controlled, until an author changes their dimensions. + +Links and buttons usually aren't. Authors provide their (text) content which determines the width. + +Days in a calendar widget build with an `` element are also User-Agent controlled. Their content is not provided by the author and dimensions do not depend on values provided by the author. + +Directly setting the `height` or `width` CSS properties makes an element not User-Agent controlled. Changing the `max-height` or `min-width` properties can make it not User-Agent controlled, if the added constraint impacts the [computed][computed values] `height` or `width` properties (i.e., if the `height` would be larger than `max-height` and is restricted by it; or if the `width` would be smaller than `min-width` and is changed by it). + +[cascaded value]: https://www.w3.org/TR/css-cascade-5/#cascade-value 'CSS definition of computed value' +[computed values]: https://www.w3.org/TR/css-cascade-3/#computed 'CSS definition of Computed Value' +[implicit role]: #implicit-role 'Definition of Implicit Role' +[origin]: https://drafts.csswg.org/css-cascade-5/#cascading-origins 'CSS definition of Cascading Origin' +[semantic role]: #semantic-role 'Definition of Semantic Role' diff --git a/test-assets/target-size/highlight-rect.js b/test-assets/target-size/highlight-rect.js new file mode 100644 index 00000000000..b170bb71d86 --- /dev/null +++ b/test-assets/target-size/highlight-rect.js @@ -0,0 +1,31 @@ +/** + * Create an element with class "highlight" around a node. + * The node needs to be non-static to allow for z-index lower than + * the highlighted element, otherwise the .highlight element will prevent + * click events to reach the node. + * + * An optional set of classes can also be added to the highlighted element, + * these are mostly intended to be either ['good'] (default) or ['bad'] to set + * the color and style of the highlighting border. + */ +function highlightRect(node, classes = ['good']) { + // Get the bounding client rect of the node + const range = document.createRange() + range.setStart(node, 0) + // Take the length of text nodes, if it exists, otherwise (element), take + // all child nodes + range.setEnd(node, node?.length ?? node.childNodes.length) + const rect = range.getBoundingClientRect() + + // Create a div sized to that rect + // See https://developer.mozilla.org/en-US/docs/Web/API/Element/getClientRects#javascript + const div = document.createElement('div') + div.classList.add('highlight', ...classes) + div.style.top = `${rect.top}px` + div.style.left = `${rect.left}px` + div.style.width = `${rect.width - 2}px` + div.style.height = `${rect.height - 2}px` + document.body.appendChild(div) + + return div +} diff --git a/test-assets/target-size/map-background.jpg b/test-assets/target-size/map-background.jpg new file mode 100644 index 00000000000..1b7858a7f6c Binary files /dev/null and b/test-assets/target-size/map-background.jpg differ diff --git a/test-assets/target-size/shared-styles.css b/test-assets/target-size/shared-styles.css new file mode 100644 index 00000000000..947ef0bc900 --- /dev/null +++ b/test-assets/target-size/shared-styles.css @@ -0,0 +1,23 @@ +.highlight { + position: absolute; + z-index: 0; +} + +.good { + border: green solid 1px; +} +.bad { + border: red dashed 1px; +} + +.highlightable { + position: relative; + z-index: 5; +} + +.placeholder { + background-color: transparent; + border: dashed 2px black; + padding: 0; + position: absolute; +} diff --git a/test-assets/target-size/zoom-in.png b/test-assets/target-size/zoom-in.png new file mode 100644 index 00000000000..e9419b5be4e Binary files /dev/null and b/test-assets/target-size/zoom-in.png differ diff --git a/test-assets/target-size/zoom-out.png b/test-assets/target-size/zoom-out.png new file mode 100644 index 00000000000..1d099a4c18f Binary files /dev/null and b/test-assets/target-size/zoom-out.png differ