نکات کلیدی
- فریمورکهای CSS در کوتاهمدت باعث افزایش سرعت و یکدستی میشوند، اما در طول زمان نگهداری از آنها بهطور فزایندهای سختتر میشود.
- یک کدبیس که از یک فریمورک CSS استفاده میکند، بهتدریج یک فریمورک سفارشی خودش را روی آن میسازد. این فریمورک استفادهکردن، فهمیدن و تغییر دادنش سخت خواهد بود.
- فریمورکهای CSS شاید انتخاب خوبی برای اپلیکیشنی باشند که قرار است سیستم طراحی فریمورک را کامل بپذیرد و هیچ تغییری در آن ندهد. این در تئوری خوب به نظر میرسد، اما در عمل اتفاق نمیافتد.
- استایلها را با خودِ CSS بنویسید، نه گزینههایی که به CSS کامپایل میشوند مثل SCSS یا JS-to-CSS. پیچیدگی اضافه زیاد است و سودش کم، چون CSS مدرن ویژگیهای فوقالعادهای دارد.
- هنگام ساخت CSS، با استایلهای معنایی (semantic) شروع کنید. این کار نیت شما را برای توسعهدهندگان دیگر روشن میکند و به آنها در انتخاب استراتژی قالببندی (templating) آزادی عمل بیشتری میدهد.
توسعهدهندگان از فریمورکهای CSS مثل Material UI، Bootstrap یا Pico استفاده میکنند تا boilerplate را کاهش دهند، کیفیت را بالا ببرند و یکدستی ایجاد کنند. اما حفظ این دستاوردها با بالغشدن کدبیس یک اپلیکیشن سخت میشود. ظاهر و حس اپلیکیشن از فریمورک فاصله میگیرد، کامپوننتهای جدید اضافه میشوند و چیدمانها و کامپوننتهای موجود تغییر میکنند. توسعهدهندگان مجبور میشوند فریمورک را پیکربندی و override کنند تا با این تغییرات هماهنگ شود. در نهایت override کردن فریمورک سختتر از این میشود که تغییرات را از صفر پیادهسازی کنید.
بهجای استفاده از فریمورک CSS، پیشنهاد میکنم توسعهدهندگان CSS سفارشی خودشان را بنویسند. وقتی نیازمندیهای اپلیکیشن تغییر میکند، توسعهدهندگان یا استایلهای موجود را تغییر میدهند یا استایلهای جدید را از یک starter کپی میکنند، نه اینکه استایلهای قبلی را override کنند. CSS مدرن ویژگیهای زیادی دارد که نوشتن استایلهای قابل نگهداری را ممکن میکند. نگهداشتن استایلها داخل خود کدبیس بهجای اینکه آنها را بهعنوان یک وابستگی خارجی وارد کنید، باعث میشود کدبیس CSS در طول زمان جمعوجور و قابلفهم باقی بماند.
معایب فریمورکهای CSS
Override کردن
Override کردن یک فریمورک وقتگیر است، نگهداریاش سخت است و احتمال خطا در آن بالاست. فریمورکها وقتی بیشترین منفعت را دارند که توسعهدهندگان در محدودههای تعیینشده خودشان حرکت کنند. خیلی از فریمورکها تا حدی امکان سفارشیسازی میدهند، اما نیازهای سفارشیسازی یک اپلیکیشن معمولاً از گزینههای داخلی فریمورک فراتر میرود. در نتیجه توسعهدهندگان مجبور میشوند به جای اینکه متخصص CSS شوند، متخصص override کردن همان فریمورک شوند. overrideها اغلب از قابلیتهایی استفاده میکنند که بخشی از API عمومی فریمورک نیستند، و همین باعث میشود سفارشیسازیها هنگام ارتقا نسخه فریمورک، مستعد شکستن باشند.
بعد از مدت کوتاهی، overrideهای فریمورک آنقدر زیاد میشوند که تیمها در عمل صاحب یک فریمورک سفارشی میشوند که از تعداد زیادی override، سفارشیسازی و توسعه تشکیل شده است. این فریمورک سفارشی قراردادها و قواعد خودش را دارد و نگهداشتنش سخت است. اغلب حتی برای توسعهدهندگانی که در فریمورک CSS اصلی متخصصاند هم غریبه و نامأنوس به نظر میرسد. مشکلاتی که با CSS خالص ساده حل میشوند، در این حالت دردسرساز میشوند چون باید در «زمینه فریمورک» حل شوند.
سختی در تحمیل یکدستی
گاهی تیمها از یک فریمورک CSS استفاده میکنند چون کل تیم محصول متعهد شده از سیستم طراحی فریمورک استفاده کند و هیچ وقت از آن منحرف نشود. خیلی از تیمها با این هدف شروع میکنند، اما تقریباً هیچکدام برای مدت قابل توجهی پایبند نمیمانند. سیستمهای طراحی فریمورکها فوقالعاده عمومیاند؛ آنها تلاش میکنند بیشتر نیازهای بیشتر اپلیکیشنها را پوشش دهند، نه اینکه همه نیازهای یک اپلیکیشن مشخص را کامل پوشش دهند. با گذشت زمان، نیازهای طراحی یک اپلیکیشن همیشه از چیزی که فریمورک فراهم میکند فاصله میگیرد.
تفاوت با فریمورکها در زبانهای دیگر
نمیتوانیم مشکلات فریمورکهای CSS را به انواع دیگر فریمورکها تعمیم دهیم؛ مثل فریمورکهای وب مانند Flask، Rails یا Spring. توسعهدهندگان اغلب بخشهای داخلی فریمورکهای CSS را override میکنند، اما هنگام استفاده از فریمورکهای وب بهندرت مجبور میشوند چنین کاری کنند. برای مثال، خیلی عجیب است که کسی مجبور شود سورسکد Flask را بخواند تا تغییری بنویسد که نحوه routing یا session management را عوض کند. اما برای توسعهدهندگانی که از MUI استفاده میکنند، کاملاً رایج است که با styleOverrides نحوه رندر شدن یک slider را تغییر دهند. همین واقعیت که کد فریمورکهای CSS غالباً override میشود، همان چیزی است که فریمورکهای CSS را خطرناک میکند.
CSS خودتان را بنویسید
وقتی CSS خودتان را مینویسید، معمولاً با یک reset، یک theme، استایلهای پایه CSS و کامپوننتها شروع میکنید. من ترجیح میدهم هر بار اینها را از صفر بنویسم، اما خیلی از توسعهدهندگان این را بیش از حد زمانبر میدانند. برای کاهش boilerplate، میتوانید به استفاده از یک کدبیس starter برای CSS فکر کنید تا استایلهای پایه را فراهم کند. توسعهدهندگان starter CSS را مستقیم داخل کدبیس خودشان اضافه میکنند، نه اینکه آن را بهعنوان یک وابستگی خارجی وارد کنند. starterها مزایای فریمورک (کاهش boilerplate، افزایش کیفیت و یکدستی) را میدهند بدون معایب آن.
من یک starter برای CSS نگهداری میکنم که برای همه قابل استفاده است، اما اگر آن به سلیقه شما نمیخورد، میتوانید خودتان با یکی از گزینههای زیر یک starter بسازید:
-
یکی از کدبیسهای فعلی خودتان (البته که بدون فریمورک ساخته شده باشد)
-
یک کدبیس متنباز با استایلهای تمیز
-
یک فریمورک CSS مینیمال مثل Pico CSS
به یاد داشته باشید که با هرکدام از این گزینهها، احتمالاً بهتر است فقط با بخش کوچکی از CSS آنها شروع کنید و بعد به مرور قطعههای جدید را اضافه کنید. با تکامل طراحی، استایلهای starter را تغییر دهید، نه اینکه آنها را override کنید.
با CSS بسازید
من معتقدم بهترین زبان برای نوشتن استایلهای اپلیکیشن، خودِ CSS است. ویژگیهای جدید CSS مثل متغیرها، scopeها، nesting و توابع مقدار (value functions) باعث شدهاند زبانهایی مثل SCSS یا JS-to-CSS دیگر آنقدر ارزش اضافهای ایجاد نکنند که پیچیدگیشان توجیهپذیر باشد. پشتیبانی IDE از CSS عالی است، اما پشتیبانی از SCSS یا JS-to-CSS اغلب عقبتر است. علاوه بر این، توسعهدهندگان برای نوشتن و نگهداری استایلهای سفارشی، در هر حال باید CSS را خوب بفهمند، فارغ از اینکه استایلها با چه زبانی نوشته شدهاند.
تمسازی، نوشتن CSS محدود به محدوده (scoped)، نوشتن CSS گویا و تغییر مقدارهای CSS نمونههایی از مسائلی هستند که قبلاً با CSS خالص سخت بودند. این ضعفها قبلاً توسعهدهندگان را از CSS دور میکرد و به سمت SCSS یا JS میبرد. اما ویژگیهای جدید CSS شکاف را کمتر کردهاند و نیاز به راهحلهای دیگر را کاهش دادهاند.
تمسازی (Theming)
الان توسعهدهندگان میتوانند با استفاده از CSS custom properties (متغیرها) تمسازی را در CSS انجام دهند. تمها همچنین میتوانند با استفاده از media query به نام prefers-color-scheme به ترجیح کاربر برای حالت تاریک یا روشن واکنش نشان دهند.
هنگام ساختاردهی یک تم، ابتدا رنگهای خام CSS را بهعنوان متغیر در بالای فایل تم تعریف کنید. سپس متغیرهای معنایی تعریف کنید، مثل –text-color و –background-color برای تم پایه. در نهایت، برای تمهای اضافی (مثل تم تاریک) متغیرهای معنایی را در صورت نیاز override کنید. از متغیرهای معنایی بهعنوان مقدار همه رنگها در باقی کد استفاده کنید تا مطمئن شوید اپلیکیشن شما درست با تمها سازگار میشود.

