CSS if(): Вградени условни изрази за по-интелигентно стилизиране

  • if() позволява условна логика върху CSS стойности със style(), media() и supports().
  • Оценявайте условията по ред; първото истинско връща стойността си, а в противен случай покрива останалите.
  • Идеално за промяна на свойство без отваряне на @media/@supports; използвайте резервни опции за съвместимост.
  • Комбинирайте с персонализирани свойства и атрибути на данни за по-автономни компоненти.

Какво представляват селекторите на атрибути в CSS

Години наред приемахме, че CSS не може да „мисли“. Въпреки това имахме заобиколни решения: @media, @supports, @container и резервни променливи Преди ни позволяваха да променяме стилове въз основа на контекста. Сега идва нова функция, която вдига летвата и по-добре се вписва в начина, по който разсъждаваме при проектиране: условната функция if() директно в стойностите на свойствата.

Това не е дим: Започвайки с Chrome 137, можете да тествате if() да създавате вградени стилове с условна логика, базирана на стил, медия и заявки за поддръжка. Поддръжката обаче все още е ограничена извън Chromium, така че е най-добре да я използвате разумно. комбинирането му с резервни варианти за браузъри, които не го разбират.

Какво имаше преди: „условни изрази“, които вече използвахме в CSS

Преди if(), CSS вече предлагаше условни механизми, всеки със собствен обхват. Те не са истински ако, но изпълняват на тяхната земя:

  • @mediaПрилага правила, ако прозорецът или устройството отговаря на критерий (ширина, ориентация, показалец и др.).
  • @поддържаАктивира стилове, ако браузърът разпознае функция или стойност.
  • @контейнер: реагира на размера или стила на контейнер, полезно за компонентно-базиран дизайн.
  • променлива() със стойност по подразбиране: не е if, но позволява „ако променливата не съществува, използвайте този резервен вариант“.

Тези подходи са мощни, въпреки че са „привързани“ към целта си: медии, подложки или контейнериФункцията if() не замества тези инструменти; по-скоро тя ги интегрира безпроблемно. интеркалирани и гранулирани в стойностите на имотите.

Какво е if() в CSS и защо е важно

уеб дизайн

Функцията ако() позволява ви да дефинирате, в рамките на стойност на свойство, списък от двойки условие:стойност, оценени по ред. Когато първото условие е вярно, свързаната с него стойност ще бъде тази, която „печели“. Това е поток, подобен на if…else на JS, но вграден в CSS.

В текущата си версия, if() разбира три типа заявки в рамките на своите условия: стил() (стилни заявки към самия елемент), средно() (медийни запитвания) и поддържа() (запитвания за поддръжка на функции). Освен това можете да добавите иначе: стойност за да покрие случая, когато нищо друго не е подходящо.

Подробен синтаксис и оценка

Общата структура е списък от клонове от тип, разделени с точка и запетая :Всяко условие е или (style(), media() или supports()) или ключовата дума още, което винаги се оценява като true.

/* Estructura básica */
propiedad: if(
  style(--estado: activo): valor-1;
  media(width < 700px): valor-2;
  supports(color: lch(60% 50 40)): valor-3;
  else: valor-por-defecto
);

Двигателят оценява клоновете по ред. Първият, който е верен, връща стойността сиАко никое условие не е вярно и няма друго, резултатът от функцията е гарантирано невалиден, което се държи като невалидна стойност и позволява външни резервни варианти влизат в действие (например, стойността по подразбиране на персонализирано свойство или каскадна предишна стойност).

Ключов детайл: ако условие или конкретна стойност в списъка е невалидна, не обезсилва цялата функция; парсерът продължава със следващата двойка. Това прави if() устойчив на едноточкови повреди в рамките на клоновете.

Типове тестове: style(), media() и supports()

style(): заявки за стил

Стил на заявките с стил() позволяват ви да попитате дали целевият елемент има определена стойност за дадено свойство (особено полезно с персонализирани свойства). За разлика от заявките в стил @container, стил() В if() се оценява върху самия елемент и незабавно, без да е необходимо да зависи от родител.

