CSS — язык программирования

Никита Дубко, Яндекс

CSS — язык программирования

Никита Дубко, разработчик интерфейсов

Кто я?

Дисклеймер

Целью доклада не является разжигание возмущения, горение седалищ и оскорбление чувств программистов. Докладчик не собирается заканчивать спикерскую карьеру таким изысканным способом. Любое нарушение мировосприятия после этого доклада целиком и полностью на совести самого слушателя. Если это кто-то ещё читает, интересный факт: люди не чихают во сне. И вы прямо сейчас видите свой нос.

CSS 🆚 JS

2009

cdtcha.narod.ru

CSS + HTML = ❤️

CSS + HTML = 💰

2019

«Я программист,
CSS пусть верстальщики пишут»
(c) Кто-то в Интернете

Is CSS a programming language?
Алексей Охрименко – CSS и HTML — это язык программирования
Lara Schenck | Algorithms in CSS | CSS Day 2019

CSS

Как попасть на FrontendConf?

Императивный подход Декларативный подход
  1. Выйти из дома.
  2. Доехать до аэропорта.
  3. Пройти регистрацию на рейс.
  4. ...
  5. Выйти из аэропорта.
  6. Поймать такси до места проведения.
  7. ...
  8. Получить беджик участника.
  9. Занять место в одном из 3 залов.
Digital October (Берсеневская Набережная, 6 ст.3, 4 этаж),
13 и 14 октября

Разместить элемент по центру

// псевдокод
var container = getContainer();
var containerSize = container.getSize();
var containerPosition = container.getPosition();

var element = getElement();
var elementSize = element.getSize();

var x = (containerSize.width - elementSize.width) / 2;
var y = (containerSize.height - elementSize.height) / 2;

element.setPosition(
    containerPosition.x + x,
    containerPosition.y + y
);

Разместить элемент по центру

.container {
    display: flex;
    justify-content: center;
    align-items: center;
}

CSS — декларативный ✅

Предметно-ориентированный язык (англ. domain-specific language, DSL — «язык, специфический для предметной области») — язык программирования, специализированный для конкретной области применения (в противоположность языку общего назначения, применимому к широкому спектру областей и не учитывающему особенности конкретных сфер знаний).

ru.wikipedia.org/wiki/Предметно-ориентированный_язык

CSS — DSL ✅

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

ru.wikipedia.org/wiki/Высокоуровневый_язык_программирования
clip-path: circle(25%);
class ClipPath final : public Longhand {
  public:
    constexpr ClipPath() : Longhand(CSSPropertyID::kClipPath, kInterpolable | kProperty, '\0') { }
    const char* GetPropertyName() const override;
    const WTF::AtomicString& GetPropertyNameAtomicString() const override;
    const char* GetJSPropertyName() const override;
    const CSSValue* ParseSingleValue(
        CSSParserTokenRange&,
        const CSSParserContext&,
        const CSSParserLocalContext&
    ) const override;
    const CSSValue* CSSValueFromComputedStyleInternal(
        const ComputedStyle&,
        const SVGComputedStyle&,
        const LayoutObject*,
        bool allow_visited_style
    ) const override;
    void ApplyInitial(StyleResolverState&) const override;
    void ApplyInherit(StyleResolverState&) const override;
    void ApplyValue(StyleResolverState&, const CSSValue&) const override;
};
chromium//src/out/Debug/gen/third_party/blink/renderer/core/css/properties/longhands.h
display: grid;

Полифил:
6684 строчки JS-кода 😱

github.com/FremyCompany/css-grid-polyfill-binaries

Высокоуровневый? 🤷‍♂️

Критерии Тьюринг-полноты

CSS — Тьюринг-полный ❌

Accidentally Turing-Complete

Правило 1️⃣1️⃣0️⃣

Rule 110
How is the rule 110 Turing complete?
Universality in Elementary Cellular Automata

Rule 110
in CSS/HTML/Human

input:not(:checked) + input:checked + input:checked
+ * + * + * + * + * + * + * + * + * + * + *
+ * + * + * + * + * + * + * + * + * + * + * {
    --cell-bg-color: hotpink;
    --cell-num-color: white;
    --cell-content: "X";
    --cell-cursor: pointer;
}

HTML + CSS —
Тьюринг-полный ✅

Язык программи́рования — формальный язык, предназначенный для записи компьютерных программ. Язык программирования определяет набор лексических, синтаксических и семантических правил, определяющих внешний вид программы и действия, которые выполнит исполнитель (обычно — ЭВМ) под её управлением.

ru.wikipedia.org/wiki/Язык_программирования

