تاروپود — خودآموز HTML و CSS

فصل ۲ از ۱۱

پیشرفت ترم
۰٪

ترم ۶ · حرفه‌ای و واقعی

`@layer` و nesting

فصل ۲پیش‌نمایش رایگان
۸ دقیقه مطالعه فصل ۲

در این فصل چه می‌سازی#

فصلِ قبل CSS ات را با دست مرتب کردی. ولی یک مشکل با نظمِ دستی حل نمی‌شود: جنگِ specificity. گاهی یک قاعده لجوجانه برنده می‌شود، هرچقدر هم پایین‌ترش قاعدهٔ دیگری بنویسی، چون specificity اش بیشتر است. این فصل دو ابزار یاد می‌گیری: @layer که به تو اجازه می‌دهد ترتیبِ برنده‌شدن را خودت تعیین کنی — حتی بالاتر از specificity — و nesting که قاعده‌های مربوط به هم را تودرتو کنارِ هم نگه می‌دارد. آخرش یک کارت داری که یک پیوندِ «کم‌رنگ» تویش، بالاخره واقعاً کم‌رنگ می‌شود.

دو لایهٔ روی‌هم‌چیده‌شدهٔ قاعده‌های CSS: یک لایهٔ پایین و یک لایهٔ بالا؛ یک فلش نشان می‌دهد قاعدهٔ لایهٔ بالا برنده است، بی‌آنکه به بزرگیِ نشانه‌های specificity اهمیت بدهد

آخر این فصل می‌توانی:

  • چند @layer نام‌گذاری کنی و ترتیبِ برنده‌شدنشان را تعیین کنی
  • بفهمی چرا یک قاعده در لایهٔ بالاتر، حتی با specificity کمتر، برنده می‌شود
  • با nesting بومیِ CSS قاعده‌های یک component را تودرتو بنویسی
  • بگویی چرا nesting را برای استایلِ پایه و حیاتی به‌کار نمی‌بری

قبل از شروع#

  • از ترم ۲: specificity و اینکه چطور شمرده می‌شود — کلِ این فصل جواب به همان است.
  • از ترم ۲: selector نوع و descendant (فاصله).
  • از فصل ۱ همین ترم: ترتیبِ منطقیِ قاعده‌ها و اسم‌گذاریِ block/element.

مثل همیشه فقط یک مرورگر لازم داری، یا فقط همین آزمایشگاه.

۱. یک جنگِ لجوجانه#

فرض کن پیوندهای درونِ کارت را نارنجی کرده‌ای، و یک class به اسمِ .muted هم داری که هر چیزی را خاکستریِ کم‌رنگ کند. حالا به پیوندِ «بعداً می‌خوانم» این class را می‌دهی. CSS ات (بدونِ layer) این است:

.card a {
  color: #bc3e1c;
}

.muted {
  color: #8a7f6a;
}

به کارت نگاه کن: پیوندِ «بعداً می‌خوانم» هنوز نارنجی است، نه خاکستری. class="muted" انگار هیچ کاری نکرد.

🔧 اگر کار نکرد: این باگ نیست، خودِ cascade است. specificity را بشمار: .card a یعنی یک class به‌علاوهٔ یک نوع، پس وزنش (۰,۱,۱) است؛ .muted فقط یک class است، وزنش (۰,۱,۰). پس .card a سنگین‌تر است و برنده می‌شود. می‌توانی .muted را پایین‌تر ببری یا سنگین‌ترش کنی، ولی این همان مسیرِ لغزنده‌ای است که به !important و کدِ غیرقابل‌نگه‌داری می‌رسد. راهِ حرفه‌ای این است که ترتیبِ برنده‌شدن را از دستِ specificity دربیاوری — و @layer دقیقاً همین کار را می‌کند.

۲. @layer: ترتیب را خودت تعیین کن#

@layer قاعده‌ها را در چند لایهٔ نام‌دار دسته می‌کند، و ترتیبِ لایه‌ها را تو تعیین می‌کنی. قانونِ کلیدی این است: وقتی دو قاعده در دو لایهٔ متفاوت‌اند، لایهٔ بعدی برنده است — بی‌اهمیت به specificity. یعنی layer ترتیب را از specificity قوی‌تر می‌گیرد.

