Усло­вия для CSS-пе­ре­мен­ных

Я нач­ну с того, что в спе­ци­фи­ка­ци­ях нет ни­че­го (Хотя и есть мо­дуль с на­зва­ни­ем “CSS Con­di­tional Rules”, не сто­ит ожи­дать, что он о CSS-пе­ре­мен­ных —в нём толь­ко вся­кое про at-rules. И, кста­ти, даже есть пред­ло­же­ние о @-пра­ви­лах @when/@else, ко­то­рые, опять же, ни­ка­ко­го от­но­ше­ния к пе­ре­мен­ным не име­ют.) про усло­вия для CSS-пе­ре­мен­ных. Я ду­маю, что это огром­ное упу­ще­ние, так как, хотя пе­ре­мен­ные уже предо­став­ля­ют кучу ве­щей, ко­то­рые невоз­мож­но до­стичь ины­ми сред­ства­ми, от­сут­ствие усло­вий очень удру­ча­ет, так как их очень мно­го для чего мож­но было бы ис­поль­зовать.

Но что, если бы нам за­хо­те­лось ис­поль­зо­вать эти во­об­ра­жа­е­мые несу­ще­ству­ю­щие услов­ные кон­струк­ции для пе­ре­мен­ных уже сей­час? Как и со мно­же­ством дру­гих ве­щей в CSS, в ка­ких-то слу­ча­ях мы мо­жем обой­тись и ха­ками.

Опре­де­ле­ние про­блемы

Итак, что нам нуж­но: воз­мож­ность при по­мо­щи един­ствен­ной CSS-пе­ре­мен­ной уметь за­да­вать раз­ные зна­че­ния для раз­ных CSS-свойств, при этом без того, что­бы эти зна­че­ния были ос­но­ва­ны на этой са­мой пе­ре­мен­ной (или дру­ги­ми сло­ва­ми —эти зна­че­ния не долж­ны вы­чис­лять­ся из на­шей пе­ре­мен­ной).

Нам нуж­ны усло­вия.

Исполь­зо­ва­ние вы­чис­ле­ний для би­нар­ных условий

Пе­рей­ду сра­зу к делу и при­ве­ду схо­ду ре­ше­ние, ко­то­рое уже поз­же объ­яс­ню, мо­же­те сна­ча­ла по­про­бо­вать сами по­нять что тут как ра­бо­тает:

:root {
    --is-big: 0;
}

.is-big {
    --is-big: 1;
}

.block {
    padding: calc(
        25px * var(--is-big) +
        10px * (1 - var(--is-big))
    );
    bor­der-width: calc(
        3px * var(--is-big) +
        1px * (1 - var(--is-big))
    );
}

В этом при­ме­ре мы за­став­ля­ем все наши эле­мен­ты с .block по­лу­чать пад­дин­ги рав­ные 10px и ши­ри­ны гра­ниц рав­ные 1px, до тех пор, пока зна­че­ние пе­ре­мен­ной --is-big на этих эле­мен­тах не ста­нет рав­ным 1, и в этом слу­чае зна­че­ния ста­нут 25px и 3px со­от­вет­ственно.

Ме­ха­низм под всем этим до­воль­но про­стой: мы ис­поль­зу­ем оба воз­мож­ных зна­че­ния в еди­ном вы­чис­ле­нии, ис­поль­зуя calc(), где мы об­ну­ля­ем одно зна­че­ние и остав­ля­ем дру­гое в за­ви­си­мо­сти от на­шей пе­ре­мен­ной, ко­то­рая мо­жет при­ни­мать одно из двух зна­че­ний: 1 или 0. Ины­ми сло­ва­ми, у нас там бу­дет 25px * 1 + 10px * 0 в од­ном слу­чае и 25px * 0 + 10px * 1 в другом.

Более слож­ные условия

Мы мо­жем ис­поль­зо­вать этот ме­тод не толь­ко для вы­бо­ра из двух воз­мож­ных зна­че­ний, но и для трёх или бо­лее. Прав­да, для каж­до­го но­во­го зна­че­ния слож­ность вы­чис­ле­ния уве­ли­чи­ва­ет­ся. Так, для трёх воз­мож­ных зна­че­ний, вы­чис­ле­ние ста­нет уже таким:

