CSS Nesting

یکی از ویژگی‌های پیش‌پردازنده CSS مورد علاقه ما اکنون در این زبان تعبیه شده است: قوانین استایل تودرتو.

قبل از تودرتوسازی، لازم بود هر انتخابگر به طور صریح و جداگانه از یکدیگر تعریف شود. این امر منجر به تکرار، حجم زیاد stylesheet و تجربه‌ی پراکنده‌ی نوشتن می‌شود.

قبل از
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

پس از تودرتوسازی ، می‌توان انتخابگرها را ادامه داد و قوانین سبک مرتبط با آن را در داخل گروه‌بندی کرد.

بعد از
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

این را در مرورگر امتحان کنید .

تودرتوسازی با کاهش نیاز به تکرار انتخابگرها و در عین حال، قرار دادن قوانین سبک برای عناصر مرتبط، به توسعه‌دهندگان کمک می‌کند. همچنین می‌تواند به سبک‌ها کمک کند تا با HTML مورد نظر خود مطابقت داشته باشند. اگر کامپوننت .nesting در مثال قبلی از پروژه حذف می‌شد، می‌توانستید به جای جستجوی فایل‌ها برای نمونه‌های انتخابگر مرتبط، کل گروه را حذف کنید.

تودرتوسازی می‌تواند به موارد زیر کمک کند: - سازماندهی - کاهش حجم فایل - بازسازی (Refactoring)

قابلیت تودرتو از کروم ۱۱۲ در دسترس است و همچنین در پیش‌نمایش فنی سافاری ۱۶۲ نیز قابل امتحان کردن است.

شروع کار با CSS Nesting

در ادامه‌ی این پست، از محیط آزمایشی زیر برای کمک به شما در تجسم انتخاب‌ها استفاده می‌شود. در این حالت پیش‌فرض، هیچ چیزی انتخاب نشده و همه چیز قابل مشاهده است. با انتخاب شکل‌ها و اندازه‌های مختلف، می‌توانید سینتکس را تمرین کرده و آن را در عمل مشاهده کنید.

شبکه‌ای رنگارنگ از دایره‌های کوچک و بزرگ، مثلث‌ها و مربع‌ها.

درون جعبه‌ی شنی دایره، مثلث و مربع وجود دارد. برخی کوچک، متوسط ​​یا بزرگ هستند. برخی دیگر آبی، صورتی یا بنفش هستند. همه آنها درون عنصر حاوی .demo قرار دارند. در زیر پیش‌نمایشی از عناصر HTML مورد نظر شما آمده است.

<div class="demo">
  <div class="sm triangle pink"></div>
  <div class="sm triangle blue"></div>
  <div class="square blue"></div>
  <div class="sm square pink"></div>
  <div class="sm square blue"></div>
  <div class="circle pink"></div>
  …
</div>

مثال‌های تودرتو

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

.parent {
  color: blue;

  .child {
    color: red;
  }
}

در این مثال، انتخابگر کلاس .child درون انتخابگر کلاس .parent به صورت تو در تو قرار گرفته است. این بدان معناست که انتخابگر .child تو در تو فقط روی عناصری اعمال می‌شود که فرزند عناصری با کلاس .parent هستند.

این مثال می‌تواند به طور جایگزین با استفاده از نماد & نوشته شود تا به صراحت مشخص کند که کلاس والد باید کجا قرار گیرد.

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

این دو مثال از نظر عملکردی معادل هستند و دلیل اینکه شما گزینه‌های بیشتری دارید با بررسی مثال‌های پیشرفته‌تر در این مقاله، روشن‌تر خواهد شد.

انتخاب دایره‌ها

برای این مثال اول، وظیفه این است که استایل‌هایی برای محو شدن و محو کردن فقط دایره‌های داخل دمو اضافه کنیم.

بدون تودرتو ، CSS امروز:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

با تودرتو کردن ، دو روش معتبر وجود دارد:

/* & is explicitly placed in front of .circle */
.demo {
  & .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

یا

/* & + " " space is added for you */
.demo {
  .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

در نتیجه ، تمام عناصر داخل .demo که دارای کلاس .circle هستند، محو و تقریباً نامرئی می‌شوند:

شبکه رنگارنگ اشکال دیگر دایره ندارد، آنها در پس‌زمینه بسیار کم‌رنگ هستند.
یک نسخه آزمایشی را امتحان کنید

انتخاب هر مثلث و مربعی

این کار نیاز به انتخاب چندین عنصر تو در تو دارد که به آن انتخابگر گروهی نیز گفته می‌شود.

بدون تودرتوسازی ، امروزه در CSS، دو راه وجود دارد:

.demo .triangle,
.demo .square {
  opacity: .25;
  filter: blur(25px);
}

یا، با استفاده از :is()

/* grouped with :is() */
.demo :is(.triangle, .square) {
  opacity: .25;
  filter: blur(25px);
}

با تودرتو کردن ، دو روش معتبر وجود دارد:

.demo {
  & .triangle,
  & .square {
    opacity: .25;
    filter: blur(25px);
  }
}

یا

.demo {
  .triangle, .square {
    opacity: .25;
    filter: blur(25px);
  }
}

در نتیجه ، فقط عناصر .circle درون .demo باقی می‌مانند:

از شبکه رنگارنگ اشکال، فقط دایره باقی می‌ماند، و سایر اشکال تقریباً نامرئی هستند.
یک نسخه آزمایشی را امتحان کنید

انتخاب مثلث‌ها و دایره‌های بزرگ

این کار به یک انتخابگر مرکب نیاز دارد، که در آن عناصر برای انتخاب شدن باید هر دو کلاس را داشته باشند.

بدون تودرتو ، CSS امروز:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

یا

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

با تودرتو کردن ، دو روش معتبر وجود دارد:

.demo {
  .lg.triangle,
  .lg.circle {
    opacity: .25;
    filter: blur(25px);
  }
}

یا

.demo {
  .lg {
    &.triangle,
    &.circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

در نتیجه ، تمام مثلث‌ها و دایره‌های بزرگ درون .demo پنهان شده‌اند:

شبکه رنگارنگ فقط شکل‌های کوچک و متوسط ​​​​را نشان می‌دهد.
یک نسخه آزمایشی را امتحان کنید
نکته حرفه‌ای با انتخابگرهای مرکب و تودرتو

علامت & در اینجا به شما کمک می‌کند، زیرا به صراحت نحوه‌ی اتصال انتخابگرهای تو در تو را نشان می‌دهد. مثال زیر را در نظر بگیرید:

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

اگرچه روشی معتبر برای تودرتو کردن است، اما نتایج با عناصری که انتظار دارید مطابقت نخواهند داشت. دلیل این امر این است که بدون & برای مشخص کردن نتیجه مطلوب از ترکیب .lg.triangle, .lg.circle ، نتیجه واقعی .lg .triangle, .lg .circle ; خواهد بود.

انتخاب همه شکل‌ها به جز شکل‌های صورتی

این کار به یک شبه کلاس تابعی نفی نیاز دارد، که در آن عناصر نباید انتخابگر مشخص شده را داشته باشند.

بدون تودرتو ، CSS امروز:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

با تودرتو کردن ، دو روش معتبر وجود دارد:

.demo {
  :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

یا

.demo {
  & :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

در نتیجه ، تمام شکل‌هایی که صورتی نیستند، درون .demo پنهان شده‌اند:

شبکه رنگارنگ اکنون تک رنگ است و فقط اشکال صورتی را نشان می‌دهد.
یک نسخه آزمایشی را امتحان کنید
دقت و انعطاف‌پذیری با &

فرض کنید می‌خواهید .demo را با انتخابگر :not() ‎ هدف قرار دهید. & برای این کار ضروری است :

.demo {
  &:not() {
    ...
  }
}

این ترکیب .demo و :not() را به .demo:not() تبدیل می‌کند، برخلاف مثال قبلی که به .demo :not() نیاز داشت. این یادآوری هنگام تو در تو کردن یک تعامل :hover بسیار مهم می‌شود.

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

مثال‌های بیشتر تودرتوسازی

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

چند مثال بعدی به طور خلاصه یک ویژگی تودرتو در CSS را معرفی می‌کنند تا به شما در درک وسعت قابلیت‌های آن کمک کنند.

تودرتو @media

رفتن به بخش دیگری از استایل‌شیت برای پیدا کردن شرط‌های مدیا کوئری که یک سلکتور و استایل‌های آن را تغییر می‌دهند، می‌تواند بسیار حواس‌پرت‌کننده باشد. این حواس‌پرتی با قابلیت تودرتو کردن شرط‌ها درست درون متن از بین رفته است.

برای راحتی سینتکس، اگر کوئری رسانه‌ای تودرتو فقط استایل‌ها را برای زمینه انتخابگر فعلی تغییر می‌دهد، می‌توان از یک سینتکس مینیمال استفاده کرد.

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

استفاده از & به طور صریح نیز می‌تواند مورد استفاده قرار گیرد:

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    &.large {
      font-size: 1.25rem;
    }
  }
}

این مثال، سینتکس گسترش‌یافته با & را نشان می‌دهد، در حالی که کارت‌های .large را نیز هدف قرار می‌دهد تا نشان دهد ویژگی‌های تودرتوی اضافی همچنان به کار خود ادامه می‌دهند.

درباره تودرتو کردن @rules بیشتر بدانید.

لانه سازی در هر جایی

تمام مثال‌ها تا این مرحله ادامه یا به یک context قبلی اضافه شده‌اند. در صورت نیاز می‌توانید context را به طور کامل تغییر دهید یا دوباره مرتب کنید.

.card {
  .featured & {
    /* .featured .card */
  }
}

علامت & نشان‌دهنده‌ی ارجاع به یک شیء انتخابگر (نه یک رشته) است و می‌تواند در هر جایی از یک انتخابگر تودرتو قرار گیرد. حتی می‌تواند چندین بار قرار گیرد:

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

اگرچه این مثال کمی بی‌فایده به نظر می‌رسد، اما مطمئناً سناریوهایی وجود دارد که امکان تکرار یک زمینه انتخابگر مفید است.

نمونه‌های تودرتوی نامعتبر

چند سناریوی سینتکس تودرتو وجود دارد که نامعتبر هستند و اگر در پیش‌پردازنده‌ها تودرتو عمل کرده باشید، ممکن است شما را متعجب کنند.

تودرتوسازی و الحاق

بسیاری از قراردادهای نامگذاری کلاس‌های CSS بر این باورند که می‌توان با استفاده از روش تودرتو، انتخابگرها را مانند رشته‌ها به هم متصل یا اضافه کرد. این روش در روش تودرتوی CSS کار نمی‌کند، زیرا انتخابگرها رشته نیستند، بلکه ارجاع به شیء هستند.

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

توضیح عمیق‌تر را می‌توانید در مشخصات فنی بیابید.

مثال لانه سازی پیچیده

تو در تو کردن درون لیست‌های انتخابگر و :is()

بلوک CSS تودرتوی زیر را در نظر بگیرید:

.one, #two {
  .three {
    /* some styles */
  }
}

این اولین مثالی است که با یک لیست انتخابگر شروع می‌شود و سپس به صورت تودرتو ادامه می‌یابد. مثال‌های قبلی فقط با یک لیست انتخابگر به پایان رسیده بودند. در این مثال تودرتو هیچ چیز نامعتبری وجود ندارد، اما یک جزئیات پیاده‌سازی بالقوه پیچیده در مورد تودرتو کردن درون لیست‌های انتخابگر، به ویژه آنهایی که شامل یک انتخابگر شناسه هستند، وجود دارد.

برای اینکه هدف تودرتوسازی عملی شود، هر لیست انتخابگر که داخلی‌ترین تودرتو نباشد، توسط مرورگر با :is() پوشانده می‌شود. این بسته‌بندی، گروه‌بندی لیست انتخابگر را در هر زمینه‌ی نوشته‌شده حفظ می‌کند. اثر جانبی این گروه‌بندی، :is(.one, #two) ، این است که ویژگی بالاترین امتیاز را در انتخابگرهای داخل پرانتز اتخاذ می‌کند. : :is() همیشه اینگونه کار می‌کند ، اما ممکن است هنگام استفاده از سینتکس تودرتو تعجب‌آور باشد زیرا دقیقاً همان چیزی نیست که نوشته شده است. خلاصه ترفند این است که تودرتوسازی با شناسه‌ها و لیست‌های انتخابگر می‌تواند منجر به انتخابگرهایی با ویژگی بسیار بالا شود.

برای خلاصه کردن مثال پیچیده، بلوک تودرتوی قبلی به این صورت روی سند اعمال خواهد شد:

:is(.one, #two) .three {
  /* some styles */
}

مراقب باشید یا به لینترهای خود آموزش دهید که هنگام تودرتو کردن درون یک لیست انتخابگر که از یک انتخابگر ID استفاده می‌کند، هشدار دهند، زیرا سطح اختصاصی بودن تمام تودرتوهای درون آن لیست انتخابگر بالا خواهد بود.

ترکیب تودرتو و اعلان‌ها

بلوک CSS تودرتوی زیر را در نظر بگیرید:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

رنگ عناصر .card blue خواهد بود.

هرگونه اعلان سبک ترکیبی به بالا منتقل می‌شود، گویی قبل از هرگونه تودرتوسازی نوشته شده است. جزئیات بیشتر را می‌توانید در spec بیابید.

راه‌های دیگری هم برای دور زدن این مشکل وجود دارد. کد زیر سه سبک رنگ را در & قرار می‌دهد که ترتیب آبشاری را همانطور که نویسنده احتمالاً در نظر داشته است، حفظ می‌کند. رنگ عناصر .card قرمز خواهد بود.

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

در واقع، تمرین خوبی است که هر استایلی که پس از تودرتو قرار می‌گیرد را با یک & محصور کنید.

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

تشخیص ویژگی

دو روش عالی برای تشخیص تودرتو بودن CSS وجود دارد: استفاده از تودرتو یا استفاده از @supports برای بررسی قابلیت تجزیه انتخابگر تودرتو.

تصویری از دموی Codepen از Bramus که می‌پرسد آیا مرورگر شما از CSS Nesting پشتیبانی می‌کند یا خیر. زیر این سوال یک کادر سبز رنگ وجود دارد که نشان‌دهنده‌ی پشتیبانی است.

استفاده از تودرتوسازی:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

استفاده از @supports :

@supports (selector(&)) {
  /* nesting parsing available */
}

همکارم براموس یک Codepen عالی دارد که این استراتژی را نشان می‌دهد.

اشکال‌زدایی با ابزارهای توسعه کروم

پشتیبانی فعلی DevTools از تودرتوسازی حداقل است. در حال حاضر، همانطور که انتظار می‌رود، استایل‌ها در پنل استایل‌ها نمایش داده می‌شوند، اما ردیابی تودرتوسازی و زمینه انتخابگر کامل آن هنوز پشتیبانی نمی‌شود. ما طراحی و برنامه‌هایی داریم تا این موضوع را شفاف و واضح کنیم.

تصویری از سینتکس تودرتوی Chrome DevTools.

کروم ۱۱۳ قصد دارد پشتیبانی بیشتری از CSS تودرتو ارائه دهد. منتظر باشید.

آینده

CSS Nesting فقط در نسخه ۱ است. نسخه ۲ قواعد نحوی بیشتری را معرفی می‌کند و احتمالاً قوانین کمتری برای حفظ کردن دارد. تقاضای زیادی برای تجزیه و تحلیل Nesting وجود دارد که محدود نباشد یا لحظات دشواری نداشته باشد.

تودرتوسازی یک پیشرفت بزرگ برای زبان CSS است. این امر پیامدهای نویسندگی را تقریباً در هر جنبه معماری CSS دارد. این تأثیر بزرگ باید قبل از مشخص شدن مؤثر نسخه ۲، عمیقاً بررسی و درک شود.

به عنوان نکته آخر، در اینجا یک دمو وجود دارد که @scope ، nesting و @layer به طور همزمان استفاده می‌کند. همه اینها بسیار هیجان‌انگیز است!

یک کارت روشن روی زمینه خاکستری. این کارت دارای عنوان و متن، چند دکمه عملیاتی و یک تصویر به سبک سایبر پانک است.