Cascade Layers؛ این بار عمیق‌تر

تو فصل ۲، وقتی درباره‌ی cascade و ترتیب پردازش CSS صحبت کردیم، به‌طور مختصر با @layer آشنا شدیم. اون‌موقع بیشتر می‌خواستیم مفهوم کلی‌اش رو بفهمیم. حالا که چندین فصل پیشرفته‌تر (از جمله selectors، specificity در عمل، و حتی nesting) رو پشت سر گذاشتیم، وقتشه یه بار دیگه با دید کامل‌تری سراغ لایه‌ها بریم و ببینیم واقعاً تو پروژه‌های بزرگ چه مشکلی رو حل می‌کنن.

یادآوری سریع: مشکل اصلی چی بود؟

مشکلی که @layer حلش می‌کنه اینه: تو یه پروژه‌ی واقعی، معمولاً چند منبع CSS مختلف با هم قاطی می‌شن؛ یه CSS ریست، یه فریم‌ورک مثل Bootstrap یا Tailwind، استایل‌های کامپوننت‌های خودتون، و شاید حتی یه سری override نهایی. وقتی specificity این منابع مختلف با هم تداخل پیدا می‌کنه، پیش‌بینی این‌که کدوم قانون واقعاً برنده می‌شه سخت و گاهی کاملاً غیرقابل‌پیش‌بینی می‌شه؛ چون همون‌طور که تو فصل ۲ دیدیم، cascade بدون لایه‌بندی، فقط بر اساس specificity و ترتیب نوشتن تصمیم می‌گیره، نه بر اساس این‌که این قانون از کدوم «منبع» اومده.

یادآوری سینتکس پایه

@layer reset, base, components, utilities;

@layer reset {
  * {
    margin: 0;
    padding: 0;
  }
}

@layer components {
  .btn {
    padding: 10px 20px;
    background: blue;
  }
}

@layer utilities {
  .text-center {
    text-align: center;
  }
}

خط اول (@layer reset, base, components, utilities;) ترتیب اولویت لایه‌ها رو از قبل تعریف می‌کنه، حتی قبل از این‌که خود لایه‌ها رو پر کنیم. هرچی لایه دیرتر تو این لیست بیاد، اولویتش بالاتره.

نکته‌ی کلیدی که تو فصل ۲ کمتر بهش پرداختیم: لایه‌ها specificity رو خنثی می‌کنن

این مهم‌ترین نکته‌ای هست که باید عمیق‌تر درکش کنید: وقتی یه قانون داخل یه @layer باشه، ترتیب لایه‌ها همیشه به specificity اون قانون اولویت داره. یعنی حتی یه id selector با specificity خیلی بالا، اگه تو یه لایه‌ی زودتر (کم‌اولویت‌تر) باشه، توسط یه class selector ساده تو یه لایه‌ی دیرتر (پراولویت‌تر) شکست می‌خوره:

@layer low, high;

@layer low {
  #header {
    color: red; /* specificity خیلی بالا */
  }
}

@layer high {
  .title {
    color: blue; /* specificity خیلی پایین‌تر */
  }
}

تو این مثال، با این‌که #header specificity بسیار بالاتری از .title داره، چون لایه‌ی high بعد از low تعریف شده، رنگ آبی برنده می‌شه (به شرطی که هر دو selector روی یه المنت match بشن). این دقیقاً برعکس رفتار عادی cascade هست که تو فصل ۲ یاد گرفتیم، و همین چیزیه که لایه‌ها رو قدرتمند می‌کنه.

استایل‌های بدون لایه: همیشه برنده‌ی نهایی

یه نکته‌ی مهم دیگه: هر قانون CSS که داخل هیچ @layerی نباشه، به‌طور خودکار بالاتر از تمام لایه‌ها قرار می‌گیره، صرف‌نظر از این‌که کجای فایل نوشته شده باشه:

@layer utilities {
  .text-center {
    text-align: center !important;
  }
}

/* این، بدون لایه است و برنده می‌شه، حتی بدون !important */
.text-center {
  text-align: right;
}

این رفتار عمداً این‌جوری طراحی شده تا استایل‌های «صریح و بدون لایه» همیشه بتونن هر چیزی رو که تو لایه‌ها تعریف شده override کنن؛ خیلی شبیه یه دریچه‌ی اضطراری برای وقتایی که واقعاً باید یه چیزی رو مطمئن باشید که اعمال می‌شه.

ادغام چند بار یه لایه

می‌تونید یه لایه رو چند بار، حتی تو فایل‌های مختلف، باز کنید و محتوا بهش اضافه کنید؛ مرورگر همه‌شون رو به همون لایه ادغام می‌کنه:

@layer components {
  .btn { padding: 10px; }
}

/* بعداً، شاید تو یه فایل دیگه */
@layer components {
  .card { border-radius: 8px; }
}

این برای پروژه‌های بزرگ که CSS از چند فایل و شاید چند تیم مختلف میاد خیلی کاربردیه.

import کردن یه فایل مستقیم داخل یه لایه

یه کاربرد رایج دیگه، وارد کردن CSS یه کتابخونه‌ی خارجی (مثل نرمالایزر یا فریم‌ورک) مستقیم داخل یه لایه‌ی مشخصه، تا مطمئن بشید specificity اون کتابخونه هیچ‌وقت باعث دردسر نمی‌شه:

@import url("normalize.css") layer(reset);
@import url("bootstrap.css") layer(vendor);
نکته سئو و پرفورمنس: استفاده از cascade layers هیچ تأثیر مستقیمی روی سئو نداره، ولی چون به شما اجازه می‌ده استایل‌ها رو منظم‌تر و بدون نیاز به specificity hack (مثل زنجیره کردن چند کلاس یا !important) بنویسید، حجم نهایی CSS معمولاً کمتر و قابل نگهداری‌تر می‌شه، که غیرمستقیم روی سرعت لود صفحه اثر مثبت داره.

اشتباه رایج: قاطی کردن ترتیب تعریف با ترتیب اولویت

خیلی‌ها فکر می‌کنن اگه لایه‌ای رو دیرتر تو فایل بنویسن، خودکار اولویتش بالاتر می‌ره؛ در حالی که اگه از قبل با @layer reset, base, components; ترتیب رو مشخص کرده باشید، همون ترتیب اولیه حکم‌فرماست، مهم نیست بعداً کدوم لایه رو زودتر یا دیرتر تو فایل پر کنید. ترتیب تعریف اولیه، همیشه برنده‌ست.

جمع‌بندی

Cascade Layers یه سطح اولویت‌بندی کاملاً جدا از specificity به CSS اضافه می‌کنه؛ لایه‌ای که دیرتر تعریف بشه (تو لیست اولیه‌ی @layer)، همیشه بر لایه‌ی زودتر غلبه می‌کنه، صرف‌نظر از این‌که selector هاش چقدر قوی باشن. استایل‌های بدون لایه هم همیشه از همه‌ی لایه‌ها بالاترن. این ابزار مخصوصاً تو پروژه‌های بزرگ که چند منبع CSS (ریست، فریم‌ورک، کامپوننت‌ها، یوتیلیتی‌ها) با هم ترکیب می‌شن، نظم و قابل‌پیش‌بینی بودن رو به cascade برمی‌گردونه.