Interaktive Hovercard erstellen

Hovercards bieten eine interaktive Vorschau von Inhalten, wenn ein Nutzer Interesse an einem Link zeigt (durch Bewegen des Mauszeigers oder Fokussieren). Diese Informationen werden Nutzern angezeigt, bevor sie die Seite aufrufen. Sie enthalten entweder die benötigten Inhalte oder helfen Nutzern, zu überprüfen, ob der Link die gesuchten Inhalte enthält.

Wenn Sie nicht interaktive Tooltips im Nur-Text-Format anstelle von strukturierten Linkvorschauen benötigen, lesen Sie den Hilfeartikel Tooltip beim Bewegen des Mauszeigers anzeigen.

1. Kurzprofil auslösen

Verwenden Sie die Interest Invokers API, um die Hovercard auszulösen. Dadurch wird die Karte sowohl beim Hovern als auch beim Fokussieren angezeigt und die Barrierefreiheit wird automatisch berücksichtigt.

  • Fügen Sie das Attribut popover="hint" zu Ihrem Kartencontainer hinzu. Verwenden Sie hint, um zu vermeiden, dass nicht zugehörige Popover-Menüs geschlossen werden, die möglicherweise geöffnet sind.
  • Fügen Sie dem Triggerlink das Attribut interestfor hinzu, das auf die id der Karte verweist.
<a href="/article" interestfor="article-preview">Article title</a>

<!-- The `id` must match the `interestfor` value on the trigger. -->
<div id="article-preview" popover="hint" class="hovercard">
  <h2>The buzz on hummingbirds</h2>
  <p class="byline">By Delphi Aguilar</p>
  <div>
    <img src="bird.jpg" alt="A vibrant hummingbird">
    <p>Brief summary of the article...</p>
  </div>
</div>

Sie müssen keinen zusätzlichen Link zu den Inhalten in der Hovercard einfügen, da dies redundant zum auslösenden Link ist.

Integrierte Bedienungshilfen für interestfor

Wenn Sie interestfor verwenden, übernimmt der Browser die Verknüpfung mit der Hilfstechnologie für Sie:

  • Implizite Semantik: Ein Ziel mit popover="hint" erhält eine implizite Mindestrolle von tooltip. Legen Sie role="tooltip" NICHT selbst fest.
  • Implizite Verknüpfung: Der Browser verknüpft das Quellelement implizit mit dem Ziel über aria-describedby, wenn das Ziel Klartext ist, oder über aria-details, wenn das Ziel interaktive Inhalte enthält. Fügen Sie dem Trigger NICHT aria-describedby oder aria-details hinzu.
  • Interaktive Inhalte: Da die Verknüpfung bei Bedarf zu aria-details wechselt, darf das Ziel interaktive Inhalte enthalten (z.B. einen Link in einer „Interessenkarte“).

2. Positionierung mit Ankerpositionierung

Positionieren Sie die Hovercard relativ zu ihrem Trigger mithilfe der CSS-Ankerpositionierung. Wenn Sie interestfor verwenden, wird der Trigger zu einem impliziten Anker für das Popover.

[popover].hovercard {
  /* Position the card below the trigger, aligned with its inline-start edge
     and spanning toward the inline-end, flipping if it overflows the viewport. */
  position-area: block-end span-inline-end;
  position-try-fallbacks: flip-block, flip-inline;
}

3. Animation beim Ein- und Ausblenden

Standardmäßig wird das Interesse für Tastatur- und Mausnutzer mit einer Verzögerung von einer halben Sekunde angezeigt und verloren. Dadurch wird verhindert, dass sich das Popover öffnet, wenn Sie mit der Tabulatortaste durch eine Seite navigieren oder die Maus bewegen, und dass es sich schließt, wenn Sie die Maus vom Trigger zum Popover bewegen. Mit der CSS-Property interest-delay können Sie das Timing anpassen.

[interestfor]{
  /* Shorthand for interest-delay-start and interest-delay-end */
  interest-delay: 0.2s 0.1s;
}

