چه زمانی از ویژگی Nesting یا تودرتو نویسی در CSS استفاده کنیم؟
با اخبار اخیر مبنی بر اینکه CSS nesting اکنون در همه مرورگرهای اصلی در دسترس است، تیم ما در حال بحث در مورد تفاوت آن با تودرتو نویسی (nesting) در Sass بود که این سوال مطرح شد: چه زمانی باید از تودرتو نویسی استفاده کنید؟
برای این سوال یک پاسخ ساده و یک پاسخ کمی پیچیدهتر وجود دارد، پاسخ ساده «پرهیز از تودرتو نویسی» است. پاسخ عملیتر و همچنین پیچیدهتر این است: از تودرتو نویسی برای شبه انتخابگرها (pseudo-selectors)، پیرایندههای والد (parent modifiers)، مدیا کوئریها (media queries) و انتخابگرهایی که بدون تودرتو نویسی کار نمیکنند استفاده کنید.
بیایید کمی در مورد آن بحث کنیم، اما قبل از هر چیزی باید بگویم این موارد برای تیم ما کار میکند، یک استاندارد حکاکی شده در سنگ نیست و شما میتوانید این توصیه را در صورتی برای شما کار نمیکند نادیده بگیرید.
فهرست محتوا
از تودرتو نویسی استفاده نکنید
ما از قراردادهای نامگذاری ماژولار مانند BEM و SUIT در CSS استفاده میکنیم. یکی از ویژگیهای مشترک همه این قواعد نامگذاری توصیه به کاهش specificity یا متمایز کردن انتخابگرها تا جای ممکن است، این موضوع منجر به قواعد عملی مانند “اجتناب از انتخابگرهای ID به نفع انتخابگرهای class” و “اجتناب از انتخابگرهای آبشاری (cascading selectors)” میشود.
یک مثال عملی در این خصوص: فرض کنید یک کلاس .button
و یک پیرایند (modifier) مانند .button.is-large
برای تغییر اندازه کلاس .button
دارید، این کلاسها به درستی کار میکنند تا اینکه فردی قاعده (rule) یا کد جدیدی اضافه میکند تا دکمهای که در بخش sidebar قرار گرفته x-large شود و از انتخابگر .sidebar .button
استفاده کند. حالا اگر شما بخواهید از کلاس .is-large
برای تغییر اندازه دکمه sidebar استفاده کنید به مشکل میخورید چون قاعده مربوط به sidebar بعد از کلاس .is-large
قرار دارد و هر دو قاعده از specificity یکسانی برخوردار هستند.
.button {}
.button.is-large {}
.sidebar .button {}
اینجاست که مجبور میشوید از !important
برای پیراینده استفاده کنید یا به ترفندیهایی مانند .button.button.is-large
روی بیاورید. هنگام استفاده از BEM این مشکل را با تعریف دو پیراینده .button--large
و .button--x-large
حل میکنیم؛ اکنون همه انتخابگرها دارای specificity یکسانی هستند و حل مشکلات آسانتر است. در نتیجه قانون کلی ما برای تودرتو کردن انتخابگرهای CSS این است که اگر یک انتخابگر بدون تودرتو نویسی یا nest شدن کار میکند آن را تودرتو نکنید.
چه مواردی باید Nest شوند یا تودرتو باشند؟
تعدادی از انتخابگرها بایستی تودرتو باشند تا به خوبی کار کنند. شبه کلاسها (pseudo-classes)، شبه عنصرها (pseudo-elements) و برخی از کلاسهای پیراینده (مثل is-active.). همچنین ما ترجیح میدهیم مدیا کوئری ها را نیز تودرتو بنویسیم تا خوانایی کدهای CSS را بهبود دهیم. در نهایت گاهی اوقات از تودرتو نویسی برای استایلها یا کدهای مرتبط با پیرایندههای والد استفاده میکنیم و ترجیح میدهیم آنها را در انتخابگرهای فرزند nest کنیم تا به راحتی پیدا شوند.
شبه کلاسها (Pseudo-Classes) و انتخابگرهای ویژگی (Attribute Selectors)
تودرتو نویسی شبه کلاسها و انتخابگرهای ویژگی باعث خوانایی کدهای CSS میشود و specificity انتخابگر را تغییر نمیدهد بنابراین گزینه مناسبی است.
/* بدون تودرتو نویسی */
a {
color: red;
}
a:hover,
a:focus {
color: blue;
}
a[aria-current="page"] {
color: green;
}
/* با تودرتو نویسی */
a {
color: red;
&:hover,
&:focus {
color: blue;
}
&[aria-current="page"] {
color: green;
}
}
شبه عنصرها (Pseudo-Elements)
این مورد نیز مانند شبه کلاسها موجب خوانایی کد میشود و specificity انتخابگر را تغییر نمیدهد.
/* بدون تودرتو نویسی */
blockquote {
position: relative;
}
blockquote::before {
content: "💬";
left: -1em;
position: absolute;
top: 0;
}
/* با تودرتو نویسی */
blockquote {
position: relative;
&::before {
content: "💬";
left: -1em;
position: absolute;
top: 0;
}
}
کلاسهای پیراینده (Modifier Classes) بخصوص
اگر این مورد (کدهایی که پایین تر قرار گرفته شده) در یک PR وجود داشته باشد، اولین پرسشام این است: آیا امکان دارد کلاس is-active را به یک کلاس پیراینده BEM یا SUIT تبدیل کرد؟ نام فعلی این کلاس را شبیه به یک کلاس کمکی (utility class) میکند و به نظر میرسد میشود از این کلاس در هر جایی استفاده کرد. اما در واقع این کلاس به کامپوننت nav-link محدود است و تغییرش به کلاس nav-link–active میتواند specificity را کاهش دهد و از تودرتو نویسی جلوگیری کند.
با اینحال گاهی اوقات شما کنترلی روی کلاس پیراینده ندارید و نمیتوانید تغییرش دهید. همچین حالتی زمانی اتفاق میافتد که این کلاس توسط یک اسکریپت third party یا افزونه وردپرس اضافه شود. اگر نمیتوانید کلاس پیراینده را تغییر دهید این امکان وجود دارد که با استفاده از تودرتو نویسی خوانایی کد را افزایش دهید.
/* بدون تودرتو نویسی */
.nav-link {
color: red;
}
.nav-link.is-active {
color: blue;
}
/* با تودرتو نویسی */
.nav-link {
color: red;
&.is-active {
color: blue;
}
}
مدیا کوئریها (Media Queries)
تودرتو نویسی مدیا کوئریها بهترین استفاده من از تودرتو نویسی است. این مثال ساده به خوبی حق مطلب را ادا نمیکند چون در دنیای واقعی تعداد زیادی قاعده زیر هر انتخابگر وجود دارد و مدیا کوئری هایی که تودرتو نباشند در انتهای سند (stylesheet) قرار میگیرند. این مورد نگهداری (maintenance) کدها را سخت میکند چون قواعدی که بر روی یک انتخابگر به خصوص تاثیر میگذارند در سند پخش شده اند.
تودرتو نویسی مدیا کوئریها یک دستاورد مهم برای خوانایی کد است و هیچ تاثیری روی specificity نمیگذارد.
/* بدون تودرتو نویسی */
h1 {
font-size: 2em;
}
h2 {
font-size: 1.5em;
}
@media (min-width: 40em) {
h1 {
font-size: 4em;
}
h2 {
font-size: 3em;
}
}
/* با تودرتو نویسی */
h1 {
font-size: 2em;
@media (min-width: 40em) {
font-size: 4em;
}
}
h2 {
font-size: 1.5em;
@media (min-width: 40em) {
font-size: 3em;
}
}
پیرایندههای والد (Parant Modifiers)
مانند کلاسهای پیراینده زمانی که شما عنصری دارید که استایلش با توجه به عنصر والد تغییر میکند اگر تغییرات را بصورت تودرتو بنویسید موجب میشود کدها در مقایسه با حالتی که بصورت مجزا و بدون تودتونویسی نوشته شدهاند راحتتر در دسترس باشند.
/* بدون تودرتو نویسی */
.card {
background: white;
color: black;
}
.card__title {
font-weight: 700;
}
.theme--dark .card {
background: black;
color: white;
}
.theme--dark .card__title {
font-weight: 600;
}
/* با تودرتو نویسی */
.card {
background: white;
color: black;
.theme--dark & {
background: black;
color: white;
}
}
.card__title {
font-weight: 700;
.theme--dark & {
font-weight: 600;
}
}
نتیجه گیری
تودرتو نویسی CSS یک ویژگی بزرگ است اما باید با احتیاط از آن استفاده شود. تودرتو نویسی specificity را افزایش میدهد و اگر دقت نکنید موجب ایجاد مشکل در نگهداری کدها میشود. ما پیشنهاد میکنیم از یک قرارداد نامگذاری ماژولار مانند BEM یا SUIT استفاده کنید تا لزوم استفاده از تودرتو نویسی را کاهش دهد. قانون این است: اگر یک قاعده بدون اینکه تودتو نوشته شود کار میکند آن را تودرتو ننویسید؛ اگرچه موقعیتهایی (مانند شبه انتخابگرها و مدیاکوئریها) هستند که تودرتو نویسی کارها را راحتر و قابل فهمتر میکند.
منبع: When to Nest CSS