طراحی پنجره پاپآپ تأیید با CSS
پنجره پاپآپ تأیید (confirmation popup یا modal confirmation) یکی از اجزای کلیدی رابط کاربری است که کاربر را برای انجام عملیات حساس مانند حذف، ارسال اطلاعات یا پرداخت تأیید میکند. در این مقاله با تمرکز بر طراحی با CSS و نکات دسترسی، نمایشپذیری و انیمیشن، یک پیادهسازی عملی و قابل توسعه را بررسی میکنیم.
چرا طراحی درست مهم است؟
- جلوگیری از اشتباهات کاربر: نمایش پیام واضح و گزینههای متفاوت.
- برخورداری از تجربه کاربری خوب: انیمیشن، اندازه مناسب و کنتراست خوب.
- دسترسی (accessibility): قابل استفاده برای صفحهخوانها و کیبورد.
ساختار پایه HTML
<button id="open-confirm">حذف آیتم</button>
<div id="confirm-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="confirm-title" aria-hidden="true">
<div class="modal-overlay"></div>
<div class="modal-content" role="document">
<h2 id="confirm-title">آیا مطمئن هستید؟</h2>
<p>این عملیات قابل بازگشت نیست. آیا میخواهید ادامه دهید؟</p>
<div class="modal-actions">
<button id="confirm-btn" class="btn btn-danger">تأیید</button>
<button id="cancel-btn" class="btn">انصراف</button>
</div>
</div>
</div>این ساختار ساده شامل یک دکمه برای باز کردن، یک پوشش (overlay) و محتوای مدال است. ویژگیهای ARIA به دسترسی کمک میکنند و حالت اولیه aria-hidden برای نشاندادن وضعیت مدال استفاده شده است.
طراحی و استایل با CSS
:root {
--overlay-bg: rgba(0,0,0,0.5);
--modal-bg: #fff;
--danger: #e53e3e;
--text: #222;
--radius: 8px;
--max-width: 500px;
--gap: 16px;
}
.modal {
position: fixed;
inset: 0;
display: none; /* shown via JS by adding .open */ align-items: center;
justify-content: center;
z-index: 1000;
}
.modal.open {
display: flex;
}
.modal-overlay {
position: absolute;
inset: 0;
background: var(--overlay-bg);
backdrop-filter: blur(3px);
opacity: 0;
transition: opacity 180ms ease;
}
.modal.open .modal-overlay {
opacity: 1;
}
.modal-content {
position: relative;
background: var(--modal-bg);
color: var(--text);
border-radius: var(--radius);
padding: calc(var(--gap) * 1.25);
width: min(92%, var(--max-width));
box-shadow: 0 8px 30px rgba(0,0,0,0.25);
transform: translateY(8px) scale(0.98);
opacity: 0;
transition: transform 200ms ease, opacity 200ms ease;
}
.modal.open .modal-content {
transform: translateY(0) scale(1);
opacity: 1;
}
.modal-actions {
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: 12px;
}
.btn {
padding: 8px 12px;
border-radius: 6px;
border: 1px solid transparent;
cursor: pointer;
background: #f2f2f2;
}
.btn:focus {
outline: 3px solid rgba(66,153,225,0.6);
outline-offset: 2px;
}
.btn-danger {
background: var(--danger);
color: white;
border-color: rgba(0,0,0,0.05);
}
/* reduced motion */@media (prefers-reduced-motion: reduce) {
.modal-overlay, .modal-content {
transition: none;
}
}در این CSS از متغیرهای CSS برای سفارشیسازی سریع استفاده شده است. نمایش و مخفیشدن مدال از طریق کلاس .open کنترل میشود. انیمیشنها سبک و قابلغیرفعال کردن با prefers-reduced-motion است. استایلهای بصری مانند radius، shadow و رنگها به تجربه کاربری کمک میکنند.
کد JavaScript برای مدیریت رفتار
const openBtn = document.getElementById('open-confirm');
const modal = document.getElementById('confirm-modal');
const overlay = modal.querySelector('.modal-overlay');
const confirmBtn = document.getElementById('confirm-btn');
const cancelBtn = document.getElementById('cancel-btn');
let lastFocused = null;
function openModal() {
lastFocused = document.activeElement;
modal.classList.add('open');
modal.setAttribute('aria-hidden', 'false');
// focus first actionable element
confirmBtn.focus();
trapFocus(modal);
}
function closeModal() {
modal.classList.remove('open');
modal.setAttribute('aria-hidden', 'true');
releaseFocusTrap();
if (lastFocused) lastFocused.focus();
}
openBtn.addEventListener('click', openModal);
overlay.addEventListener('click', closeModal);
cancelBtn.addEventListener('click', closeModal);
confirmBtn.addEventListener('click', () => {
// place confirmation logic here (e.g., submit, delete)
console.log('Confirmed');
closeModal();
});
// close on Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.classList.contains('open')) {
closeModal();
}
});
/* Simple focus trap */let focusableElements = [];
let firstFocusable = null;
let lastFocusable = null;
function trapFocus(root) {
focusableElements = Array.from(root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'))
.filter(el => !el.hasAttribute('disabled'));
firstFocusable = focusableElements[0];
lastFocusable = focusableElements[focusableElements.length - 1];
root.addEventListener('keydown', handleTab);
function handleTab(e) {
if (e.key !== 'Tab') return;
if (e.shiftKey) {
if (document.activeElement === firstFocusable) {
e.preventDefault();
lastFocusable.focus();
}
} else {
if (document.activeElement === lastFocusable) {
e.preventDefault();
firstFocusable.focus();
}
}
}
root._handleTab = handleTab;
}
function releaseFocusTrap() {
if (modal._handleTab) {
modal.removeEventListener('keydown', modal._handleTab);
modal._handleTab = null;
}
}این اسکریپت وظیفه باز/بستن مدال، مدیریت فوکوس و نگهداشتن فوکوس داخل مدال (focus trap) را دارد. عملکرد تأیید (confirm) در اینجا با یک console.log نشان داده شده؛ شما میتوانید آن را با عملیات واقعی مثل فراخوانی API یا حذف آیتم جایگزین کنید.
نکات دسترسی و تجربه کاربری (UX)
- از aria-labelledby و aria-modal برای شناسایی مدال استفاده کنید.
- همیشه گزینهٔ لغو (Cancel) را در دسترس قرار دهید و رنگها را معنادار انتخاب کنید (مثلاً رنگ قرمز برای موارد خطر).
- در دستگاههای موبایل عرض مدال را محدود و دکمهها را لمسیپسند طراحی کنید.
- برای کاربرانی که حرکت کم میخواهند، انیمیشنها را با prefers-reduced-motion غیرفعال کنید.
- تراپ فوکوس مهم است؛ مطمئن شوید کاربر کیبورد بتواند بین کنترلها گردش کند.
مزایا و معایب پیادهسازی با CSS+JS
| مزایا | معایب |
|---|---|
| کنترل کامل روی ظاهر و انیمیشنها | نیاز به مدیریت فوکوس و رفتار با JS |
| قابلیت سفارشیسازی با CSS variables | پذیرش نادرست ARIA در نسخههای ضعیف یا بدون JS |
نکات حرفهای و بهینهسازی
- اگر مدال برای عملیات مهم است، از متن واضح و دکمهٔ تأیید با نام عملیاتی (مثلاً “حذف دائمی”) استفاده کنید.
- از رنگها و آیکونهای معنیدار استفاده کنید اما به کنتراست توجه داشته باشید.
- برای فرمهای داخل مدال، اندازه ورودیها را مناسب کنید و ارورهای احتمالی را واضح نشان دهید.
- برای کاهش بار DOM، مدال را تنها زمانی به DOM اضافه کنید که لازم است (lazy mount).
نتیجهگیری
پنجره پاپآپ تأیید باید ترکیبی از طراحی زیبا، دسترسی صحیح و رفتار قابلپیشبینی باشد. با استفاده از CSS برای ظاهر و انیمیشن و مقدار کمی JS برای مدیریت رفتار و فوکوس، میتوانید یک مدال تأیید حرفهای، قابلدسترس و قابل توسعه بسازید.
در صورت نیاز میتوان کد را برای فریمورکهای مختلف (React, Vue) یا برای موارد پیچیدهتر مانند چند مرحلهای کردن تأیید یا افزودن لایهٔ تأیید دوم گسترش داد.
آیا این مطلب برای شما مفید بود ؟




