إظهار تلميح عند تمرير مؤشر الماوس

يتوقع المستخدمون رؤية معلومات إضافية ذات صلة دون تغيير سياقهم تمامًا. يمكن أن يكون عرض تلميح عندما يكون المستخدم مهتمًا بمزيد من المعلومات مفيدًا لتقديم تعريفات لمصطلح ما، أو توضيح الإجراء الذي سيتخذه زر يحتوي على رمز فقط، أو تقديم إرشادات إضافية لحقل النموذج.

إنشاء تلميح

يمكنك إنشاء نافذة منبثقة بالسلوك المطلوب من خلال إضافة السمة popover="hint" إلى <div> أو عنصر آخر مناسب من الناحية الدلالية. عندما يفتح المستخدم تلميح الشاشة، يؤدي ذلك إلى إخفاء تلميحات الشاشة الأخرى في popover="hint"، ولكن لا يؤدي إلى إخفاء تلميحات الشاشة في auto أو manual. وتتولّى أيضًا إغلاق مربّعات النص المساعدة المتداخلة.

ويوفّر أيضًا سلوك الإغلاق البسيط، فعندما ينقر المستخدم أو يركّز خارج النافذة المنبثقة، يتم إغلاقها.

يجب أن يحتوي عنصر تلميح على سمة id بقيمة فريدة:

<!-- MANDATORY: The tooltip container `<div>` must have a `popover` attribute.
     the value of `"hint"` ensures it can be "light dismissed". -->
<div popover="hint" id="tooltip">Tooltip content</div>

يعبّر المستخدم عن اهتمامه بالمعلومات الإضافية من خلال تمرير مؤشر الماوس فوق عنصر <a> أو <button> أو التركيز عليه. يجب أن يحتوي العنصر على سمة interestfor تتطابق مع سمة id الخاصة بتلميح الشاشة.

<!-- The `interestfor` attribute can be applied to a `<button>` element: -->
<button interestfor="tooltip">Tooltip trigger</button>

<!-- The `interestfor` attribute can also be applied to an `<a>` element: -->
<a interestfor="tooltip" href="">Tooltip trigger</a>

يجب أن يتضمّن المشغّل مؤشرًا مرئيًا يشير إلى توفّر معلومات إضافية من خلال التفاعل مع المشغّل.

ميزات تسهيل الاستخدام المدمجة في "interestfor"

عند استخدام interestfor، يتعامل المتصفّح مع ربط التكنولوجيا المساعِدة نيابةً عنك:

  • الدلالات الضمنية: يكتسب الهدف الذي يتضمّن السمة popover="hint" دورًا ضمنيًا كحدّ أدنى هو tooltip. لا تضبط role="tooltip" بنفسك.
  • الربط الضمني: يربط المتصفّح ضمنيًا عنصر المصدر بالهدف من خلال aria-describedby عندما يكون الهدف نصًا عاديًا، أو من خلال aria-details عندما يحتوي الهدف على محتوى تفاعلي. لا تُضِف aria-describedby أو aria-details إلى المشغّل.
  • المحتوى التفاعلي: بما أنّ الارتباط ينتقل إلى aria-details عند الحاجة، يُسمح للهدف باحتواء محتوى تفاعلي (مثل رابط داخل "بطاقة اهتمام").

قيود تسهيل الاستخدام (WCAG 1.4.13)

حتى مع معالجة interestfor للدلالات المذكورة أعلاه، يجب أن يستوفي التنفيذ معيار WCAG 1.4.13 (المحتوى عند التمرير أو التركيز):

  • قابلة للإغلاق: يجب أن يتمكّن المستخدمون من إغلاق تلميح الشاشة بدون تحريك مؤشر الماوس أو تركيز لوحة المفاتيح (على سبيل المثال، من خلال الضغط على مفتاح Escape). وتدير سمة popover الأصلية عملية الربط هذه تلقائيًا.
  • قابلية التمرير: يجب أن يكون المؤشر قادرًا على التحرك فوق محتوى تلميح الشاشة نفسه بدون اختفاء تلميح الشاشة. يسمح هذا للمستخدمين الذين لديهم أدوات تكبير بقراءة نص التلميح بأمان.
  • الثبات: يجب أن يظلّ التلميح مرئيًا إلى أن تتم إزالة عامل التفعيل الذي يعتمد على تمرير مؤشر الماوس أو التركيز، أو إلى أن يغلقه المستخدم صراحةً، أو إلى أن يصبح محتواه غير صالح.

