البرمجة مبتدئ 9 دقيقة

كيفية إضافة وضع داكن (Dark Mode) إلى موقعك

لم يعد الوضع الداكن ترفاً — المستخدمون يتوقعونه. التطبيق الصحيح يعتمد على CSS custom properties لكل الألوان، وخاصية data-theme على عنصر <html> للتبديل بين الثيمات، وسكريبت صغير مدمج في <head> يُطبّق التفضيل المحفوظ قبل أول رسم للصفحة. إذا نُفّذ بشكل صحيح، لن يكون هناك وميض للثيم الخاطئ ولا اعتماد على JavaScript في التنسيق نفسه.

الخطوات

  1. 1

    تعريف ألوان المتغيرات في :root

    استبدل كل لون ثابت في CSS بـ custom property. عرّف قيم الوضع الفاتح جميعها على :root. هذا هو المصدر الوحيد للحقيقة — لا يجب أن يظهر أي لون كقيمة hex أو rgb مباشرة في أي مكان آخر.

    css
    :root {
      --bg:        #ffffff;
      --bg-subtle: #f5f5f5;
      --surface:   #ffffff;
      --border:    #e0e0e0;
      --text:      #111111;
      --text-muted:#666666;
      --accent:    #0070f3;
      --accent-hover: #0050c9;
    }
  2. 2

    تجاوز المتغيرات داخل [data-theme="dark"]

    أضف كتلة ثانية تُعيد تعريف متغيرات الألوان فقط بقيم الوضع الداكن. كل شيء آخر في CSS يبقى كما هو — ستتبنى المكونات تلقائياً القيم الجديدة للمتغيرات.

    css
    [data-theme="dark"] {
      --bg:        #0d0d0d;
      --bg-subtle: #1a1a1a;
      --surface:   #1e1e1e;
      --border:    #2e2e2e;
      --text:      #f0f0f0;
      --text-muted:#a0a0a0;
      --accent:    #3b9eff;
      --accent-hover: #60b0ff;
    }
  3. 3

    تطبيق المتغيرات على جميع العناصر

    راجع ملف CSS واستبدل الألوان الثابتة بـ var() في كل مكان — الخلفيات، والنصوص، والحدود، والظلال، والمدخلات، والأزرار. إذا فاتك لون واحد، فلن يستجيب لتبديل الثيم.

    css
    body {
      background-color: var(--bg);
      color: var(--text);
    }
    
    .card {
      background: var(--surface);
      border: 1px solid var(--border);
    }
    
    a {
      color: var(--accent);
    }
    a:hover {
      color: var(--accent-hover);
    }
  4. 4

    إضافة زر التبديل

    ضع زراً في شريط التنقل أو الرأسية. سيتحدث الأيقونة عبر JavaScript. اجعل الأمر بسيطاً — زر واحد، مهمة واحدة.

    html
    <button id="theme-toggle" aria-label="Toggle dark mode">
      <span id="theme-icon">🌙</span>
    </button>
  5. 5

    كتابة JavaScript للتبديل

    يقرأ السكريبت الثيم الحالي من خاصية data-theme، يعكسه، يحفظه في localStorage، ويحدّث أيقونة الزر. ضع هذا في ملف JS الرئيسي أو في <script> في نهاية <body>.

    javascript
    const btn  = document.getElementById('theme-toggle');
    const icon = document.getElementById('theme-icon');
    const root = document.documentElement;
    
    btn.addEventListener('click', () => {
      const isDark = root.dataset.theme === 'dark';
      const next   = isDark ? 'light' : 'dark';
    
      root.dataset.theme = next;
      localStorage.setItem('theme', next);
      icon.textContent   = next === 'dark' ? '☀️' : '🌙';
    });
  6. 6

    قراءة prefers-color-scheme كافتراضي

    للزوار لأول مرة الذين ليس لديهم تفضيل محفوظ، اقرأ إعداد نظام التشغيل عبر prefers-color-scheme: dark. هذا هو الافتراض الصحيح — لا تفرض الوضع الفاتح على شخص يستخدم الوضع الداكن في كل مكان.

    javascript
    // تُستدعى مرة واحدة عند التحميل لضبط الأيقونة الأولية
    function applyStoredTheme() {
      const saved  = localStorage.getItem('theme');
      const system = window.matchMedia('(prefers-color-scheme: dark)').matches
                       ? 'dark' : 'light';
      const theme  = saved ?? system;
    
      document.documentElement.dataset.theme = theme;
      document.getElementById('theme-icon').textContent =
        theme === 'dark' ? '☀️' : '🌙';
    }
    
    applyStoredTheme();
  7. 7

    منع وميض الثيم الخاطئ (FOUC)

    إذا نُفّذ JavaScript للثيم بعد رسم الصفحة، سيرى الزوار في الوضع الداكن وميضاً للثيم الفاتح للحظة. الحل: سكريبت <script> مصغر مدمج في <head> — قبل أي رابط CSS — يضبط data-theme بشكل متزامن. يعمل قبل الرسم، فلا شيء يومض.

    يجب أن يكون هذا السكريبت مدمجاً، وليس ملفاً خارجياً مؤجلاً أو غير متزامن.

    html
    <!-- ضع هذا أول عنصر داخل <head> -->
    <script>
      (function () {
        var saved  = localStorage.getItem("theme");
        var system = window.matchMedia("(prefers-color-scheme: dark)").matches
                       ? "dark" : "light";
        document.documentElement.dataset.theme = saved || system;
      })();
    </script>
  8. 8

    تنعيم الانتقال بين الثيمات

    أضف transition قصيراً على الخصائص التي تتغير بين الثيمات حتى لا يبدو التبديل مفاجئاً. انقل فقط خصائص الألوان — وليس خصائص التخطيط كـ width أو transform التي ستبطئ كل animation.

    css
    *, *::before, *::after {
      transition:
        background-color 0.2s ease,
        color            0.2s ease,
        border-color     0.2s ease;
    }