.block {
    padding: calc(
        100px * (1 - var(--foo)) * (2 - var(--foo)) * 0.5 +
         20px * var(--foo) * (2 - var(--foo)) +
          3px * var(--foo) * (1 - var(--foo)) * -0.5
    );
}

Тут это вы­чис­ле­ние при­ни­ма­ет три воз­мож­ных зна­че­ния для пе­ре­мен­ной --foo —0, 1 и 2, и вы­чис­ля­ет пад­динг рав­ный 100px, 20px или 3px со­от­вет­ственно.

Об­щий прин­цип тот же: нам нуж­но каж­дый воз­мож­ный ре­зуль­тат умно­жить на вы­ра­же­ние, да­ю­щее 1 для нуж­но­го зна­че­ния пе­ре­мен­ной и 0 для осталь­ных. И это вы­ра­же­ние со­став­ля­ет­ся так же про­сто: нам нуж­но об­ну­лять каж­дое иное воз­мож­ное зна­че­ние пе­ре­мен­ной. По­сле чего нам нуж­но под­ста­вить то зна­че­ние, ко­то­рое долж­но да­вать 1 в по­лу­чив­ше­е­ся вы­ра­же­ние и до­ба­вить мно­жи­тель для того, что­бы при­ве­сти-таки ре­зуль­тат к этой са­мой еди­нице.

Возмож­ная ло­вуш­ка в спе­ци­фи­ка­циях

С уве­ли­че­ни­ем слож­но­сти вы­чис­ле­ний по­яв­ля­ет­ся шанс, что они пе­ре­ста­нут ра­бо­тать. По­че­му? В спе­ци­фи­ка­ции есть та­кая вот за­мет­ка (в моём пе­ре­во­де):

Бра­у­зе­ры долж­ны под­дер­жи­вать calc()-вы­ра­же­ния, со­сто­я­щие как ми­ни­мум из 20 тер­ми­нов, где каж­дое ЧИС­ЛО, РАЗ­МЕР­НОСТЬ или ПРО­ЦЕНТ яв­ля­ет­ся тер­ми­ном. Если calc()- вы­ра­же­ние со­дер­жит боль­ше тер­ми­нов, чем под­дер­жи­ва­ет­ся, та­кое вы­ра­же­ние долж­но счи­тать­ся нева­лидным.

Ко­неч­но, я немно­го по­те­сти­ро­вал это дело и не смог най­ти по­доб­ных огра­ни­че­ний в су­ще­ству­ю­щих бра­у­зе­рах, но, так или ина­че, есть шанс, что если вы на­пи­ше­те до­ста­точ­но слож­ный код, то вы столк­нё­тесь с этим огра­ни­че­ни­ем, ну или ка­кие-то бра­у­зе­ры вполне мо­гут его в бу­ду­щем до­ба­вить, так что будь­те осто­рожны.

Усло­вия для цветов

Как мож­но уви­деть, та­кие вы­чис­ле­ния мо­гут ис­поль­зо­вать­ся толь­ко для тех ве­щей, ко­то­рые вы мо­же­те вы­чис­лить, так что не по­лу­чит­ся ис­поль­зо­вать это дело для пе­ре­клю­че­ния зна­че­ний свойств типа dis­play и ана­ло­гич­ных. Но что на­счёт цве­тов? На са­мом деле, мы мо­жем вы­чис­лять зна­че­ния от­дель­ных ком­по­нент цве­та. К со­жа­ле­нию, сей­час это бу­дет ра­бо­тать толь­ко в веб­ки­тах и блин­ках, а вот Fire­fox пока не под­дер­жи­ва­ет calc() внут­ри rgba() или дру­гих цве­то­вых функций.

Но ко­гда та­кая под­держ­ка по­явит­ся (ну или если вам за­хо­чет­ся по­экс­пе­ри­мен­ти­ро­вать над этим де­лом там, где оно уже ра­бо­та­ет), мы мо­жем де­лать вещи вро­де этой:

