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

Никита Дубко

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

Никита Дубко

Кто я?

Дисклеймер

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

CSS 🆚 JS

2009

cdtcha.narod.ru

CSS + HTML = ❤️

CSS + HTML = 💰

2019

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

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

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 —
Тьюринг-полный ✅

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
<figure class="app-column-item app-card">
    <h3 class="talkname">...</h3>
    <h4>Сергій Бабіч<br><small>Львів</small></h4>
    <img class="app-card-img" src="babich.jpg"Сергій Бабіч">
    <figcaption class="app-card-caption">
        <p class="description">...</p>
        <p>...</p>
    </figcaption>
</figure>
ru.bem.info

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

TDD

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

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

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

Hermione

npm install -g hermione
Тестируем пользовательские сценарии вместе с «Гермионой»
// .hermione.conf.js
module.exports = {
    sets: {
        desktop: {
            files: 'tests/desktop'
        }
    },
    browsers: {
        chrome: {
            desiredCapabilities: {
                browserName: 'chrome'
            }
        }
    }
};
github.com/gemini-testing/hermione
webdriver.io/docs/api.html
// tests/desktop/lvivcss.test.js
const assert = require('chai').assert;

describe('lvivcss', function() {
    it('should be ok', function() {
        return this.browser
            .url('https://lvivcss.org')
            .getText('h1.logo')
            .then(function(title) {
                assert.equal(title, `LvivCSS'19`)
            })
            .setWindowSize(1440, 540)
            .assertView('plain', 'body')
            .setWindowSize(1440, 520)
            .assertView('boom', 'body');
    });
});
github.com/gemini-testing/hermione

1440x540

1440x520

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

Процесс написания CSS-алгоритмов

Лайфхак 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
neesoglasnaja.github.io/LvivCSS-19

Лайфхак 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

CSS — не враг

Но его нужно изучать

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 Rock-Paper-Scissors by Alvaro Montoro
@keyframes changeOrder {
    from { z-index: 6; }
    to { z-index: 1; }
}

label {
    animation: changeOrder 3s infinite linear;
}

label:nth-of-type(1) { animation-delay: -0.0s; }
label:nth-of-type(2) { animation-delay: -0.5s; }
label:nth-of-type(3) { animation-delay: -1.0s; } 
Are There Random Numbers in CSS?
Are There Random Numbers in CSS?
Are There Random Numbers 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 Whack-a-mole by Alvaro Montoro
Игра на чистом CSS, без грязной HTML-разметки

Мораль

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

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

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

mefody.github.io/talks/css-programming/lviv.html
@dark_mefody
n.a.dubko@gmail.com
Parser DOM / CSSOM Cascade Layout Paint Composite