اول یک خط، ترتیبِ لایه‌ها را اعلام کن؛ بعد قاعده‌ها را داخلِ لایهٔ خودشان بگذار:

@layer base, components, utilities;

@layer components {
  .card a {
    color: #bc3e1c;
  }
}

@layer utilities {
  .muted {
    color: #8a7f6a;
  }
}

آن خطِ اول می‌گوید ترتیب این است: base، بعد components، بعد utilities. حالا .muted در utilities است که بعد از components می‌آید، پس برنده می‌شود — با اینکه specificity اش کمتر است.

چک کن: حالا «بعداً می‌خوانم» خاکستریِ کم‌رنگ شد و «ادامهٔ مطلب» نارنجی ماند. تو قاعدهٔ لجوجِ component را نگه داشتی، فقط .muted را بردی به یک لایهٔ بالاتر تا وقتی لازم شد، تمیز رویش را بگیرد.

Checkpoint. قبل از ادامه، جواب بده: اگر در خطِ اول ترتیب را برعکس کنی و بنویسی @layer utilities, components; چه می‌شود؟ (جواب: حالا components بعد از utilities است، پس .card a دوباره برنده می‌شود و پیوند نارنجی می‌ماند. ترتیبِ آن خطِ اعلان همه‌چیز را تعیین می‌کند، نه ترتیبِ نوشتنِ خودِ قاعده‌ها.)

💡 نکته: یک ترتیبِ رایج همین است: reset، base، layout، components، utilities. utility ها را آخر می‌گذاری چون قرار است کارِ کوچکِ خودشان را همیشه انجام دهند؛ reset را اول چون باید پایین‌ترین اولویت را داشته باشد. این همان دسته‌بندیِ فصلِ قبل است، ولی این‌بار مرورگر ترتیبش را تضمین می‌کند.

۳. nesting: قاعده‌های مربوط را تودرتو بنویس#

الان قاعده‌های کارت پخش‌اند: .card، .card__title، .card a هرکدام جدا. با nesting بومیِ CSS می‌توانی قاعده‌های مربوط به یک چیز را تویش تودرتو کنی. داخلِ .card یک & می‌گذاری که یعنی «خودِ .card»:

.card {
  background-color: #ffffff;
  border-radius: 12px;
  padding: 16px;

  & .card__title {
    margin-block-end: 8px;
  }

  & a {
    color: #bc3e1c;
  }
}

& .card__title دقیقاً یعنی .card .card__title، و & a یعنی .card a — همان چیزی که قبلاً جدا می‌نوشتی، فقط حالا کنارِ هم و تودرتو. مزیتش خوانایی است: همه‌چیزِ مربوط به کارت در یک block جمع است.

۴. یک هشدارِ صادقانه دربارهٔ nesting#

nesting بومی در ۲۰۲۶ تقریباً همه‌جا کار می‌کند و می‌توانی با خیال راحت استفاده‌اش کنی. ولی یک نکتهٔ مهم هست که باید بدانی: یک مرورگرِ خیلی قدیمی که nesting را نمی‌شناسد، کلِ قاعدهٔ تودرتو را دور می‌ریزد — نه فقط بخشِ داخلی را، بلکه کلِ آن block را. این با خیلی از ویژگی‌های دیگر فرق دارد که وقتی ناشناخته‌اند فقط بی‌سروصدا نادیده می‌شوند.

نتیجهٔ عملی‌اش یک عادتِ ساده است: استایلِ پایه و حیاتی — مثل reset، رنگِ body، اندازهٔ فونت — را تودرتو ننویس؛ صاف و مستقیم بنویس تا همه‌جا کار کند. nesting را برای گروه‌کردنِ استایلِ component ها به‌کار ببر، جایی که اگر یک مرورگرِ عتیقه آن را کمی ساده‌تر نشان دهد، صفحه هنوز خوانا و سالم است. این همان فکرِ progressive enhancement است: پایه برای همه کار کند، تزئینِ اضافه برای مرورگرهای امروزی.

