توسعه فرانت‌اند

CSS :has() در عمل: الگوهای کاربردی

عنصر هدف و combinator، تفاوت ظاهر و منطق برنامه، invalid و user-invalid، specificity و fallback با سه checkbox مستقل.

1404/11/23 2 دقیقه مطالعه 1,082 بازدید

یک گزینه داخل کارت انتخاب می‌شود و لازم است قاب همان کارت تغییر کند. پیش از :has() معمولاً برای این ظاهر، class اضافی روی والد یا منطق JavaScript نوشته می‌شد. این selector امکان می‌دهد عنصر بر اساس رابطه مشخص با عنصر دیگر انتخاب شود. دامنه آن ظاهر و انتخاب در CSS است؛ قرار نیست جای وضعیت برنامه، اعتبارسنجی سرور یا منطق کامل تعامل را بگیرد.

برای استفاده مفید، رابطه را دقیق بیان کنید: «labelی که input فرزند مستقیم آن checked است». این جمله روشن‌تر از «والد فعال را پیدا کن» است. عنصر هدف، محدوده و شرط باید معلوم باشند. Selector گسترده می‌تواند در محتوای بعدی به موارد ناخواسته هم بخورد. شروع از markup واقعی کمک می‌کند قاعده به ساختار مشخصی وابسته باشد و تغییر بعدی قابل بررسی بماند.

عنصر انتخاب‌شده و شرط داخل آن

مرجع :has در MDN آن را pseudo-class رابطه‌ای توضیح می‌دهد. بخش پیش از :has عنصر هدف است و آرگومان درباره رابطه با آن شرط می‌گذارد. شرط می‌تواند به descendant، فرزند مستقیم یا رابطه مجاور مربوط باشد. به همین دلیل نام «parent selector» همه کاربردها را پوشش نمی‌دهد. باید معلوم باشد کدام عنصر ظاهر تازه می‌گیرد.

برای نمونه، کارت دارای تصویر و کارت دارای توضیح می‌توانند ظاهر متفاوت داشته باشند، اما selector عکس را انتخاب نمی‌کند مگر همان هدف نوشته شود. شرط وجود یک img با دریافت موفق آن عکس هم یکسان نیست. DOM ممکن است img داشته باشد ولی منبع شکست خورده باشد. قاعده CSS بر ساختار تکیه می‌کند و نباید نتیجه‌ای درباره کیفیت داده یا شبکه از آن برداشت شود.

نمونه کامل انتخاب سه گزینه

کد زیر را در فایل choices.html با UTF-8 ذخیره و به صورت HTML باز کنید. تمام CSS داخل style است و JavaScript، تصویر یا وابستگی خارجی ندارد. سه label با کلاس choice وجود دارد و هرکدام یک checkbox فرزند مستقیم دارند. این‌ها ترجیح‌های آموزشی‌اند و هیچ فرم ارسالی یا ذخیره پایدار ندارند. انتخاب native حتی اگر :has پشتیبانی نشود باقی می‌ماند؛ تغییر قاب یک بهبود بصری است.

