@supports؛ وقتی میخواید مطمئن بشید مرورگر یه ویژگی رو میفهمه
تو درسهای قبل، چند بار به این نکته اشاره کردیم که بعضی ویژگیهای جدید CSS (مثل subgrid یا oklch) ممکنه تو همهی مرورگرها پشتیبانی نشن. تا اینجا فقط پیشنهاد میکردیم یه fallback دستی بذارید. اما CSS یه ابزار داره که دقیقاً برای همین ساخته شده: @supports. با این، میتونید مستقیم تو خود CSS بپرسید «آیا مرورگر این ویژگی رو پشتیبانی میکنه؟» و بر اساس جواب، استایل متفاوتی بدید.
سینتکس پایه
@supports (display: grid) {
.layout {
display: grid;
}
}
این کد میگه: «اگه مرورگر از display: grid پشتیبانی میکنه، این قوانین رو اعمال کن». شرط داخل پرانتز دقیقاً همون فرمت یه اعلان معمولی CSS (ویژگی و مقدار) رو داره، نه فقط اسم ویژگی بهتنهایی.
چرا باید ویژگی و مقدار رو با هم چک کرد، نه فقط اسم ویژگی؟
یه نکتهی مهم اینه که خیلی وقتها خود اسم ویژگی رو همهی مرورگرها میشناسن، ولی یه مقدار خاصش رو نه. مثلاً display که سالهاست وجود داره، ولی مقدار subgrid براش نسبتاً جدیده:
@supports (grid-template-rows: subgrid) {
.card {
grid-template-rows: subgrid;
}
}
اگه فقط مینوشتید @supports (grid-template-rows)، تقریباً همهی مرورگرها true برمیگردوندن، چون خود ویژگی رو میشناسن؛ ولی این به این معنی نیست که مقدار subgrid رو هم پشتیبانی میکنن. به همین خاطر همیشه باید جفت ویژگی-مقدار رو تست کنید، نه فقط اسم ویژگی.
not: تست برعکس
میتونید شرط رو برعکس هم بذارید؛ یعنی «اگه پشتیبانی نمیکنه»:
@supports not (aspect-ratio: 1 / 1) {
.video-wrapper {
padding-top: 56.25%;
}
}
این دقیقاً همون الگوی fallback هست که تو درس aspect-ratio بهش اشاره کردیم، ولی این بار بهجای نوشتن دستی دو خط پشت سر هم و امیدوار بودن که مرورگر قدیمی خط دوم رو نادیده بگیره، صریحاً میگید «فقط وقتی پشتیبانی نمیشه، این تریک قدیمی رو اجرا کن».
ترکیب چند شرط با and و or
میتونید چند شرط رو با and یا or ترکیب کنید:
@supports (display: grid) and (gap: 1rem) {
.layout {
display: grid;
gap: 1rem;
}
}
@supports (color: oklch(50% 0.1 250)) or (color: lch(50% 50 250)) {
.box {
color: oklch(50% 0.1 250);
}
}
تو مثال دوم، اگه مرورگر حداقل یکی از oklch یا lch رو پشتیبانی کنه، شرط برقرار میشه. برای گروهبندی شرطهای پیچیدهتر، میشه از پرانتز تو در تو هم استفاده کرد، دقیقاً مثل عبارتهای منطقی تو برنامهنویسی.
selector(): چک کردن پشتیبانی از یه selector خاص
یه نوع دیگه از @supports که کمتر شناختهشدهست، چک کردن پشتیبانی selector هاست، نه فقط ویژگیها:
@supports selector(:has(a)) {
.card:has(img) {
border: 2px solid gold;
}
}
این خیلی مهمه چون selector هایی مثل :has() نسبتاً جدید هستن، و ممکنه یه selector معتبر باشه ولی مرورگر هنوز نشناستش. بدون selector()، مرورگر قدیمیتر اون قانون CSS رو کاملاً نادیده میگیره (که خودش هم یه fallback ضمنیه)، ولی گاهی میخواید صریحاً یه رفتار جایگزین هم براش تعریف کنید.
چرا اصلاً لازمه از @supports استفاده کنیم؟ مگه مرورگر خودش ویژگی ناشناخته رو نادیده نمیگیره؟
این سؤال خیلی خوبیه و جواب کوتاهش «بله، ولی...» هست. مرورگر واقعاً هر declaration ناشناخته رو نادیده میگیره؛ پس چرا اصلاً به @supports نیاز داریم؟ مشکل اونجاست که گاهی میخواید یه ست کامل و هماهنگ از استایلها رو فقط وقتی اجرا کنید که یه ویژگی خاص پشتیبانی بشه، نه اینکه تکتک declaration ها بهصورت جدا نادیده گرفته بشن. مثلاً اگه بخواید کل layout یه بخش رو بر اساس grid یا subgrid عوض کنید، میخواید یه بلوک کامل CSS بهصورت یکجا فعال یا غیرفعال بشه، نه اینکه بعضی خطهاش اجرا بشه و بعضی نه و نتیجهی نهایی یه ترکیب ناقص و بههمریخته بشه.
@supports فقط پشتیبانی مرورگر از سینتکس رو چک میکنه، نه اینکه آیا اون ویژگی درست کار میکنه یا باگ داره. یعنی ممکنه یه مرورگر تکنیکی از یه ویژگی «پشتیبانی» کنه ولی پیادهسازیش باگدار باشه؛ تو این موارد @supports کمکی نمیکنه و باید جداگانه تست کنید.
اشتباه رایج: نوشتن مقدار نامعتبر داخل شرط
یه اشتباه رایج اینه که آدم فکر میکنه هر چیزی داخل پرانتز @supports بنویسه، همون رو تست میکنه؛ در حالی که مقدار داخل پرانتز باید خودش یه declaration کاملاً معتبر CSS باشه (ویژگی: مقدار). نوشتن چیزی مثل @supports (grid) بدون مقدار، یه شرط نامعتبره و معمولاً همیشه false برمیگرده یا رفتار غیرقابلپیشبینی داره.
جمعبندی
@supports اجازه میده بر اساس اینکه مرورگر یه ویژگی، مقدار، یا حتی یه selector خاص رو پشتیبانی میکنه یا نه، بلوکهای کامل CSS رو شرطی اجرا کنید. همیشه ویژگی و مقدار رو با هم تست کنید، نه فقط اسم ویژگی؛ از not برای تعریف صریح fallback استفاده کنید؛ و برای selector های جدید مثل :has() از selector() کمک بگیرید. این ابزار خصوصاً وقتی مهمه که میخواید یه ست کامل و هماهنگ از استایلها رو یکجا فعال یا غیرفعال کنید.
