---
title: 'Tailwind v4 الوضع الداكن: إعداد، تبديل وإصلاحات (2026)'
description: 'تفعيل الوضع الداكن في Tailwind CSS v4: كود @custom-variant dark المختصر، تبديل الـ class بدون وميض، دعم ثيم النظام، وليه dark: بيتوقف عن العمل.'
url: https://nerdleveltech.com/ar/tailwind-v4-dark-mode
language: ar
date: '2026-06-15'
category: frontend
tags:
  - tailwind css
  - tailwind v4
  - dark mode
  - custom-variant
  - frontend
  - css
markdown_url: https://nerdleveltech.com/ar/tailwind-v4-dark-mode.md
attribution: 'Source: NerdLevelTech — https://nerdleveltech.com/ar/tailwind-v4-dark-mode'
terms: https://nerdleveltech.com/llms.txt
---

# Tailwind v4 الوضع الداكن: إعداد، تبديل وإصلاحات (2026)

في Tailwind CSS v4، لم يعد خيار الإعداد `darkMode` يُطبق افتراضيًا — فالإصدار الرابع يعتمد على "CSS أولاً". قم بتمكين وضع الظلام القائم على الفئات (class-based) عن طريق إضافة `@custom-variant dark (&:where(.dark, .dark *));` إلى ملف CSS الخاص بك بعد `@import "tailwindcss";`، ثم قم بتبديل فئة `dark` على عنصر `<html>`. بدون ذلك، سيتبع `dark:` تفضيلات النظام فقط.

## ملخص

لا يزال Tailwind CSS v4 يشحن متغير `dark:`، لكنه نقل الإعدادات من `tailwind.config.js` إلى ملف CSS الخاص بك. افتراضيًا، يتتبع `dark:` نظام التشغيل عبر `prefers-color-scheme` بدون أي جافا سكريبت.[^docs] لتشغيل وضع الظلام من فئة `dark` بدلاً من ذلك، أضف سطرًا واحدًا — `@custom-variant dark (&:where(.dark, .dark *));` — إلى ورقة الأنماط الخاصة بك.[^docs] السبب وراء معظم تقارير "وضع الظلام في Tailwind v4 لا يعمل" هو أن مفتاح الإعداد القديم `darkMode: 'class'` لم يعد جزءًا من نموذج "CSS أولاً" في الإصدار الرابع، لذا تفقد المشاريع التي تمت ترقيتها ميزة تبديل الفئات حتى يتم إضافة هذا السطر.[^upgrade] تم التحقق من هذا الدليل مقابل **Tailwind CSS v4.3.1**[^tw] وتم تجميع وفحص كل قصاصة كود CSS في 15 يونيو 2026.

## ما ستتعلمه

- لماذا يتوقف `dark:` عن العمل بعد الترقية إلى Tailwind v4، والحل المكون من سطر واحد
- أين يتم إعداد وضع الظلام الآن بعد أن أصبح الإصدار الرابع يعتمد على "CSS أولاً" ولا يتم تحميل `tailwind.config.js` افتراضيًا
- كيف يعمل سلوك `prefers-color-scheme` الافتراضي بدون أي جافا سكريبت
- كيفية إضافة زر تبديل لوضع الظلام يعتمد على الفئات وحفظه في `localStorage`
- كيفية منع وميض السمة الخاطئة (FOUC) باستخدام سكربت `<head>` مضمن
- كيفية بناء زر تبديل ثلاثي (فاتح / داكن / نظام)
- كيفية استخدام سمة `data-theme` بدلاً من الفئة
- أكثر أخطاء وضع الظلام شيوعًا في Tailwind v4، مع حلولها

## لماذا "لا يعمل" وضع الظلام في Tailwind v4؟