<!doctype html>
<html lang="fa" dir="rtl"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>گزینه‌های نمایش نمونه</title><style>*{box-sizing:border-box}body{margin:0;color:#17243b;background:#f2f4f7;font-family:Tahoma,Arial,sans-serif;line-height:1.9}main{width:min(36rem,calc(100% - 2rem));margin:auto;padding-block:2rem}fieldset{border:1px solid #8998ad;padding:1rem}legend{font-weight:bold}.choice{display:flex;align-items:center;gap:.7rem;padding:1rem;margin-block:.7rem;border:2px solid #a1afc3;border-radius:.5rem;background:white;cursor:pointer}.choice input{width:1.2rem;height:1.2rem;flex:none;accent-color:#173f78}.choice:focus-within{outline:3px solid #946000;outline-offset:3px}@supports selector(:has(*)){.choice:has(>input:checked){border-color:#173f78;background:#e8f0ff}}</style></head><body><main><h1>ترجیح‌های نمایشی آموزشی</h1><fieldset><legend>موارد مورد نظر را انتخاب کنید</legend><label class="choice"><input type="checkbox" name="show-date"><span>نمایش تاریخ</span></label><label class="choice"><input type="checkbox" name="show-summary"><span>نمایش خلاصه</span></label><label class="choice"><input type="checkbox" name="show-category"><span>نمایش دسته</span></label></fieldset><p>این انتخاب‌ها فقط وضعیت کنترل‌های نمونه‌اند و اطلاعاتی ارسال یا ذخیره نمی‌کنند.</p></main></body></html>

fieldset و legend نام گروه را بیان می‌کنند. هر label یک عنوان قابل خواندن دارد و checkbox از ترتیب طبیعی صفحه‌کلید استفاده می‌کند. selector choice با شرط input:checked، قاب و پس‌زمینه همان گزینه را تغییر می‌دهد. برای focus-within هم outline جدا تعریف شده است؛ focus و checked یک معنی ندارند. این تفکیک کمک می‌کند فرد هم محل حرکت و هم وضعیت انتخاب را تشخیص دهد.

Combinator را آگاهانه انتخاب کنید

علامت فرزند مستقیم رابطه را محدود می‌کند. اگر checkbox بعدها داخل wrapper تازه قرار گیرد، قاعده نمونه دیگر به آن ساختار نمی‌خورد و باید همزمان اصلاح شود. شرط descendant گسترده‌تر است و می‌تواند یک checkbox تو در توی نامرتبط را هم پیدا کند. انتخاب هرکدام به قرارداد markup بستگی دارد. رابطه را در توضیح مؤلفه بنویسید تا تغییر ساختار بی‌خبر ظاهر را خراب نکند.

در رابطه مجاور، ممکن است ظاهر یک heading بر اساس عنصر بعدی انتخاب شود. این کاربرد هم به ترتیب واقعی سند وابسته است. اگر ترتیب فقط با CSS جابه‌جا شده باشد، selector ترتیب DOM را می‌بیند، نه برداشت بصری شما را. برای طراحی کارت، راهنمای Card Layout درباره ترتیب و معنی عناصر توضیح دارد. :has به ساختار واکنش نشان می‌دهد و ساختار را اصلاح نمی‌کند.

وجود محتوا با وضعیت برنامه متفاوت است

nav دارای لینک فعال می‌تواند قاب متفاوت بگیرد، اما تعیین اینکه کدام لینک فعال است معمولاً به route و قرارداد برنامه مربوط است. CSS خودبه‌خود مقصد جاری را از منطق داخلی شما استخراج نمی‌کند. class یا aria-current معتبر می‌تواند داده لازم را فراهم کند. انتخاب والد بر اساس آن، فقط بخش ظاهر را انجام می‌دهد. این تقسیم مسئولیت از پنهان شدن منطق در selectorهای پیچیده جلوگیری می‌کند.

برای محتوای دریافت‌شده async، تغییر DOM می‌تواند باعث matching تازه شود. این رفتار برای تنظیم ظاهر مفید است، ولی اعلام وضعیت و خطا به کاربر مسئولیت جدا دارد. اگر کلاس خطا یا متن status اضافه می‌شود، باید معنی و زمان آن درست باشد. راهنمای اعلان‌ها درباره خبر قابل دسترس توضیح می‌دهد. رنگ گرفتن ظرف فرم جای توضیح علت شکست را نمی‌گیرد.

اعتبارسنجی فرم را زودهنگام نمایش ندهید

input required ممکن است پیش از تعامل هم invalid باشد. قاعده‌ای که کل فرم را از آغاز قرمز می‌کند، می‌تواند خطا را پیش از تلاش فرد نشان دهد. زمان ارائه بازخورد را طراحی کنید. مرجع :user-invalid درباره حالت نامعتبر پس از تعامل کاربر توضیح دارد. دامنه پشتیبانی و رفتار محیط باید با قرارداد پروژه هماهنگ باشد.

CSS می‌تواند نشانه بصری بسازد، اما متن علت، ارتباط آن با فیلد و اعتبارسنجی سمت سرور همچنان لازم‌اند. اگر نمونه شما form:has(:invalid) دارد، باید markup فیلد، required و پیام مربوط هم نشان داده شوند. یک selector تنها راهنمای عملی کامل نیست. نمونه این مقاله به انتخاب checkbox محدود شده تا رفتار روشن بماند و پیام خطایی که وجود ندارد به آن نسبت داده نشود.

Specificity و ترکیب با where

پیچیدگی selector می‌تواند override بعدی را سخت کند. Specificity در :has به آرگومان‌ها مرتبط است و افزودن یک id می‌تواند وزن قاعده را تغییر دهد. برای سیستم طراحی، مقدار لازم را محدود نگه دارید. اگر فقط برای حل یک conflict مدام selector را سنگین‌تر کنید، قرارداد cascade مبهم می‌شود. کلاس مؤلفه، layer و ترتیب قواعد هم می‌توانند انتخاب‌های واضح‌تری فراهم کنند.

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

پشتیبانی و fallback

برای پروژه واقعی، سازگاری :has را از مرجع به‌روز و محیط‌های هدف بررسی کنید. @supports با selector امکان جدا کردن بهبود را می‌دهد، همان‌طور که در نمونه دیده می‌شود. پایه باید بدون آن قابل استفاده باشد. checkbox و متن می‌توانند وضعیت را بیان کنند حتی اگر قاب تغییر نکند. اگر قابلیت ضروری به matching وابسته است، مسیر جایگزین باید به صورت واقعی طراحی شود.

Fallback همیشه به معنی تکرار همان ظاهر با JavaScript نیست. گاهی رفتار native و متن کافی است. تصمیم به نیاز محصول مربوط است. برای چیدمان، راهنمای واکنش‌گرایی توضیح می‌دهد که قواعد ذاتی و شرط‌ها نقش‌های مختلفی دارند. Container Query فضای کانتینر را بررسی می‌کند و :has رابطه ساختار را؛ شباهت شرطی بودن آن‌ها دلیل یکی بودن دامنه نیست.

عملکرد را با دامنه واقعی بسنجید

قواعدی که از root یا یک ظرف بسیار بزرگ شروع می‌شوند و شرط گسترده دارند، می‌توانند کار matching بیشتری ایجاد کنند، به‌ویژه در DOM متغیر. این به معنی کند بودن قطعی همه کاربردهای :has نیست. محدوده و رابطه دقیق را ترجیح دهید و نیاز واقعی را در نظر بگیرید. برای سه checkbox، ساختار محدود است؛ تعمیم همین selector به همه عناصر صفحه بدون دلیل انتخاب مناسبی نیست.

ظاهر را از تصمیم‌های داده جدا نگه دارید تا تغییر UI قابل پیگیری باشد. اگر CSS بر وجود محتوا تکیه می‌کند، موارد متن خالی، wrapper تازه و عنصر مخفی را در قرارداد لحاظ کنید. وجود عنصر hidden هم ممکن است از نظر selector با نبودن آن متفاوت باشد. قاعده باید حالت مورد نظر را ببیند، نه هر نشانه ساختاری مشابه. این جزئیات از خطاهای خاموش پس از تغییر markup جلوگیری می‌کنند.

تحویل الگوی قابل نگهداری

در توضیح نمونه، عنصر هدف، رابطه فرزند و وضعیت matching را بنویسید. نام کلاس در CSS باید markup واقعی داشته باشد و حالت‌ها با محتوا هماهنگ باشند. نمونه بعدی با selector تازه به ساختار متناظر نیاز دارد؛ خواننده نباید آن را حدس بزند. درباره نقش کنترل‌ها، راهنمای نشانه‌ها و اهداف انتخاب به جدا کردن ظاهر و معنی کمک می‌کند.

:has ابزار مفیدی برای ظاهر وابسته به رابطه است. می‌تواند classهای صرفاً نمایشی را کم کند و برخی قواعد را به ساختار نزدیک‌تر نگه دارد. اما اعتبارسنجی، خبر قابل دسترس و رفتار برنامه همچنان قرارداد جدا دارند. نتیجه خوب زمانی ساخته می‌شود که پایه بدون بهبود هم قابل استفاده باشد و selector دقیقاً همان حالت واقعی را انتخاب کند که طراحی درباره آن توضیح می‌دهد.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!