:root {
    --is-red: 0;
}

.block {
    back­ground: rgba(
        calc(
            255*var(--is-red) +
            0*(1 - var(--is-red))
            ),
        calc(
            0*var(--is-red) +
            255*(1 - var(--is-red))
            ),
        0, 1);
}

Тут у нас бу­дет по умол­ча­нию зе­лё­ный цвет, и крас­ный, если мы за­да­дим --is-red зна­че­ние 1 (сто­ит от­ме­тить, что если ка­кой-то ком­по­нент дол­жен быть ну­лём, то мы, оче­вид­но, мо­жем про­сто все его мно­же­те­ли опу­стить для бо­лее ком­пакт­ной за­пи­си, но тут я их оста­вил для луч­ше­го по­ни­ма­ния ал­го­рит­ма).

И, так как мы мо­жем вы­чис­лять лю­бые ком­по­нен­ты цве­та, мы мо­жем со­зда­вать для них наши услов­ные вы­чис­ле­ния (и, воз­мож­но, смо­жем де­лать их даже для гра­ди­ен­тов? Вам сто­ит это по­про­бо­вать!).

Оче­ред­ная ло­вуш­ка в спе­ци­фи­ка­циях

Ко­гда я те­сти­ро­вал как ра­бо­та­ют улов­ные вы­чис­ле­ния для цве­тов, я на­ткнул­ся на очень, очень стран­ное огра­ни­че­ние в спе­ци­фи­ки­ци­ях (Таб Ат­кинс рас­ска­зал о том, что эта про­бле­ма с ком­по­нен­та­ми цве­та была по­прав­ле­на в спе­ци­фи­ка­ци­ях (но ис­прав­ле­ние ещё не под­дер­жа­но бра­у­зе­ра­ми). Ура! Та­к­же он ска­зал, что есть ещё ре­ше­ние —ис­поль­зо­вать внут­ри rgba про­цен­ты, а я со­вер­шен­но о та­кой воз­мож­но­сти за­был, хаха.). Огра­ни­че­ние под на­зва­ни­ем «про­вер­ка ти­пов». Те­перь я её офи­ци­аль­но нена­ви­жу. Что это огра­ни­че­ние зна­чит —если ваше свой­ство при­ни­ма­ет толь­ко зна­че­ние с ти­пом <in­te­ger>, то если у вас внут­ри calc() бу­дут дроб­ные чис­ла или лю­бое де­ле­ние, то даже если в ре­зуль­та­те бу­дет га­ран­ти­ро­ва­но це­лое чис­ло, то так на­зы­ва­е­мый «re­solved type» бу­дет не <in­te­ger>, а <num­ber>, что, в свою оче­редь, не даст этим свой­ствам при­ни­мать это зна­че­ние как ва­лид­ное. А так как, если по­смот­реть выше, в на­ших услов­ных вы­ра­же­ни­ях с бо­лее чем дву­мя зна­че­ни­я­ми ока­жут­ся дроб­ные мо­ди­фи­ка­то­ры, то они сде­ла­ют наши вы­чис­ле­ния нева­лид­ны­ми, как для ком­по­нент цве­та, так и для дру­гих свойств, при­ни­ма­ю­щих толь­ко <in­te­ger> (на­при­мер, z-in­dex).

Вот та­кое вы­ра­жение:

calc(255 * (1 - var(--bar)) * (var(--bar) - 2) * -0.5)

Не бу­дет ва­лид­ным внут­ри rgba(). Из­на­чаль­но я даже ду­мал, что та­кое по­ве­де­ние —баг, осо­бен­но учи­ты­вая, что цве­то­вые функ­ции во­об­ще хо­ро­шо пе­ре­ва­ри­ва­ют вся­кие зна­че­ния, вы­хо­дя­щие за ра­зум­ные гра­ни­цы (вы вполне мо­же­те на­пи­сать rgba(9001, +9001, -9001, 42) и это даст вам ва­лид­ный жёл­тый цвет), но вот эта вот ти­пи­за­ция ока­зы­ва­ет­ся слиш­ком слож­но пе­ре­ва­ри­ва­е­мой для бра­у­зеров.