/* Estado embebido en una custom property */
.card {
  --status: attr(data-status type(<custom-ident>));
  border-color: if(
    style(--status: pending): royalblue;
    style(--status: complete): seagreen;
    else: gray
  );
  background-color: if(
    style(--status: pending): #eff7fa;
    style(--status: complete): #f6fff6;
    else: #f7f7f7
  );
}

Dentro de стил() Можете да използвате логически оператори намлява, or y не, плюс скоби за групиране, което улеснява сложни комбинации щати. Имайте предвид, че въпросите за стил на @контейнер днес те не поддържат „нормални“ свойства (само персонализирани), докато стил() вътре в if() Използва се за определяне на стойността на едно свойство на самия елемент.

media(): преплетени медийни заявки

Con средно() Можете да обусловите стойността на свойство със специфична медийна заявка, без да отделяте стила в друг @media блок. Това е идеално, когато просто искате да промените имот в зависимост от околната среда.

/* Ejemplo para puntero fino vs grueso */
button {
  aspect-ratio: 1;
  width: if(
    media(any-pointer: fine): 30px;
    else: 44px
  );
}

Този блок е еквивалентен на писането на базово правило плюс @media което предефинира собствеността, но концентрира логиката на едно място. Можете също да използвате видове медии (например, печат) или медийни функции с логика и/или/не.

/* Media type */
.elemento {
  background: if(
    media(print): white;
    else: #eee
  );
}

/* Media feature con rango */
.caja {
  margin: if(
    media(width < 700px): 0 auto;
    else: 20px auto
  );
}

Ако имате нужда промяна на много селектори или няколко свойства В същото време, традиционният блок @media е все още по-добър. За специфични вариации на едно твърдение, if() е по-изразителен.

supports(): заявки за поддръжка

Con поддържа() Питате дали браузърът разбира определена функция (свойство, стойност, селектор и т.н.) и избирате стойността съответно. Идеален за прогресивно подобрение без дублиране на блокове @supports.

/* Color de amplia gama si está soportado */
body {
  background-color: if(
    supports(color: oklch(0.7 0.185 232)): oklch(0.7 0.185 232);
    else: #00adf3
  );
}

/* Consulta de soporte de selector */
video {
  outline-width: if(
    supports(selector(:buffering)): 1em;
    else: initial
  );
}

Не забравяйте, че за клон с поддържа() вътре във функцията if(), самият браузър трябва поддръжка if()Оттук е важно да се дефинира солидни резервни варианти извън функцията.

Честота и позиция на друго

Можете да използвате едно или повече други във функцията и да ги поставите където пожелаете. Най-често срещаният начин обаче е да поставите един още в края като стойност по подразбиране. Ако сложите „else“ в началото, винаги ще печели и последващите условия няма да бъде оценяван.

/* Útil para depurar: colocamos un else intermedio */
.elemento {
  background-image: if(
    style(--flag: on): url("ok.png");
    else: url("debug.png"); /* si la primera no encaja, mostramos pista */
    supports(background: paint(foo)): paint(foo)
  );
}

Освен това, функция ако() съставен само от иначе: стойност, или дори празно, е синтактично валидно, макар и не много полезно. По-добре е стойността да се присвои директно ако няма логика.

Пълни, частични стойности и влагане

Функцията може да вземе цялата стойност на дадено свойство или само част от него в рамките на стенографияТова позволява много изразителни композиции, без да се отклонява от едно и също твърдение, с по-малко повторения на код.

/* Decidimos solo el color dentro de un shorthand */
.box {
  border: 2px solid if(
    supports(color: lch(60% 50 40)): lch(60% 50 40 / 0.7);
    else: rgb(100 120 200 / 0.7)
  );
}

функции ако() може да се вгнездява в други ако(), а също и в роли като изчисление ()Това позволява по-прецизно моделиране на решения без дублиране на селектори или отваряне на нови блокове.

/* Anidación doble: esquema y preferencia de color */
.elemento {
  color: if(
    style(--scheme: ice): if(
      media(prefers-color-scheme: dark): oklch(85% 0.04 220);
      else: oklch(35% 0.04 220)
    );
    style(--scheme: fire): if(
      media(prefers-color-scheme: dark): oklch(90% 0.1 30);
      else: oklch(40% 0.1 30)
    );
    else: black
  );
}