کد کاملِ این فصل#

/* styles.css */
@layer base, components, utilities;

@layer base {
  * {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }

  body {
    font-family: Tahoma, sans-serif;
    background-color: #f6edda;
    color: #2c2114;
    line-height: 1.7;
    padding: 24px;
  }

  a {
    color: #2a6b93;
  }
}

@layer components {
  .card {
    background-color: #ffffff;
    border: 1px solid #d8ccae;
    border-radius: 12px;
    padding: 16px;
    max-width: 360px;

    /* nesting: ghava'ed-e daroon-e card inja lah mishavand */
    & .card__title {
      margin-block-end: 8px;
    }

    & a {
      color: #bc3e1c;
    }
  }
}

@layer utilities {
  .muted {
    color: #8a7f6a;
  }
}

و index.html:

<!-- index.html -->
<!DOCTYPE html>
<html lang="fa" dir="rtl">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>کارت با لایه‌ها</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <main class="page">
      <article class="card">
        <h2 class="card__title">مقالهٔ امروز</h2>
        <p>یک یادداشتِ کوتاه دربارهٔ CSS، با دو پیوند.</p>
        <p><a href="#">ادامهٔ مطلب</a></p>
        <p><a href="#" class="muted">بعداً می‌خوانم</a></p>
      </article>
    </main>
  </body>
</html>

توجه کن که بخشِ base — reset و body — تودرتو نشده و صاف نوشته شده؛ دقیقاً همان عادتی که بخشِ قبل گفت. فقط .card که یک component است تودرتو شده.

یک بلوکِ کد که قاعده‌های یک کارت به‌صورت تودرتو داخلِ یک قاعدهٔ بیرونی جمع شده‌اند، در برابرِ همان قاعده‌ها به‌صورتِ چند بلوکِ جدا و پخش

🤖 با AI: یک قاعدهٔ تودرتو به دستیار AI ات بده و بپرس «این nesting دقیقاً به کدام selector های تخت ترجمه می‌شود؟». جوابش را همان‌جا در آزمایشگاه امتحان کن و با چشمت چک کن که واقعاً همان عنصرها را می‌گیرد — AI گاهی معنیِ & را در حالت‌های پیچیده اشتباه می‌گوید، پس دیدن مهم‌تر از باور کردن است.

واژه‌های تازهٔ این فصل#

کلمه تلفظ به حروف فارسی یعنی چه
@layer اَت-لِیِر قاعده‌ها را در لایه‌های نام‌دار دسته می‌کند؛ ترتیبِ لایه، برنده را تعیین می‌کند
layer order لِیِر اُردِر ترتیبِ لایه‌ها؛ لایهٔ بعدی برنده است، بالاتر از specificity
nesting نِستینگ نوشتنِ قاعده‌ها تودرتو داخلِ یک قاعدهٔ دیگر
& اَمپِرسَند داخلِ nesting یعنی «همین selector بیرونی»
progressive enhancement پروگرِسیو اِنهنسمِنت پایه برای همه کار کند، تزئینِ اضافه برای مرورگرهای امروزی

تمرین‌ها

اول خودت فکر کن یا امتحان کن — بعد اینجا را باز کن.

در فصل بعد#

الان می‌توانی cascade را در مقیاسِ بزرگ کنترل کنی و کدت را تودرتو و تمیز نگه‌داری. فصل بعد یک قدم بالاتر می‌رویم و مثلِ یک حرفه‌ای به کارت و دکمه نه به‌عنوان «چند قاعدهٔ CSS»، بلکه به‌عنوان component — یک تکهٔ مستقلِ قابل‌تکرار — فکر می‌کنیم؛ تکه‌ای که هرجای صفحه بگذاری‌اش، بی‌آنکه به همسایه‌اش وابسته باشد، درست کار کند.

به آخر این فصل رسیدی!

اگر ساختی و جواب داد، این دکمه مال توست.