توفّر البطاقات المنبثقة معاينة تفاعلية للمحتوى عندما يُبدي المستخدم اهتمامًا برابط معيّن (من خلال تمرير مؤشر الماوس فوقه أو التركيز عليه). يظهر هذا المقتطف للمستخدمين قبل الانتقال إلى الصفحة، ويقدّم لهم المحتوى الذي يحتاجون إليه أو يساعدهم في التأكّد من أنّ الرابط سيحتوي على المحتوى الذي يبحثون عنه.
إذا كنت بحاجة إلى تلميحات نصية عادية غير تفاعلية بدلاً من معاينات الروابط المنظَّمة، يُرجى الاطّلاع على عرض تلميح عند تمرير مؤشر الماوس.
1. كيفية تفعيل البطاقة المنبثقة
استخدِم واجهة برمجة التطبيقات 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- تحريك الدخول والخروج
By default, interest is shown and lost for keyboard and mouse users with a delay of half a second. يمنع ذلك فتح النافذة المنبثقة المستهدَفة أثناء التنقّل في الصفحة باستخدام مفتاح Tab أو تحريك الماوس، ويمنع إغلاقها أثناء تحريك الماوس من المشغّل إلى النافذة المنبثقة. لضبط التوقيت، استخدِم سمة 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="..."> عادي، سيظل بإمكان المتصفحات التي لا تتيح استخدام البطاقات المنبثقة التنقّل عند النقر إذا اخترت التعامل مع البطاقة المنبثقة كتحسين تدريجي. عندما يكون من الضروري توفير دعم للبطاقات المنبثقة في جميع المتصفّحات، يمكنك تحميل polyfills بشكل مشروط حسب الحاجة.
الخيارات الاحتياطية وتوافق المتصفّح مع 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.
الخيارات الاحتياطية وتوافق المتصفّحات مع ميزة 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);
}