تحدث معظم حالات "عدم عمل وضع الظلام في Tailwind v4" بسبب تغيير واحد: مفتاح إعداد `darkMode` لم يعد جزءًا من الإعداد الافتراضي. يعتمد Tailwind v4 على "CSS أولاً"، ولا يتم تحميل ملف `tailwind.config.js` تلقائيًا، لذا فإن `darkMode: 'class'` ليس له أي تأثير ما لم تختر صراحةً العودة إلى الإعدادات القديمة باستخدام توجيه `@config`.[^upgrade] لا تزال أدوات `dark:bg-gray-900` الخاصة بك تُجمع — لكنها تعتمد افتراضيًا على استعلام وسائط النظام، لذا فإن تبديل فئة `.dark` لن يفعل شيئًا حتى تقوم بتفعيل الخيار.

هناك سبب ثانٍ وأكثر دهاءً. قامت أداة الترقية التلقائية (`@tailwindcss/upgrade`)، في بعض المشاريع، بإعادة كتابة الإعداد القديم القائم على الفئات إلى متغير معطل مثل `@custom-variant dark (@media not print { .dark & })`، والذي لا يتصرف كزر تبديل للفئات. إذا قمت بالترقية وتوقف زر التبديل عن العمل بصمت، افتح ملف CSS الخاص بك وتحقق من الشكل الذي تمت إعادة كتابة المتغير إليه.[^issue]

لتأكيد ما ينتجه البناء (build) الخاص بك فعليًا، انظر إلى ملف CSS المجمع. بدون متغير مخصص، يتم تجميع أداة `dark:` إلى استعلام وسائط `prefers-color-scheme`:

```css
/* dark:bg-gray-900 with NO @custom-variant — system-driven */
.dark\:bg-gray-900 {
  @media (prefers-color-scheme: dark) {
    background-color: var(--color-gray-900);
  }
}
```

إذا كنت تريد أن تتحكم فئة ما في السمة ولا تزال ترى `@media (prefers-color-scheme: dark)` في المخرجات، فهذا يعني أن تجاوز المتغير (variant override) مفقود أو مشوه.

## أين يتم إعداد وضع الظلام في Tailwind v4؟

تقوم بإعداد وضع الظلام في ملف CSS الخاص بك، وليس في ملف إعداد جافا سكريبت. افتح ورقة الأنماط حيث تستورد Tailwind وقم بتجاوز متغير `dark` مباشرة أسفل الاستيراد:[^docs]

```css
/* app.css */
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
```

هذا السطر الوحيد `@custom-variant` هو الإعداد الكامل القائم على الفئات. بعد إضافته، يتم تطبيق أدوات `dark:` كلما ظهرت فئة `dark` في مكان سابق في شجرة HTML:[^docs]

```html
<html class="dark">
  <body>
    <div class="bg-white dark:bg-gray-900">
      <!-- styled for dark mode -->
    </div>
  </body>
</html>
```

قد ترى دروسًا تعليمية أخرى تكتب التجاوز كـ `&:is(.dark *)`. هذا يعمل، لكن `:is()` يتبنى خصوصية (specificity) وسيطه الأكثر تحديدًا، مما يرفع خصوصية كل أداة `dark:` ويمكن أن يسبب أخطاء تجاوز محيرة لاحقًا. الصيغة الرسمية `&:where(.dark, .dark *)` تستخدم `:where()`، والتي تتمتع دائمًا بخصوصية صفرية، لذا تظل أدوات الظلام الخاصة بك بنفس خصوصية نظيراتها الفاتحة تمامًا.[^where] يفضل استخدام الصيغة الرسمية.

إذا كنت تقوم بإعداد مشروع جديد بدلاً من إصلاح مشروع موجود، فقم بتثبيت حزم v4 أولاً[^tw][^vite] واستورد Tailwind مرة واحدة في ملف CSS الرئيسي الخاص بك:

```bash
npm install tailwindcss @tailwindcss/vite
```

```ts
// vite.config.ts
import { defineConfig from "vite";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [tailwindcss()],
});
```