Возмож­ные ре­шения?

Есть одно до­воль­но да­лё­кое от иде­а­ла ре­ше­ние. Так как в на­шем слу­чае мы зна­ем и же­ла­е­мое зна­че­ние, и про­блем­ный мо­ди­фи­ка­тор с дро­бью, то мы мо­жем пред­вы­чис­лить их вме­сте и округ­лить пе­ред тем, как встав­лять в calc(). Да, во мно­гих слу­ча­ях по­лу­ча­е­мое зна­че­ние бу­дет чуть от­ли­чать­ся из-за по­те­ри в точ­но­сти. Но это же луч­ше, чем ни­че­го, ведь правда?

Хотя есть ещё одно ре­ше­ние, но ко­то­рое бу­дет ра­бо­тать толь­ко с цве­та­ми —мы мо­жем ис­поль­зо­вать hsla вме­сто rgba, так как в та­ком слу­чае внут­ри бу­дут не це­лые чис­ла, а то, что таки нор­маль­но пе­ре­жё­вы­ва­ет calc(). Но да, для свойств вро­де z-in­dex это не про­ка­тит. И даже для цве­тов всё рав­но воз­мож­ны неболь­шие по­те­ри в точ­но­сти если пе­ре­во­дить для это­го rgb в hsl. Но эти по­те­ри долж­ны быть мень­ше, чем в преды­ду­щем ре­шении.

Пре­про­цессинг

То­гда как для би­нар­ных усло­вий вполне ре­аль­но пи­сать вы­чис­ле­ния вруч­ную, для бо­лее слож­ных слу­ча­ев, или в слу­чае тех же цве­тов, нам бы при­го­ди­лись ин­стру­мен­ты, ко­то­рые бы поз­во­ли­ли де­лать это всё ав­то­ма­ти­че­ски. К сча­стью, у нас есть для это­го пре­про­цес­соры.

Вот как я ре­а­ли­зо­вал это быст­рень­ко на Стай­лу­се (Мож­но по­смот­реть на этот же код на Code­Pen in ac­tion.):

con­di­tional($var, $val­ues...)
  $re­sult = ''

  // If there is only an ar­ray passed, use its con­tents
  if length($val­ues) == 1
    $val­ues = $val­ues[0]

  // Val­i­dat­ing the val­ues and check if we need to do any­thing at all
  $type = null
  $equal = true

  for $value, $i in $val­ues
    if $i > 0 and $value != $val­ues[0]
      $equal = false

    $val­ue_­type = typeof($value)
    $type = $type || $val­ue_­type
    if !($type == 'unit' or $type == 'rgba')
      er­ror('Con­di­tional func­tion can ac­cept only num­bers or col­ors')

    if $type != $val­ue_­type
      er­ror('Con­di­tional func­tion can ac­cept only same type val­ues')

  // If all the val­ues are equal, just re­turn one of them
  if $equal
    re­turn $val­ues[0]

  // Han­dling num­bers
  if $type == 'unit'
    $re­sult = 'calc('
    $i_­count = 0
    for $value, $i in $val­ues
      $mul­ti­plier = ''
      $mod­i­fier = 1
      $j_­count = 0
      for $j in 0..(length($val­ues) - 1)
        if $j != $i
          $j_­count = $j_­count + 1
          // We could use just the gen­eral mul­ti­plier,
          // but for 0 and 1 we can sim­plify it a bit.
          if $j == 0
            $mod­i­fier = $mod­i­fier * $i
            $mul­ti­plier = $mul­ti­plier + $var
          else if $j == 1
            $mod­i­fier = $mod­i­fier * ($j - $i)
            $mul­ti­plier = $mul­ti­plier + '(1 - ' + $var + ')'
          else
            $mod­i­fier = $mod­i­fier * ($i - $j)
            $mul­ti­plier = $mul­ti­plier + '(' + $var + ' - ' + $j + ')'

          if $j_­count < length($val­ues) - 1
            $mul­ti­plier = $mul­ti­plier + ' * '

      // If value is zero, just don't add it there lol
      if $value != 0
        if $mod­i­fier != 1
          $mul­ti­plier = $mul­ti­plier + ' * ' + (1 / $mod­i­fier)
        $re­sult = $re­sult + ($i_­count > 0 ? ' + ' : '') + $value + ' * ' + $mul­ti­plier
        $i_­count = $i_­count + 1

    $re­sult = $re­sult + ')'

  // Han­dling col­ors
  if $type == 'rgba'
    $hues = ()
    $sat­u­ra­tions = ()
    $light­nesses = ()
    $al­phas = ()

    for $value in $val­ues
      push($hues, unit(hue($value), ''))
      push($sat­u­ra­tions, sat­u­ra­tion($value))
      push($light­nesses, light­ness($value))
      push($al­phas, al­pha($value))

    $re­sult = 'hsla(' + con­di­tional($var, $hues) + ', ' + con­di­tional($var, $sat­u­ra­tions) + ', ' + con­di­tional($var, $light­nesses) + ', ' + con­di­tional($var, $al­phas) +  ')'

  re­turn un­quote($re­sult)

