جستجوی محتوای پنهان

میاناهای وب اغلب محتوا را از دید پنهان می‌کنند تا تجربه کاربری را بهبود بخشند، فضای صفحه‌نمایش را ذخیره کنند، یا عملکرد صفحه را افزایش دهند. روش‌های سنتی مانند display: none یا visibility: hidden برای پنهان کردن محتوا به‌صورت بصری کار می‌کنند، اما همچنین باعث می‌شوند که آن محتوا برای صفحه‌خوان‌ها و ویژگی‌های مرورگر مانند «یافتن در صفحه» کاملاً غیرقابل‌دسترس شود.

برای پنهان کردن محتوا به‌صورت بصری اما همچنان قابل‌جستجو بودن آن برای کاربران و امکان پیوند عمیق به آن ازطریق قطعه‌های نشانی وب و پیوندهای «پیمایش به قطعه نوشتار»، می‌توانید از عنصر 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 باز/بسته، یا چرخاندن نمادهای آکاردئونی):
    • باید شنونده رویداد را برای رویداد beforematch اضافه کنید.
    • شنونده رویداد beforematch را مستقیماً روی عنصری که مشخصه hidden="until-found" را دارد ثبت کنید. ازآنجایی‌که رویداد حباب‌سازی می‌کند، می‌توانید به‌جای آن از واگذاری رویداد با ثبت یک شنونده واحد در عنصر والد (مانند محفظه برگه) برای مدیریت هم‌زمان چندین بخش پنهان استفاده کنید.
    • درون شنونده رویداد، منطق را برای همگام‌سازی عناصر میانای کاربر مرتبط (مانند بستن برگه‌های باز دیگر یا تغییر وضعیت دکمه مبدل) اجرا کنید.

کد نمونه

هدف: رندر کردن محفظه پنهانی که محتوای آن برای کاربر نامرئی باقی می‌ماند تا زمانی که کاربر کلمه‌ای را در آن بخش جستجو کند.

درحال استفاده از عنصر <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"

  • باید حاشیه‌ها، فاصله‌گذاری‌ها، و پس‌زمینه‌ها را به‌جای اعمال مستقیم روی عنصر دارای مشخصه 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"

برای عناصر میانای کاربر استاندارد مانند آکاردئون‌ها یا بخش‌های «بیشتر بخوانید»، از جاوا اسکریپت برای تشخیص ویژگی و نمایش همه محتوا درصورت پشتیبانی نشدن از ویژگی استفاده کنید.

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.
  });
}

برای الگوهای واسط کاربر ناسازگار (مانند پانل‌های انحصاری سفارشی که محتوا در یک منطقه بصری مشترک قرار دارد)، حالت بازگشت باید تمام محتوا را به‌صورت خطی در زیر ناحیه تعاملی اصلی استخراج و نمایش دهد و از قطعات لنگر نشانی وب استفاده کند تا کاربران بتوانند مستقیماً به بخش‌های مربوطه پیمایش کنند.