Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions files/en-us/glossary/top_layer/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Elements that will appear in the top layer include:
- Fullscreen elements, i.e., elements that have been caused to display in fullscreen mode by a successful {{domxref("Element.requestFullscreen()")}} call.
- {{htmlelement("dialog")}} elements displayed as a modal via a successful {{domxref("HTMLDialogElement.showModal()")}} call.
- Popover elements shown via a successful {{domxref("HTMLElement.showPopover()")}} call.
- The picker of a drop-down [customizable `<select>` element](/en-US/docs/Learn_web_development/Extensions/Forms/Customizable_select).

Some browsers, such as Chrome, show elements placed in the top layer inside a special DOM tree entry. For example:

Expand All @@ -28,3 +29,4 @@ Note that the top layer is an internal browser concept and cannot be directly ma
- {{htmlelement("dialog")}} element, {{domxref("HTMLDialogElement")}} interface
- [Popover API](/en-US/docs/Web/API/Popover_API)
- {{CSSXref(":fullscreen")}} pseudo-class
- [Customizable select elements](/en-US/docs/Learn_web_development/Extensions/Forms/Customizable_select)
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,12 @@ Let's have a look at the work so far — note how the picker arrow rotates smoot

The drop-down picker can be targeted using the {{cssxref("::picker()", "::picker(select)")}} pseudo-element. As mentioned earlier, the picker contains everything inside the `<select>` element that isn't the button and the `<selectedcontent>`. In our example, this means all the `<option>` elements and their contents.

First of all, the picker's default black {{cssxref("border")}} is removed:
When the picker is opened, its contents (contained within the `::picker(select)` pseudo-element) are promoted to the {{glossary("top layer")}}, because the picker is a [popover](/en-US/docs/Web/API/Popover_API). This ensures that the picker displays on top of other elements, and interacts gracefully with other popovers on the page (for example, closing unrelated ones that are already open).

> [!NOTE]
> The select picker is also subject to [top-layer ancestor matching boundary](/en-US/docs/Web/CSS/Reference/Selectors/Pseudo-classes#top-layer_ancestor_matching_boundary) behavior, which ensures that {{cssxref(":hover")}}, {{cssxref(":active")}}, or {{cssxref(":focus-within")}} styles applied to the `<select>` will only match the picker's descendants while the picker is interacted with, not the `<select>` itself.

In our example, we start by removing the picker's default black {{cssxref("border")}}:

```css live-sample___third-render live-sample___fourth-render live-sample___full-render
::picker(select) {
Expand Down Expand Up @@ -354,7 +359,7 @@ The list of transitioned properties features `opacity`, however it also includes
- {{cssxref("display")}}
- : The `display` values changes from `none` to `block` when the popover changes state from hidden to shown. This needs to be animated to ensure that other transitions are visible.
- {{cssxref("overlay")}}
- : The `overlay` value changes from `none` to `auto` when the popover changes state from hidden to shown, to promote it to the {{glossary("top layer")}}, then back again when it is hidden to remove it. This needs to be animated to ensure the removal of the popover from the top layer is deferred until the transition completes, ensuring the transition is visible.
- : The `overlay` value changes from `none` to `auto` when the popover changes state from hidden to shown, to promote it to the top layer, then back again when it is hidden to remove it. This needs to be animated to ensure the removal of the popover from the top layer is deferred until the transition completes, ensuring the transition is visible.

> [!NOTE]
> The [`allow-discrete`](/en-US/docs/Web/CSS/Reference/Properties/transition-behavior#allow-discrete) value is needed to enable discrete property animations.
Expand Down
47 changes: 47 additions & 0 deletions files/en-us/web/css/reference/selectors/pseudo-classes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,53 @@ These pseudo-classes require some interaction by the user in order for them to a
- {{CSSxRef(":target-current")}}
- : Matches the {{cssxref("::scroll-marker")}} pseudo-element of a {{cssxref("scroll-marker-group")}} that is currently scrolled to, in other words, the **active** scroll marker.

### Top-layer ancestor matching boundary

When setting styles using a `:hover`, `:active`, or `:focus-within` pseudo-class selector, a nested set of elements will match the selector up the DOM tree. If the hierarchy includes an element in the {{glossary("top layer")}} (for example, a [popover](/en-US/docs/Web/API/Popover_API) or [customizable `<select>`](/en-US/docs/Learn_web_development/Extensions/Forms/Customizable_select) picker), the matching will stop at that element.

For example, the following code features a customizable `<select>` element and a popover. We've set every element in the page to have a thick blue dashed {{cssxref("border")}} on hover.

```html live-sample___matching-boundary
<main>
<select>
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>

<div>
<button popovertarget="mypopover">Toggle popover</button>
<section id="mypopover" popover>
<p>I am a popover</p>
<button>I am a popover button</button>
</section>
</div>
</main>
```

```css hidden live-sample___matching-boundary
* {
padding: 5px;
}
```

```css live-sample___matching-boundary
select,
::picker(select) {
appearance: base-select;
}

:hover {
border: 5px dashed blue;
}
```

{{embedlivesample("matching-boundary", "100%", 200)}}

Note how when you hover the `<select>` or the popover toggle button, all ancestors of those elements will get the border. However, when you open the select picker or the popover and hover one of their descendants, the matching stops at the top-layer ancestor (the select picker or popover themselves).

This behavior stops component styles set on those pseudo-classes from spilling out of a top layer component into the surrounding page, which can cause a user interface to look broken.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great.


## Functional pseudo-classes

These pseudo-classes accept a [selector list](/en-US/docs/Web/CSS/Reference/Selectors/Selector_list) or [forgiving selector list](/en-US/docs/Web/CSS/Reference/Selectors/Selector_list#forgiving_selector_list) as a parameter.
Expand Down