София Валитова, ВКонтакте
CSS иногда работает не так, как я ожидаю
height: calc(3px+4px)
height: calc(3px - 4px)
height: calc(25% - 0)
CSS иногда работает не так, как я ожидаю
height: calc(3px+4px)
height: calc(3px - 4px) // => 0px
height: calc(25% - 0)
Посмотрим в спецификацию и пойдем гуглить статьи с примерами
Если определять интуитивно, то вот так:
Но давайте попробуем более формально.
<style-rule> ::=
<selectors-list> { <properties-list> }
<selectors-list> ::=
<selector>[':' <pseudo-class>] ['::' <pseudo-element>]
[',' <selectors-list>]
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
Попробуем описать грамматику отрицательных чисел от -1 до -9:
<neg_num> ::= "-" <num>
<num> ::= "1" | "2" | "3" | "4" | "5" |
| "6" | "7" | "8" | "9"
Попробуем описать грамматику отрицательных чисел от -1 до -9:
<neg_num> ::= "-" <num>
<num> ::= "1" | "2" | "3" | "4" | "5" |
| "6" | "7" | "8" | "9"
Попробуем описать грамматику отрицательных чисел от -1 до -9:
<neg_num> ::= "-" <num>
<num> ::= "1" | "2" | "3" | "4" | "5" |
| "6" | "7" | "8" | "9"
Сложение отрицательных чисел:
<add_expr> ::= <neg_num> "+" "(" <neg_num> ")"
Попробуем описать грамматику отрицательных чисел от -1 до -9:
<neg_num> ::= "-" <num>
<num> ::= "1" | "2" | "3" | "4" | "5" |
| "6" | "7" | "8" | "9"
Сложение отрицательных чисел:
<add_expr> ::= <neg_num> "+" "(" <neg_num> ")"
Попробуем описать грамматику отрицательных чисел от -1 до -9:
<neg_num> ::= "-" <num>
<num> ::= "1" | "2" | "3" | "4" | "5" |
| "6" | "7" | "8" | "9"
Сложение отрицательных чисел:
<add_expr> ::= <neg_num> "+" "(" <neg_num> ")"
| "text" или 'text' | терминал |
| <A> | нетерминал |
| <A> ::= <B> | <A> заменимо на <B> |
| <A> <B> | конкатенация |
| <A> | <B> | один из элементов |
| integer | имя класса нетерминалов, описывается не через BNF |
<expression> ::= <add_expr>
<add_expr> ::= <mul_expr> '+' <add_expr>
| <mul_expr> '-' <add_expr>
| <mul_expr>
<mul_expr> ::= integer '*' <mul_expr>
| integer '/' <mul_expr>
| integer '%' <mul_expr>
| integer
integer ::= [0-9]+ <- класс нетерминалов
<expression> ::= <add_expr>
<add_expr> ::= <mul_expr> '+' <add_expr>
| <mul_expr> '-' <add_expr>
| <mul_expr>
<mul_expr> ::= integer '*' <mul_expr>
| integer '/' <mul_expr>
| integer '%' <mul_expr>
| integer
integer ::= [0-9]+
<expression> ::= <add_expr>
<add_expr> ::= <mul_expr> '+' <add_expr>
| <mul_expr> '-' <add_expr>
| <mul_expr>
<mul_expr> ::= integer '*' <mul_expr>
| integer '/' <mul_expr>
| integer '%' <mul_expr>
| integer
integer ::= [0-9]+
<expression> ::= <add_expr>
<add_expr> ::= <mul_expr> '+' <add_expr>
| <mul_expr> '-' <add_expr>
| <mul_expr>
<mul_expr> ::= integer '*' <mul_expr>
| integer '/' <mul_expr>
| integer '%' <mul_expr>
| integer
integer ::= [0-9]+
<expression> ::= <add_expr>
<add_expr> ::= <mul_expr> '+' <add_expr>
| <mul_expr> '-' <add_expr>
| <mul_expr>
<mul_expr> ::= integer '*' <mul_expr>
| integer '/' <mul_expr>
| integer '%' <mul_expr>
| integer
integer ::= [0-9]+
<expression> ::= <add_expr>
<add_expr> ::= <mul_expr> '+' <add_expr>
| <mul_expr> '-' <add_expr>
| <mul_expr>
<mul_expr> ::= integer '*' <mul_expr>
| integer '/' <mul_expr>
| integer '%' <mul_expr>
| integer
integer ::= [0-9]+
<expression> ::= <add_expr>
<add_expr> ::= <mul_expr> [ ('+' | '-') <add_expr> ]
<mul_expr> ::= integer [ ('*' | '/' | '%') <mul_expr> ]
integer ::= [0-9]+
<mul_expr> ::= integer '*' <mul_expr>
| integer '/' <mul_expr>
| integer '%' <mul_expr>
| integer
<add_expr> ::= <mul_expr> '+' <add_expr>
| <mul_expr> '-' <add_expr>
| <mul_expr>
| [<A>] | условное вхождение |
| (<A> | <B>) <C> | группировка |
| {<A>} | повторение элемента (0 или более раз) |
<style-rule> ::=
<selectors-list> '{' <properties-list> '}'
<selectors-list> ::=
<selector>[':' <pseudo-class>] ['::' <pseudo-element>]
[',' <selectors-list>]
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
<style-rule> ::=
<selectors-list> '{' <properties-list> '}'
.class#id {
height: initial;
width: 100%;
}
<style-rule> ::=
<selectors-list> '{' <properties-list> '}'
.class#id }
height: initial;
width: 100%;
}
<style-rule> ::=
<selectors-list> '{' <properties-list> '}'
.class#id {
height: initial;
width: 100%;
}
<style-rule> ::=
<selectors-list> '{' <properties-list> '}'
.class#id {
height: initial;
width: 100%;
}
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
.class#id {}
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
.class#id {
height: initial
}
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
.class#id {
height: initial
}
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
.class#id {
height: initial
}
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
.class#id {
height: initial
}
<properties-list> ::=
[<property> ':' <value>] [';' <properties-list>]
.class#id {
height: initial;
width: 100%
}
.class {
height: initial;
width: 100%;
border-width: 2px medium 4px;
box-shadow: rgba(0,0,0,0.4) 10px 10px inset;
margin: 0 -7px 0 2px;
transition: opacity .2s ease, visibility .2s ease;
}
margin: 0 -7px 0 2px;
0 -7px 0 2px - 4 токена <length>
<margin> ::= "auto"
| <length>
| <length> {" "} <length>
| <length> {" "} <length> {" "} <length>
| <length> {" "} <length> {" "} <length> {" "} <length>
initial
<length>
<'background-attachment'>
| [<A> | <B>] <C> | группировка |
| <A> || <B> || <C> | один или более из группы в заданном порядке |
| <A> && <B> && <C> | один или более из группы в любом порядке |
| <A>* | ноль или более раз |
| <A>+ | один или более раз |
| <A>? | необязательный |
| <A> {n} | А повторяется n раз |
| <A> {n, m} | А повторяется не меньше n раз и не больше m раз |
| <A># | один или более раз, разделенные запятыми |
<'margin'> ::= "auto" | <length>{1, 4}
<'line-height'> ::=
normal | <number> | <length> | <percentage>
<'font-family'> =
[ <family-name> | <generic-family> ]#
<'border-width'> =
[ <length> | thick | medium | thin ]{1,4}
border-width: 3px;
border-width: thick;
border-width: medium thick;
border-width: 8em thick;
<'text-shadow'> =
[ inset? [ <length>{2,4} <color>? ]# ] | none
text-shadow: none;
text-shadow: 1px 1px 2px black;
text-shadow: inset 1px 1px 2px black;
text-shadow: inset 1px 1px 2px black,
0 0 1em red, 0 3vw green;
CSS иногда работает не так, как я ожидаю
height: calc(3px+4px)
height: calc(3px - 4px) // => 0px
height: calc(25% - 0)
calc(50%-2em);
calc(50% - 2em); // => <length> '-' <length>
calc(50% -2em); // => <length> <length>
calc(50% - -2em);
calc(50% - (-2em));
CSS иногда работает не так, как я ожидаю
height: calc(3px+4px)
height: calc(3px - 4px) // => 0px
height: calc(25% - 0)
Нельзя использовать в одном выражении несовместимые типы
calc(5px + 10s) // => <length> '+' <time>
calc(5deg / 5em) // => <angle> '/' <length>
calc(5px - 5) // => <length> '-' <number-token>
calc(5px - 0) // => <length> '-' <number-token>
CSS иногда работает не так, как я ожидаю
height: calc(3px+4px)
height: calc(3px - 4px) // => 0px
height: calc(25% - 0)
height: -12px
height: calc(-12px) // => 0px
Проверка соответствия значения свойства его грамматике
Проверка соответствия значения свойства его грамматике
Проверка соответствия значения свойства его грамматике
Проверка соответствия значения свойства его грамматике
height : <length>[0,∞] | auto | <percantage>
* Negative values for 'height' are illegal.
height: -12px // => auto
height: calc(-12px) // => 0px
Проводится перед каскадом
height: -12px // => auto
height: calc(-12px) // => 0px
height: -12s // => auto
height: calc(-12s) // => auto
Проверка финального типа, но не диапазона
height: calc(-12px);
// => 0px при обращении
height: calc(-12px);
// => 0px при обращении
Разные ситуации:
height: -12px;
// property syntax check
height: calc(-12px);
// calc range check
height: 100px; // => 100px
height: 50%; // => 50px
height: inherit; // 25px
height: 100px; // => 100px
height: calc(50% - 25px); // => 25px
height: inherit; // => calc(50% - 25px) => 0px
CSS иногда работает не так, как я ожидаю
height: calc(3px+4px)
height: calc(3px - 4px) // => 0px
height: calc(25% - 0)
#el {
background-color: red;
animation: anim infinite 3s;
}
@keyframes anim {
50% { background-color: blue; }
}
#el {
--color-stop: red;
background: var(--color-stop);
animation: anim infinite 3s;
}
@keyframes anim {
50% { --color-stop: blue; }
}
Потому что изначально CSS-переменные не типизированы
div {
--name: red;
--name: 11px;
--name: calc(14deg * 3);
}
#el {
--color-stop: red;
margin: 50px;
animation: anim infinite 3s;
}
@keyframes anim {
50% { --color-stop: 10px;
margin: var(--color-stop); }
}
Браузер не знает, как построить переход от одного значения к другому
red => ??? => blue
red => ??? => 10px
CSS.registerProperty({
name: '--color-stop',
syntax: '<color>',
inherits: false,
initialValue: 'transparent'
})
#el {
--color-stop: red;
background: var(--color-stop);
animation: anim infinite 3s;
}
@keyframes anim {
50% { --color-stop: blue; }
}
const height = CSS.px(2);
elem.attributeStyleMap.set("height", height);
elem.attributeStyleMap.get("height"); // =>
// CSSUnitValue {value: 2, unit: "px"}
Презентация сделана с помощью Shower