Да, кода до­воль­но мно­го, но этот мик­син спо­со­бен ге­не­ри­ро­вать усло­вия как для чи­сел, так и для цве­тов, и не толь­ко для би­нар­ных усло­вий, но и для лю­бо­го чис­ла воз­мож­ных зна­че­ний в них.

Ис­поль­зо­ва­ние мик­си­на очень простое:

bor­der-width: con­di­tional(var(--foo), 10px, 20px)

Пер­вый ар­гу­мент —наша пе­ре­мен­ная, вто­рым ар­гу­мен­том бу­дет то зна­че­ние, ко­то­рое долж­но при­ме­нять­ся ко­гда пе­ре­мен­ная бу­дет рав­на 0, тре­тий ар­гу­мент —1, и т.д.

Вы­зов мик­си­на выше сге­не­рит вот та­кое услов­ное вы­ра­жение:

bor­der-width: calc(10px * (1 - var(--foo)) + 20px * var(--foo));

А вот бо­лее слож­ный при­мер с цве­тами:

color: con­di­tional(var(--bar), red, lime, re­bec­ca­pur­ple, or­ange)

Он сге­не­рит то, что вы точ­но не за­хо­ти­те пи­сать вручную:

color: hsla(calc(120 * var(--bar) * (var(--bar) - 2) * (var(--bar) - 3) * 0.5 + 270 * var(--bar) * (1 - var(--bar)) * (var(--bar) - 3) * 0.5 + 38.82352941176471 * var(--bar) * (1 - var(--bar)) * (var(--bar) - 2) * -0.16666666666666666), calc(100% * (1 - var(--bar)) * (var(--bar) - 2) * (var(--bar) - 3) * 0.16666666666666666 + 100% * var(--bar) * (var(--bar) - 2) * (var(--bar) - 3) * 0.5 + 49.99999999999999% * var(--bar) * (1 - var(--bar)) * (var(--bar) - 3) * 0.5 + 100% * var(--bar) * (1 - var(--bar)) * (var(--bar) - 2) * -0.16666666666666666), calc(50% * (1 - var(--bar)) * (var(--bar) - 2) * (var(--bar) - 3) * 0.16666666666666666 + 50% * var(--bar) * (var(--bar) - 2) * (var(--bar) - 3) * 0.5 + 40% * var(--bar) * (1 - var(--bar)) * (var(--bar) - 3) * 0.5 + 50% * var(--bar) * (1 - var(--bar)) * (var(--bar) - 2) * -0.16666666666666666), 1);

