CSS شرطی با :has و :nth-last-child

استاد چیدمان
ما میتوانیم با CSS بررسی کنیم که آیا تعداد یک عنصر گروه کمتر یا مساوی با یک عدد است. برای مثال داشتن یک شبکه با سه یا چند عنصر. ممکن است تعجب کنید که چرا این حتی ضروری است. در برخی موارد، یک مؤلفه یا طرح ممکن است بر اساس تعداد عناصر فرزند تغییر کند.
سالهاست که در CSS وجود دارد، اما اکنون با CSS قدرتمندتر میشود :has. ما می توانیم هر دو را ترکیب کنیم nth-last-child انتخابگر همراه با :has برای طلسم کردن، بله! درست شنیدی
اوایل امسال پستی با عنوان Conditional CSS منتشر کردم که در آن نشان دادم چگونه برخی از توابع CSS به ما در ایجاد رابط های کاربری شرطی کمک می کنند. در این مقاله، من چند نمونه از جایی که میتوانیم انتخابگر CSS را ترکیب کنیم، برجسته میکنم :has برای داشتن حالت های شرطی جزء/طرح بندی.
معرفی به :nth-last-child
یکی از عوامل اصلی در این مقاله است :nth-last-child کلاس شبه ما می توانیم از این انتخابگر برای تمسخر استفاده کنیم شمارش عناصر کودک
بیایید بررسی کنیم که چگونه کار می کند. من سعی خواهم کرد نحوه عملکرد آن را با کلمات ساده توضیح دهم.
شکل زیر را در نظر بگیرید:

ما یک لیست از 5 کارت داریم. من از این به عنوان مثال استفاده می کنم تا نشان دهم چه کاری می توانیم انجام دهیم :nth-last-child.
در CSS زیر داریم n + 3 یعنی:
li:nth-last-child(n + 3) {
}
سه مورد اول را از آخر انتخاب کنید و از سومین مورد بشمارید.
بیایید نگاه دقیق تری بیندازیم. ابتدا باید 3 عنصر را از آخر بشماریم. با این کار، عنصر 3 در واقع اولین عنصری است که تا انتهای لیست می شماریم.

با شمارش معکوس از سومین مورد تا پایان، موارد انتخاب شده در اینجا آمده است:

محدودیت در میزان درخواست در CSS
همانطور که در این مقاله عالی توسط Heydon Pickering توضیح داده شد، می توانیم استفاده کنیم :nth-last-child به عنوان درخواست مقدار
شکل زیر را در نظر بگیرید:

ما لیستی از اطلاعات داریم که در صورت داشتن 5 مورد یا بیشتر، متفاوت نمایش داده می شود.
ul>
li>li>
li>li>
li>li>
ul>
li {
}
li:nth-last-child(n + 5),
li:nth-last-child(n + 5) ~ li {
width: 50%;
display: inline-block;
border-bottom: 0;
}
در حالی که کار می کند، هنوز هم از برخی جهات کمی محدود است.
امکان استایل دادن به والد بر اساس تعداد عناصر وجود ندارد.
تصور کنید باید اضافه کنیم display: flex به همه
:nth-last-child انتخابگر شبه کلاس
دلیل آن این است که اضافه display: flex هر عنصر را وادار می کند تا در نظم خاص خود باقی بماند، که با طرحی که باید به دست آید مطابقت ندارد.
li:nth-last-child(n + 5),
li:nth-last-child(n + 5) ~ li {
width: 50%;
display: flex;
flex-direciton: column;
}

ما می توانیم این را با display: inline-flex در عوض، اما هنوز راه حل بهینه برای من نیست. دلیل آن این است که مرورگر فاصله بین عناصر HTML را می شمارد، آنها باید به صورت زیر باشند:
ul>
li>li>
li>li>
li>li>
ul>
اگر این کار را نکنیم، display: inline-flex همان اثر را خواهد داشت display: flex. یکی از راه حل های اصلاح این است که عرض را 1٪ کاهش دهید.
li:nth-last-child(n + 5),
li:nth-last-child(n + 5) ~ li {
width: 49%;
display: flex;
flex-direciton: column;
}
آنها را در اندازه های مختلف پنجره کار کنید
بدون توانایی کنترل بر والدین، شکل دادن به چیدمان لیست به این آسانی نیست. به عنوان مثال، زمانی که عرض کانتینر یا ویوپورت کوچکتر است، باید 1 عنصر را در هر خط نمایش دهیم.
کار مدیریت فاصله بیشتر
وقتی 3 عنصر یا کمتر وجود دارد، فاصله افقی است و زمانی که 5 عنصر یا بیشتر باشد، فاصله عمودی است. ما میتوانیم با چرخاندن کادر از افقی به عمودی یا با استفاده از CSS، این را به صورت دستی مدیریت کنیم gap با فلکس باکس اما باز هم مجبوریم استفاده کنیم inline-flex برای این مورد
CSS :nth-last-child pseudoclass کلید ساخت چیدمان های مشروط است. با ترکیب آن با CSS :has انتخابگر، میتوانیم بررسی کنیم که آیا عنصر والد حداقل تعداد معینی عنصر دارد یا خیر و بر اساس آن به آن استایل میدهیم. امکانات بی پایان هستند!
از موارد و مثال استفاده کنید
شبکه ای که بسته به تعداد عناصر فرزند تغییر می کند

