مشروع: معرض مكوّنات تفاعلية — CSS المتقدم
مشروع: معرض مكوّنات تفاعلية
ستبني صفحة واحدة تعرض مكتبة مكوّنات صغيرة — مثل صفحات أنظمة التصميم في الشركات — تجمع كل ما في الدورة.
المكوّنات المطلوبة
1. أزرار بأربعة أشكال (أساسي، خطر، شفاف، صغير) بمتغيرات المكوّن، مع hover و focus-visible و active.
2. بطاقة قابلة للقلب ثلاثية الأبعاد: صورة في الأمام ووصف في الخلف، تنقلب عند المرور وعند التركيز (:focus-within) حتى تعمل بلوحة المفاتيح.
3. بطاقة متكيفة بـ container query: رأسية في الحاوية الضيقة وأفقية في العريضة.
4. مؤشر تحميل و شريط تقدم متحرك.
5. نافذة حوار بعنصر <dialog> الأصلي مع خلفية ::backdrop وحركة ظهور.
6. مبدّل الوضع الليلي يعتمد على light-dark() و color-scheme.
نافذة dialog بلا مكتبات
<button type="button" class="btn" onclick="document.getElementById('info').showModal()">افتح النافذة</button>
<dialog id="info" aria-labelledby="info-title">
<h2 id="info-title">مرحباً</h2>
<p>هذه نافذة أصلية: تحبس التركيز وتُغلق بزر Esc تلقائياً.</p>
<form method="dialog">
<button class="btn" type="submit">إغلاق</button>
</form>
</dialog>dialog {
border: none;
border-radius: var(--radius-md, 12px);
padding: 24px;
max-width: min(90vw, 480px);
}
dialog::backdrop {
background: rgb(0 0 0 / 50%);
}
dialog[open] {
animation: pop 200ms ease-out;
}
@keyframes pop {
from { opacity: 0; scale: 0.95; }
}<dialog> مع showModal() يمنحك مجاناً: طبقة فوق كل شيء (لا z-index)، حبس التركيز داخلها، الإغلاق بـ Esc، وخلفية ::backdrop.
البطاقة القابلة للقلب بلوحة المفاتيح
.flip { perspective: 900px; }
.flip-inner {
position: relative;
transform-style: preserve-3d;
transition: rotate 600ms ease-in-out;
}
.flip:hover .flip-inner,
.flip:focus-within .flip-inner {
rotate: y 180deg;
}
.flip-face {
backface-visibility: hidden;
}
.flip-back {
position: absolute;
inset: 0;
rotate: y 180deg;
}ضع داخل البطاقة رابطاً أو زراً: عندما يصل إليه التركيز بـ Tab تنقلب البطاقة.
قائمة التحقق
- [ ] كل الألوان والمسافات من tokens.css — لا قيم سحرية في المكوّنات.
- [ ] كل عنصر تفاعلي له :focus-visible واضح.
- [ ] كل الحركات تحرّك transform/opacity فقط.
- [ ] prefers-reduced-motion: reduce يوقف الحركات (والبطاقة تُظهر الوجهين بدون قلب).
- [ ] الوضعان الفاتح والداكن بتباين كافٍ.
- [ ] الصفحة تعمل بعرض 320px وفي dir="ltr" أيضاً (خصائص منطقية).
تحديات إضافية
- إشعار (toast) ينزلق من حافة الشاشة في اتجاه القراءة الصحيح لكل لغة.
- حركة ظهور مرتبطة بالتمرير بـ animation-timeline: view() داخل @supports.
- حلقة تقدم دائرية متحركة بـ @property و conic-gradient.
أنت الآن تملك أدوات CSS الحديثة كاملة تقريباً. الخطوة التالية: JavaScript لإضافة السلوك والتفاعل الحقيقي.
@import url("tokens.css");
/* ===== البطاقة القابلة للقلب ===== */
.flip {
perspective: 900px;
inline-size: 260px;
block-size: 320px;
}
.flip-inner {
position: relative;
block-size: 100%;
transform-style: preserve-3d;
transition: rotate 600ms ease-in-out;
}
.flip:hover .flip-inner,
.flip:focus-within .flip-inner {
rotate: y 180deg;
}
.flip-face {
position: absolute;
inset: 0;
display: grid;
place-items: center;
padding: var(--space-4, 1rem);
border-radius: var(--radius-md, 12px);
background: var(--color-surface, white);
backface-visibility: hidden;
}
.flip-back {
rotate: y 180deg;
}
/* ===== مؤشر التحميل وشريط التقدم ===== */
@keyframes spin {
to { rotate: 1turn; }
}
.spinner {
inline-size: 32px;
aspect-ratio: 1;
border: 3px solid color-mix(in oklch, currentColor 20%, transparent);
border-block-start-color: currentColor;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes progress {
from { scale: 0 1; }
to { scale: 1 1; }
}
.progress-bar {
block-size: 6px;
background: var(--color-brand, #6366f1);
transform-origin: inline-start;
animation: progress 2s ease-out both;
}
/* ===== النافذة ===== */
dialog {
border: none;
border-radius: var(--radius-md, 12px);
padding: var(--space-6, 1.5rem);
max-inline-size: min(90vw, 480px);
}
dialog::backdrop {
background: rgb(0 0 0 / 50%);
}
dialog[open] {
animation: pop 200ms ease-out;
}
@keyframes pop {
from { opacity: 0; scale: 0.95; }
}
/* ===== احترام تقليل الحركة ===== */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
/* بلا قلب: نعرض الوجهين تحت بعضهما */
.flip-inner { transform-style: flat; }
.flip-face { position: static; backface-visibility: visible; }
.flip-back { rotate: none; }
}اختبر فهمك