Сто­ит от­ме­тить, что у меня в мик­сине нет под­держ­ки тех мест, где при­ни­ма­ют­ся толь­ко <in­te­ger>, так что он мо­жет не ра­бо­тать для z-in­dex и про­чих. Но он уже кон­вер­ти­ру­ет цве­та в hsla(), что­бы с ними справ­лять­ся (хотя и это мож­но до­де­лать так, что­бы это про­ис­хо­ди­ло толь­ко то­гда ко­гда нуж­но, а не все­гда). Дру­гая вещь, ко­то­рую я не ре­а­ли­зо­вал (пока?) в этом мик­сине —воз­мож­ность про­ки­ды­вать в ка­че­стве зна­че­ний дру­гие CSS-пе­ре­мен­ные. Это вполне воз­мож­но для тех свойств, что при­ни­ма­ют не <in­te­ger>, так как их мож­но бу­дет про­сто под­став­лять в наши услов­ные вы­чис­ле­ния. Воз­мож­но, ко­гда-ни­будь я и най­ду вре­мя что­бы это до­де­лать. А пока мож­но для про­стых слу­ча­ев пи­сать эти вы­ра­же­ния вруч­ную сле­дуя ал­го­рит­му, опи­сан­но­му в этой статье.

Фол­беки

Ко­неч­но, если вы дей­стви­тель­но со­би­ра­е­тесь всё это дело ис­поль­зо­вать, вам по­на­до­бит­ся воз­мож­ность ис­поль­зо­вать фол­бе­ки. Для бра­у­зе­ров, не под­дер­жи­ва­ю­щих пе­ре­мен­ные, это про­сто —мож­но опре­де­лять де­кла­ра­цию с фол­бе­ком за­ранее:

.block {
    padding: 100px; /* fall­back */
    padding: calc(
        100px * ((1 - var(--foo)) * (2 - var(--foo)) / 2) +
         20px * (var(--foo) * (2 - var(--foo))) +
          3px * (var(--foo) * (1 - var(--foo)) / -2)
    );
}

Но вот ко­гда дело до­хо­дит до цве­тов, то по­яв­ля­ет­ся про­бле­ма: как толь­ко по­яв­ля­ют­ся пе­ре­мен­ные, то по фак­ту (и это оче­ред­ное очень стран­ное ме­сто в спе­ци­фи­ка­ци­ях), тупо лю­бая де­кла­ра­ция, в ко­то­рой есть CSS-пе­ре­мен­ные, ока­зы­ва­ет­ся ва­лид­ной. А это зна­чит, что не по­лу­чит­ся ис­поль­зо­вать фол­бек для чего-либо, где есть CSS-пе­ре­менные:

back­ground: blue;
back­ground: I 💩 CSS VAR(--I)ABLES;

Вот это вот —ва­лид­но со­глас­но спе­ци­фи­ка­ци­ям, фон бу­дет при­ни­мать своё ini­tial зна­че­ние, а фол­бек при­ме­нять­ся не бу­дет (даже если ну со­вер­шен­но оче­вид­но, что осталь­ные ча­сти зна­че­ния ну уж точ­но некор­рект­ны).

Так что, для того, что­бы предо­став­лять фол­бе­ки в по­доб­ных слу­ча­ях, нам надо бу­дет вос­поль­зо­вать­ся обёрт­кой с @sup­ports, в ко­то­рой мы бу­дем про­ве­рять под­держ­ку все­го кро­ме пе­ре­менных.

В на­шем слу­чае нам надо до­ба­вить та­кую обёрт­ку для Firefox:

.block {
    color: #f00;
}
@sup­ports (color: rgb(0, calc(0), 0)) {
    .block {
        color: rgba(calc(255 * (1 - var(--foo))), calc(255 * var(--foo)), 0, 1);
  }
}

Тут мы те­сти­ру­ем под­держ­ку вы­чис­ле­ний внут­ри цве­то­вых функ­ций, по­сле чего при­ме­ня­ем услов­ное вы­чис­ле­ние для цве­та внут­ри этой про­верки.

В прин­ци­пе, вполне воз­мож­но со­зда­вать та­кие фол­бе­ки ав­то­ма­ти­че­ски, но я бы не ре­ко­мен­до­вал ис­поль­зо­вать для это­го пре­про­цес­со­ры —слож­ность того, что для это­го нуж­но бу­дет де­лать уже пре­вы­ша­ет воз­мож­но­сти пре­про­цес­соров.

Сце­на­рии ис­поль­зо­вания