/* calc() con porcentaje condicionado */
.panel {
  width: calc(
    if(style(--scheme: wide): 70%; else: 50%) - 50px
  );
}

Можем също да използваме if(), за да решим свободни части от имот като горен марж в рамките на съкращение или специфичен фонов компонент, без да се дублира това, което не се променя.

Практически примери, преплетени

1) Достъпът на бутон зависи от вида на показалеца

Ако устройството има фина показалка (напр. мишка), бутонът ще бъде по-малък; на сензорните екрани сме го увеличили до 44px, за да отговорим на препоръките за достъпност. Едно твърдение, две поведения.

button {
  aspect-ratio: 1;
  width: if(
    media(any-pointer: fine): 30px;
    else: 44px
  );
}

Горното е еквивалентно на база + блок @media, но ето така не разпределяте логиката на множество сайтове и намаляват възможността за грешки.

2) Широка гама от цветове с резервен вариант

Ако браузърът разбира ОКЛЧ, използваме този цвят и, докато сме тук, показваме информативно съобщение в ::следВ противен случай прилагаме безопасен шестнадесетичен. Съвместимост без драма.

body {
  background-color: if(
    supports(color: oklch(0.7 0.185 232)): oklch(0.7 0.185 232);
    else: #00adf3
  );
}

body::after {
  content: if(
    supports(color: oklch(0.7 0.185 232)): "Tu navegador admite OKLCH";
    else: "Tu navegador no admite OKLCH"
  );
}

Ако искате да разгледате визуалната разлика между RGB и модерните пространства, разгледайте ресурси като oklch.comЩе видите защо си струва да осиновите тези пространства, когато има подкрепа.

3) Карти, които се променят според статуса на потребителския интерфейс

Съхранява състоянието в състояние на данните, прочетете го с attr() към персонализирано свойство и вземане на решения с него стил()Елегантен начин да самостоятелни компоненти.

<div class="card" data-status="complete">...</div>

.card {
  --status: attr(data-status type(<custom-ident>));
  border-color: if(
    style(--status: pending): royalblue;
    style(--status: complete): seagreen;
    else: gray
  );
  background-color: if(
    style(--status: pending): #eff7fa;
    style(--status: complete): #f6fff6;
    else: #f7f7f7
  );
}

С този модел, промяна на атрибута на данните в HTML променя множество свойства, без да докосва допълнителен CSS или JS, превключващ класове.

Иначе и ред на оценка: как if() мисли

Условията се оценяват в реда, в който се появяватПървото истинско връща стойността и оценката спира. Ако нито едно не е успешно, резултатът ще бъде гарантирано невалиден, което позволява външни резервни варианти (напр. каскадна предишна стойност или стойността по подразбиране на браузъра).

Можете също да поставите друго по средата За дебъгване: ако искате да знаете дали първото условие не работи, поставете else, който връща например изображение за „дебъгване“ и т.н. визуализирате проблема ясно.

Резервни варианти за браузъри без if()

if() не предизвиква магически автоматично деградиране: Нуждаете се от стойност на резервациятаПърво поставете безопасен за различни браузъри оператор, а след това версията на if(), която го отменя, когато се поддържа. Това е препоръчителният модел.

.box {
  padding: 16px; /* Fallback para navegadores sin if() */
  padding: if(
    style(--size: "2xl"): 24px;
    else: 16px
  );
}

По този начин, браузърите без if() ще използват първия ред; тези, които го поддържат, ще оценят втория и ще го замени.

Съвместимост и текущо състояние

програмиране

Според най-скорошната предоставена информация, Chrome 137 вече позволява тестване на if() и Edge в еквивалентната си версия наследява поддръжката. Други източници припомнят, че освен Chromium, имплементацията все още не е широко разпространено и че предложението ще продължи да се развива в рамките на W3C, така че е препоръчително да се запази реалистични очаквания.