Компью́терная програ́мма
1) комбинация компьютерных инструкций и данных, позволяющая аппаратному обеспечению вычислительной системы выполнять вычисления или функции управления (стандарт ISO/IEC/IEEE 24765:2010);
2) синтаксическая единица, которая соответствует правилам определённого языка программирования, состоящая из определений и операторов или инструкций, необходимых для определённой функции, задачи или решения проблемы (стандарт ISO/IEC 2382-1:1993)

ru.wikipedia.org/wiki/Компьютерная_программа

Задача: разместить элемент по центру контейнера.

Инструкции:

.center {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

CSS — язык программирования ✅

Спасибо за внимание!

CSS Algorithms

Что с этим делать?

Программирование
⬇️
CSS

Мы — программисты прямоугольников! 💪

Лайфхак 1.
Принцип единой ответственности

border-style: SOLID

Плохо ❌

.promo {
    display: block;
    padding: 20px;
    margin-bottom: 20px;
    background-color: #09f;
    color: #fff;
    text-shadow: 0 0 1px rgba(0,0,0,0.25);
    border-radius: 4px;
}
The single responsibility principle applied to CSS

Хорошо ✅

.island {
    display: block;
    padding: 20px;
    margin-bottom: 20px;
}

.promo {
    background-color: #09f;
    color: #fff;
    text-shadow: 0 0 1px rgba(0,0,0,0.25);
    border-radius: 4px;
}
The single responsibility principle applied to CSS
ru.bem.info

Лайфхак 2.
Разработка через тестирование

TDD

Скорость разработки 😃

Технический долг 💩

Лайфхак 3.
Тестирование вёрстки

Hermione

npm install -g hermione
Тестируем пользовательские сценарии вместе с «Гермионой»

Лайфхак 4.
Заглушки

Процесс написания CSS-алгоритмов
Hello Houdini: Placeholder Box

Лайфхак 5.
Переиспользование кода

@mixin block($w, $h, $d, $x, $y, $z, $color, $angle: '0, 0, 0, 0') {
    transform: translate3d($x, $y, $z) rotate3d(#{$angle});
    will-change: transform;

    .front { @include front($w, $h, $d, $color); }
    .back { @include back($w, $h, $d, $color); }
    .right { @include right($w, $h, $d, darken($color, 10%)); }
    .left { @include left($w, $h, $d, darken($color, 10%)); }
    .top { @include top($w, $h, $d, darken($color, 5%)); }
    .bottom { @include bottom($w, $h, $d, darken($color, 5%)); }
}
#DailyCssImages - Day 17. Zombie

Лайфхак 6.
Вычисления

:root {
    --r: 255;
    --g: 20;
    --b: 147;
    --primary-color: rgb(var(--r), var(--g), var(--b));
}

.my-element {
    --e-width: 200px;
    --e-border-width: 20px;
    background-color: var(--primary-color);
    width: calc(var(--e-width) + var(--e-border-width));
}
<div class="one two">I have 40px margin</div>

:root {
    --root-offset: 20px;
}
.one {
    --offset: 40px;
}
.two {
    margin: var(--offset, var(--root-offset, 30px));
}
CSS Custom Properties in Depth
<div class="two">I have 20px margin</div>

:root {
    --root-offset: 20px;
}
.one {
    --offset: 40px;
}
.two {
    margin: var(--offset, var(--root-offset, 30px));
}
DRY Switching with CSS Variables: The Difference of One Declaration
Animated ☯ with CSS variables (WebKit only)

Логическое И

.animal {
    --has-mustache: 1;
    --has-paws: 1;
    --has-tail: 1;

    --has-documents: calc(
        var(--has-mustache, 0) *
        var(--has-paws, 0) *
        var(--has-tail, 0)
    );
}

Логическое НЕ

.language {
    --undefined-is-not-a-function: 1;

    --is-js: var(--undefined-is-not-a-function, 0);
    --is-css: calc(
        1 - var(--is-js)
    );
}

Логическое ИЛИ

.human {
    --can-frontend: 1;
    --can-backend: 0;

    --is-developer: calc(
        var(--can-frontend) * var(--can-backend) +
        var(--can-frontend) * (1 - var(--can-backend)) +
        (1 - var(--can-frontend)) * var(--can-backend)
    );
}

Метод Квайна



⬇️

ru.wikipedia.org/wiki/Метод_Куайна

Логическое ИЛИ

.human {
    --can-frontend: 1;
    --can-backend: 0;

    --is-developer: calc(
        var(--can-frontend) +
        (1 - var(--can-frontend)) * var(--can-backend)
    );
}

Логическое ИЛИ с хаком

.human {
    --can-frontend: 1;
    --can-backend: 0;

    --is-developer: clamp(
        0,
        calc(var(--can-frontend) + var(--can-backend)),
        1)
    );
}
clamp()

clamp()

width: clamp(10px, 4em, 80px);
width: max(10px, min(4em, 80px));
max()

max()

Логическое ИЛИ через И и НЕ

.human {
    --can-frontend: 1;
    --can-backend: 0;

    /* not (A or B) = (not A) and (not B) */
    --is-developer: calc(1 -
        (1 - var(--can-frontend)) * (1 - var(--can-backend))
    );
}
clamp()
Logical Operations with CSS Variables
Rule 110

Rule 110 for CSS+HTML

😎

[css-values] Trigonometric functions
[css-values] Trigonometric functions
drafts.csswg.org/css-values/#math

Лайфхак 7.
Дебаг

Хороший алгоритм решения проблемы

  1. воспроизвести проблему;
Отладка CSS в боевых условиях, Никита Дубко

Лайфхак 8.
Знание языка

Как хорошо вы знаете CSS? 👨🏼‍🏫

Даны следующие классы:

.red { color: red; }
.blue { color: blue; }

Какого цвета должны быть эти дивы?

<div class="red blue">
<div class="blue red">
twitter.com/mxstbr/status/1038073603311448064 Twitter War Facepalm
twitter.com/marinintim/status/1159505600742641666
cssbattle.dev
<b style="background: #0B2429;
          color: #F3AC3C;
          zoom: 200;
          left: -5.59px;
          top: -8.3px;
          position: absolute">k

Опасные свойства для анимаций ❌

csstriggers.com

Нейтральные свойства ⚠️

Безопасные свойства ✅

CSS на GPU ⚡️

CSS loader 🐛
dotCSS 2017 - Tim Carry - Building a search engine in CSS

A search engine in CSS
demo

#input[value='l'i] ~ #results #result55,
#input[value='la'i] ~ #results #result55,
#input[value='lau'i] ~ #results #result55,
#input[value='laur'i] ~ #results #result55,
#input[value='laura'i] ~ #results #result55 {
    display: block;
}
#option[id]:checked ~ #results #result12,
#option[id]:checked ~ #results #result55 {
    display: block;
}
twitter.com/jon_neal/status/1158804042870677506
body {
    font-family: sans-serif;
}
h1, p {
    font-family: "no-parens", sans-serif;
}

