מידע בכרטיסים צפים מספק תצוגה מקדימה אינטראקטיבית של תוכן כשמשתמש מביע עניין בקישור (על ידי העברת העכבר מעליו או התמקדות בו). התצוגה המקדימה מוצגת למשתמשים לפני שהם עוברים לתוכן, והיא מספקת להם את התוכן שהם צריכים או עוזרת לוודא שהקישור יכיל את התוכן שהם מחפשים.
אם אתם צריכים הסברים קצרים בטקסט פשוט ולא אינטראקטיביים במקום תצוגות מקדימות של קישורים מובנים, עיינו במאמר הצגת הסבר קצר כשמעבירים את העכבר מעל פריט.
1. הפעלת המידע בכרטיס צף
משתמשים ב-API של Interest Invokers כדי להפעיל את המידע בכרטיס הצף. כך הכרטיס יופיע גם כשמעבירים מעליו את העכבר וגם כשמתמקדים בו, והוא יטפל באופן אוטומטי בהגדרות הנגישות.
- מוסיפים את המאפיין
popover="hint"למאגר הכרטיסים. כדאי להשתמש ב-hintכדי להימנע מסגירת תפריטים קופצים לא קשורים שעשויים להיות פתוחים. - מוסיפים את המאפיין
interestforלקישור הטריגר, שמפנה אל ה-idשל הכרטיס.
<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>
אין צורך לכלול קישור נוסף לתוכן בתוך המידע בכרטיס הצף, כי הוא מיותר בקישור שמפעיל את הכרטיס.
נגישות מובנית ב-interestfor
כשמשתמשים ב-interestfor, הדפדפן מטפל בחיבור של הטכנולוגיה המסייעת:
- סמנטיקה משתמעת: יעד עם
popover="hint"מקבל תפקיד מינימלי משתמע שלtooltip. אל תגדירו אתrole="tooltip"בעצמכם. - שיוך משתמע: הדפדפן משייך באופן משתמע את רכיב המקור ליעד באמצעות
aria-describedbyכשהיעד הוא טקסט פשוט, או באמצעותaria-detailsכשהיעד מכיל תוכן אינטראקטיבי. אל תוסיפו אתaria-describedbyאו אתaria-detailsלטריגר. - תוכן אינטראקטיבי: מכיוון שהשיוך עובר אל
aria-detailsלפי הצורך, היעד יכול להכיל תוכן אינטראקטיבי (למשל, קישור בתוך "כרטיס עניין").
2. מיקום באמצעות Anchor Positioning
ממקמים את המידע בכרטיס הצף ביחס לטריגר שלו באמצעות מיקום עוגן ב-CSS. כשמשתמשים ב-interestfor, הטריגר הופך לעוגן מרומז של החלון הקופץ.
[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. אנימציה של כניסה ויציאה
כברירת מחדל, המיקוד מוצג ומוסר למשתמשים במקלדת ובעכבר בהשהיה של חצי שנייה. כך אפשר למנוע מהחלון הקופץ המטורגט להיפתח כשעוברים בין טאבים בדף או מזיזים את העכבר, ולמנוע ממנו להיסגר כשמזיזים את העכבר מהטריגר לחלון הקופץ. כדי לשנות את התזמון, משתמשים במאפיין ה-CSS interest-delay.
[interestfor]{
/* Shorthand for interest-delay-start and interest-delay-end */
interest-delay: 0.2s 0.1s;
}
אם סביר להניח שהמשתמשים יעברו בין כמה טריגרים ברצף מהיר, כדאי להגדיר את ההשהיה הראשונית ל-0s אם חלון קופץ שמופעל על ידי עניין כבר פתוח.
:root:has(:interest-source) [interestfor] {
interest-delay-start: 0s;
}
משתמשים ב-@starting-style כדי להגדיר את אנימציית הכניסה וב-transition-behavior: allow-discrete (יחד עם display ו-overlay) כדי להוסיף אנימציה ליציאה מהשכבה העליונה, ולחסום את המעברים מאחורי @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. אופציונלי: מעבר חלק לדף הבא
אפשר להשתמש במעברי תצוגה בין מסמכים כדי ליצור אנימציית "שינוי צורה" חלקה בין המידע בכרטיס הצף לבין דף היעד. במאמר מעברים עקביים בין מסמכים מוסבר איך להטמיע את התכונה.
אם מקצים ערכי view-transition-name תואמים לרכיבים בכרטיס הצף ולרכיבים המקבילים שלהם בדף הבא, הדפדפן יציג אותם באנימציה במהלך הניווט. אתם יכולים לציין כמה אלמנטים (למשל: כותרות, תמונות, שורות קרדיט) כדי ליצור אפקט מורפינג מורכב עם כמה אלמנטים. מקצים את view-transition-name לרכיבים בחלון הקופץ הפתוח באמצעות :popover-open, כדי להימנע מיצירת view-transition-name כפולים או מדרישה ל-view-transition-name ספציפיים לקישור.
/* 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;
}
}
חובה: כדי לוודא שהמעבר יציב ולא מהבהב, דף היעד צריך להשתמש ב-blocking="render" וב-<link rel="expect"> כדי להמתין לניתוח של תוכן קריטי לפני העיבוד של הפריים הראשון.
<!-- 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;
}
אסטרטגיות חלופיות
מכיוון שהטריגר הוא קישור <a href="..."> רגיל, דפדפנים שלא תומכים במידע בכרטיס צף עדיין יכולים לנווט בלחיצה אם בוחרים להתייחס למידע בכרטיס צף כשיפור הדרגתי (progressive enhancement). אם נדרשת תמיכה במידע בכרטיס צף בדפדפנים שונים, צריך לטעון polyfills באופן מותנה לפי הצורך.
תמיכה בדפדפנים וחלופות ל-Popover
Popover API הוא בעיקר שיפור הדרגתי (progressive enhancement), אבל להתנהגויות שמגדירות אותו – קידום לשכבה העליונה, סגירה בלחיצה מחוץ לאלמנט והפעלה של popovertarget – אין מקבילה ב-CSS בלבד. בדפדפנים ישנים יותר צריך להשתמש ב-polyfill, או להגדיר חלופה ידנית אם אתם מעדיפים לא להשתמש ב-polyfill.
Polyfill: כדי לתמוך במאפיין popover בדפדפנים ישנים יותר, צריך לטעון את @oddbird/popover-polyfill באופן מותנה. חובה: צריך לזהות את התכונה על ידי בדיקת המאפיין popover ב-HTMLElement.prototype, ולטעון את ה-polyfill רק כשאין תמיכה מקומית – אל תטענו אותו ללא תנאי.
עם bundler או מפת ייבוא:
// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
import("@oddbird/popover-polyfill");
}
בלי כלי לאריזת קוד, מייבאים מ-CDN בתוך <script type="module">:
<script type="module">
if (!("popover" in HTMLElement.prototype)) {
import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
}
</script>
אזהרה לגבי סגנון: ה-polyfill לא יכול להגדיר את המחלקה המדומה :popover-open, אז הוא מחיל במקום זאת מחלקה .\:popover-open. חובה: צריך לשלב את שניהם עם :is() או :where(), אחרת דפדפנים שאין בהם :popover-open יתעלמו מהכלל כולו:
[popover]:is(:popover-open, .\:popover-open) {
display: block;
}
לחלופין, כדי להשתמש ב-fallback מדור קודם בלי polyfill, אפשר להשתמש ב-position: fixed ולחשב קואורדינטות באופן ידני באמצעות getBoundingClientRect() או להסתמך על מיקום ברירת המחדל עם inset: auto אם זה מתאים לתרחיש לדוגמה.
תמיכה בדפדפנים וחלופות ל-Interest invokers
צריך להוסיף ל-Interest Invokers פוליפיל (polyfill) מותנה באמצעות חבילת הפוליפיל interestfor מ-NPM. עדיף להשתמש ב-polyfill כחלק מחבילה ולא ב-CDN.
חובה: מזהים את התכונה על ידי בדיקת המאפיין interestForElement ב-HTMLButtonElement.prototype, וטוענים את ה-polyfill רק כשאין תמיכה מקומית.
<script type="module">
if (!HTMLButtonElement.prototype.hasOwnProperty("interestForElement")) {
// CDN link only used for example, prefer bundling.
await import("https://unpkg.com/interestfor@latest");
}
</script>
אזהרות לגבי CSS Polyfill
כשמשתמשים ב-polyfill, ה-CSS API משתנה קצת כדי לפצות על היעדר התמיכה המקורית במאפיינים ובמחלקות פסאודו:
- מחלקה מדומה (Pseudo-class): ה-polyfill לא יכול להגדיר מחלקות מדומות אמיתיות של
:interest-sourceו-:interest-target, אז הוא מחיל במקומן מחלקות של.interest-sourceו-.interest-target. חובה: צריך לשלב אותם עם:is()כדי לתמוך במצבים מקוריים ובמצבים עם polyfill.
/* Styles to apply when the effect is being previewed */
:is(:interest-source, .interest-source) { /* ... */ }
:is(:interest-target, .interest-target) { /* ... */ }
- מאפייני CSS: ב-
interest-delay, ב-interest-delay-startוב-interest-delay-end, ה-polyfill דורש שימוש במשתני CSS כי הוא לא יכול לקרוא את המאפיינים המותאמים אישית ישירות בכל הדפדפנים.
/* 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);
}