نظرة عامة أساسية حول كيفية إنشاء مكوّن مربّع حوار منبثق قابل للتكيّف وسهل الاستخدام
في هذه المشاركة، أريد مشاركة أفكار حول كيفية إنشاء مكوّن مربّع حوار منبثق. جرِّب الإصدار التجريبي.
إذا كنت تفضّل مشاهدة الفيديوهات، يمكنك الاطّلاع على نسخة من هذه المشاركة على YouTube:
نظرة عامة
النوافذ المنبثقة هي رسائل قصيرة غير تفاعلية وغير متزامنة للمستخدمين. ويتم استخدامها بشكل عام كنمط لملاحظات الواجهة لإعلام المستخدم بنتائج إجراء معيّن.
التفاعلات
تختلف الإشعارات المنبثقة عن الإشعارات والتنبيهات و الطلبات لأنّه لا يمكن التفاعل معها، ولا يُقصد إغلاقها أو إبقاؤها ظاهرة. تقدّم الإشعارات معلومات أكثر أهمية أو رسائل متزامنة تتطلب التفاعل أو رسائل على مستوى النظام (بدلاً من مستوى الصفحة). تكون الإشعارات المنبثقة أكثر استسلامًا من استراتيجيات الإشعارات الأخرى.
Markup
يُعدّ العنصر
<output>
خيارًا جيدًا للرسالة المنبثقة لأنّه يتم الإعلان عنها على شاشة
القارئين. توفّر لغة HTML الصحيحة قاعدة آمنة يمكننا تحسينها باستخدام JavaScript و
CSS، وسيكون هناك الكثير من JavaScript.
نخب
<output class="gui-toast">Item added to cart</output>
يمكن أن يكون أكثر
شمولاً
من خلال إضافة role="status"
. يقدّم ذلك بديلاً في حال عدم منح المتصفّح عناصر <output>
دورًا
ضمنيًا
وفقًا للمواصفات.
<output role="status" class="gui-toast">Item added to cart</output>
حاوية لفائف الخبز المحمّص
يمكن عرض أكثر من إشعار عائم في الوقت نفسه. من أجل تنسيق عدة إشعارات منبثقة، يتم استخدام حاوية. تتحكّم هذه الحاوية أيضًا في موضع الرسائل المنبثقة على الشاشة.
<section class="gui-toast-group">
<output role="status">Wizard Rose added to cart</output>
<output role="status">Self Watering Pot added to cart</output>
</section>
التنسيقات
اخترت تثبيت الإشعارات المنبثقة في
inset-block-end
مساحة العرض، وفي حال إضافة المزيد من الإشعارات المنبثقة، يتم تجميعها من تلك الحافة على الشاشة.
حاوية واجهة المستخدم الرسومية
تُجري حاوية الإشعارات المنبثقة جميع عمليات التنسيق لعرض الإشعارات المنبثقة. يتم تحديده
fixed
لمساحة العرض ويستخدم السمة المنطقية
inset
لتحديد
الحواف التي سيتم تثبيتها عليها، بالإضافة إلى جزء صغير من padding
من حافة block-end
نفسها.
.gui-toast-group {
position: fixed;
z-index: 1;
inset-block-end: 0;
inset-inline: 0;
padding-block-end: 5vh;
}
بالإضافة إلى تحديد موضع حاوية مربّع المعلومات المنبثق في إطار العرض، تكون حاوية مربّع المعلومات المنبثق
حاوية شبكة يمكنها محاذاة مربّعات المعلومات المنبثقة وتوزيعها. يتمّ وضع العناصر في وسط الشاشة كمجموعة باستخدام justify-content
وفي وسط الشاشة بشكلٍ فردي باستخدام justify-items
.
أضِف القليل من gap
حتى لا تلتصق الخبز المحمص ببعضها.
.gui-toast-group {
display: grid;
justify-items: center;
justify-content: center;
gap: 1vh;
}
إشعار منبثق لواجهة المستخدم الرسومية
يحتوي مربّع الرسائل المنبثقة الفردي على بعض padding
، وبعض الزوايا الأكثر نعومة باستخدام
border-radius
،
ودالة min()
لتحديد
حجم مربّع الرسائل المنبثقة على الأجهزة الجوّالة وأجهزة الكمبيوتر المكتبي. يمنع الحجم المتوافق مع جميع الأجهزة في ملف CSS التالي
تضخّم النوافذ المنبثقة إلى أكثر من% 90 من إطار العرض أو
25ch
.
.gui-toast {
max-inline-size: min(25ch, 90vw);
padding-block: .5ch;
padding-inline: 1ch;
border-radius: 3px;
font-size: 1rem;
}
الأنماط
بعد ضبط التنسيق والموضع، أضِف CSS للمساعدة في التكيّف مع إعدادات المستخدم وتفاعلاته.
حاوية الخبز المحمص
لا تكون الإشعارات المنبثقة تفاعلية، ولا يؤدي النقر عليها أو التمرير السريع عليها إلى أي إجراء، ولكنها تستهلك حاليًا أحداث المؤشر. يمكنك منع النوافذ المنبثقة من سرقة النقرات باستخدام ملف CSS التالي.
.gui-toast-group {
pointer-events: none;
}
إشعار منبثق لواجهة المستخدم الرسومية
يمكنك منح الإشعارات المنبثقة مظهرًا متوافقًا فاتحًا أو داكنًا باستخدام خصائص مخصّصة ونظام الألوان HSL و query media preference.
.gui-toast {
--_bg-lightness: 90%;
color: black;
background: hsl(0 0% var(--_bg-lightness) / 90%);
}
@media (prefers-color-scheme: dark) {
.gui-toast {
color: white;
--_bg-lightness: 20%;
}
}
Animation
من المفترض أن يظهر إشعار منبثق جديد مع مؤثر متحرك عند دخوله إلى الشاشة.
يتمّ تسهيل استخدام المحتوى الذي يضمّ حركة بطيئة من خلال ضبط قيم translate
على 0
بشكلٍ
تلقائي، ولكن من خلال تعديل قيمة الحركة إلى مدة في طلب
وسائط يستند إلى الإعدادات المفضّلة للحركة . يظهر للجميع بعض الصور المتحركة، ولكن يظهر للبعض فقط مربّع الإشعار المنبثق الذي يتحرك مسافة معيّنة.
في ما يلي الإطارات الرئيسية المستخدَمة في الصورة المتحركة للشريط المنبثق. ستتحكّم لغة CSS في موعد ظهور إشعار التلميح ومدة ظهوره ووقت اختفائه، وكل ذلك في صورة متحركة واحدة.
@keyframes fade-in {
from { opacity: 0 }
}
@keyframes fade-out {
to { opacity: 0 }
}
@keyframes slide-in {
from { transform: translateY(var(--_travel-distance, 10px)) }
}
بعد ذلك، يُعدّ عنصر مربّع الرسائل المنبثقة المتغيّرات وينظّم الإطارات الرئيسية.
.gui-toast {
--_duration: 3s;
--_travel-distance: 0;
will-change: transform;
animation:
fade-in .3s ease,
slide-in .3s ease,
fade-out .3s ease var(--_duration);
}
@media (prefers-reduced-motion: no-preference) {
.gui-toast {
--_travel-distance: 5vh;
}
}
JavaScript
بعد أن تصبح الأنماط وHTML القابلَين للوصول من خلال قارئ الشاشة جاهزين، تكون لغة JavaScript مطلوبة لتنسيق إنشاء الإشعارات المنبثقة وإضافتها وإزالتها استنادًا إلى أحداث المستخدم. يجب أن تكون تجربة المطوّر لمكوّن مربّع الرسائل المنبثقة بسيطة وسهلة البدء، على النحو التالي:
import Toast from './toast.js'
Toast('My first toast')
إنشاء مجموعة الإشعارات المنبثقة والإشعارات المنبثقة
عند تحميل وحدة مربّع الرسائل المنبثقة من JavaScript، يجب أن تنشئ حاوية مربّع رسائل منبثقة
وتضيفها إلى الصفحة. اخترت إضافة العنصر قبل body
، ما سيقلّل من احتمالية حدوث مشاكل في تجميع
z-index
لأنّ الحاوية فوق الحاوية الخاصة
بجميع عناصر النصّ.
const init = () => {
const node = document.createElement('section')
node.classList.add('gui-toast-group')
document.firstElementChild.insertBefore(node, document.body)
return node
}
يتمّ استدعاء الدالة init()
داخليًا في الوحدة، ما يؤدي إلى إخفاء العنصر
بصفته Toaster
:
const Toaster = init()
يتم إنشاء عنصر HTML للرسالة المنبثقة باستخدام الدالة createToast()
. تتطلّب الدالة
بعض النصوص للرسالة المنبثقة، وتُنشئ عنصر <output>
وتزيّنه
ببعض الفئات والسمات، وتضبط النص، وتُعيد العقدة.
const createToast = text => {
const node = document.createElement('output')
node.innerText = text
node.classList.add('gui-toast')
node.setAttribute('role', 'status')
return node
}
إدارة إشعار منبثق واحد أو عدّة إشعارات
تضيف JavaScript الآن حاوية إلى المستند لاحتواء الإشعارات المنبثقة وتكون
جاهزة لإضافة الإشعارات المنبثقة التي تم إنشاؤها. تنظِّم الدالة addToast()
معالجة رسائل Toast واحدة
أو عدّة رسائل. أولاً، التحقّق من عدد الإشعارات المنبثقة وما إذا كانت الحركة مقبولة،
ثم استخدام هذه المعلومات لإلحاق الإشعار المنبثق أو إنشاء بعض الرسوم المتحرّكة الأنيقة لكي تظهر الإشعارات المنبثقة الأخرى "لإفساح المجال" للإشعار المنبثق الجديد
const addToast = toast => {
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
Toaster.children.length && motionOK
? flipToast(toast)
: Toaster.appendChild(toast)
}
عند إضافة أول رسالة مصغّرة، يضيف Toaster.appendChild(toast)
رسالة مصغّرة إلى
الصفحة التي تشغّل صور CSS المتحركة: عرض الصورة المتحركة، الانتظار 3s
، إخفاء الصورة المتحركة.
يتمّ استدعاء flipToast()
عندما تكون هناك إشعارات Toast حالية، باستخدام أسلوب
يُسمّى FLIP من قِبل Paul
Lewis. والفكرة هي احتساب الفرق
في مواضع الحاوية، قبل إضافة النافذة المنبثقة الجديدة وبعدها.
يمكنك اعتبار ذلك مثل وضع علامة على مكان "محمّصة الخبز" الآن، ومكانها المستقبلي، ثم
إضافة مؤثرات متحركة من مكانها السابق إلى مكانها الحالي.
const flipToast = toast => {
// FIRST
const first = Toaster.offsetHeight
// add new child to change container size
Toaster.appendChild(toast)
// LAST
const last = Toaster.offsetHeight
// INVERT
const invert = last - first
// PLAY
const animation = Toaster.animate([
{ transform: `translateY(${invert}px)` },
{ transform: 'translateY(0)' }
], {
duration: 150,
easing: 'ease-out',
})
}
تُستخدم شبكة CSS لرفع التخطيط. عند إضافة إشعار منبثق جديد، تضعه الشبكة في البداية وتترك مسافة بينه وبين الإشعارات الأخرى. وفي الوقت نفسه، يتم استخدام تأثير متحرك على الويب لتحريك الحاوية من موضعها القديم.
تجميع كل JavaScript معًا
عند استدعاء Toast('my first toast')
، يتم إنشاء رسالة مصغّرة وإضافتها إلى الصفحة
(ربما يتم أيضًا إنشاء صورة متحرّكة للحاوية لاستيعاب الرسالة المصغّرة الجديدة)، ويتم عرض
وعد
ويتم
مراقبة الرسالة المصغّرة التي تم إنشاؤها عند اكتمال المحتوى المتحرّك في CSS (الصور المتحرّكة الثلاث للإطارات الرئيسية) لحلّ الوعد.
const Toast = text => {
let toast = createToast(text)
addToast(toast)
return new Promise(async (resolve, reject) => {
await Promise.allSettled(
toast.getAnimations().map(animation =>
animation.finished
)
)
Toaster.removeChild(toast)
resolve()
})
}
أعتقد أنّ الجزء المربك في هذا الرمز هو وظيفة Promise.allSettled()
وتعيين toast.getAnimations()
. بما أنّني استخدمت عدّة صور متحرّكة للإطارات الرئيسية
لرسالة Toast، لمعرفة ما إذا كانت قد اكتملت جميعها، يجب أن تتم أولاً
طلب كل منها من JavaScript، ثم يجب مراقبة كل من
finished
الوعد الذي يُقدّمه كل منها لإكمال العملية.
allSettled
يناسبنا ذلك، حيث يتم حلّ المشكلة تلقائيًا بعد تنفيذ كل الوعود التي تقدّمها. يعني استخدام await Promise.allSettled()
أنّ السطر التالي من
الرمز البرمجي يمكنه إزالة العنصر بثقة وافتراض أنّ النافذة المنبثقة قد أكملت
دورة حياتها. أخيرًا، يؤدي استدعاء resolve()
إلى الوفاء بالوعد العالي المستوى لعرض رسالة Toast حتى تتمكّن
المطوّرون من تنظيف الرمز البرمجي أو تنفيذ عمل آخر بعد ظهور رسالة Toast.
export default Toast
أخيرًا، يتم تصدير الدالة Toast
من الوحدة لنصوص برمجية أخرى تتمكّن من
استيرادها واستخدامها.
استخدام مكوّن Toast
يتم استخدام مربّع التنبيه المنبثق أو تجربة المطوّر لمربّع التنبيه المنبثق من خلال استيراد الدالة
Toast
واستدعائها باستخدام سلسلة رسالة.
import Toast from './toast.js'
Toast('Wizard Rose added to cart')
إذا أراد المطوّر إجراء عملية تنظيف أو أيّ إجراء آخر، يمكنه استخدام async وawait بعد عرض مربّع التلميح.
import Toast from './toast.js'
async function example() {
await Toast('Wizard Rose added to cart')
console.log('toast finished')
}
الخاتمة
الآن بعد أن عرفت كيف فعلت ذلك، كيف ستفعل ذلك؟ 🙂
لننوّع أساليبنا ونتعرّف على جميع الطرق لإنشاء تطبيقات على الويب. أنشئ عرضًا توضيحيًا وأرسِل إلينا رابطًا على Twitter، وسنضيفه إلى قسم الريمكسات التي أنشأها المستخدمون أدناه.
الريمكسات التي أنشأها المستخدمون
- @_developit باستخدام HTML/CSS/JS: الإصدار التجريبي والرمز البرمجي
- Joost van der Schee باستخدام HTML/CSS/JS: العرض الترويجي والرمز البرمجي