Positiebewuste tooltips

Als je tooltips of pop-overs maakt met CSS-ankerpositionering, kan de browser het element automatisch 'omdraaien' naar een reservepositie als het anders de viewport zou overschrijden. Als dit gebeurt, kun je de stijl van de gepositioneerde content aanpassen, bijvoorbeeld om een pijl te verplaatsen die van de gepositioneerde content naar het anker wijst.

Verankerde containerquery's lossen dit op door je de actieve positioneringsstatus van een element te laten opvragen en de stijlen dienovereenkomstig toe te passen. Ga naar Viewport-Aware Dropdowns voor algemene verankerde dropdownmenu's en flyout-positionering met viewport-botsing (zonder de richtingspijl opnieuw te stylen).

Het probleem

Stel je een tooltip voor die standaard boven het anker verschijnt. Onderaan staat een pijl-omlaag. Als de gebruiker scrollt en de tooltip omdraait zodat deze onder het anker verschijnt, wijst de pijl nu de verkeerde kant op en staat deze aan de verkeerde kant van de tooltip.

De oplossing: verankerde containerquery's

Door container-type: anchored in te stellen voor je gepositioneerde element, maak je er een querycontainer van die op de hoogte is van de eigen ankergepositioneerde status. Je kunt dan de @container anchored()-query gebruiken om de onderliggende elementen of pseudo-elementen te updaten.

1. De tooltip en trigger maken

Gebruik de Popover API om een tooltip te maken. Als je de popover aanroept via popovertarget, wordt er automatisch een impliciete ankerverbinding gemaakt met de triggerknop. Er is dus geen expliciete anchor-name of position-anchor vereist.

<button popovertarget="tooltip" id="anchor" aria-describedby="tooltip">anchor</button>
<div id="tooltip" popover role="tooltip"></div>

De stijlen voor pop-upinzet en -marge resetten voor gebruik met ankerpositionering, maar alleen als ankerpositionering wordt ondersteund.

@supports (anchor-name: --my-anchor) {
  [popover] {
    inset: auto;
    margin: unset;
  }
}

2. De container instellen

Pas container-type: anchored toe op het element dat wordt gepositioneerd. Voor dit element moet ook position-try-fallbacks zijn gedefinieerd om het omdraaien aan te zetten.

#tooltip {
  position: fixed;
  position-area: block-start;
  position-try-fallbacks: flip-block;

  /* Enable anchored container queries */
  container-type: anchored;
}

3. Stijl op basis van de reserveoptie

Gebruik @container anchored(fallback: <value>) om stijlen toe te passen als een specifieke reserve actief is.

Net als alle containerquery's kan @container alleen afstammelingen van de container opmaken. Een veelgebruikte strategie om de pijlen te maken, is met de pseudoelementen ::before en ::after. Deze worden behandeld als afstammelingen en kunnen rechtstreeks worden opgemaakt. Als we de tooltip zelf willen opmaken (zoals in stap 4), voegen we een onderliggend element toe aan de tooltip en maken we de pijl in het pseudoelement ::before.

<div id="tooltip" popover role="tooltip">
  <div class="tooltip-content">Tooltip</div>
</div>
.tooltip-content::before {
  /* Default "down" arrow for the 'top' position */
  content: "▼";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 1rem;
}

/* Update to an "up" arrow when the 'flip-block' fallback (bottom) is active */
@container anchored(fallback: flip-block) {
  .tooltip-content::before {
    content: "▲";
    inset-block-start: 0;
    inset-block-end: auto;
  }
}

4. De container zelf vormgeven

Als je eigenschappen van de container zelf wilt wijzigen (zoals margin of background-color) wanneer deze wordt omgedraaid, gebruik je een intern wrapperelement.

  1. Pas container-type: anchored toe op het buitenste gepositioneerde element.
  2. Target het binnenste element in het @container-blok.
@container anchored(fallback: flip-block) {
  .tooltip-content {
    border-radius: 0 0 .5rem .5rem;
    margin-block-start: 0.25rem;
  }
}

Praktische tips

  • Geef de voorkeur aan logische fallbacks: Gebruik zoekwoorden zoals flip-block en flip-inline in position-try-fallbacks voor eenvoudigere query's die RTL en verschillende schrijfmodi automatisch verwerken.
  • Gebruik pseudo-elementen voor pijlen: Tooltip-pijlen zijn puur decoratief en zijn perfecte kandidaten voor ::before of ::after, die kunnen worden opgemaakt via verankerde containerquery's zonder extra DOM.

Reservestrategieën

De pijl positioneren op basis van de toegepaste fallback is een progressive enhancement en er is geen andere manier om te reageren op de fallback-positie. Als je de pijl wilt verbergen in browsers die geen containerquery's voor ankerposities ondersteunen, test je op CSS-ondersteuning met @supports (container-type: anchored).

@supports (container-type: anchored) {
  .tooltip-content::before {
    content: "▼";
  }
}

Fallbacks en browserondersteuning voor Popover

De Popover API is voornamelijk progressive enhancement, maar de bepalende gedragingen (promotie van de bovenste laag, licht sluiten en aanroepen van popovertarget) hebben geen equivalent dat alleen CSS gebruikt. Oudere browsers hebben een polyfill nodig, of een handmatige fallback als je er liever geen verzendt.

Polyfill: Als je het kenmerk popover wilt ondersteunen in oudere browsers, laad je @oddbird/popover-polyfill voorwaardelijk. VERPLICHT: Voer een functiedetectie uit door te controleren op de property popover op HTMLElement.prototype en laad de polyfill alleen als systeemeigen ondersteuning ontbreekt. Laad de polyfill NIET onvoorwaardelijk.

Met een bundler of importtoewijzing:

// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
  import("@oddbird/popover-polyfill");
}

Zonder bundler importeer je vanuit een CDN in een <script type="module">:

<script type="module">
  if (!("popover" in HTMLElement.prototype)) {
    import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
  }
</script>

Opmerking over de stijl: De polyfill kan de echte pseudoklasse :popover-open niet definiëren, dus wordt in plaats daarvan de klasse .\:popover-open toegepast. VERPLICHT: Combineer de 2 met :is() of :where(), anders negeren browsers zonder :popover-open de hele regel:

[popover]:is(:popover-open, .\:popover-open) {
  display: block;
}

Als alternatief kun je voor een verouderde fallback zonder polyfill position: fixed gebruiken en de coördinaten handmatig berekenen via getBoundingClientRect() of vertrouwen op de standaardpositionering met inset: auto als dat acceptabel is voor de use case.

Browsers die de Popover API niet ondersteunen, ondersteunen ook geen ankerpositionering. De tooltip verschijnt dan in het midden van het scherm.