توسعه فرانت‌اند

CSS Cascade Layers: مدیریت Specificity

تقدم Layer را از Specificity جدا کنید؛ قوانین بدون لایه، وارونگی Important و مهاجرت CSS را با نمونه کامل دو کارت در یک فایل HTML ببینید.

1404/12/27 2 دقیقه مطالعه 1,002 بازدید

یک کلاس ساده را تغییر می‌دهید، اما رنگ عوض نمی‌شود. Selector را طولانی‌تر می‌کنید و بعد با قانون دیگری درگیر می‌شوید. مشکل همیشه Specificity نیست؛ جایگاه قانون در Cascade، منبع، اهمیت و ترتیب هم اثر دارند. Cascade Layers با دستور @layer امکان می‌دهد گروه‌های سبک را در یک ترتیب صریح قرار دهید. این ابزار جای فهم Cascade را نمی‌گیرد، ولی کمک می‌کند رابطه سبک کتابخانه، پایه، Component و اصلاح‌ها به جنگ Selector تبدیل نشود. برای استفاده درست، باید قوانین عادی و !important را جدا ببینید.

Layer پیش از Specificity مطرح می‌شود

وقتی دو قانون از نظر منبع و اهمیت در شرایط قابل مقایسه‌اند، ترتیب لایه می‌تواند پیش از Specificity تعیین‌کننده باشد. بنابراین Selector طولانی در لایه پایین‌تر، الزاماً قانون کوتاه در لایه بالاتر را شکست نمی‌دهد. این همان ارزش اصلی ابزار است: قرارداد معماری می‌تواند از جزئیات Selector مستقل‌تر باشد. اما مقایسه را به همه منشأها، سبک Inline و همه وضعیت‌ها تعمیم ندهید. Cascade چند مرحله دارد و Layer فقط یکی از آن‌هاست.

مرجع @layer در MDN روش تعریف و ترتیب لایه‌ها را توضیح می‌دهد. برای قوانین عادی نویسنده، لایه‌ای که در ترتیب بعدتر است نسبت به لایه قبلی تقدم دارد. قوانین عادی بدون لایه نیز نسبت به قوانین عادی لایه‌دار تقدم دارند. همین نکته در مهاجرت مهم است: انتقال بعضی فایل‌ها به Layer و رها کردن بقیه بدون Layer ممکن است نتیجه‌ای متفاوت از انتظار بسازد.

ترتیب را یک بار و زود مشخص کنید

می‌توانید نام لایه‌ها را در یک اعلان اولیه به ترتیب بنویسید و محتوای هر لایه را بعداً اضافه کنید. باز کردن دوباره همان نام، لایه تازه‌ای در انتهای ترتیب نمی‌سازد؛ قواعد به همان لایه تعلق می‌گیرند. این امکان برای فایل‌های جدا مفید است. ترتیب باید با قرارداد تیم هماهنگ باشد. اگر هر Component مستقل نام و ترتیب جدیدی بسازد، معماری کلی دوباره مبهم می‌شود. تعداد کم و نقش روشن معمولاً نگهداری ساده‌تری دارد.

نام‌هایی مانند reset،base،components و utilities نمونه‌اند، نه استاندارد اجباری. باید بدانید هر گروه چه مسئولیتی دارد. Reset قرارداد پیش‌فرض را تنظیم می‌کند، Base عناصر عمومی را شکل می‌دهد و Component سبک بخش مشخص را دارد. Utilities اگر استفاده می‌شوند باید نقش محدود و قابل فهم داشته باشند. لایه‌ای با نام «هرچیز» یا «اصلاح نهایی» ممکن است در طول زمان به محل انباشت استثنا تبدیل شود. نام، جای قرارداد واقعی را نمی‌گیرد.

نمونه کامل برای دیدن تقدم

فایل زیر همه HTML و CSS لازم را دارد و به کتابخانه، فونت یا فایل خارجی وابسته نیست. آن را با نام index.html ذخیره کنید و در مرورگر پشتیبان Cascade Layers باز کنید. کارت اول نشان می‌دهد قانون کوتاه در لایه utilities می‌تواند رنگ تعیین‌شده با Selector دارای ID در components را تغییر دهد. کارت دوم یک قانون عادی بدون Layer دارد تا تفاوت آن هم دیده شود. این نمونه آموزشی است و قرار نیست معماری کامل Design System باشد.