زمانی که باید یک شبکه را بر اساس تعداد عناصر تغییر دهیم، با CSS فعلی این امکان وجود ندارد. در شبکه CSS می توانیم استفاده کنیم minmax() یک ویژگی شبکه پویا که بر اساس فضای موجود تغییر می کند.
در اینجا برداشت من از شبکه CSS است minmax():
.list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
نتیجه ممکن است به این صورت باشد:

این کامل نیست. ما کنترل زیادی نداریم زیرا باید مقدار آن را تغییر دهیم 150px ج minmax(). وقتی 4 مورد یا کمتر وجود داشته باشد، می تواند عالی عمل کند و برای 5 مورد یا بیشتر شکسته شود.
راه حل؟ می توانیم با CSS بررسی کنیم :has اگر بیش از 5 مورد یا بیشتر وجود دارد و تغییر دهید minmax() ارزش بر این اساس
.list {
--item-size: 200px;
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(var(--item-size), 1fr)
);
gap: 1rem;
}
.list:has(li:nth-last-child(n + 5)) {
--item-size: 150px;
}
تازه عوض شدم --item-size متغیر برای آسانتر خواندن کد و جلوگیری از تکرار.
ویدیوی زیر را تماشا کنید و متوجه شوید که چگونه ستون های شبکه با افزودن یا حذف عناصر تغییر می کنند.
این قدرتمند نیست؟
در شکل زیر یک هدر داریم که وقتی عناصر ناوبری 4 یا بیشتر هستند باید چیدمان آن را تغییر دهد. با CSS :has و :nth-last-child، می توانیم این را تشخیص دهیم و طرح را تغییر دهیم.

.site-header:has(li:nth-last-child(n + 4)) {
.site-header__wrapper > * {
flex: initial;
}
.site-header__start {
order: 2;
}
.site-header__middle {
order: -1;
text-align: start;
}
.site-header__end {
margin-left: auto;
}
}
اون بالاست Sass کد هنگامی که در CSS وانیلی نوشته می شود، می تواند کمی سخت به نظر برسد.
.site-header:has(li:nth-last-child(n + 4)) .site-header__wrapper > * {
flex: initial;
}
.site-header:has(li:nth-last-child(n + 4)) .site-header__start {
order: 2;
}
.site-header:has(li:nth-last-child(n + 4)) .site-header__middle {
order: -1;
text-align: start;
}
.site-header:has(li:nth-last-child(n + 4)) .site-header__end {
margin-left: auto;
}
آیا می توانیم بهتر عمل کنیم؟ بله، اما این به خوبی پشتیبانی نمی شود (هنوز!). میتوانیم یک متغیر CSS بولی اضافه کنیم که وقتی سرصفحه دارای 4 عنصر یا بیشتر باشد تغییر میکند و سپس از یک استایل برای تغییر هدر استفاده میکنیم.
.site-header:has(li:nth-last-child(n + 4)) {
--layout-2: true;
}
این متغیر را تنظیم می کند --layout-2 وقتی عناصر ناوبری 4 یا بیشتر باشد.
@container style(--layout-2: true) {
.site-header__wrapper {
> * {
flex: initial;
}
}
.site-header__start {
order: 2;
}
.site-header__middle {
order: -1;
text-align: start;
}
.site-header__end {
margin-left: auto;
}
}
به نظر من این تمیز و بسیار بهتر از قرار دادن تمام سبک های CSS در داخل به نظر می رسد :has انتخابگر
نسخه ی نمایشی
بخش اخبار پویا
طرح زیر یک بخش خبری است که وقتی تعداد موارد 3 یا بیشتر باشد، باید طرح آن را تغییر دهد.

