ویژگی تصویر

استفاده از CSS Modules در پروژه‌ها — مقدمه و ضرورت

  /  CSS   /  استفاده از CSS Modules در پروژه ها
بنر تبلیغاتی الف

CSS Modules یک روش مدرن برای نوشتن استایل‌های محلی (scoped) در پروژه‌های وب است. هدف اصلی حل مشکل تداخل اسامی (namespace collision) و نگهداری بهتر استایل‌ها در اپلیکیشن‌های بزرگ است. در ادامه به توضیحات، مثال‌های عملی، پیکربندی‌ و نکات حرفه‌ای می‌پردازیم.

مزایا و کاربردهای اصلی

  • اسکوپ محلی: هر کلاس به صورت پیش‌فرض فقط برای کامپوننت مربوطه معتبر است و از تداخل با دیگر کامپوننت‌ها جلوگیری می‌کند.
  • قابلیت نگهداری: تفکیک استایل‌ها بر اساس کامپوننت، خوانایی و بازاستفاده را افزایش می‌دهد.
  • یکپارچه با ابزارهای مدرن: سازگار با Webpack، Rollup، Vite و فریم‌ورک‌هایی مثل React و Next.js.
  • پشتیبانی از ترکیب کلاس‌ها: امکان composition، global، و استفاده از CSS variables برای تم‌ها وجود دارد.

نمونه ساده: ساختار فایل‌ها

فرض کنید یک کامپوننت React به نام Card دارید:

/* Card.module.css */.container {
  background: white;
  border-radius: 8px;
  padding: 16px;
}
.title {
  font-size: 18px;
  color: #222;
}

در این فایل CSS، پسوند .module.css نشان می‌دهد که این فایل به عنوان CSS Module پردازش می‌شود.

// Card.jsx
import React from 'react';
import styles from './Card.module.css';

export default function Card({ title, children }) {
  return (
    <div className={styles.container}>
      <h3 className={styles.title}>{title}</h3>
      <div>{children}</div>
    </div>
  );
}

در اینجا، import کردن فایل CSS به صورت یک شیء (object) انجام می‌شود که کلیدهای آن نام کلاس‌های تعریف‌شده در CSS و مقادیر آن نام‌های تولیدشده‌ی منحصر به فرد (hashed) است. این باعث می‌شود کلاس‌ها فقط در همین کامپوننت اعمال شوند.

ترکیب کلاس‌ها و حالت‌های داینامیک

برای ترکیب چند کلاس و وضعیت‌های شرطی معمولاً از بسته‌ای مثل classnames استفاده می‌کنند:

// Card.jsx (with classnames)
import React from 'react';
import cn from 'classnames';
import styles from './Card.module.css';

export default function Card({ title, highlighted }) {
  return (
    <div className={cn(styles.container, { [styles.highlighted]: highlighted })}>
      <h3 className={styles.title}>{title}</h3>
    </div>
  );
}

در این مثال، وقتی prop مقدار highlighted را داشته باشد، کلاس styles.highlighted به container اضافه می‌شود. توجه داشته باشید که دسترسی به کلیدهای شیء styles باید با bracket notation هنگام نام‌های داینامیک انجام شود.

پیکربندی ساده در Webpack

// webpack.config.js (relevant part)
module.exports = {
  module: {
    rules: [
      {
        test: /.module.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /.css$/,
        exclude: /.module.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader']
      }
    ]
  }
};

این کانفیگ جداسازی فایل‌های معمولی CSS و CSS Modules را نشان می‌دهد. فایل‌هایی که پسوند .module.css دارند با گزینه modules پردازش می‌شوند تا کلاس‌ها به صورت محلی تولید شوند.

نکات پیشرفته و بهترین شیوه‌ها

  • استفاده از نام‌گذاری خوانا: حتی با hash شدن اسامی، استفاده از نام‌های معنادار (مثلاً button__primary) کمک به نگهداری می‌کند.
  • ترکیب با CSS Variables: برای تم‌ها و حالت‌های داینامیک، متغیرهای CSS بهترین گزینه هستند و می‌توانند بین ماژول‌ها به صورت global استفاده شوند.
  • استفاده از :global و :local: در CSS Modules می‌توانید بخش‌هایی را که باید جهانی باشند مشخص کنید. نمونه:
/* example.module.css */:global(.reset) {
  margin: 0;
  padding: 0;
}
.localClass {
  color: blue;
}

کلاس .reset در سطح global باقی می‌ماند و برای ریست کردن استایل‌ها استفاده می‌شود، در حالی که .localClass فقط در ماژول جاری scoped است.

تایپ‌اسکریپت و تعریف نوع‌ها

وقتی از TypeScript استفاده می‌کنید، بهتر است برای فایل‌های CSS Module یک اعلان نوع بسازید تا import از CSS خطا ندهد:

// custom.d.ts
declare module '*.module.css' {
  const classes: { [key: string]: string };
  export default classes;
}

این اعلان به TypeScript می‌گوید که فایل‌های .module.css یک شیء از رشته‌ها صادر می‌کنند و هنگام import، تایپ‌ها معتبر خواهند بود.

مزایا و معایب — جدول مقایسه‌ای

مزایامعایب
جلوگیری از تداخل کلاس‌ها
نگهداری بهتر و modular
سازگاری با ابزارهای مدرن
نیاز به پیکربندی اولیه در برخی ابزارها
فرایندهای انتزاعی‌تر برای برخی استایل‌های global
ممکن است در تیم‌های قدیمی مقاومت شود

مواردی که باید مراقب باشید

  • استفاده بیش از حد از :global می‌تواند مزیت Isolation را از بین ببرد.
  • برای کامپوننت‌های کوچک و پروژه‌های ساده، CSS Modules ممکن است اضافه بر نیاز باشد؛ انتخاب باید متناسب با مقیاس پروژه باشد.
  • در SSR (مثل Next.js) معمولاً نیاز به تنظیمات اضافی برای استخراج استایل‌ها یا اطمینان از SSR-friendly loader‌ها دارید.

نکات بهینه‌سازی و تجربه حرفه‌ای

  • از PostCSS و Autoprefixer برای سازگاری مرورگرها استفاده کنید.
  • در پروژه‌های بزرگ، از naming convention ثابت و مستند استفاده کنید (مثلاً BEM ترکیب شده با ماژول‌ها).
  • برای استایل‌های مشترک و تغییر تم، از CSS variables در سطح root یا از یک ماژول global جداگانه بهره ببرید.
  • در تست‌های واحد و اسنپ‌شات، نام‌های hash را ایزوله یا mock کنید تا تست‌ها پایدار بمانند.

جمع‌بندی

CSS Modules راه‌حلی قدرتمند برای مدیریت استایل در اپلیکیشن‌های مدرن است. این روش با ایجاد اسکوپ محلی، نگهداری را ساده‌تر کرده و خطر تداخل کلاس‌ها را به حداقل می‌رساند. با این حال، باید نکات پیکربندی، استفاده از :global و ترکیب با ابزارهای build را در نظر گرفت تا تجربه توسعه و کارایی در پروژه حفظ شود.

در صورتی که نیاز به نمونه پیکربندی کامل برای فریم‌ورک یا پرسش در مورد تعامل CSS Modules با ابزار خاصی دارید، نام فریم‌ورک/ابزار خود را بفرستید تا مثال اختصاصی ارائه شود.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: