ساخت مودال پاپآپ با CSS
مودالها (پاپآپها) بخش مهمی از تجربه کاربری وب هستند؛ برای نمایش پیام، فرمها، تاییدیهها یا محتوای موقت استفاده میشوند. در این مقاله با روشهای ساخت مودال فقط با CSS (و در صورت نیاز به بهبود دسترسی، ترکیب با مقدار کمی JS) آشنا میشوید. نمونههای عملی، نکات دسترسی و بهینهسازی برای موبایل نیز توضیح داده شدهاند.
روش اول — مودال ساده با :target
<a href="#modal">Open Modal</a>
<div id="modal" class="modal">
<div class="modal-content" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<a href="#" class="modal-close" aria-label="Close">×</a>
<h2 id="modal-title">عنوان مودال</h2>
<p>این یک نمونه مودال ساختهشده با :target است.</p>
</div>
</div>
/* CSS */.modal {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.6);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease;
}
.modal:target {
opacity: 1;
pointer-events: auto;
}
.modal-content {
position: relative;
background: #fff;
padding: 1.5rem;
max-width: 600px;
width: calc(100% - 2rem);
border-radius: 6px;
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
}
.modal-close {
position: absolute;
right: 1rem;
top: 1rem;
text-decoration: none;
font-size: 1.5rem;
color: #333;
}این کد با استفاده از سلیکتر :target وقتی لینک به #modal هدایت میشود، مودال را نشان میدهد. مزیت ساده بودن و عدم نیاز به JS است. معایب: تغییر fragment در URL (تاثیر بر تاریخچه مرورگر)، نداشتن کنترل پیشرفته صفحهکلید (مثلاً Esc یا قفل کردن فوکوس) و مشکلات دسترسی برای برخی از کاربران.
بهبود UI و انیمیشن
/* اضافه کردن انیمیشن و transform برای ظاهر نرمتر */.modal {
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease;
}
.modal .modal-content {
transform: scale(0.95);
transition: transform 0.25s ease, opacity 0.25s ease;
opacity: 0;
}
.modal:target {
opacity: 1;
pointer-events: auto;
}
.modal:target .modal-content {
transform: scale(1);
opacity: 1;
}در این بهبود، از transform و transition استفاده شده تا باز و بسته شدن مودال نرمتر دیده شود. همچنین اندازه و حاشیه محتوا برای نمایش بهتر در موبایل با width: calc(100% – 2rem) در نظر گرفته شده است.
روش دوم — Checkbox hack (بدون JS و بدون fragment)
<input type="checkbox" id="modalToggle" class="modal-toggle" />
<label for="modalToggle" class="open-button">Open Modal</label>
<div class="modal">
<div class="modal-content" role="dialog" aria-modal="true">
<label for="modalToggle" class="modal-close">×</label>
<h2>عنوان</h2>
<p>مودال با استفاده از چکباکس نمایش داده میشود.</p>
</div>
</div>
/* CSS */.modal-toggle { display: none; }
.modal {
position: fixed; inset:0; display:flex; align-items:center; justify-content:center;
background: rgba(0,0,0,0.6); opacity:0; pointer-events:none; transition:opacity .25s;
}
.modal-toggle:checked ~ .modal {
opacity:1; pointer-events:auto;
}
.modal-content { background:#fff; padding:1.5rem; border-radius:6px; width:90%; max-width:600px; }این روش با input نوع checkbox وضعیت باز/بسته بودن مودال را نگه میدارد؛ مزیت اصلی حذف fragment از URL است. اما محدودیتها شامل عدم امکان بستن با کلید Esc و نیاز به تگهای نگارشی (label) برای باز/بسته کردن است.
دسترسی (Accessibility) و کنترل فوکوس
برای مودالهای حرفهای لازم است که:
- عنصر مودال role=”dialog” و aria-modal=”true” داشته باشد.
- فوکوس هنگام باز شدن به اولین کنترل داخل مودال منتقل شود و هنگام بستن بازگردد.
- فوکوس بین عناصر داخل مودال محصور (focus trap) شود.
- قابلیت بستن با کلید Esc فراهم شود.
این موارد با CSS محض قابل پیادهسازی کامل نیستند؛ بنابراین پیشنهاد میشود برای مدیریت فوکوس و Esc از مقدار کمی JS استفاده کنید.
// Optional JS برای بستن با Escape و بازگرداندن فوکوس
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
// اگر از checkbox
const cb = document.getElementById('modalToggle');
if (cb && cb.checked) {
cb.checked = false;
return;
}
// اگر از :target
if (location.hash === '#modal') {
history.back();
}
}
});
// سادهترین focus management (نمونه)
const openBtn = document.querySelector('.open-button');
const modal = document.getElementById('modal');
openBtn && openBtn.addEventListener('click', () => {
setTimeout(() => {
const focusable = modal.querySelector('button, [href], input, textarea, select, [tabindex]:not([tabindex="-1"])');
focusable && focusable.focus();
}, 50);
});این اسکریپت کوتاه به Esc پاسخ میدهد و در حالت checkbox آن را خاموش میکند یا در حالت fragment با history.back() به حالت قبلی برمیگردد. اسکریپت دوم تلاش میکند فوکوس را به اولین عنصر قابل فوکوس در مودال منتقل کند. برای یک focus trap کامل نیاز به کتابخانه یا پیادهسازی طولانیتر است.
مقایسه روشها
| روش | پیچیدگی | قابلیت دسترسی | کنترل کامل |
|---|---|---|---|
| :target | کم | متوسط (مشکلات URL) | محدود |
| Checkbox | کم | متوسط (نیاز به label) | محدود |
| JS محور | بیشتر | خوب (در صورت پیادهسازی صحیح) | کاملاً قابل کنترل |
نکات عملی و بهترین روشها
- برای محتوای ساده و اطلاعرسانی کوتاه، روش CSS-only مناسب است؛ اما برای فرمها و تعاملات حساس از JS استفاده کنید.
- همیشه role و ariaهای لازم را اضافه کنید: role=”dialog” و aria-modal=”true” و aria-labelledby/aria-describedby.
- در موبایل، اندازه مودال را به گونهای تنظیم کنید که صفحهپشتزمینه قابل اسکرول نشود یا تجربه کاربری را مختل نکند.
- برای بهبود تجربه، انیمیشنهای نرم و محدود به تغییر opacity/transform انتخاب کنید تا عملکرد بهتر بماند.
- برای پروژههای بزرگ از کتابخانههای شناختهشده (مثلاً Reach UI یا Radix) استفاده کنید که مسائل دسترسی را از پیش حل کردهاند.
نتیجهگیری
ممکن است هدف شما نمایش سریع و ساده یک پیام باشد یا ساخت مودال تعاملی و دسترسپذیر برای فرمها. با روشهای CSS-only میتوانید به سرعت مودال بسازید، اما برای دسترسی کامل و کنترل رفتار کلیدها و تمرکز، ترکیب CSS با JS کوتاه و مستحکم بهترین گزینه است. همیشه تست با صفحهخوانها و صفحهکلید را فراموش نکنید.
آیا این مطلب برای شما مفید بود ؟




