Kodax

مشروع: معرض مكوّنات تفاعلية — 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; }
}
اختبر فهمك