<!doctype html>
<html lang="fa" dir="rtl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>نمونه Cascade Layers</title>
<style>
@layer base, components, utilities;
@layer base {
 body {font-family:system-ui;background:#f5f6f8;color:#18212a;margin:2rem;line-height:1.8}
 .card {background:white;border:1px solid #bbc5ce;padding:1rem;margin-block:1rem;border-radius:.6rem}
}
@layer components {
 #demo .card {color:#a01818}
}
@layer utilities {
 .text-accent {color:#1458a0}
}
.unlayered {color:#12602c}
</style></head><body><main id="demo"><h1>تقدم لایه‌ها در قوانین عادی</h1>
<article class="card text-accent"><h2>کارت اول: آبی</h2><p>لایه utilities از components بعدتر است.</p></article>
<article class="card text-accent unlayered"><h2>کارت دوم: سبز</h2><p>قانون عادی بدون لایه بر قانون عادی لایه‌دار مقدم است.</p></article>
</main></body></html>

انتظار می‌رود متن کارت اول آبی و متن کارت دوم سبز باشد. در کارت اول، نام لایه و ترتیب آن پیش از Specificity تعیین‌کننده شده است. در کارت دوم، قانون عادی بدون لایه تقدم دارد. اگر مرورگر پشتیبانی نکند، قواعد داخل @layer ممکن است اعمال نشوند؛ پشتیبانی باید با مرورگرهای هدف پروژه بررسی شود. این مقاله ادعای اجرای آزمون مرورگر در محیط انتشار ندارد. کد برای خواندن و اجرای مستقل مخاطب کامل ارائه شده است.

چرا ID قوی‌تر برنده نشد؟

در نمونه، Selector کارت اول در components دارای ID است، اما قانون .text-accent در utilities قرار دارد. چون هر دو قانون عادی در منبع نویسنده‌اند و ترتیب لایه‌ها مشخص است، لایه بعدی مقدم می‌شود. اگر هر دو داخل یک لایه باشند، نوبت معیارهای بعدی مانند Specificity می‌رسد. این تفاوت کمک می‌کند برای Override یک کتابخانه همیشه مجبور به تکرار زنجیره Selector آن نباشید. البته ابتدا باید کتابخانه واقعاً در لایه مناسب قرار گرفته باشد.

این رفتار به معنی حذف Specificity نیست. داخل هر لایه همچنان باید Selectorها را قابل نگهداری بنویسید. استفاده گسترده از ID یا زنجیره طولانی می‌تواند اصلاح‌های همان لایه را سخت کند. Layer و نام‌گذاری Component دو موضوع مرتبط ولی مستقل‌اند. ابزار تازه، سبک نامنظم را خودکار تمیز نمی‌کند. برای هر قانون جدید، مسئولیت و محدوده را مشخص کنید و از افزودن Override بدون فهم منبع مقدار فعلی فاصله بگیرید.

دام مهم: !important ترتیب را معکوس می‌کند

برای اعلان‌های Important، ترتیب لایه‌ها معکوس می‌شود. اعلان Important در لایه زودتر، نسبت به لایه بعدتر تقدم دارد و اعلان Important لایه‌دار از Important بدون لایه مقدم‌تر است. مرجع !important در MDN این وارونگی را توضیح می‌دهد. بنابراین جمله «آخرین Layer همیشه برنده است» غلط است. باید اهمیت اعلان و مرحله‌های Cascade را مشخص کنید. نمونه این مقاله عمداً از !important استفاده نمی‌کند تا رفتار قوانین عادی روشن بماند.

از Important برای جبران معماری نامعلوم استفاده نکنید. اگر هر اصلاح با آن نوشته شود، ترتیب تازه هم به جنگ دیگری تبدیل می‌شود. بعضی کاربردها ممکن است دلیل معتبر داشته باشند، اما باید محدود و مستند باشند. همچنین سبک‌های کاربر و نیازهای دسترس‌پذیری جایگاه خود را دارند. هدف شما نباید قفل کردن همه ظاهرها به شکلی باشد که کاربر نتواند نیاز خود را اعمال کند. در تحلیل مقدار، منشأ و اهمیت را همراه Layer ببینید.

ورود سبک کتابخانه و فایل‌های جدا

اگر ابزار ساخت و مرورگر هدف پشتیبانی می‌کنند، می‌توان سبک واردشده را به Layer مشخص نسبت داد. این کار باید با قواعد جایگاه Import و نحوه خروجی ابزار سازگار باشد. کپی چند خط Import بدون بررسی ترتیب نهایی، می‌تواند نتیجه متفاوتی بدهد. خروجی CSS را در قرارداد Build ببینید و مطمئن شوید تبدیل‌ها ترتیب مورد نظر را حفظ می‌کنند. نام لایه باید در فایل اصلی یا قرارداد مشترک تعریف شده باشد تا ورود فایل‌ها غافلگیرکننده نباشد.

در پروژه‌ای با CSS Modules یا سبک تولیدشده توسط کتابخانه، محل تزریق نیز اهمیت دارد. Layer می‌تواند رابطه گروه‌ها را روشن کند، اما همه ابزارها قرارداد یکسان ندارند. نسخه و راهنمای ابزار منتخب را بررسی کنید. اگر سبک Inline از Component ثالث می‌آید، آن را با قانون عادی لایه‌دار هم‌رده ندانید. پیش از اضافه کردن استثنا، بفهمید مقدار از کجا آمده است. ابزار توسعه مرورگر برای دیدن منشأ و قانون برنده کمک می‌کند.

مهاجرت پروژه قدیمی

انتقال تدریجی را با یک بخش محدود آغاز کنید. فهرست منابع سبک، قواعد بدون Layer و استفاده‌های Important را بشناسید. اگر فقط فایل تازه را لایه‌دار کنید، سبک‌های قدیمی بدون Layer ممکن است همچنان برنده باشند. این نتیجه به معنی خراب بودن ابزار نیست؛ قرارداد Cascade را تغییر داده‌اید. برای هر مرحله، محدوده و انتظار را بنویسید. تغییر هم‌زمان تمام نام‌ها و معماری، پیدا کردن علت اختلاف را سخت می‌کند.

یک ترتیب مشترک تعریف کنید و گروه‌های مسئولیت را به‌تدریج منتقل کنید. استثناها را با دلیل ثبت کنید تا «موقت» به قانون دائمی نامعلوم تبدیل نشود. در Design Tokens، مقدارهای مشترک از کاربرد جدا می‌شوند؛ Layer ترتیب قواعد را تنظیم می‌کند. این دو مکمل‌اند، ولی یکی جای دیگری نیست. داشتن Token برای رنگ، تقدم دو قانون رنگ را تعیین نمی‌کند. داشتن Layer نیز نام و معنای Token را درست نمی‌کند.

اشکال‌زدایی با ترتیب درست سؤال‌ها

وقتی مقدار مورد انتظار اعمال نمی‌شود، ابتدا ببینید قانون اصلاً بارگذاری و معتبر شده یا نه. سپس منشأ، اهمیت، Layer و Selector را بررسی کنید. ممکن است مشکل از Media Query، ارث‌بری یا ویژگی دیگری باشد، نه از Specificity. افزایش فوری طول Selector، داده تشخیصی کمی می‌دهد و هزینه بعدی می‌سازد. در DevTools مقدار محاسبه‌شده و قواعد کنارگذاشته‌شده را ببینید تا تصمیم بر اساس رفتار واقعی باشد.

در مثال‌های CSS Grid نیز ساختار HTML و کلاس‌های واقعی لازم‌اند. برای توضیح Cascade، نمونه باید تمام Selectorها و عناصر مربوط را نشان دهد؛ کد جدا از زمینه ممکن است رفتار را ناقص توضیح دهد. اگر یک نمونه به فایل خارجی نیاز دارد، همان فایل و روش اجرا را بدهید. مثال این مقاله مستقل است تا تقدم Layer با نبودن وابستگی یا کلاس تعریف‌نشده اشتباه نشود.

قرارداد نگهداری

در مستند تیم، نام لایه‌ها، ترتیب، محل تعریف و قاعده استفاده از Important را کوتاه بنویسید. Component تازه باید بداند در کدام گروه قرار می‌گیرد. برای Override، ابتدا ابزار موجود و محدوده مسئولیت را بررسی کنید، نه اینکه همیشه لایه تازه بسازید. معیار موفقیت، کم شدن اصلاح‌های غافلگیرکننده و روشن بودن دلیل تقدم است. Cascade Layers زمانی ارزش دارد که نظم تصمیم‌ها را در خروجی واقعی CSS قابل فهم کند.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!