Wenn Nutzer wahrscheinlich mehrere Trigger schnell nacheinander auslösen, legen Sie die anfängliche Verzögerung auf 0s fest, wenn bereits ein interessenbezogenes Pop-over geöffnet ist.

:root:has(:interest-source) [interestfor] {
  interest-delay-start: 0s;
}

Verwenden Sie @starting-style, um die Einblendungsanimation zu definieren, und transition-behavior: allow-discrete (zusammen mit display und overlay), um die Ausblendungsanimation aus der obersten Ebene zu animieren. Die Übergänge werden hinter @media (prefers-reduced-motion: no-preference) gesteuert.

[popover].hovercard {
  opacity: 0;
  transform-origin: top;
}

[popover].hovercard:popover-open {
  opacity: 1;
  transform: translateY(0) scale(1);
}

@starting-style {
  [popover].hovercard:popover-open {
    opacity: 0;
    transform: translateY(-10px) scale(0.95);
  }
}

/* MANDATORY: Respect user preference for reduced motion by selectively applying transitions. */
@media (prefers-reduced-motion: no-preference) {
  [popover].hovercard {
    transition:
      opacity,
      transform,
      display,
      overlay;
    transition-duration: 0.4s;
    transition-behavior: allow-discrete;
  }
}

4. OPTIONAL: Nahtloser Übergang zur nächsten Seite

Optional können Sie dokumentübergreifende Ansichtsübergänge verwenden, um eine nahtlose „Morphing“-Animation zwischen der Hovercard und der Landingpage zu erstellen. Informationen zur Implementierung finden Sie unter Konsistente dokumentübergreifende Übergänge.

Wenn Sie Elementen in der Minikarte und ihren Entsprechungen auf der nächsten Seite übereinstimmende view-transition-name-Werte zuweisen, animiert der Browser sie während der Navigation. Sie können mehrere Elemente (z.B. Titel, Bilder, Verfasserzeilen) benennen, um einen komplexen Morphing-Effekt mit mehreren Elementen zu erstellen. Weisen Sie Elementen im geöffneten Pop-over mit :popover-open die view-transition-name zu, um doppelte view-transition-names oder link-spezifische view-transition-names zu vermeiden.

/* Opt-in to cross-document transitions on both pages */
@view-transition {
  navigation: auto;
}

/* Don't show transitions when loading this page */
::view-transition-group(*) {
  animation-duration: 0s;
}

/* Assign names ONLY when the popover is open to ensure only the correct elements are selected. */
[popover]:popover-open {
  view-transition-name: --hovercard;
  view-transition-class: morph;

  h2 {
    view-transition-name: --title;
    view-transition-class: morph;
  }

  img {
    view-transition-name: --image;
    view-transition-class: morph;
  }
}

OBLIGATORISCH: Damit der Übergang stabil ist und nicht flackert, sollten auf der Zielseite blocking="render" und <link rel="expect"> verwendet werden, um auf das Parsen kritischer Inhalte zu warten, bevor der erste Frame gerendert wird.

<!-- On the destination page: -->
<head>
  <!-- Block rendering until the hero image and title are parsed,
       ensuring the view transition snapshot is taken at the right time. -->
  <link rel="expect" href="#main-content" blocking="render">
</head>
<body>
  <main id="main-content">
    <h1>The buzz on hummingbirds</h1>
    <img src="bird.jpg">
  </main>
</body>
/* On the destination page: */
main {
  view-transition-name: --hovercard;
  view-transition-class: morph;
}
h1 {
  view-transition-name: --title;
  view-transition-class: morph;
}
img {
  view-transition-name: --image;
  view-transition-class: morph;
}

/* By default no transition */
::view-transition-group(*) {
  animation-duration: 0s;
}
/* Short transition for morphing elements */
::view-transition-group(.morph) {
  animation-duration: 0.4s;
}
/* Disable transition if no `old` view */
::view-transition-new(.morph):only-child {
  animation-duration: 0s;
}

Fallback-Strategien