Някои оценки говорят за около ~47% покритие засега (към момента на първоначалното му пускане). Моята препоръка е да го използвате в продукция само ако контролирате средата или ако вашата резервна стратегия е твърдо; в противен случай го нанасяйте на постепенни слоеве или в контролирана среда.

Връзка с @media, @supports и @container

Правилата if() и at се допълват, а не се изключват взаимно. @media или @supports са все още по-добри, когато искате прилагайте пълни набори от правила към множество свойства/селектори. if() е перфектен, когато имате нужда от точни решения относно една единствена стойност, запазвайки логиката, свързана с имота, което улеснява поддръжката.

В компонентно-ориентирания дизайн, дуото от @контейнер (за да се отговори на оформлението на контейнера) и ако() със стил() (за да се променят специфични свойства на самия компонент) отваря много мощни потоци и по-малко многословен.

Предложението @when и @else

В допълнение към if(), има предложения като например @when / @else които поставят условни изрази на ниво правило, със синтаксис, предназначен да четете по-добре сложни условия които, с обединените заедно @media и @supports, стават трудни за поддръжка.

@when media(width <= 600px) {
  .container { display: flex; flex-direction: column; }
}
@else {
  .container { display: flex; flex-direction: row; }
}

Можете да комбинирате и, или, не и използвайте скоби за групиране. В тривиални случаи е достатъчен @media, но в по-богати комбинации @when/@else придобива четивност.

@when media(width <= 600px) and supports(display: grid) {
  /* ... */
}
@else media(width >= 600px) and supports(display: flex) {
  /* ... */
}
@else {
  /* Fallback final */
}

Тези правила все още се развиват и реалното им прилагане може да отнеме време, но целта им е да опростяване на разширените условни предложения на ниво стилов лист.

Модели, ограничения и съвети

  • Поддържайте клоните подредени за вероятност и яснота. Първият верен вариант печели, така че сортирайте, имайки предвид производителността и четивността.
  • Употреба иначе окончателно като стойност по подразбиране; ако я зададете напред, съкращавате оценката от останалите условия.
  • Не забравяйте, че if() решава един имот наведнъжАко трябва да промените много неща наведнъж, помислете за @media/@supports или разделянето им на няколко оператора.
  • за отстраняване на грешки, добавете оператор else между тях с ярък цвят или предупредително изображение. Бързо ще видите кой клон не работи.
  • Комбинирайте с персонализирани свойства да експортирате състояния от HTML (data-attributes) или от други селектори и да определяте стойности без JS.
  • Избягвайте злоупотребата с много дълги верижни условни изрази; ако загубите четенето, е време да извличане на логика на друго място.

Бързо сравнение с „обичайното“

Преди: base + @media/@supports с пренаписвания; сега: ако() преплетени без разделяне на логиката. По-малко CSS, повече локална сплотеност в декларацията. Поддръжка на печалба.

Преди: JS за превключване на класове или състояния; сега: персонализирани свойства + стил() да се определят свойствата. С if() намалявате зависимостта от императивен код за прости визуални вариации.

Бележки за внедряване и бъдещи комбинации

Появата на if() съвпада с други линии на езиковата еволюция: стилови заявки по избор, възможно заявки за диапазон интегрирано в бъдещето и предложението за @функция за персонализирани функции. Заедно тези части привличат повече декларативни и композируеми.

Засега се съсредоточете върху трите налични теста (стил(), средно(), поддържа()) и затвърдете резервната си стратегия. С Chrome 137 вече можете да започнете прототип и измерване реалното въздействие върху вашата кодова база.

Идеята за „условни изрази в CSS“ се е превърнала от пожелателно мислене в конкретен инструмент, който, с някои нюанси, вече може да се използва в съвместими среди. С if() стиловете печелят... преплетена логика, по-малко повторения и по-добро капсулиране, и се съчетава перфектно с персонализирани променливи, атрибути на данни и медийни заявки. Въпреки че поддръжката му все още не е универсална, приемането на прогресивни модели и подготовката за резервни варианти ще ви позволи да започнете да се възползвате още днес от начин на мислене за CSS, който е по-близък до начина, по който проектираме интерфейси: вземане на решения точно там, където са приложими.