/* https://github.com/adobe-fonts/adobe-blank */
@font-face {
    font-family: no-parens;
    src: url("...");
    unicode-range: U+0028, U+0029; /* () */
}
Removing parentheses in pure CSS
browserhacks.com

Лайфхак 9.
Следить за новостями

Houdini 🔮

twitter.com/csshoudini
Proposal: Custom functions for modifying CSS values
CSS.registerComputedValueHook({
    inputProperties: ["transform", "--slide-*"],
    outputProperties: ["transform"],
    computedValue: function(input, output) {
        const tx = input.get("--slide-x");
        const ty = input.get("--slide-y");
        const translate = new CSSTranslate(tx, ty);
        output.set("transform",
            new CSSTransformValue(
                translate,
                ...input.get('transform')
            )
        );
    }
});
CSS and Houdini
CSS.registerFunction({
    "name": "--darken",
    "inputArguments": ["<color>", "<percentage>"],
}, (color, percent) => {
    const newColor = color.toHSL();
    newColor.lightness *= (1 - percent.value/100);
    return newColor;
});

.element {
    color: --darken(tomato, 12%);
}
CSS and Houdini
CSS.registerFunction(
    {
        "name": "--random",
        "per": "element",
    },
    () => CSS.number(Math.random())
);

JS-in-CSS 👀

CSS Properties and Values
API

:root {
    --sidebar-width: 400px;
}

.closed {
    --sidebar-width: 80px;
}

body {
    transition: --sidebar-width 1s;
}
// JavaScript
CSS.registerProperty({
    name: '--sidebar-width',
    syntax: '<length>',
    inherits: true,
    initialValue: '80px'
});
/* CSS */
@property --sidebar-width {
    syntax: "<length>",
    inherits: true,
    initialValue: "80px"
}

Möbius bars with Houdini magic

KharkivCSS #4 2018 — Микита Дубко "Houdini — CSS, который JavaScript"

Псевдоэлементы

Pseudo-elements

Псевдоэлементы 🧪

Pseudo-elements
Pseudo-classes

Лайфхак 10.
Эксперименты

codepen.io
codepen.io/dark_mefody/pen/aJVBVK
Clip Clop Clippity Clop [CSS Only]

Cinema Seat Preview demo

Cinema Seat Preview Experiment With CSS
Игра на чистом CSS, без грязной HTML-разметки

Мораль

CSS —
удобный инструмент

Лучше разобраться и заработать 💰,
чем ругать

Спасибо за внимание!

mefody.github.io/talks/css-programming/fc.html
@dark_mefody
mefody@yandex-team.ru
Parser DOM / CSSOM Cascade Layout Paint Composite