انتخابگر :has() در CSS را که تحولی در انتخاب والد است، کاوش کنید. کاربردهای عملی، سازگاری بین مرورگرها و تکنیکهای پیشرفته برای متحول کردن استایلدهی CSS خود را بیاموزید.
تسلط بر انتخابگر :has() در CSS: آزادسازی قدرت انتخاب والد
سالها بود که توسعهدهندگان CSS در آرزوی راهی ساده و مؤثر برای انتخاب عناصر والد بر اساس فرزندانشان بودند. انتظار به پایان رسید! شبهکلاس (pseudo-class) :has()
بالاخره از راه رسید و در حال متحول کردن روش نوشتن CSS ما است. این انتخابگر قدرتمند به شما این امکان را میدهد که یک عنصر والد را در صورتی که حاوی یک عنصر فرزند خاص باشد، هدف قرار دهید و دنیایی از امکانات را برای استایلدهی پویا و واکنشگرا باز میکند.
انتخابگر :has() چیست؟
شبهکلاس :has()
یک شبهکلاس رابطهای (relational pseudo-class) در CSS است که لیستی از انتخابگرها را به عنوان آرگومان میپذیرد. این انتخابگر، عنصری را انتخاب میکند که حداقل یکی از انتخابگرهای موجود در لیست آرگومان، با یکی از نوادگان (descendants) آن عنصر مطابقت داشته باشد. به زبان سادهتر، این انتخابگر بررسی میکند که آیا یک عنصر والد، فرزند خاصی را دارد یا نه، و اگر داشت، عنصر والد انتخاب میشود.
سینتکس پایه آن به این صورت است:
والد:has(فرزند) { /* قوانین CSS */ }
این کد، عنصر والد
را تنها در صورتی انتخاب میکند که حداقل یک عنصر فرزند
در آن وجود داشته باشد.
چرا :has() اینقدر مهم است؟
به طور سنتی، CSS در توانایی خود برای انتخاب عناصر والد بر اساس فرزندانشان محدود بود. این محدودیت اغلب نیازمند راهحلهای پیچیده جاوا اسکریپت یا ترفندهایی برای دستیابی به استایلدهی پویا بود. انتخابگر :has()
نیاز به این روشهای دستوپاگیر را از بین میبرد و امکان نوشتن کدهای CSS تمیزتر، قابل نگهداریتر و با عملکرد بهتر را فراهم میکند.
در اینجا دلایلی که چرا :has()
یک تحول بزرگ است، آورده شده است:
- استایلدهی سادهشده: قوانین پیچیده استایلدهی که قبلاً به جاوا اسکریپت نیاز داشتند، اکنون با CSS خالص قابل دستیابی هستند.
- قابلیت نگهداری بهبودیافته: کدهای CSS تمیز و مختصر، فهم، اشکالزدایی و نگهداری آسانتری دارند.
- عملکرد بهتر: استفاده از انتخابگرهای بومی CSS معمولاً عملکرد بهتری نسبت به راهحلهای مبتنی بر جاوا اسکریپت دارد.
- انعطافپذیری بیشتر: انتخابگر
:has()
انعطافپذیری بیشتری در ایجاد طراحیهای پویا و واکنشگرا فراهم میکند.
مثالهای پایه از انتخابگر :has()
بیایید با چند مثال ساده شروع کنیم تا قدرت انتخابگر :has()
را نشان دهیم.
مثال ۱: استایلدهی یک Div والد بر اساس وجود یک تصویر
فرض کنید میخواهید به یک عنصر <div>
تنها در صورتی که حاوی یک عنصر <img>
باشد، یک حاشیه (border) اضافه کنید:
div:has(img) {
border: 2px solid blue;
}
این قانون CSS یک حاشیه آبی به هر <div>
که حداقل یک عنصر <img>
داشته باشد، اعمال میکند.
مثال ۲: استایلدهی یک آیتم لیست بر اساس وجود یک Span
فرض کنید لیستی از آیتمها دارید و میخواهید آیتم لیستی را که حاوی یک عنصر <span>
با یک کلاس خاص است، برجسته کنید:
li:has(span.highlight) {
background-color: yellow;
}
این قانون CSS رنگ پسزمینه هر <li>
که حاوی یک <span>
با کلاس "highlight" باشد را به زرد تغییر میدهد.
مثال ۳: استایلدهی برچسب فرم بر اساس اعتبار ورودی
شما میتوانید از :has()
برای استایلدهی برچسب یک فرم بر اساس معتبر یا نامعتبر بودن فیلد ورودی مرتبط با آن (در ترکیب با شبهکلاس :invalid
) استفاده کنید:
label:has(+ input:invalid) {
color: red;
font-weight: bold;
}
این کد، برچسب را قرمز و ضخیم میکند اگر فیلد ورودی که بلافاصله بعد از آن قرار دارد، نامعتبر باشد.
کاربردهای پیشرفته انتخابگر :has()
انتخابگر :has()
وقتی با دیگر انتخابگرها و شبهکلاسهای CSS ترکیب شود، حتی قدرتمندتر هم میشود. در اینجا چند مورد استفاده پیشرفته آورده شده است:
مثال ۴: هدف قرار دادن عناصر خالی
شما میتوانید از شبهکلاس :not()
در کنار :has()
برای هدف قرار دادن عناصری که فرزند خاصی را *ندارند* استفاده کنید. برای مثال، برای استایلدهی divهایی که تصویر *ندارند*:
div:not(:has(img)) {
background-color: #f0f0f0;
}
این کد یک پسزمینه خاکستری روشن به هر <div>
که حاوی عنصر <img>
نباشد، اعمال میکند.
مثال ۵: ایجاد طرحبندیهای پیچیده
انتخابگر :has()
میتواند برای ایجاد طرحبندیهای پویا بر اساس محتوای یک کانتینر استفاده شود. برای مثال، شما میتوانید طرحبندی یک گرید (grid) را بر اساس وجود نوع خاصی از عنصر در داخل یک سلول گرید تغییر دهید.
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.grid-item:has(img) {
grid-column: span 2;
}
این کد باعث میشود یک آیتم گرید، در صورتی که حاوی تصویر باشد، دو ستون را اشغال کند.
مثال ۶: استایلدهی پویای فرم
شما میتوانید از :has()
برای استایلدهی پویای عناصر فرم بر اساس وضعیت آنها (مثلاً اینکه آیا در حالت فوکوس، پر شده یا معتبر هستند) استفاده کنید.
.form-group:has(input:focus) {
box-shadow: 0 0 5px rgba(0, 0, 255, 0.5);
}
.form-group:has(input:valid) {
border-color: green;
}
.form-group:has(input:invalid) {
border-color: red;
}
این کد یک سایه جعبهای آبی هنگام فوکوس ورودی، یک حاشیه سبز اگر ورودی معتبر باشد، و یک حاشیه قرمز اگر ورودی نامعتبر باشد، اضافه میکند.
مثال ۷: استایلدهی بر اساس تعداد فرزندان
اگرچه :has()
مستقیماً تعداد فرزندان را نمیشمارد، اما میتوانید آن را با دیگر انتخابگرها و ویژگیهای CSS ترکیب کنید تا به نتایج مشابهی دست یابید. برای مثال، میتوانید از :only-child
برای استایلدهی یک والد استفاده کنید اگر فقط یک فرزند از نوع خاصی داشته باشد.
div:has(> p:only-child) {
background-color: lightgreen;
}
این کد یک <div>
را با پسزمینه سبز روشن استایلدهی میکند تنها در صورتی که حاوی یک عنصر <p>
به عنوان تنها فرزند مستقیم خود باشد.
سازگاری بین مرورگرها و Fallbackها
تا اواخر سال ۲۰۲۳، انتخابگر :has()
از پشتیبانی عالی در مرورگرهای مدرن از جمله کروم، فایرفاکس، سافاری و اج برخوردار است. با این حال، بررسی سازگاری در وبسایت Can I use قبل از استفاده در محیط پروداکشن، به ویژه اگر نیاز به پشتیبانی از مرورگرهای قدیمیتر دارید، بسیار مهم است.
در اینجا خلاصهای از ملاحظات سازگاری آورده شده است:
- مرورگرهای مدرن: پشتیبانی عالی در آخرین نسخههای کروم، فایرفاکس، سافاری و اج.
- مرورگرهای قدیمی: عدم پشتیبانی در مرورگرهای قدیمی (مانند اینترنت اکسپلورر).
فراهم کردن Fallbackها
اگر نیاز به پشتیبانی از مرورگرهای قدیمیتر دارید، باید fallback (راه حل جایگزین) فراهم کنید. در اینجا چند استراتژی وجود دارد:
- جاوا اسکریپت: از جاوا اسکریپت برای تشخیص پشتیبانی مرورگر از
:has()
و اعمال استایلهای جایگزین در صورت لزوم استفاده کنید. - Feature Queries: از کوئریهای ویژگی CSS (
@supports
) برای ارائه استایلهای مختلف بر اساس پشتیبانی مرورگر استفاده کنید. - ارتقاء تدریجی (Progressive Enhancement): با یک طراحی پایه و کاربردی که در همه مرورگرها کار میکند شروع کنید، و سپس به تدریج طراحی را برای مرورگرهایی که از
:has()
پشتیبانی میکنند، بهبود بخشید.
در اینجا مثالی از استفاده از feature query آورده شده است:
.parent {
/* استایلدهی پایه برای همه مرورگرها */
border: 1px solid black;
}
@supports selector(:has(img)) {
.parent:has(img) {
/* استایلدهی بهبودیافته برای مرورگرهایی که از :has() پشتیبانی میکنند */
border: 3px solid blue;
}
}
این کد یک حاشیه سیاه به عنصر .parent
در همه مرورگرها اعمال میکند. در مرورگرهایی که از :has()
پشتیبانی میکنند، اگر عنصر .parent
حاوی یک تصویر باشد، یک حاشیه آبی اعمال خواهد کرد.
ملاحظات عملکرد
در حالی که :has()
مزایای قابل توجهی ارائه میدهد، توجه به تأثیر بالقوه آن بر عملکرد، به ویژه هنگام استفاده گسترده یا با انتخابگرهای پیچیده، ضروری است. مرورگرها باید انتخابگر را برای هر عنصر در صفحه ارزیابی کنند، که میتواند از نظر محاسباتی پرهزینه باشد.
در اینجا چند نکته برای بهینهسازی عملکرد :has()
آورده شده است:
- انتخابگرها را ساده نگه دارید: از استفاده از انتخابگرهای بیش از حد پیچیده در داخل شبهکلاس
:has()
خودداری کنید. - محدوده را محدود کنید:
:has()
را به عناصر یا کانتینرهای خاص اعمال کنید، نه به صورت سراسری. - عملکرد را تست کنید: از ابزارهای توسعهدهنده مرورگر برای نظارت بر عملکرد قوانین CSS خود و شناسایی گلوگاههای بالقوه استفاده کنید.
اشتباهات رایج برای اجتناب
هنگام کار با انتخابگر :has()
، به راحتی میتوان اشتباهاتی مرتکب شد که منجر به نتایج غیرمنتظره میشود. در اینجا برخی از اشتباهات رایج برای اجتناب آورده شده است:
- مشکلات Specificity: اطمینان حاصل کنید که قوانین
:has()
شما از اولویت (specificity) کافی برای بازنویسی سایر قوانین CSS برخوردار هستند. از همان مراحل عیبیابی اولویت که همیشه استفاده میکنید، بهره ببرید. - تودرتوی نادرست: ساختار تودرتوی عناصر خود را دوباره بررسی کنید تا مطمئن شوید که انتخابگر
:has()
عنصر والد صحیح را هدف قرار میدهد. - انتخابگرهای بیش از حد پیچیده: از استفاده از انتخابگرهای بیش از حد پیچیده در داخل شبهکلاس
:has()
خودداری کنید، زیرا این امر میتواند بر عملکرد تأثیر بگذارد. - فرض کردن فرزندان مستقیم: به یاد داشته باشید که
:has()
هر *نوادهای* را بررسی میکند، نه فقط فرزندان مستقیم را. اگر نیاز به هدف قرار دادن فقط فرزندان مستقیم دارید، از ترکیبکننده فرزند مستقیم (>
) استفاده کنید (مثلاًdiv:has(> img)
).
بهترین شیوهها برای استفاده از :has()
برای به حداکثر رساندن مزایای انتخابگر :has()
و جلوگیری از مشکلات احتمالی، این بهترین شیوهها را دنبال کنید:
- هوشمندانه از آن استفاده کنید: فقط زمانی از
:has()
استفاده کنید که مزیت واضحی نسبت به سایر تکنیکهای CSS یا راهحلهای جاوا اسکریپت داشته باشد. - آن را ساده نگه دارید: انتخابگرهای ساده و خوانا را به انتخابگرهای پیچیده و درهمپیچیده ترجیح دهید.
- به طور کامل تست کنید: قوانین CSS خود را در مرورگرها و دستگاههای مختلف تست کنید تا مطمئن شوید که مطابق انتظار عمل میکنند.
- کد خود را مستند کنید: به کد CSS خود کامنت اضافه کنید تا هدف و عملکرد قوانین
:has()
خود را توضیح دهید. - دسترسیپذیری را در نظر بگیرید: اطمینان حاصل کنید که استفاده شما از
:has()
تأثیر منفی بر دسترسیپذیری (accessibility) ندارد. به عنوان مثال، برای انتقال اطلاعات مهم تنها به تغییرات استایلی که توسط:has()
ایجاد میشود تکیه نکنید؛ از ویژگیهای ARIA یا مکانیزمهای جایگزین برای کاربران دارای معلولیت استفاده کنید.
مثالهای دنیای واقعی و موارد استفاده
بیایید چند مثال از دنیای واقعی را بررسی کنیم که چگونه انتخابگر :has()
میتواند برای حل چالشهای طراحی رایج استفاده شود.
مثال ۸: ایجاد منوهای ناوبری واکنشگرا
شما میتوانید از :has()
برای ایجاد منوهای ناوبری واکنشگرا استفاده کنید که بر اساس وجود آیتمهای منوی خاص، با اندازههای مختلف صفحه سازگار میشوند.
سناریویی را تصور کنید که میخواهید بسته به اینکه کاربر وارد شده است یا نه، یک منوی ناوبری متفاوت نمایش دهید. اگر وارد شده باشند، ممکن است گزینههای پروفایل و خروج را نشان دهید، در غیر این صورت ممکن است ورود/ثبتنام را نشان دهید.
nav:has(.user-profile) {
/* استایلها برای کاربران وارد شده */
}
nav:not(:has(.user-profile)) {
/* استایلها برای کاربران خارج شده */
}
مثال ۹: استایلدهی کامپوننتهای کارت
انتخابگر :has()
میتواند برای استایلدهی کامپوننتهای کارت بر اساس محتوای آنها استفاده شود. برای مثال، شما میتوانید تنها در صورتی که یک کارت حاوی تصویر باشد، به آن سایه اضافه کنید.
.card:has(img) {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
مثال ۱۰: پیادهسازی تمهای پویا
شما میتوانید از :has()
برای پیادهسازی تمهای پویا بر اساس ترجیحات کاربر یا تنظیمات سیستم استفاده کنید. برای مثال، میتوانید رنگ پسزمینه صفحه را بر اساس اینکه کاربر حالت تاریک (dark mode) را فعال کرده است یا نه، تغییر دهید.
body:has(.dark-mode) {
background-color: #333;
color: #fff;
}
این مثالها تطبیقپذیری انتخابگر :has()
و توانایی آن در حل طیف گستردهای از چالشهای طراحی را نشان میدهند.
آینده CSS: قدم بعدی چیست؟
معرفی انتخابگر :has()
یک گام مهم رو به جلو در تکامل CSS است. این انتخابگر به توسعهدهندگان قدرت میدهد تا شیوهنامههای (stylesheets) پویاتر، واکنشگراتر و قابل نگهداریتری با وابستگی کمتر به جاوا اسکریپت ایجاد کنند. با ادامه رشد پشتیبانی مرورگرها از :has()
، میتوانیم انتظار داشته باشیم که استفادههای نوآورانهتر و خلاقانهتری از این انتخابگر قدرتمند ببینیم.
با نگاه به آینده، کارگروه CSS در حال بررسی سایر ویژگیها و بهبودهای هیجانانگیزی است که قابلیتهای CSS را بیش از پیش گسترش خواهند داد. این موارد عبارتند از:
- Container Queries: به کامپوننتها اجازه میدهد تا استایل خود را بر اساس اندازه کانتینرشان، به جای ویوپورت، تطبیق دهند.
- Cascade Layers: کنترل بیشتری بر روی آبشار (cascade) و اولویت (specificity) قوانین CSS فراهم میکند.
- انتخابگرهای پیشرفتهتر: معرفی انتخابگرهای جدیدی که میتوانند عناصر را بر اساس ویژگیها، محتوا و موقعیتشان در درخت سند هدف قرار دهند.
با بهروز ماندن با آخرین تحولات CSS و استقبال از ویژگیهای جدیدی مانند :has()
، توسعهدهندگان میتوانند پتانسیل کامل CSS را آزاد کرده و تجربیات وب واقعاً استثنایی ایجاد کنند.
نتیجهگیری
انتخابگر :has()
یک افزودنی قدرتمند به جعبه ابزار CSS است که امکان انتخاب والد را فراهم کرده و امکانات جدیدی برای استایلدهی پویا و واکنشگرا باز میکند. در حالی که در نظر گرفتن سازگاری مرورگر و پیامدهای عملکردی آن بسیار مهم است، مزایای استفاده از :has()
برای داشتن کدهای CSS تمیزتر، قابل نگهداریتر و با عملکرد بهتر، غیرقابل انکار است. این انتخابگر متحولکننده را بپذیرید و استایلدهی CSS خود را امروز متحول کنید!
به یاد داشته باشید که دسترسیپذیری را در نظر بگیرید و مکانیزمهای جایگزین برای مرورگرهای قدیمیتر فراهم کنید. با پیروی از بهترین شیوههای ذکر شده در این راهنما، میتوانید از پتانسیل کامل انتخابگر :has()
بهرهمند شوید و تجربیات وب واقعاً استثنایی برای کاربران در سراسر جهان ایجاد کنید.