Da der Trigger ein standardmäßiger <a href="...">-Link ist, können Browser ohne Unterstützung beim Klicken trotzdem navigieren, wenn Sie die Kurzinfo als progressive Verbesserung behandeln. Wenn die Hovercard-Unterstützung für mehrere Browser erforderlich ist, laden Sie Polyfills nach Bedarf.

Fallbacks und Browserunterstützung für Popover

Die Popover API ist größtenteils eine progressive Verbesserung, aber ihre definierenden Verhaltensweisen – die Hochstufung auf die oberste Ebene, das Schließen durch Klicken außerhalb des Popovers und der Aufruf von popovertarget – haben kein CSS-Äquivalent. Ältere Browser benötigen ein Polyfill oder ein manuelles Fallback, wenn Sie kein Polyfill bereitstellen möchten.

Polyfill: Damit das Attribut popover in älteren Browsern unterstützt wird, lade @oddbird/popover-polyfill bedingt. OBLIGATORISCH: Prüfe, ob die Funktion unterstützt wird, indem du nach der Property popover in HTMLElement.prototype suchst, und lade das Polyfill nur, wenn die native Unterstützung fehlt. Lade es NICHT bedingungslos.

Mit einem Bundler oder einer Importzuordnung:

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

Ohne Bundler importieren Sie aus einem CDN in einem <script type="module">:

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

Einschränkung beim Styling: Das Polyfill kann die echte Pseudoklasse :popover-open nicht definieren, daher wird stattdessen die Klasse .\:popover-open angewendet. OBLIGATORISCH: Kombinieren Sie die beiden mit :is() oder :where(). Andernfalls verwerfen Browser, die :popover-open nicht unterstützen, die gesamte Regel:

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

Alternativ können Sie für einen Legacy-Fallback ohne Polyfill position: fixed verwenden und die Koordinaten manuell über getBoundingClientRect() berechnen oder die Standardpositionierung mit inset: auto verwenden, wenn das für den Anwendungsfall akzeptabel ist.

Fallbacks und Browserunterstützung für Interest Invoker

Interest Invokers müssen bedingt mit dem Polyfill-Paket interestfor von NPM polyfilled werden. Bündeln Sie das Polyfill, anstatt das CDN zu verwenden.

OBLIGATORISCH: Prüfen Sie, ob die Funktion unterstützt wird, indem Sie nach dem Attribut interestForElement in HTMLButtonElement.prototype suchen. Laden Sie das Polyfill nur, wenn die native Unterstützung fehlt.

<script type="module">
  if (!HTMLButtonElement.prototype.hasOwnProperty("interestForElement")) {
    // CDN link only used for example, prefer bundling.
    await import("https://unpkg.com/interestfor@latest");
  }
</script>

Einschränkungen bei CSS-Polyfills

Wenn Sie das Polyfill verwenden, ändert sich die CSS API geringfügig, um die fehlende Unterstützung für native Pseudoklassen und Attribute zu berücksichtigen:

  • Pseudoklassen: Das Polyfill kann keine echten :interest-source- und :interest-target-Pseudoklassen definieren. Stattdessen werden die Klassen .interest-source und .interest-target angewendet. OBLIGATORISCH: Kombinieren Sie sie mit :is(), um sowohl native als auch Polyfill-Zustände zu unterstützen.
/* Styles to apply when the effect is being previewed */
:is(:interest-source, .interest-source) { /* ... */ }
:is(:interest-target, .interest-target) { /* ... */ }
  • CSS-Eigenschaften: Für interest-delay, interest-delay-start und interest-delay-end erfordert das Polyfill die Verwendung von CSS-Variablen, da es die benutzerdefinierten Eigenschaften nicht in allen Browsern direkt lesen kann.
/* Adjust the start and end delay for interest invokers */
[interestfor] {
  --interest-delay-start: 0.2s;
  interest-delay-start: var(--interest-delay-start);
  --interest-delay-end: 0.1s;
  interest-delay-end: var(--interest-delay-end);
}