با ترکیب CSS :has و :nth-last-child، می توانیم یک متغیر CSS را ایجاد کنیم که توسط یک استایل پرس و جو بررسی می شود.
اول، من سبک پیش فرض نقشه را افقی فرض می کنم.
div class="layout">
article class="card">article>
article class="card">article>
article class="card">article>
div>
.layout {
display: grid;
grid-gap: 1rem;
}
.card {
display: flex;
gap: 1rem;
align-items: center;
}
سپس باید شماره را بررسی کنم .card عناصر
.layout:has(.card:nth-last-child(n + 4)) {
--layout-4: true;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
حالا متغیر CSS را داریم --layout-4 که تنها زمانی تغییر می کند که 4 مورد یا بیشتر داشته باشیم. ما میتوانیم این را با یک پرس و جوی سبک و بهروزرسانی بررسی کنیم .card بر این اساس سبک
@container style(--layout-4: true) {
.card {
flex-direction: column;
}
.card__thumb {
flex: 1;
width: 100%;
aspect-ratio: 4 / 3;
}
}
نسخه ی نمایشی
اقدامات مودال
در یک سیستم طراحی، ممکن است نیاز داشته باشیم که به صورت پویا تراز اقدامات مودال را بر اساس تعداد اقداماتی که داریم کنترل کنیم.
شکل زیر را در نظر بگیرید:

مثلاً اگر اکشنی داریم باید مرکز باشد. در غیر این صورت، آنها را به سمت راست تراز کنید.
این CSS است:
.modal__footer {
display: flex;
justify-content: center;
gap: 0.5rem;
}
.modal__footer:has(a:nth-last-child(n + 2)) {
justify-content: flex-end;
}
ساده است، درست است؟ در اینجا یک نسخه ی نمایشی در عمل است.
نسخه ی نمایشی
آواتارهای کاربر
در وب سایت های تحریریه، یک مقاله می تواند توسط چندین نویسنده نوشته شود. یک الگوی رایج این است که وقتی چندین نویسنده داریم، تصاویر نویسنده را با فاصله منفی مرتب کنیم.
![]()
تنها با استفاده از درخواست های کمیت، می توانیم به حداقل هایی دست یابیم که عبارتند از:
- فاصله منفی را اضافه کنید (آواتارها را روی هم قرار دهید).
- اندازه آواتار را در صورت وجود چندتایی کاهش دهید.
img:nth-last-child(n + 2) ~ img {
border: 2px solid #fff;
margin-left: -0.25rem;
width: 30px;
height: 30px;
}
موارد فوق کار می کند اما محدود کننده است. اگر بخواهیم خود ظرف را استایل کنیم چطور؟ خوب، اینجا جایی است که CSS :has قدرتمند می شود.
ابتدا باید یک متغیر CSS را بررسی و تغییر دهیم:
.post-author:has(img:nth-last-child(n + 2)) {
--multiple-avatars: true;
}
اگر این متغیر CSS درست باشد، آنگاه استایل ها را روی چند آواتار اعمال می کنیم:
@container style(--multiple-avatars: true) {
.avatars-list {
display: flex;
background-color: #efefef;
padding: 8px 12px;
border-radius: 50px;
}
img:not(:first-child) {
border: solid 2px #fff;
margin-left: -0.25rem;
}
}
ویدیوی زیر را ببینید:
نسخه ی نمایشی
کرونولوژی
مثال جالب دیگری که در آن CSS شرطی به خوبی کار می کند مولفه تایم لاین است.

در این مثال، من میخواهم زمانی که 4 مورد یا بیشتر وجود دارد، خط زمانی از یک لیست عمودی به یک سبک متناوب تغییر کند.
من اول استفاده کردم :nth-last-child با CSS :has:
.timeline-wrapper:has(.timeline__item:nth-last-child(n + 4)) {
--alternating: true;
}
در صورت رعایت موارد فوق، CSS زیر اعمال خواهد شد:
@container style(--alternating: true) {
}
آنچه در مورد استفاده از درخواست های سبک در اینجا مفید است این است که می توانیم از این سبک در صفحه دیگری استفاده مجدد کنیم. لازم نیست CSS مشروط باشد.
من ممکن است چیزی شبیه به این انجام دهم:
.timeline-wrapper--page-10 {
--alternating: true;
}
لطفا اهمیت نده .timeline-wrapper--page-10، این یک نام کلاسی عمداً دلخواه است. متغیر CSS را می توان در هر جایی که بخواهیم اختصاص داد و CSS بلافاصله کار می کند.
آن را یک بار بنویسید و در بسیاری از موارد کار خواهد کرد.
توجه: این نسخه نمایشی در Chrome Canary خراب میشود، و من حدس میزنم به این دلیل است که از شبه عناصر در درخواستهای سبک استفاده میکنم. من در حال بررسی بیشتر این موضوع هستم و در صورت دریافت اطلاعات بیشتر مقاله را به روز خواهم کرد.
نسخه ی نمایشی
شبکه آرم ها
یکی از چیزهای پیچیده ای که در CSS باید با آن مقابله کرد، تراز کردن چندین لوگو و اطمینان از ظاهر خوب آنهاست. با CSS شرطی می توانیم تعداد لوگوها را شناسایی کرده و اندازه آنها را کمی کاهش دهیم.

ul:has(li:nth-last-child(n + 8)) img {
max-width: 160px;
height: 35px;
}
نسخه ی نمایشی
Outro
این یکی از مقالات جالبی بود که روی آن کار کردم. ترکیب ویژگیهای مدرن CSS میتواند راههای جدید و هیجانانگیزی را برای ساخت طرحبندی فعال کند، و مثالهای این مقاله نیز از این قاعده مستثنی نبودند.
تغییر یک سبک بر اساس تعداد موارد ممکن است یک بار استفاده نباشد. می توان آن را در موارد استفاده مختلف بازیابی کرد. با استفاده از استایل کوئری ها می توانیم یک بار بنویسیم و در همه جا دوباره از آنها استفاده کنیم.



