|
| 1 | +<pre class='metadata'> |
| 2 | +Title: CSS Conditional Values Module Level 1 |
| 3 | +Shortname: css-conditional-values |
| 4 | +Level: 1 |
| 5 | +Status: UD |
| 6 | +ED: https://drafts.csswg.org/css-color-5/ |
| 7 | +Group: csswg |
| 8 | +Work Status: exploring |
| 9 | +Editor: Lea Verou, Invited Expert, http://lea.verou.me/about, w3cid 52258 |
| 10 | +Abstract: This module explores additions to CSS to enable conditional values. |
| 11 | +Repository: w3c/csswg-drafts |
| 12 | +Default Highlight: css |
| 13 | +Inline Github Issues: title |
| 14 | +Warning: Not Ready |
| 15 | +</pre> |
| 16 | + |
| 17 | +Introduction {#intro} |
| 18 | +===================== |
| 19 | + |
| 20 | + <em>This section is not normative.</em> |
| 21 | + |
| 22 | + Authors frequently need to set a property to different values based |
| 23 | + on the relation between certain values. |
| 24 | + |
| 25 | + For example, a web component may support several keyword-based custom properties |
| 26 | + and may want to set several different property values based on each keyword value. |
| 27 | + |
| 28 | + As another example, ... |
| 29 | + |
| 30 | + Note: TODO expand motivation |
| 31 | + |
| 32 | +Value Definitions {#values} |
| 33 | +--------------------------- |
| 34 | + |
| 35 | + This specification follows the <a href="https://www.w3.org/TR/CSS2/about.html#property-defs">CSS property definition conventions</a> from [[!CSS2]] |
| 36 | + using the <a href="https://www.w3.org/TR/css-values-3/#value-defs">value definition syntax</a> from [[!CSS-VALUES-3]]. |
| 37 | + Value types not defined in this specification are defined in CSS Values & Units [[!CSS-VALUES-3]]. |
| 38 | + Combination with other CSS modules may expand the definitions of these value types. |
| 39 | + |
| 40 | + In addition to the property-specific values listed in their definitions, |
| 41 | + all properties defined in this specification |
| 42 | + also accept the <a>CSS-wide keywords</a> as their property value. |
| 43 | + For readability they have not been repeated explicitly. |
| 44 | + |
| 45 | +Boolean data types {#boolean} |
| 46 | +============================== |
| 47 | + |
| 48 | +Boolean constants: ''true'' and ''false'' {#bool-constants} |
| 49 | +-------------------------------------------------------------- |
| 50 | + |
| 51 | +<pre class="prod def"> |
| 52 | + <dfn export><boolean-constant></dfn> = <dfn export>'true'</dfn> | <dfn export>'false'</dfn> |
| 53 | +</pre> |
| 54 | + |
| 55 | +Logical comparisons: The <<condition>> type |
| 56 | +--------------------------------------------- |
| 57 | + |
| 58 | +<pre class="prod def" nohighlight> |
| 59 | + <dfn export><condition></dfn> = not <<condition-in-parens>> |
| 60 | + | <<condition-in-parens>> [ and <<condition-in-parens>> ]* |
| 61 | + | <<condition-in-parens>> [ or <<condition-in-parens>> ]* |
| 62 | + <dfn export><condition-in-parens></dfn> = ( <<condition>> ) | <<atomic-condition>> |
| 63 | + <dfn export><atomic-condition></dfn> = <<comparison-operand>> <<comparison-operator>> <<comparison-operand>> | <<boolean-constant>> |
| 64 | + <dfn export><comparison-operand></dfn> = <<dimension>> | <<number>> | <<percentage>> | <<ident>> |
| 65 | + <dfn><comparison-operator></dfn> = [ '=' | '>=' | '>' | '<' | '<=' ] |
| 66 | +</pre> |
| 67 | + |
| 68 | +<<condition>> values are logical expressions that resolve to a <<boolean-constant>> |
| 69 | +by performing simple comparisons and following basic boolean operators. |
| 70 | +When using 'and' or 'or' operators, precedence must be enforced with parentheses. |
| 71 | +The ''not'' operator does not require this, and has higher precedence than ''and'' and ''or''. |
| 72 | + |
| 73 | +Both <<comparison-operand>> values in <<atomic-condition>> need to be of the same type. If they are not, the entire condition becomes an |
| 74 | +<dfn export>invalid condition</dfn> and evaluates as 'false'. |
| 75 | + |
| 76 | +Issue: Do we need a third, "invalid" state here? |
| 77 | + |
| 78 | +These operations are only defined on <a>computed values</a>. |
| 79 | +(As a result, it is not necessary to define, for example, |
| 80 | +how to compare a <<length>> value of ''15pt'' with ''5em'' |
| 81 | +since such values will be resolved to their <a>canonical unit</a> |
| 82 | +before being passed to any of the above procedures.) |
| 83 | + |
| 84 | +<div class=example> |
| 85 | + For example, ''5px > 4deg'' is an invalid condition because the first operand is a <<length>> and the second is an <<angle>>. |
| 86 | +</div> |
| 87 | + |
| 88 | +The host syntax defines how relative values (such as percentages or em units) are resolved in <<comparison-operand>>. |
| 89 | +When <<condition>> is used in a declaration, these relative values resolve against the declaration property. |
| 90 | + |
| 91 | +Note: Why are using '=' for equality and not ':' as is established in [[css-conditional-4]] already? |
| 92 | +Because a lot of third party code (syntax highlighters etc) assumes that colons separate declarations and would break. |
| 93 | + |
| 94 | +Issue: Do we need a "not equals" operator or is 'not(op1 = op2)' sufficient? |
| 95 | + |
| 96 | +Issue: How low level should this be? Do we need to define how logical operators work? |
| 97 | + |
| 98 | +The <<condition>> is resolved at computed value time, though its calculation tree may be simplified earlier. |
| 99 | + |
| 100 | +<div class=example> |
| 101 | + For example, ''(5px > 4px) and (1em = 2em)'' |
| 102 | + can be simplified to ''(true) and (false)'' |
| 103 | + and then to ''false'' at parse time |
| 104 | + and serialized as such. |
| 105 | +</div> |
| 106 | + |
| 107 | +<h4 id='condition-computed-value'> |
| 108 | +Computed Value</h4> |
| 109 | + |
| 110 | +The [=computed value=] of a <<condition>> value |
| 111 | +is its [=calculation tree=] [=simplified=], |
| 112 | +using all the information available at [=computed value=] time. |
| 113 | +(Such as the ''em'' to ''px'' ratio, |
| 114 | +how to resolve percentages etc.) |
| 115 | + |
| 116 | +Where percentages are not resolved at computed-value time, |
| 117 | +they are not resolved in <<condition>>. |
| 118 | + |
| 119 | +The [=calculation tree=] is again simplified at [=used value=] time; |
| 120 | +with [=used value=] time information, |
| 121 | +a <<condition>> always simplifies down to a single <<boolean-constant>>. |
| 122 | + |
| 123 | +Issue: Define these concepts for comparisons (currently they point to calc()) |
| 124 | + |
| 125 | +Inline conditionals: The ''if()'' function |
| 126 | +=========================================== |
| 127 | + |
| 128 | +The ''if()'' function allows authors to set a property value (or parts thereof) to different values based on certain conditions. |
| 129 | + |
| 130 | +<pre class="prod def"> |
| 131 | +<<if()>> = if( <<condition>>, <<if-true>> [, <<antecedent>>]) |
| 132 | +<<consequent>> = <<declaration-value>> |
| 133 | +<<antecedent>> = <<declaration-value>> |
| 134 | +</pre> |
| 135 | + |
| 136 | +<div class=example> |
| 137 | + Authors can write mini media queries by comparing viewport and absolute units: |
| 138 | + |
| 139 | + <pre>flex-flow: if(100vw > 500px, row, column);</pre> |
| 140 | +</div> |
| 141 | + |
| 142 | +When <<antecedent>> is omitted, it defaults to ' ' (empty value). |
| 143 | + |
| 144 | +<div class=example> |
| 145 | + This allows authors to use conditionals to toggle certain parts |
| 146 | + of a value and even "compose" a property value from a series of conditionals: |
| 147 | + |
| 148 | + <pre>background: if(var(--raised) = on, linear-gradient(white, transparent)) hsl(200 100% 50%);</pre> |
| 149 | +</div> |
| 150 | +<div class=example> |
| 151 | + This also allows authors to write multiple branches for the same value |
| 152 | + side by side instead of deeply nesting them: |
| 153 | + |
| 154 | + <pre> |
| 155 | + font-size: if(var(--size) = small, 2em) |
| 156 | + if(var(--size) = medium, 3em) |
| 157 | + if(var(--size) = large, 5em) |
| 158 | + </pre> |
| 159 | +</div> |
| 160 | + |
| 161 | +If after substitution of all ''if()'' values in a property value, |
| 162 | +the resulting declaration is invalid, |
| 163 | +the property containing the ''if()'' function is <a>invalid at computed-value time</a>. |
| 164 | + |
| 165 | +When ''if()'' is used in shorthands, it has the same |
| 166 | +<a href="../css-variables/#variables-in-shorthands">behavior</a> |
| 167 | +as the ''var()'' function, for the same reasons. |
| 168 | + |
| 169 | +Issue: How to disambiguate when used in a place where arguments are disambiguated by type? |
| 170 | +Unlike ''var()'', this cannot just be resolved at substitution, |
| 171 | +because we need to be able to interpret the values to compute the condition and perform the substitution accordingly. |
0 commit comments