```css
/* src/style.css — the single @import replaces the old base/components/utilities trio */
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
```

للحصول على شرح أعمق لإعداد "CSS أولاً"، وتوجيه `@theme`، ومسارات `@source`، راجع الدليل المصاحب [Tailwind v4 + Vite من الصفر](https://nerdleveltech.com/tailwind-v4-vite-css-first-theme-config-tutorial).

## هل يعمل وضع الظلام في Tailwind v4 بدون جافا سكريبت؟

نعم. افتراضيًا، وقبل إضافة أي تجاوز `@custom-variant`، يتم تشغيل متغير `dark:` بالكامل بواسطة ميزة الوسائط `prefers-color-scheme`، لذا فهو يتبع نظام التشغيل بدون جافا سكريبت وبدون أي فئة على الإطلاق.[^docs] إذا كان مطلبك الوحيد هو "احترام سمة نظام تشغيل المستخدم"، فلن تحتاج إلى زر تبديل أو سكربت أو `localStorage` — فقط اكتب أدوات `dark:` الخاصة بك وانطلق:

```html
<!-- Follows the OS theme automatically, zero JS -->
<div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100">
  <h1 class="text-2xl font-bold">Zero Gravity</h1>
  <p class="text-gray-500 dark:text-gray-400">Writes in any orientation.</p>
</div>
```

يتم دعم `prefers-color-scheme` عبر جميع المتصفحات الحالية، لذا فإن هذا المسار آمن للاستخدام كأساس.[^pcs] أضف تجاوز `@custom-variant` فقط عندما تريد أن يقوم المستخدمون بتبديل السمة يدويًا.

## كيفية إضافة زر تبديل لوضع الظلام يعتمد على الفئات؟

للسماح للمستخدمين بتبديل السمات، قم بإضافة أو إزالة فئة `dark` على عنصر `<html>` واحفظ الاختيار. مع وجود سطر `@custom-variant dark (&:where(.dark, .dark *));`، يبدو زر التبديل البسيط كالتالي:

```html
<button id="theme-toggle" type="button"
        class="rounded-md border px-3 py-2 dark:border-gray-700">
  Toggle theme
</button>
```

```js
// theme-toggle.js
const root = document.documentElement;

document.getElementById("theme-toggle").addEventListener("click", () => {
  const isDark = root.classList.toggle("dark");
  localStorage.theme = isDark ? "dark" : "light";
});
```

هذا الكود مستقل عن إطارات العمل: نفس الـ `classList.toggle("dark")` يعمل في HTML العادي، أو React، أو Astro، أو Vue، أو Svelte، لأن Tailwind يهتم فقط بوجود فئة `dark` على عنصر سلف. الكتابة في `localStorage` هي ما يجعل الاختيار يستمر بعد إعادة تحميل الصفحة — ولكنها بمفردها تسبب وميضًا، وهو ما يعالجه القسم التالي.

## كيفية منع وميض وضع الظلام (FOUC)؟

يحدث وميض الثيم الخاطئ لأن سكربت التبديل الخاص بك يعمل بعد أن يكون المتصفح قد رسم الصفحة بالفعل بالثيم الافتراضي. الحل هو تعيين كلاس `dark` قبل الرسم الأول عن طريق تضمين سكربت صغير في `<head>`، فوق ملف الأنماط (stylesheet) الخاص بك:[^docs]

```html
<head>
  <!-- Runs before paint — no flash of the wrong theme -->
  <script>
    if (
      localStorage.theme === "dark" ||
      (!("theme" in localStorage) &&
        window.matchMedia("(prefers-color-scheme: dark)").matches)
    ) {
      document.documentElement.classList.add("dark");
    } else {
      document.documentElement.classList.remove("dark");
    }
  </script>
  <link rel="stylesheet" href="/style.css" />
</head>
```

لأن هذا السكربت مضمن (inline) ومتزامن في الـ `<head>`، فإنه ينفذ قبل رندر الـ body، لذا يتم تطبيق الثيم الصحيح عند أول رسم تماماً. احتفظ به مضمناً — تحميله كملف خارجي يعيد ظهور الوميض، لأن المتصفح قد يرسم الصفحة قبل وصول الملف. في التطبيقات التي تعتمد على الرندر من جهة السيرفر (server-rendered)، يمكنك تحقيق نفس النتيجة عن طريق رندر `class="dark"` على وسم `<html>` من السيرفر بناءً على التفضيل المخزن، وهو نمط متوافق مع SSR لأطر العمل مثل المذكور في [دليل البث والتخزين المؤقت في Next.js](https://nerdleveltech.com/nextjs-16-streaming-suspense-use-cache-tutorial).[^docs]

## كيف تدعم ثيمات الفاتح، والداكن، والنظام؟

يوفر زر التبديل الكامل ثلاث حالات — فاتح صريح، داكن صريح، و"اتباع نظامي". توثيقات Tailwind تتبع هذا النموذج باستخدام ثلاث عمليات لـ `localStorage`: تعيين `theme` إلى `"light"`، أو تعيينه إلى `"dark"`، أو إزالته تماماً للعودة إلى إعدادات نظام التشغيل.[^docs] تعبير التهيئة الرسمي يتعامل مع الحالات الثلاث:[^docs]

```js
// Best inlined in <head> to avoid FOUC.
// dark when: explicit "dark", OR no stored choice AND the OS prefers dark.
document.documentElement.classList.toggle(
  "dark",
  localStorage.theme === "dark" ||
    (!("theme" in localStorage) &&
      window.matchMedia("(prefers-color-scheme: dark)").matches),
);
```

قم بربط كل زر بعملية `localStorage` المقابلة، ثم أعد تشغيل تعبير التبديل:

```js
// theme-controls.js
function applyTheme() {
  document.documentElement.classList.toggle(
    "dark",
    localStorage.theme === "dark" ||
      (!("theme" in localStorage) &&
        window.matchMedia("(prefers-color-scheme: dark)").matches),
  );
}

document.getElementById("light").onclick = () => { localStorage.theme = "light"; applyTheme(); };
document.getElementById("dark").onclick  = () => { localStorage.theme = "dark";  applyTheme(); };
document.getElementById("system").onclick = () => { localStorage.removeItem("theme"); applyTheme(); };

// Keep "system" mode live when the OS theme changes while the page is open
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
  if (!("theme" in localStorage)) applyTheme();
});
```

مراقب التغيير في `matchMedia` هو التفصيل الذي تتجاهله معظم الشروحات: في وضع "النظام"، يجب أن تتحدث الصفحة إذا قام المستخدم بتغيير ثيم نظام التشغيل الخاص به بينما التبويب مفتوح. `window.matchMedia` وحدث الـ `change` الخاص به مدعومان في جميع المتصفحات الحالية.[^matchmedia]

## كيف تستخدم سمة بيانات (data attribute) بدلاً من الكلاس؟

إذا كنت تفضل `data-theme="dark"` على الكلاس — وهو أمر شائع في أنظمة التصميم التي تستخدم بالفعل سمات البيانات للثيمات — فقم بتجاوز المتغير (variant) باستخدام محدد سمة بدلاً من ذلك:[^docs]

```css
@import "tailwindcss";
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
```

```html
<html data-theme="dark">
  <body>
    <div class="bg-white dark:bg-black"><!-- ... --></div>
  </body>
</html>
```

كل شيء آخر — التبديل، سكربت الـ FOUC، منطق الحالات الثلاث — يبقى كما هو؛ أنت فقط تقوم بتعيين `document.documentElement.dataset.theme = "dark"` بدلاً من تبديل الكلاس. غلاف `:where()` يحافظ على الخصوصية (specificity) عند الصفر هنا أيضاً.[^where]

## الأخطاء الشائعة في الوضع الداكن لـ Tailwind v4 (وإصلاحاتها)

كل صف أدناه يمثل حالة فشل حقيقية مستخلصة من المشكلات التي يبلغ عنها الأشخاص بعد الترقية.

| العرض                                               | السبب                                                                                          | الإصلاح                                                                                   |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `dark:` يتجاهل كلاس `.dark`                         | لا يوجد تجاوز لـ `@custom-variant` — `dark:` يعتمد افتراضياً على استعلام الوسائط (media query) | أضف `@custom-variant dark (&:where(.dark, .dark *));` بعد `@import "tailwindcss";`[^docs] |
| التبديل كان يعمل في v3، وتعطل بعد الترقية           | `darkMode: 'class'` ليس جزءاً من إعدادات v4 التي تعتمد على CSS أولاً                           | انقل الإعداد إلى CSS عبر `@custom-variant`[^upgrade]                                      |
| يبدو أن المتغير قد تم تعيينه ولكنه لا يزال يفشل     | أداة الترقية أنتجت `@custom-variant dark (@media not print { .dark & })`                       | استبدله بالصيغة الرسمية `&:where(.dark, .dark *)`[^issue]                                 |
| أدوات الداكن (dark utilities) تتجاوز بشكل غير متوقع | استخدام `&:is(.dark *)`، مما يرفع الخصوصية                                                     | انتقل إلى `&:where(...)` للحصول على خصوصية صفرية[^where]                                  |
| الصفحة تومض باللون الفاتح ثم الداكن عند التحميل     | سكربت التبديل يعمل بعد الرسم الأول                                                             | ضمن سكربت الثيم في `<head>` فوق ملف الأنماط الخاص بك[^docs]                               |
| وضع "النظام" يتجاهل تغييرات نظام التشغيل المباشرة   | لا يوجد مراقب لحدث `change` في `matchMedia`                                                    | أضف مراقب `change` يعيد التطبيق عندما لا يكون هناك خيار مخزن[^matchmedia]                 |

## الأسئلة الشائعة

**لماذا لا يعمل الوضع الداكن في Tailwind v4؟** مفتاح الإعداد `darkMode` ليس جزءاً من إعداد CSS-first في v4. يتطلب الوضع الداكن المعتمد على الكلاس وجود `@custom-variant dark (&:where(.dark, .dark *));` في ملف CSS الخاص بك؛ بدونه، يتبع `dark:` فقط `prefers-color-scheme`.[^upgrade][^docs]

**أين أقوم بضبط `darkMode` في Tailwind v4؟** في ملف CSS الخاص بك، مباشرة تحت `@import "tailwindcss";`. لا يقوم v4 بتحميل `tailwind.config.js` تلقائياً، لذا فإن خيار `darkMode` لم يعد سارياً إلا إذا اخترت استخدام إعداد قديم عبر `@config`.[^upgrade]

**هل يحتاج الوضع الداكن في Tailwind v4 إلى JavaScript؟** لا. السلوك الافتراضي لـ `prefers-color-scheme` لا يحتاج إلى أي JavaScript. تحتاج فقط إلى JS لعمل زر تبديل يدوي يتجاوز إعدادات نظام التشغيل.[^docs]

**هل يجب أن أستخدم `:is()` أم `:where()` في المتغير؟** استخدم `:where()`. فهو يتمتع بخصوصية صفرية، لذا تظل أدوات `dark:` بنفس خصوصية إصداراتها الفاتحة. أما `:is()` فيرث خصوصية أكثر وسائطه تحديداً ويمكن أن يسبب أخطاء في التجاوز.[^where]

**كيف أوقف وميض الثيم (FOUC)؟** قم بتضمين سكربت صغير في `<head>`، فوق ملف الأنماط الخاص بك، يضيف كلاس `dark` قبل أن يرسم المتصفح الصفحة. السكربتات الخارجية أو المؤجلة (deferred) تعمل بعد فوات الأوان.[^docs]

**كيف أدعم خيار "النظام" بجانب الفاتح والداكن؟** قم بتخزين `"light"` أو `"dark"` في `localStorage` للاختيارات الصريحة، واستخدم `removeItem("theme")` للعودة إلى نظام التشغيل. أعد التقييم باستخدام `window.matchMedia("(prefers-color-scheme: dark)")`.[^docs]

## الخلاصة

إصدار Tailwind v4 لم يقم بإزالة الوضع الداكن (dark mode) — بل قام بنقل مفتاح التحكم به. المتغير الافتراضي `dark:` يتبع نظام التشغيل بدون أي كود إضافي، وسطر واحد من CSS، وهو `@custom-variant dark (&:where(.dark, .dark *));`، يقوم بترقية ذلك إلى كلاس (class) يمكنك التحكم به.[^docs] إذا تعطل مفتاح التبديل لديك بعد الترقية، فغالباً ما يكون السبب هو مفتاح إعداد `darkMode` المفقود، والذي يتم إصلاحه بواسطة نفس السطر المذكور.[^upgrade] أضف سكريبت `<head>` المضمن لتحميل الصفحة بدون وميض (flash-free)، ومنطق الحالات الثلاث لمفتاح تبديل حقيقي، وبذلك ستحصل على وضع داكن جاهز للإنتاج يعمل في أي إطار عمل (framework).

بعد ذلك، قم بتثبيت بقية إعدادات v4 الخاصة بك باستخدام [دليل Tailwind v4 + Vite المعتمد على CSS أولاً](https://nerdleveltech.com/tailwind-v4-vite-css-first-theme-config-tutorial)، وإذا كنت جديداً على قواعد التتابع (cascade rules) الأساسية التي تجعل `:where()` مهماً، فابدأ بـ [مقدمة أساسيات CSS](https://nerdleveltech.com/introduction-to-css-presentation-part-1).

[^docs]: "Dark mode — Core concepts," Tailwind CSS documentation (v4.3), covering the default `prefers-color-scheme` behavior, the `@custom-variant dark (&:where(.dark, .dark *))` override, the data-attribute variant, and the inline-`head` FOUC script. <https://tailwindcss.com/docs/dark-mode>

[^upgrade]: "Upgrading to Tailwind v4: Missing Defaults, Broken Dark Mode, and Config Issues," tailwindlabs/tailwindcss Discussion #16517 — documents dark-mode breakage after upgrading to v4's CSS-first model, where the `darkMode` config key no longer applies by default. <https://GitHub.com/tailwindlabs/tailwindcss/discussions/16517>

[^tw]: tailwindcss on npm — version 4.3.1, published 2026-06-12. <https://www.npmjs.com/package/tailwindcss>

[^issue]: "\[v4] upgrade does not work for dark mode variant with media query," tailwindlabs/tailwindcss Issue #16171 — the automatic upgrade can emit a non-functional `@custom-variant dark (@media not print { .dark & })`. <https://GitHub.com/tailwindlabs/tailwindcss/issues/16171>

[^where]: ":where() always has 0 specificity, whereas :is() takes the specificity of its most specific argument." MDN Web Docs, `:where()`. <https://developer.mozilla.org/en-US/docs/Web/CSS/:where>

[^vite]: @tailwindcss/vite on npm — version 4.3.1, the official v4 Vite plugin. <https://www.npmjs.com/package/@tailwindcss/vite>

[^pcs]: "prefers-color-scheme," MDN Web Docs — a CSS media feature supported across current browsers. <https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme>

[^matchmedia]: "Window\.matchMedia()," MDN Web Docs — يرجع `MediaQueryList` يرسل حدث `change` عندما تتغير حالة المطابقة. <https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia>