scopeهای CSS
scopeهای CSS امکان محدودکردن استایلها به یک عنصر یا کامپوننت مشخص را فراهم میکنند. scopeها به توسعهدهندگان اجازه میدهند برای کامپوننتهای خاص استایل بنویسند بدون اینکه نگران اثر آن روی بخشهای دیگر کدبیس باشند (و بدون نیاز به نوشتن قوانین بیش از حد خاص). پشتیبانی مرورگرها از scopeها با سرعت در حال بهتر شدن است، بنابراین انتظار داشته باشید خیلی زود بتوانید بدون محدودیت از آنها استفاده کنید. کد زیر h1 را قرمز میکند، اما هیچ h1 خارج از تگ section مشخصشده را تحت تأثیر قرار نمیدهد.

سینتکس تو در تو
CSS از سینتکس تو در تو پشتیبانی میکند، مشابه سینتکسی که SCSS محبوبش کرد. این کار نوشتن CSS را راحتتر میکند و میتواند خوانایی را بهتر کند. استایلهای تو در تو کمک میکنند گروهبندی منطقی استایلها را بهتر بیان کنید و نیاز به تکرار selectorهای مشترک در قوانین متعدد را کاهش دهید.

توابع کمکی
CSS مجموعه رو به رشدی از توابع مقدار مانند calc و color-mix دارد که به توسعهدهندگان اجازه میدهند هنگام تعریف یک مقدار CSS، محاسبه یا پردازش انجام دهند. این کار تعداد متغیرهای CSS موردنیاز را کاهش میدهد و امکان تعریف استایلهای منعطف را میدهد که بهسادگی قابل توسعهاند.
پیچیدگیهای غیر CSS
راهحلهای غیر CSS مثل SCSS یا JS-to-CSS معایب قابل توجهی دارند و آنها را به انتخاب ضعیفی برای استایلهای اپلیکیشن تبدیل میکنند. بزرگترین عیب، مرحله کامپایل است. اگر استایلها در زمان build به CSS کامپایل شوند، جریان کاری توسعهدهنده و تنظیمات سیستم پیچیدهتر میشود. اگر استایلها در زمان اجرا به CSS کامپایل شوند، کارایی میتواند افت کند و شکست در کامپایل روی کاربران اثر بگذارد. در هر حالت، مرورگرها استایلها را به شکل CSS اجرا (و دیباگ) میکنند، بنابراین توسعهدهندگان باید CSS تولیدشده را بفهمند.
علاوه بر این، توسعهدهندگان باید بررسی کنند راهحلهای compile-to-CSS چگونه با نرمافزار موجود آنها تعامل دارند. فریمورکهای جدیدتر مثل NextJS یا Remix کد سمت کلاینت را هم در مرورگر و هم روی سرور اجرا میکنند. یعنی کامپایل استایل باید هم در مرورگر و هم روی سرور اجرا شود که میتواند Node یا محیطی شبیه worker مثل Cloudflare Workers یا Deno باشد. بسیاری از گزینههای فعلی compile-to-CSS از این محیطها خوب پشتیبانی نمیکنند. همچنین بسیاری از فریمورکهای محبوب مثل React اکنون از پاسخهای HTTP استریمشده استفاده میکنند، که استایلهای کامپایلشونده در زمان اجرا را بهشدت پیچیدهتر میکند.
CSS معنایی استفاده کنید
از نام کلاسهای معنایی (کلاسهای قابل استفاده مجدد با نامهایی بر اساس معنای مفهومی) برای گروهبندی استایلهای رایج استفاده کنید. کلاسهای معنایی نیت یک گروه از استایلها را برای مصرفکنندگان بیان میکنند. نامگذاری یکی از مهمترین کارهایی است که بهعنوان توسعهدهنده انجام میدهیم تا نرمافزارمان استفادهپذیرتر و قابل تطبیقتر شود. باید برای نامگذاری کلاسهای CSS وقت و انرژی جدی بگذاریم، مخصوصاً وقتی سیستمی میسازیم که دیگران قرار است بعداً آن را تغییر دهند و توسعه دهند (به هر حال، نرمافزار بیشتر از آنکه نوشته شود، خوانده میشود).
نامهای معنایی همچنین به توسعهدهندگان انعطاف میدهند تا استراتژی templating خود را انتخاب کنند. نامهای کلاس اتمیک (atomic) یعنی کلاسهای تکمنظوره با نامهایی بر اساس عملکرد بصری، مانند چیزی که Tailwind CSS محبوب کرد، توسعهدهندگان را مجبور میکند برای کاهش تکرار markup، کامپوننتها یا partialهای ریز بسازند. توسعهدهندگان مجبور میشوند کامپوننتها را از هم جدا کنند تا استایلها را کپسوله کنند، که نتیجهاش کامپوننتهای بیش از حد عمومی با لیست بلند و گیجکنندهای از گزینههاست.
از گزینههای چیدمان مدرن استفاده کنید
گزینههای چیدمان مدرن مثل Flexbox و Grid به توسعهدهندگان اجازه میدهند layoutهای واکنشگرا را با markup تمیز و CSS تمیز بسازند. یعنی دیگر لازم نیست با layoutهای قدیمی شبکه ۱۲ ستونه سر و کله بزنیم که انعطاف را محدود میکنند و markup را شلوغ میکنند. یک قاعده سرانگشتی خوب این است: برای چیدمان یکبعدی از Flexbox استفاده کنید و برای چیدمان دوبعدی از Grid.
چگونه CSS سفارشی را ساختاربندی کنیم
برای شروع، حداقل مجموعه استایلهایی را که برای ساخت استایلهای سراسری پایه اپلیکیشن لازم دارید بنویسید یا وارد کنید. این احتمالاً شامل یک CSS reset، استایلهای تم رنگ، چیدمان پایه و تایپوگرافی است. وقتی به کامپوننتهای پیچیدهتری مثل دکمهها، دراپ داونها، جدولها، مدلها، tooltipها و غیره نیاز پیدا کردید، این استایلها را مستقیم داخل کدبیس خودتان بنویسید یا اضافه کنید.
استایلهای اپلیکیشن را بخشی از کدبیس خودتان بدانید، نه یک وابستگی خارجی. وقتی استایلهای اپلیکیشن از چیزی که با آن شروع کردید فاصله میگیرد، استایلهای پایه را تغییر دهید، نه اینکه آنها را override کنید. این کار کمک میکند استایلها جمعوجور و قابل فهم باقی بمانند.
استایلهای سراسری را ترجیح دهید و در صورت نیاز استایلهای scoped بنویسید
استایلهای سراسری استایلهایی هستند که روی کل اپلیکیشن اعمال میشوند. بدون استایلهای سراسری حفظ ظاهر و حس یکدست سخت است. اولین استایلهایی که مینویسید احتمالاً استایلهای سراسری هستند؛ استایلهایی که روی کل اپلیکیشن اعمال میشوند و بهندرت override میشوند.
وقتی استایلهای جدید مینویسید، کمی وقت بگذارید تا محدوده اثر آنها را مشخص کنید. در ابتدا احتمالاً محدوده اثر محدود است، پس میتوان آنها را به شکل استایلهای محدود (scoped) با استفاده از کلاسها یا @scope نوشت. با گذشت زمان، الگوهای تکراری که در استایلهای scoped دیده میشوند میتوانند به استایلهای سراسری استخراج شوند. CSS خود را زیاد بازآرایی (refactor) کنید!
CSS بنویسید
در پایان، با اینکه فریمورکهای CSS محبوباند، من فکر میکنم اغلب انتخاب بدی برای استایلدادن به یک اپلیکیشن هستند. در پروژه بعدیتان با CSS خالص کار کنید؛ یا از صفر شروع کنید یا از starter من یا یک گزینه مشابه بهعنوان نقطه شروع استفاده کنید. خواهید دید میتوانید خیلی سریع استایلهای اولیه اپلیکیشن را بسازید و در طول زمان هم نگهداریشان کنید.