تحديد موضع التلميح

يتم تحديد موضع تلميح الشاشة باستخدام تحديد موضع الإرساء في CSS. عند فتح تلميح باستخدام interestfor، يصبح عنصر التفعيل تلقائيًا نقطة ارتساء ضمنية للنافذة المنبثقة.

في المتصفّحات الحديثة التي تتيح تحديد موضع الارتساء الأصلي، لا تحتاج إلى تحديد anchor-name على عامل التفعيل أو position-anchor على تلميح الشاشة. يمكنك تحديد موضع تلميح الشاشة مباشرةً بالنسبة إلى نقطة الارتكاز الضمنية باستخدام position-area والتعامل مع قلب التصادم باستخدام position-try-fallbacks:

[popover] {
  /* Implicit anchor from interestfor: no anchor-name or position-anchor needed */
  position-area: top;
  position-try-fallbacks: flip-block;
  margin: unset;
}

استراتيجيات احتياطية

الخيارات الاحتياطية وتوافق المتصفّحات مع ميزة 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 قليلاً لمراعاة عدم توفّر فئة زائفة وسمة أصليتين:

  • الفئات الصورية: لا يمكن لـ 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);
}

الخيارات الاحتياطية وتوافق المتصفّحات مع Popover

تعتمد واجهة Popover API في الغالب على التحسين التدريجي، ولكن سلوكياتها المحدّدة، مثل الترقية إلى الطبقة العليا والإغلاق البسيط واستدعاء popovertarget، ليس لها مكافئ في CSS فقط. تحتاج المتصفّحات القديمة إلى polyfill أو إلى إجراء احتياطي يدوي إذا كنت تفضّل عدم شحنها.

Polyfill: لإتاحة السمة popover في المتصفّحات القديمة، يمكنك تحميل @oddbird/popover-polyfill بشكل مشروط. إجراء إلزامي: يجب رصد الميزة من خلال التحقّق من السمة popover في HTMLElement.prototype، وتحميل polyfill فقط في حال عدم توفّر الدعم الأصلي، ويجب عدم تحميله بدون شروط.

باستخدام حزمة أو خريطة استيراد:

// 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;
}

بدلاً من ذلك، يمكنك استخدام position: fixed واحتساب الإحداثيات يدويًا من خلال getBoundingClientRect() أو الاعتماد على تحديد الموضع التلقائي باستخدام inset: auto إذا كان ذلك مقبولاً لحالة الاستخدام، وذلك كحل بديل قديم بدون polyfill.

لا يوفّر popover-polyfill سلوك التلميح في المتصفّحات التي تتوافق مع popover ولكن ليس مع popover="hint". بالنسبة إلى هذه المتصفحات، قد يظل التلميح المفتوح من خلال التركيز مفتوحًا عند فتح تلميح ثانٍ من خلال التمرير.

لإتاحة المتصفّحات التي لا تتضمّن ميزة تحديد موضع الارتساء، يمكنك استخدام polyfill @oddbird/css-anchor-positioning. بدلاً من ذلك، يمكنك استخدام @supports لتحديد موضع احتياطي.

عند استخدام polyfill في @oddbird/css-anchor-positioning لإتاحة المتصفّحات القديمة، يُرجى العِلم أنّ polyfill لا يتيح استخدام نقاط الارتساء الضمنية أو position-area في النوافذ المنبثقة. اضبط anchor-name بشكل صريح على عامل التفعيل، واضبط position-anchor على النافذة المرافِقة، وحدِّد الموضع باستخدام دوال الإدراج anchor() بدلاً من position-area:

<!-- MANDATORY: Conditionally install the anchor positioning polyfill -->
<script type="module">
  if (!("anchorName" in document.documentElement.style)) {
    await import("https://unpkg.com/@oddbird/css-anchor-positioning");
  }
</script>
button[interestfor="tooltip-attrs"] {
  /* MANDATORY: Each trigger and popover pair must have a unique anchor name, referenced by `anchor-name` on the trigger and `position-anchor` on the popover. */
  anchor-name: --tooltip-attrs;
}
#tooltip-attrs {
  position-anchor: --tooltip-attrs;
  /* If using the anchor positioning polyfill with a popover, DO use `anchor()` functions, and not `position-area. */
  top: anchor(bottom);
  left: anchor(right);
  margin: unset;
}