Я, прав­да, не люб­лю рас­пи­сы­вать сце­на­рии ис­поль­зо­ва­ния для ве­щей, необ­хо­ди­мость в ко­то­рых оче­вид­на. Так что я буду кра­ток. И да, я опи­шу сце­на­рии ис­поль­зо­ва­ния усло­вий не толь­ко для пе­ре­мен­ных, но и для вы­чис­ле­ний с по­мо­щью calc().

  • Усло­вия для CSS-пе­ре­мен­ных мо­гут быть иде­аль­ны для те­ма­ти­за­ции бло­ков. С их по­мо­щью мож­но иметь на­бор про­ну­ме­ро­ван­ных тем и по­том при­ме­нять их к бло­кам (и даже ко вло­жен­ным!) ис­поль­зуя толь­ко одну CSS-пе­ре­мен­ную типа --block-vari­ant: 1. Это то, что невоз­мож­но сде­лать чем-то кро­ме как пе­ре­мен­ны­ми, а если по­явит­ся необ­хо­ди­мость за­да­вать для темы раз­ные зна­че­ния для раз­ных свойств, то без усло­вий при­ш­лось бы за­да­вать це­лый на­бор раз­ных пе­ре­мен­ных каж­дый раз ко­гда хо­чет­ся при­ме­нить тему.

  • Ти­по­гра­фи­ка. Если бы была воз­мож­ность ис­поль­зо­вать срав­не­ния с <, <=, > и >=, то мож­но было бы со­здать на­бор «пра­вил» для раз­ных раз­ме­ров шриф­та, что­бы ав­то­ма­ти­че­ски под­би­рать вы­со­ту стро­ки, жир­ность и дру­гие свой­ства шриф­та в за­ви­си­мо­сти от ис­ход­но­го раз­ме­ра. Это и сей­час воз­мож­но, ко­неч­но, но не то­гда, ко­гда нуж­но иметь «шаги» для раз­ме­ров, а не про­сто зна­че­ния вы­чис­лен­ные из em-ов.

  • Адап­тив­ный ди­зайн. Ну, если бы были пол­но­цен­ные усло­вия для вы­чис­ле­ний, то это было бы по­чти что теми са­мы­ми «el­e­ment queries» —мож­но было бы смот­реть на vw или ши­ри­ну ро­ди­те­лей и ре­шать ка­кие зна­че­ния при­ме­нять в ка­ком случае.

На­вер­ня­ка есть и дру­гие сце­на­рии ис­поль­зо­ва­ния для усло­вий, рас­ска­жи­те если при­ду­ма­е­те! Я сам, уве­рен, на­ты­кал­ся на мно­же­ство из них, но, так как у меня очень пло­хая па­мять, то я не за­по­ми­наю всё-всё, что я хочу де­лать с CSS. По­то­му что я хочу де­лать всё.

Будущее

Я бы очень хо­тел уви­деть усло­вия для CSS-пе­ре­мен­ных в спе­ци­фи­ки­ци­ях CSS, так что­бы нам не при­хо­ди­лось при­бе­гать к ха­кам и мы мог­ли бы ис­поль­зо­вать усло­вия и для невы­чис­ля­е­мых зна­че­ний. Ну и даже с ха­ка­ми пока невоз­мож­но ис­поль­зо­вать усло­вия кро­ме как стро­го­го ра­вен­ства, так что ни­ка­ких нам «если пе­ре­мен­ная боль­ше, чем X» и по­доб­ных ве­щей. Я не вижу при­чин по­че­му в CSS нель­зя до­ба­вить пол­но­цен­ные усло­вия, так что если вы зна­ко­мы с кем-то, кто раз­ра­ба­ты­ва­ет спе­ци­фи­ка­ции CSS —вы им на­мек­ни­те там. Я толь­ко на­де­юсь, что нам не от­ве­тят что-то вро­де «про­сто ис­поль­зуй­те JS» и не ста­нут де­лать пред­по­ло­же­ния о том, по­че­му это в прин­ци­пе невоз­мож­но. Да вот же, оно уже воз­мож­но, пус­кай и с ха­ка­ми. Не мо­жет быть ни­ка­ких оправ­даний.