Karty informacyjne wyświetlają interaktywny podgląd treści, gdy użytkownik wyrazi zainteresowanie linkiem (przez najechanie kursorem lub zaznaczenie). Są one wyświetlane użytkownikom, zanim przejdą do strony, i zawierają potrzebne im treści lub pomagają sprawdzić, czy link prowadzi do treści, których szukają.
Jeśli potrzebujesz zwykłych, nieinteraktywnych etykietek, a nie ustrukturyzowanych podglądów linków, zapoznaj się z artykułem Wyświetlanie etykietki po najechaniu kursorem.
1. Wyświetlanie karty informacyjnej
Aby wywołać kartę informacyjną, użyj interfejsu API Interest Invokers. Dzięki temu karta będzie się wyświetlać zarówno po najechaniu kursorem, jak i po zaznaczeniu, a także automatycznie obsłuży ułatwienia dostępu.
- Dodaj atrybut
popover="hint"do kontenera karty. Użyjhint, aby uniknąć zamykania niepowiązanych menu wyskakujących, które mogą być otwarte. - Dodaj atrybut
interestfordo linku aktywującego, wskazującidkarty.
<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>
Nie musisz dodawać dodatkowego linku do treści w karcie informacyjnej, ponieważ jest on zbędny w przypadku linku aktywującego.
Ułatwienia dostępu wbudowane w usługę interestfor
Gdy używasz elementu interestfor, przeglądarka obsługuje połączenie z technologią wspomagającą osoby z niepełnosprawnością:
- Semantyka niejawna: element docelowy z atrybutem
popover="hint"uzyskuje niejawną minimalną rolętooltip. NIE ustawiaj samodzielnie parametrurole="tooltip". - Powiązanie domyślne: przeglądarka domyślnie kojarzy element źródłowy z elementem docelowym za pomocą
aria-describedby, gdy element docelowy jest zwykłym tekstem, lub za pomocąaria-details, gdy element docelowy zawiera treści interaktywne. NIE dodawaj do regułyaria-describedbyaniaria-details. - Treści interaktywne: ponieważ powiązanie przełącza się na
aria-details, gdy jest to konieczne, element docelowy MOŻE zawierać treści interaktywne (np. link w „karcie zainteresowań”).
2. Pozycjonowanie za pomocą pozycjonowania zakotwiczonego
Ustaw pozycję karty informacyjnej względem jej aktywatora za pomocą pozycjonowania kotwicy CSS. Gdy używasz interestfor, aktywator staje się niejawną kotwicą wyskakującego okienka.
[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. Animowanie wejścia i wyjścia
Domyślnie zainteresowanie jest wyświetlane i tracone w przypadku użytkowników klawiatury i myszy z półsekundowym opóźnieniem. Zapobiega to otwieraniu docelowego wyskakującego okienka podczas przechodzenia między kartami na stronie lub poruszania myszą oraz zamykaniu go podczas przesuwania myszy z elementu wyzwalającego do wyskakującego okienka. Aby dostosować czas, użyj właściwości CSS interest-delay.
[interestfor]{
/* Shorthand for interest-delay-start and interest-delay-end */
interest-delay: 0.2s 0.1s;
}
Jeśli użytkownicy mogą szybko przechodzić przez kilka reguł, ustaw opóźnienie początkowe na 0s, jeśli wyskakujące okienko wywołane przez zainteresowanie jest już otwarte.
:root:has(:interest-source) [interestfor] {
interest-delay-start: 0s;
}
Użyj @starting-style, aby zdefiniować animację wejścia, i transition-behavior: allow-discrete (wraz z display i overlay), aby animować wyjście z górnej warstwy, blokując przejścia za pomocą @media (prefers-reduced-motion: no-preference).
[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. OPCJONALNIE: płynne przejście do następnej strony
Możesz też użyć przejść między widokami w różnych dokumentach, aby utworzyć płynną animację „morfowania” między kartą informacyjną a stroną docelową. Wskazówki dotyczące implementacji znajdziesz w artykule Spójne przejścia między dokumentami.
Jeśli przypiszesz pasujące wartości view-transition-name do elementów na karcie informacyjnej i ich odpowiedników na następnej stronie, przeglądarka będzie je animować podczas nawigacji. Możesz nazwać wiele elementów (np. tytuły, obrazy, podpisy), aby utworzyć złożony, wieloelementowy efekt przekształcania. Przypisz view-transition-name do elementów w otwartym wyskakującym okienku za pomocą :popover-open, aby uniknąć tworzenia duplikatów view-transition-name lub konieczności stosowania view-transition-name dla konkretnych linków.
/* 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;
}
}
OBOWIĄZKOWE: aby przejście było stabilne i nie migotało, strona docelowa powinna używać blocking="render" i <link rel="expect">, aby poczekać na przeanalizowanie kluczowych treści przed wyrenderowaniem pierwszej klatki.
<!-- 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;
}
Strategie zastępcze
Ponieważ aktywator jest standardowym linkiem <a href="...">, przeglądarki bez obsługi mogą nadal nawigować po kliknięciu, jeśli zdecydujesz się traktować kartę informacyjną jako progresywne ulepszanie. Jeśli wymagana jest obsługa kart informacyjnych w różnych przeglądarkach, w razie potrzeby wczytuj warunkowo polyfille.
Kreacje zastępcze i obsługa wyskakujących okienek w przeglądarkach
Interfejs Popover API to głównie progresywne ulepszanie, ale jego definiujące zachowania – promowanie warstwy górnej, lekkie odrzucanie i wywoływanie popovertarget – nie mają odpowiednika tylko w CSS. Starsze przeglądarki wymagają polyfilla lub ręcznego rozwiązania zastępczego, jeśli nie chcesz go dostarczać.
Polyfill: aby obsługiwać atrybut popover w starszych przeglądarkach, warunkowo wczytuj @oddbird/popover-polyfill. OBOWIĄZKOWO: wykryj funkcję, sprawdzając właściwość popover w HTMLElement.prototype, i wczytaj polyfill tylko wtedy, gdy brakuje obsługi natywnej – NIE wczytuj go bezwarunkowo.
Za pomocą bundlera lub mapy importu:
// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
import("@oddbird/popover-polyfill");
}
Bez bundlera, importuj z sieci CDN w tagu <script type="module">:
<script type="module">
if (!("popover" in HTMLElement.prototype)) {
import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
}
</script>
Uwaga dotycząca stylów: polyfill nie może zdefiniować rzeczywistej pseudoklasy :popover-open, więc zamiast tego stosuje klasę .\:popover-open. OBOWIĄZKOWO: połącz te 2 właściwości za pomocą :is() lub :where(), w przeciwnym razie przeglądarki, które nie obsługują :popover-open, odrzucą całą regułę:
[popover]:is(:popover-open, .\:popover-open) {
display: block;
}
Możesz też użyć position: fixed i ręcznie obliczyć współrzędne za pomocą getBoundingClientRect() lub polegać na domyślnym pozycjonowaniu za pomocą inset: auto, jeśli jest to akceptowalne w danym przypadku użycia.
Zastępcze i obsługiwane przez przeglądarki wywołania zainteresowań
Elementy wywołujące zainteresowanie muszą być warunkowo wypełniane za pomocą pakietu polyfill interestfor z NPM. Zamiast korzystać z CDN, lepiej dołączyć polyfill do pakietu.
OBOWIĄZKOWO: wykryj funkcję, sprawdzając właściwość interestForElement w HTMLButtonElement.prototype, i wczytaj polyfill tylko wtedy, gdy brakuje obsługi natywnej.
<script type="module">
if (!HTMLButtonElement.prototype.hasOwnProperty("interestForElement")) {
// CDN link only used for example, prefer bundling.
await import("https://unpkg.com/interestfor@latest");
}
</script>
Zastrzeżenia dotyczące kodu polyfill CSS
W przypadku korzystania z kodu polyfill interfejs CSS API zmienia się nieznacznie, aby uwzględnić brak obsługi natywnej pseudoklasy i właściwości:
- Pseudoklasy: polyfill nie może definiować rzeczywistych pseudoklas
:interest-sourcei:interest-target, więc zamiast nich stosuje klasy.interest-sourcei.interest-target. OBOWIĄZKOWO: połącz je z:is(), aby obsługiwać zarówno stany natywne, jak i stany polyfill.
/* Styles to apply when the effect is being previewed */
:is(:interest-source, .interest-source) { /* ... */ }
:is(:interest-target, .interest-target) { /* ... */ }
- Właściwości CSS: w przypadku
interest-delay,interest-delay-startiinterest-delay-endpolyfill wymaga użycia zmiennych CSS, ponieważ nie może odczytać właściwości niestandardowych bezpośrednio we wszystkich przeglądarkach.
/* 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);
}