חיפוש תוכן מוסתר

ממשקי אינטרנט מסתירים לעיתים קרובות תוכן מהתצוגה כדי לשפר את חוויית המשתמש, לחסוך מקום במסך או לשפר את מהירות הטעינה של הדף. שיטות מסורתיות כמו display: none או visibility: hidden מסתירות את התוכן באופן חזותי, אבל הן גם הופכות את התוכן הזה לבלתי נגיש לחלוטין לקוראי מסך ולתכונות של דפדפנים כמו "חיפוש בדף".

כדי להסתיר תוכן באופן חזותי אבל עדיין לאפשר למשתמשים לחפש אותו ולקשר אליו בקישורי עומק באמצעות פרגמנטים של כתובות URL וקישורים מסוג "גלילה לפרגמנט טקסט", אתם יכולים להשתמש ברכיב ה-HTML‏ <details> או במאפיין hidden="until-found". באופן כללי, מומלץ להשתמש ברכיב <details> כי קל יותר להטמיע ולתחזק אותו, אבל יש מקרים מורכבים יותר שבהם <details> לא מספיק וצריך להשתמש ב-hidden="until-found".

לדוגמה:

  • אם אתם רוצים שליטה מלאה על הסגנון של מנגנון ההצגה/ההסתרה.
  • אם הרכיבים האינטראקטיביים להצגה או להסתרה של התוכן נמצאים בחלק אחר של ה-DOM.
  • אם אתם לא רוצים לתמוך בהסתרת התוכן אחרי שהוא מוצג.

איך מטמיעים

כברירת מחדל, הרכיב <details> כולל טקסט נגיש שניתן לחפש בו, ולא נדרשת הטמעה מיוחדת. אם אפשר, עדיף להשתמש ב-<details> ולא ב-hidden="until-found".

אם אתם צריכים להשתמש ב-hidden="until-found", פעלו לפי ההוראות הבאות:

  1. הוספת המאפיין: מוסיפים את מאפיין ה-HTML‏ hidden="until-found" ישירות לרכיבים שמכילים את התוכן שרוצים להסתיר.
  2. סנכרון מצב ממשק המשתמש: אם לממשק יש מצבים קשורים שתלויים בחשיפה של התוכן (למשל, עדכון מאפייני ARIA, החלפת מצב פתוח/סגור של מחלקות CSS או סיבוב סמלי אקורדיון):
    • חובה להוסיף רכיב event listener לאירוע beforematch.
    • רושמים את רכיב ה-event listener של beforematch ישירות ברכיב שכולל את המאפיין hidden="until-found". מכיוון שהאירוע מבעבע, אפשר גם להשתמש בהקצאת אירועים על ידי רישום של מאזין יחיד ברכיב הורה (כמו מאגר כרטיסיות) כדי לנהל כמה קטעים מוסתרים בבת אחת.
    • בתוך רכיב ה-event listener, מפעילים את הלוגיקה לסנכרון רכיבים קשורים בממשק המשתמש (כמו סגירת כרטיסיות פתוחות אחרות או שינוי המצב של מתג).

קוד לדוגמה

המטרה: להציג מאגר נסתר שבו התוכן לא גלוי למשתמש עד שהוא מחפש מילה בקטע הזה.

שימוש ברכיב <details>

<details>
  <summary>Click to expand</summary>
  <p>This content is visually hidden.</p>
</details>

הצהרות גילוי נאות שסותרות זו את זו

כשמטפלים באזורי תוכן שמוציאים זה את זה, כמו אקורדיון בלעדי, משתמשים ברכיב ה-HTML המקורי <details> עם מאפיין name משותף.

<div class="accordion-group">
  <!-- The name attribute creates an exclusive disclosure group -->
  <details class="disclosure" name="my-accordion">
    <summary>Section 1</summary>
    <p>Section 1 content</p>
  </details>

  <details class="disclosure" name="my-accordion" open>
    <summary>Section 2</summary>
    <p>Section 2 content</p>
  </details>

  <details class="disclosure" name="my-accordion">
    <summary>Section 3</summary>
    <p>Section 3 content</p>
  </details>
</div>

שימוש במאפיין hidden="until-found"

<!-- The browser automatically removes hidden="until-found" upon a search match -->
<div class="hidden-container" hidden="until-found">
  <p>This content is visually hidden.</p>
</div>

הודעות גילוי נאות מותאמות אישית שמוציאות זו את זו

כשמטפלים באזורים מותאמים אישית שמוציאים זה את זה ונשלטים על ידי כפתורים חיצוניים, צריך לוודא שרק החלונית התואמת נשארת גלויה. בגורם המטפל באירועים beforematch, חובה לסנכרן מצבי ARIA קשורים, כמו הגדרת aria-expanded="true" בלחצן השליטה.

<div class="custom-accordion">
  <div class="controls">
    <button aria-expanded="true" aria-controls="panel-1" id="btn-1">Section 1</button>
    <button aria-expanded="false" aria-controls="panel-2" id="btn-2">Section 2</button>
  </div>

  <div id="panel-1" class="panel">
    <p>Section 1 content (visible)</p>
  </div>

  <div id="panel-2" class="panel" hidden="until-found">
    <p>Section 2 content (hidden)</p>
  </div>
</div>
const accordion = document.querySelector('.custom-accordion');

accordion.addEventListener('beforematch', (e) => {
  // Hide all panels and synchronize button states before the browser reveals the matched panel
  accordion.querySelectorAll('.panel').forEach((panel) => {
    if (panel !== e.target) {
      panel.hidden = 'until-found';
    }
  });
  accordion.querySelectorAll('button').forEach((btn) => {
    const controls = btn.getAttribute('aria-controls');
    btn.setAttribute('aria-expanded', controls === e.target.id ? 'true' : 'false');
  });
});

שיטות מומלצות להשגת היעד hidden="until-found"

  • מומלץ להחיל גבולות, מרווח פנימי ורקעים על רכיבי wrapper משניים בתצוגת עץ, ולא ישירות על הרכיב עם המאפיין hidden="until-found". כך אפשר למנוע שינויים לא מכוונים בפריסה או שאריות חזותיות כשהרכיב מוסתר.
  • אל תפעילו את display: none,‏ visibility: hidden או כל מאפיין CSS משויך של display או visibility ישירות על רכיבים עם המאפיין hidden="until-found". הפעולה הזו משבשת את הפונקציונליות המקורית ומסתירה את התוכן מאינדקס החיפוש באופן סופי.
  • אל תשתמשו ב-hidden="until-found" למידע רגיש, לאסימוני נתונים פנימיים או לנתונים לא רלוונטיים שלא אמורים להיחשף בחיפוש.
  • אל תשתמשו ב-hidden="until-found" כתחליף לטקסט "לקורא מסך בלבד" (‎.sr-only).

תמיכה בדפדפנים ושיטות חלופיות

אל תימנעו משימוש ב-hidden="until-found" בגלל שאין תמיכה בדפדפן, כי היתרונות של הנגישות עולים בהרבה על העלות של הטמעת חלופה.

‫hidden="until-found" כברירת מחדל

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

if (!('onbeforematch' in HTMLElement.prototype)) {
  // Expand all hidden content for unsupported browsers
  document.querySelectorAll('[hidden="until-found"]').forEach((el) => {
    el.removeAttribute('hidden');
    // MANDATORY: also update any aria references to this element.
  });
}

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