הסברים קצרים שמותאמים למיקום

כשיוצרים הסברים קצרים או חלונות קופצים באמצעות מיקום עוגן ב-CSS, הדפדפן יכול "להפוך" את הרכיב באופן אוטומטי למיקום חלופי אם הוא חורג מאזור התצוגה. במקרים כאלה, יכול להיות שתרצו לשנות את הסגנון של התוכן הממוקם, למשל לשנות את המיקום של חץ שמצביע מהתוכן הממוקם אל העוגן.

שאילתות קונטיינר מעוגנות פותרות את הבעיה הזו בכך שהן מאפשרות לשלוח שאילתות לגבי מצב המיקום הפעיל של רכיב ולהחיל סגנונות בהתאם. כדי לקבל מידע כללי על מיקום של תפריטים נפתחים ותפריטי משנה מעוגנים עם היפוך התנגשות באזור התצוגה (בלי עיצוב מחדש של החץ לכיוון), אפשר לעיין במאמר תפריטים נפתחים שמותאמים לאזור התצוגה.

הבעיה

דמיינו הסבר קצר שמופיע מעל העוגן שלו כברירת מחדל. בתחתית שלו יש חץ שפונה כלפי מטה. אם המשתמש גולל וההסבר הקצר מתהפך ומופיע מתחת לעוגן, החץ מצביע עכשיו לכיוון הלא נכון ונמצא בצד הלא נכון של ההסבר הקצר.

הפתרון: שאילתות קונטיינר מעוגנות

כשמגדירים את container-type: anchored ברכיב הממוקם, הוא הופך למאגר שאילתות שמודע למצב המיקום שלו ביחס לעוגן. אחר כך אפשר להשתמש בשאילתה @container anchored() כדי לעדכן את הצאצאים או את הרכיבים המדומים שלה.

1. יצירת הטריגר וההסבר הקצר

משתמשים ב-Popover API כדי ליצור הסבר קצר. הפעלת החלון הקופץ באמצעות popovertarget יוצרת באופן אוטומטי חיבור עוגן משתמע עם לחצן ההפעלה, כך שאין צורך ב-anchor-name או ב-position-anchor מפורשים.

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

איפוס סגנונות השוליים וההוספה של החלון הקופץ לשימוש עם מיקום עוגן, אבל רק אם יש תמיכה במיקום עוגן.

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

2. הגדרת המאגר

מגדירים את המאפיין container-type: anchored לרכיב שרוצים למקם. כדי להפעיל את התכונה של היפוך, צריך להגדיר גם את position-try-fallbacks ברכיב הזה.

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

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

3. סגנון שמבוסס על הצורה החלופית

אפשר להשתמש ב-@container anchored(fallback: <value>) כדי להחיל סגנונות כשחלופה ספציפית פעילה.

כמו כל שאילתות הקונטיינר, @container יכול לעצב רק צאצאים של הקונטיינר. אסטרטגיה נפוצה ליצירת החצים היא באמצעות הרכיבים המדומים ::before ו-::after, שמטופלים כצאצאים וניתן לעצב אותם ישירות. עם זאת, כדי לעצב את ה-tooltip עצמו (כמו שמוצג בשלב 4), נוסיף רכיב צאצא ל-tooltip וניצור את החץ ברכיב המדומה ::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. עיצוב הקונטיינר עצמו

אם אתם צריכים לשנות מאפיינים בקונטיינר עצמו (כמו margin או background-color) כשהוא מתהפך, אתם צריכים להשתמש ברכיב wrapper פנימי.

  1. מגדירים את container-type: anchored לרכיב החיצוני.
  2. מטרגטים את האלמנט הפנימי בתוך הבלוק @container.
@container anchored(fallback: flip-block) {
  .tooltip-content {
    border-radius: 0 0 .5rem .5rem;
    margin-block-start: 0.25rem;
  }
}

שיטות מומלצות

  • העדיפו חלופות לוגיות: השתמשו במילות מפתח כמו flip-block ו-flip-inline ב-position-try-fallbacks לשאילתות פשוטות יותר שמטפלות ב-RTL ובמצבי כתיבה שונים באופן אוטומטי.
  • שימוש ברכיבי פסאודו לחצים: החצים של הטיפים הם דקורטיביים בלבד, והם מועמדים מושלמים ל-::before או ל-::after, שאפשר לעצב באמצעות שאילתות של מאגרים מעוגנים בלי DOM נוסף.

אסטרטגיות חלופיות

מיקום החץ על סמך החלופה שהוחלה הוא שיפור הדרגתי (progressive enhancement), ואין דרך אחרת להגיב למיקום החלופי. כדי להסתיר את החץ בדפדפנים שלא תומכים בשאילתות של קונטיינרים למיקום של עוגנים, בודקים את התמיכה ב-CSS באמצעות @supports (container-type: anchored).

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

תמיכה בדפדפנים וחלופות ל-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 אם זה מתאים לתרחיש לדוגמה.

דפדפנים שלא תומכים ב-Popover API גם לא תומכים במיקום עוגן, ולכן ההסבר הקצר יופיע במרכז המסך.