التصميم الديناميكي للألوان في React: ما وراء متغيرات CSS
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
تتوقف معظم دروس التصميم عند مفتاح الوضع الداكن. تبديل فئة على <html>، قلب حفنة من متغيرات CSS، انتهى. هذا يغطي حالة شائعة لكنه يفوّت المشكلة الأكثر إثارة: ماذا لو تمكّن المستخدمون من اختيار لونهم التجاري؟ ماذا لو خدم منتج SaaS الخاص بك عملاء متعددين، لكل منهم هويته الخاصة؟
هنا يبدأ التصميم الديناميكي للألوان — ومتغيرات CSS وحدها ليست كافية. تحتاج إلى خوارزميات ألوان في وقت التشغيل، وحالة React تبقى عبر التنقل، واستراتيجيات استمرارية، وبنية لا تعيد رسم شجرة مكوناتك بأكملها في كل مرة يتحرك فيها شريط تمرير.
نهج متغيرات CSS لثيمات React
الأساس: بنية الرموز الدلالية
/* globals.css */
:root {
--bg-base: #F8FAFC;
--bg-surface: #FFFFFF;
--bg-sunken: #F1F5F9;
--text-primary: #1E293B;
--text-secondary: #64748B;
--text-disabled: #94A3B8;
--brand-primary: #2563EB;
--brand-hover: #1D4ED8;
--brand-subtle: #EFF6FF;
--on-brand: #FFFFFF;
--border-default: #E2E8F0;
--border-strong: #CBD5E1;
--status-error: #DC2626;
--status-success: #16A34A;
--status-warning: #D97706;
}
حين تحدّث --brand-primary في JavaScript، يتحدث كل مكوّن يشير إليه فوراً.
توليد الثيمات في وقت التشغيل باستخدام خوارزميات الألوان
توليد مجموعة الرموز الكاملة
import chroma from 'chroma-js';
function generateThemeTokens(brandHex) {
const brand = chroma(brandHex);
const brandLuminance = brand.luminance();
const onBrand = brandLuminance > 0.179 ? '#000000' : '#FFFFFF';
const scale = chroma.scale([
chroma(brandHex).brighten(2.5).desaturate(0.5).hex(),
brandHex,
chroma(brandHex).darken(2.5).hex(),
]).mode('oklch').colors(11);
return {
'--brand-primary': brandHex,
'--brand-hover': chroma(brandHex).darken(0.5).hex(),
'--brand-active': chroma(brandHex).darken(1).hex(),
'--brand-subtle': scale[1],
'--on-brand': onBrand,
};
}
سياق React لإدارة حالة الثيم
بنية ThemeContext
// contexts/ThemeContext.tsx
import {
createContext,
useContext,
useEffect,
useState,
useCallback,
type ReactNode,
} from 'react';
import { generateThemeTokens } from '../lib/theme-generator';
interface ThemeState {
brandHex: string;
mode: 'light' | 'dark' | 'system';
}
const ThemeContext = createContext<any>(undefined);
const STORAGE_KEY = 'app-theme';
export function ThemeProvider({ children }: { children: ReactNode }) {
const [state, setState] = useState<ThemeState>(() => {
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) return JSON.parse(stored) as ThemeState;
} catch {}
return { brandHex: '#2563EB', mode: 'system' };
});
useEffect(() => {
const tokens = generateThemeTokens(state.brandHex);
const root = document.documentElement;
Object.entries(tokens).forEach(([prop, value]) => {
root.style.setProperty(prop, value as string);
});
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
}, [state]);
const setBrand = useCallback((hex: string) => {
setState(prev => ({ ...prev, brandHex: hex }));
}, []);
return (
<ThemeContext.Provider value={{ ...state, setBrand }}>
{children}
</ThemeContext.Provider>
);
}
فئات الألوان الديناميكية في Tailwind CSS
الحل 1: جسر متغيرات CSS
/* styles.css (Tailwind v4) */
@import "tailwindcss";
@theme {
--color-brand: var(--brand-primary);
--color-brand-hover: var(--brand-hover);
--color-brand-subtle: var(--brand-subtle);
--color-on-brand: var(--on-brand);
}
الآن bg-brand وtext-brand وhover:bg-brand-hover فئات Tailwind صالحة تعكس قيمة --brand-primary في وقت التشغيل.
منع وميض الثيم الافتراضي عند التحميل
// app/layout.tsx (Next.js App Router)
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ar" suppressHydrationWarning>
<head>
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
try {
var stored = JSON.parse(localStorage.getItem('app-theme') || '{}');
var brand = stored.brandHex || '#2563EB';
document.documentElement.style.setProperty('--brand-primary', brand);
} catch(e) {}
})();
`,
}}
/>
</head>
<body>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
);
}
الخلاصة الرئيسية
- متغيرات CSS المخصصة هي الأساس — الرموز الدلالية المسمّاة بدورها لا بقيمة لونها تتيح تغيير الثيم الكامل دون تعديل المكونات.
- توليد الرموز في وقت التشغيل من hex لون تجاري واحد يتطلب: مقياساً للإضاءة والظلام، والتحقق من تباين WCAG لنص on-brand، وحساباً منفصلاً لمتغيرات الوضع الداكن.
- سياق React يدير حالة الثيم ويطبق الرموز على DOM كتأثير جانبي.
- أضف تأخيراً 150ms للحسابات المكلفة حين ترتبط بمدخلات مستمرة.
- لـ Tailwind CSS: عرّف جسر متغيرات CSS في
@themeحتى تعكس فئاتbg-brandقيمة الرمز في وقت التشغيل. - استخدم Shade Generator وPalette Generator.