نصائح ومحاذير

  • لا تستخدم <code>prefers-color-scheme</code> داخل كتلة <code>@media</code> لألوانك الرئيسية — لا يمكن تجاوزه بزر التبديل. استخدم <code>data-theme</code> بدلاً من ذلك.
  • خزّن تفضيل المستخدم كـ "light" أو "dark" وليس كقيمة boolean — يسهل توسيعها لثيم ثالث لاحقاً.
  • اختبر مع تعطيل JavaScript: سكريبت الرأسية المدمج سيعمل لأنه متزامن، لكن زر التبديل لن يعمل. هذا مقبول.
  • إذا كنت تستخدم CSS-in-JS أو Tailwind، ينطبق نفس المبدأ — عرّف أسماء المتغيرات مرة واحدة وبادل القيم عبر class أو attribute على <code>&lt;html&gt;</code>.
  • قد تحتاج الأيقونات والصور نسخاً منفصلة للوضع الداكن. استخدم <code>picture</code> مع مصدر <code>media="(prefers-color-scheme: dark)"</code> أو بادل <code>src</code> عبر JS مع تغيير الثيم.

خاتمة

يرتكز تطبيق الوضع الداكن الصحيح على ثلاثة أعمدة: CSS custom properties تجعل كل لون قابلاً للتبديل، وخاصية data-theme التي تُنفّذ التبديل الفعلي، وسكريبت مدمج في الرأسية يمنع وميض الثيم. احصل على هذه الثلاثة بشكل صحيح وسيتبع الباقي — زر التبديل، والحفظ، والافتراضي حسب النظام — بشكل طبيعي. التطبيق بأكمله لا يتجاوز 50 سطراً من الكود.

#CSS #JavaScript #UX
العودة إلى جميع الأدلة

هل تحتاج مساعدة في مشروعك؟

احجز استشارة مجانية لمدة 30 دقيقة لمناقشة تحدياتك التقنية واستكشاف الحلول معًا.