Представьте, что вы — разумный человек. Вы знаете, что CSS — это язык стилей. Cascading Style Sheets. Для оформления. Не для логики. Не для программирования. Просто цвета, шрифты, отступы.

А потом вы заходите на CodePen.

И там кто-то сделал полностью рабочий калькулятор. На чистом CSS. Без JavaScript. Кто-то другой запрограммировал игру в крестики-нолики. С искусственным интеллектом. На CSS. Третий создал 3D-лабиринт с first-person камерой. Управление клавиатурой. Опять же — на CSS.

И вы думаете: "Что за чёрт? Как это вообще работает?"

Добро пожаловать в мир CSS-программирования. Это место, где люди делают вещи не потому, что они нужны, а потому что это технически возможно. Где checkbox становится ячейкой памяти. Где :checked — это ваш Boolean. Где общее количество строк кода больше, чем если бы вы просто написали на JavaScript. Но зато — без JavaScript!

Сейчас я покажу вам, как работает эта магия. И почему это одновременно гениально и абсурдно.

Главный трюк: The Checkbox Hack

Вся эта "магия" держится на одном хитром приёме, который называется Checkbox Hack. Это краеугольный камень всей CSS-логики. Без него ничего бы не работало.

Как это работает:

  1. Берёте <input type="checkbox"> (или <input type="radio">)

  2. Скрываете его визуально через CSS: position: absolute; left: -9999px;

  3. Рядом ставите <label>, привязанный к чекбоксу через атрибут for

  4. Пользователь кликает на label — чекбокс меняет состояние

  5. Используете псевдокласс :checked и селекторы (+, ~) для изменения стилей

Переводя на человеческий:

<input type="checkbox" id="toggle" class="hidden">
<label for="toggle">Кликни меня</label>
<div class="content">Этот контент появится/исчезнет</div>
.hidden {
  position: absolute;
  left: -9999px;
}

.content {
  display: none;
}

#toggle:checked ~ .content {
  display: block;
}

Бац! У вас есть интерактивность. Без JavaScript. Чекбокс — это ваша переменная Boolean. Он может быть true (checked) или false (unchecked). Это 1 бит памяти.

И тут начинается цирк.

Потому что если у вас есть 1 бит памяти, вы можете сделать 8 бит. А если у вас 8 бит, вы можете сделать 64. А если у вас 64 бита — у вас уже есть всё, что нужно для калькулятора.

Что можно сделать с checkbox hack

Давайте посмотрим, что люди создали, используя этот простой трюк.

1. Табы, аккордеоны, модальные окна

Это стандартное применение. Нормальное. Даже полезное.

#tab1:checked ~ .tab-content-1,
#tab2:checked ~ .tab-content-2 {
  display: block;
}

Кликнул на таб — открылся контент. Ничего сверхъестественного. Любой разумный разработчик скажет: "Окей, это можно использовать для простых случаев". Chris Coyier с CSS-Tricks даже написал статью об этом ещё в 2012 году, и она актуальна до сих пор.

Вердикт: Полезно. Легкое. Работает.

2. Toggle-переключатели и кастомные чекбоксы

Опять же, вполне разумно. Дефолтные чекбоксы уродливы. Хочется красиво. Скрываете оригинальный чекбокс, рисуете свой через ::before и ::after. Используете :checked для изменения стилей.

input[type="checkbox"] {
  position: absolute;
  opacity: 0;
}

label::before {
  content: '';
  width: 50px;
  height: 25px;
  background: #ccc;
  border-radius: 25px;
  transition: 0.3s;
}

input:checked + label::before {
  background: #4CAF50;
}

Результат: Красивые переключатели в стиле iOS, Android, или любой другой дизайн-системы.

Вердикт: Совершенно нормально. Нет вопросов.

3. Dropdown-меню и navigation

Тоже вполне адекватное использование. Особенно для мобильных меню. Скрытый чекбокс — label в виде "гамбургера" — меню выезжает сбоку при клике.

#menu-toggle:checked ~ nav {
  left: 0;
  /* Меню выезжает из-за экрана */
}

Проблема одна: если пользователь кликнет вне меню, оно не закроется. Потому что у чекбокса нет события "клик вне элемента". Для этого нужен JavaScript. Но для 80% случаев — работает отлично.

Вердикт: Разумное применение. Легковесное решение.


И вот тут начинается безумие.

4. Калькулятор на чистом CSS

Да. Полностью рабочий калькулятор. Вы можете складывать, вычитать, умножать, делить. Есть дробные числа. Есть дисплей, который показывает результат.

Как это вообще работает?

Ключевая фича: CSS counters. Это механизм для автоматической нумерации элементов (как в упорядоченных списках). Но оказывается, counters можно использовать для вычислений.

body {
  counter-reset: result 0;
}

.set-number {
  counter-increment: result 5;
  /* Увеличиваем счётчик на 5 */
}

.display::after {
  content: counter(result);
  /* Выводим значение счётчика */
}

Проблема: counters могут хранить только целые числа. Для дробных чисел приходится разделять число на целую и дробную части, хранить их отдельно, а потом склеивать через content.

Второй прикол: вся логика калькулятора реализована через тысячи селекторов CSS. Буквально. Для каждой комбинации "цифра + операция + цифра" написан отдельный селектор.

#num1:checked ~ #num2:checked ~ #add:checked ~ .result {
  counter-increment: result 3;
  /* 1 + 2 = 3 */
}

Вердикт: Технически впечатляющее. Практически бесполезное. Но доказывает, что CSS может в арифметику.

5. Игры на чистом CSS

Это уже хардкор. Люди создали:

  • Крестики-нолики (с AI-противником на основе захардкоженных ходов)

  • Арканоид (отбивание шарика платформой)

  • Лабиринты (управление клавишами)

  • Whack-a-Mole (бей крота)

  • Стрелялки (типа Duck Hunt)

  • Тетрис (вращение фигур и стакинг)

  • Шахматы (полностью рабочие, но без проверки правил)

Принцип работы:

  1. Каждая клетка игрового поля — это radio button

  2. Клик по label перемещает "персонажа" (меняет состояние radio button)

  3. :checked селектор показывает/скрывает элементы в зависимости от текущей позиции

  4. CSS animations создают движение (враги, объекты)

  5. Таймер игры — CSS animation-delay (например, "game over" появляется через 100 секунд)

Пример из игры "Kill the Birds":

.game-over {
  height: 0;
  opacity: 0;
  animation: curtain 0.6s ease-in;
  animation-delay: 100s;
  /* Появляется через 100 секунд */
  animation-fill-mode: forwards;
}

@keyframes curtain {
  to {
    height: 100vh;
    opacity: 1;
  }
}

Счётчик времени:

.timer::before {
  content: '9';
  animation: countdown 10s step-end;
  /* Прыгает с 9 до 0 */
}

@keyframes countdown {
  0% { content: '9'; }
  10% { content: '8'; }
  20% { content: '7'; }
  /* ... и так далее */
  90% { content: '0'; }
}

Вердикт: Это уже не CSS. Это какой-то боевой язык ассемблера, замаскированный под стили.

6. 3D-графика и первое лицо

Да, вы правильно поняли. Люди создали полноценные 3D-сцены на CSS. С перспективой. С глубиной. С анимацией.

Основные инструменты:

  • perspective: 1000px; — устанавливает "камеру"

  • transform-style: preserve-3d; — сохраняет 3D-пространство для дочерних элементов

  • transform: rotateX() rotateY() rotateZ(); — вращение в 3D

  • transform: translateZ(); — движение по оси Z (вглубь/на зрителя)

Пример 3D-куба:

.cube {
  width: 200px;
  height: 200px;
  position: relative;
  transform-style: preserve-3d;
  animation: rotateCube 10s infinite linear;
}

.face {
  position: absolute;
  width: 200px;
  height: 200px;
  background: rgba(255, 0, 0, 0.7);
}

.front  { transform: translateZ(100px); }
.back   { transform: rotateY(180deg) translateZ(100px); }
.right  { transform: rotateY(90deg) translateZ(100px); }
.left   { transform: rotateY(-90deg) translateZ(100px); }
.top    { transform: rotateX(90deg) translateZ(100px); }
.bottom { transform: rotateX(-90deg) translateZ(100px); }

@keyframes rotateCube {
  to { transform: rotateX(360deg) rotateY(360deg); }
}

Но это ещё не всё. Кто-то создал первое лицо 3D-мир на CSS. С комнатами. С дверями. С навигацией клавишами. Через :target селектор (который срабатывает при изменении URL хеша).

#room1:target ~ .scene {
  transform: translate3d(0, 0, 0);
}

#room2:target ~ .scene {
  transform: translate3d(-2000px, 0, 0);
}

Вердикт: CSS превратился в движок рендеринга 3D-графики. Страшно представить, что будет дальше.

Почему это работает (с технической точки зрения)

Давайте разберёмся, почему CSS вообще способен на это.

1. Чекбокс как ячейка памяти

Чекбокс имеет два состояния: checked и unchecked. Это 1 бит информации. Если у вас есть 10 чекбоксов, у вас 10 бит. Если 100 — 100 бит.

Но тут есть нюанс. В классическом программировании вы можете менять значение переменной когда угодно. В CSS — только через взаимодействие пользователя. Вы не можете написать:

/* Это не работает */
#checkbox1:checked {
  #checkbox2: checked;
}

Вы можете только показать/скрыть элементы в зависимости от состояния чекбокса.

2. Селекторы как условные операторы

#toggle:checked ~ .element {
  display: block;
}

Это эквивалент:

if (toggle.checked) {
  element.style.display = 'block';
}

Чем больше комбинаций чекбоксов, тем сложнее "логика":

#a:checked ~ #b:checked ~ #c:not(:checked) ~ .result {
  /* Если A и B включены, но C выключен */
  background: red;
}

Это if (a && b && !c).

3. CSS counters как арифметика

counter-reset: total 0;
counter-increment: total 5;
content: counter(total);

Это переменная + операция инкремента. Можно складывать, вычитать (через отрицательные инкременты), умножать (через несколько инкрементов подряд).

Проблема: нельзя делать деление и дробные числа напрямую. Приходится изобретать костыли.

4. CSS animations как таймеры

animation: event 5s forwards;
animation-delay: 10s;

Это setTimeout(event, 10000). Анимация запускается через 10 секунд, выполняется 5 секунд, и остаётся в конечном состоянии.

5. :target как роутинг

#page1:target ~ .content-1 { display: block; }
#page2:target ~ .content-2 { display: block; }

Это SPA (Single Page Application) без JavaScript. URL меняется — контент меняется.

Почему это гениально

1. Нет зависимости от JavaScript

Если пользователь отключил JS (или у него старый браузер, или он использует Tor), ваше приложение всё равно работает. Accessibility на максимум.

2. Нет runtime-ошибок

CSS не крашится. Если селектор неправильный — элемент просто не изменится. Нет "undefined is not a function". Нет "Cannot read property of null".

3. Hardware acceleration

CSS transforms и animations обрабатываются GPU. Это значит 60 FPS даже на мобильных устройствах. JavaScript animations часто тормозят.

4. Это охренеть как весело

Серьёзно. Создать калькулятор на CSS — это как решать головоломку. Это челлендж. Это доказательство, что вы можете.

Почему это абсурдно

1. Нечитаемый код

Попробуйте прочитать 5000 строк CSS-селекторов для калькулятора. Это ад. Отладка невозможна. Поддержка невозможна.

2. Огромный размер файла

CSS-калькулятор весит больше, чем JavaScript-версия. CSS-игра "The Mine" — 10,000+ строк SCSS. После компиляции — 20,000+ строк CSS.

3. Отсутствие переменных и циклов

В нормальных языках вы пишете:

for (let i = 0; i < 100; i++) {
  createEnemy(i);
}

В CSS вы пишете 100 отдельных правил вручную. Или генерируете их препроцессором (что уже не "чистый CSS").

4. Невозможность динамической логики

Вы не можете изменить поведение в runtime. Всё должно быть заранее прописано в CSS. Для игры это значит: все возможные ходы и состояния должны быть захардкожены.

5. Семантика HTML ломается

Вы используете <input type="checkbox"> не как чекбокс, а как переменную Boolean. Это нарушает семантику. Screen readers для слепых пользователей будут в шоке: "Why are there 50 checkboxes on this page?!"

6. Это медленно

Да, CSS animations — hardware accelerated. Но если у вас 100 чекбоксов и тысячи селекторов, браузер начинает тупить. Потому что каждый клик пересчитывает все селекторы для всех элементов.

Настоящие примеры безумия

Давайте посмотрим на конкретные проекты, которые реально существуют.

CSS Rock-Paper-Scissors

Полностью рабочая игра "Камень-ножницы-бумага". Выбираете оружие — компьютер выбирает случайно — результат показывается.

Хитрость: "случайность" сделана через CSS animations с разной длительностью. Вы не можете предсказать, в какой момент кликнете, поэтому выбор компьютера кажется случайным.

CSS Tic-Tac-Toe с AI

Крестики-нолики, где компьютер делает оптимальные ходы.

Хитрость: все возможные комбинации ходов заранее прописаны. Если вы поставили X в центр, компьютер ставит O в угол. Если вы пошли в угол — компьютер идёт в центр. Это не AI. Это гигантская таблица if-else.

The Mine: No JS, CSS Only Adventure Game

Полноценная приключенческая игра. Вы ходите по лабиринту, собираете ключи, открываете двери, избегаете ловушек.

Хитрость: 10,000+ строк SCSS. Каждая клетка лабиринта — radio button. Каждый переход — селектор типа:

#cell1:checked ~ #cell2:checked ~ .player {
  transform: translate(100px, 0);
}

Вердикт: Это безумие. Восхитительное, но безумие.

CSS Calculator with Decimals

Калькулятор с поддержкой дробных чисел. Сложение, вычитание, умножение, деление.

Хитрость: Число разделено на целую и дробную части. Каждая хранится в отдельном counter. При выводе они склеиваются через content: counter(integer) '.' counter(decimal).

Проблема: округление. CSS counters не умеют в дробную математику. Поэтому все вычисления делаются в фиксированной точке (умножаем всё на 100, вычисляем, делим обратно).

Pure CSS 3D FPS World

Первое лицо 3D-мир с комнатами, дверями, текстурами. Управление клавишами (через :target).

Хитрость: Вся сцена — набор div-ов с transform: translate3d(). При переходе в другую комнату меняется URL хеш, срабатывает :target, применяется новый transform.

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

Мнение сообщества

Мнение разумных людей:

"Это интересный эксперимент, но не используйте это в продакшене. Семантика ломается, accessibility страдает, код нечитаем."

Мнение энтузиастов:

"Это доказывает, что CSS — Тьюринг-полный язык! Мы можем сделать что угодно!"

Правда:

CSS НЕ Тьюринг-полный. Потому что:

  1. Нет полноценных переменных (только counters)

  2. Нет циклов (только анимации)

  3. Нет способа изменить состояние без взаимодействия пользователя

Но CSS + HTML + User Interaction в сумме Тьюринг-полные. Потому что пользователь может кликать в любой последовательности, а чекбоксы — это память.

Когда это реально полезно

Окей, хватит троллить. Давайте честно: когда checkbox hack действительно полезен?

1. Простые toggle UI

Аккордеоны, табы, dropdown-меню — это норм. Если вам не нужна сложная логика (например, закрытие меню при клике вне), checkbox hack отлично работает.

2. Лёгкие landing pages

Если у вас статичный сайт без сложной интерактивности, checkbox hack может заменить 90% JavaScript. Меньше зависимостей, быстрее загрузка.

3. Accessibility fallback

Если JavaScript не загрузился или отключён, CSS-версия продолжит работать. Это хороший паттерн: делаете базовую функциональность на CSS, улучшаете через JS.

4. Мобильные меню

Навигация на мобильных часто делается через checkbox hack. Это легковесно, работает везде, не требует библиотек.

5. Кастомные формы

Красивые чекбоксы, radio buttons, toggle switches — всё это лучше делать через CSS, чем тащить jQuery UI.

Когда это НЕ полезно

1. Любая сложная логика

Если вам нужно больше, чем "показать/скрыть", используйте JavaScript. Не пытайтесь воссоздать Spring Framework на CSS.

2. Динамические данные

CSS не может обрабатывать API-запросы, парсить JSON, обновлять данные в реальном времени. Для этого нужен JS.

3. Production-приложения

Не делайте калькулятор на CSS для банковского приложения. Просто не делайте.

4. Accessibility-critical интерфейсы

Если ваш сайт используют люди с ограниченными возможностями, не ломайте семантику HTML ради CSS-трюков.

5. Когда у вас есть дедлайн

Написать toggle на JavaScript — 5 минут. Написать на CSS checkbox hack — 5 минут. Написать калькулятор на CSS — 5 дней. Написать на JS — 2 часа.

Вывод: CSS-программирование — это искусство, а не инженерия

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

Checkbox hack — гениальный хак. Он использует стандартное поведение HTML (связь label и input) + стандартные возможности CSS (псевдоклассы и селекторы) для создания интерактивности. Это не баг. Это не exploit. Это легитимная техника, описанная в спецификациях.

Но это не значит, что нужно писать всё на CSS. Калькулятор на CSS — это как забить гвоздь микроскопом. Технически возможно. Впечатляюще. Но нахрена?

Правда в том, что большинство CSS-игр и приложений созданы для челленджа. Для доказательства концепта. Для фана. Авторы прекрасно понимают, что это не production-код. Это эксперимент. Это исследование границ возможного.

И в этом вся прелесть. CSS-программирование — это как code golf. Цель не в практичности. Цель — сделать невозможное возможным.


P.S. Если вы сейчас думаете: "Окей, это прикольно, попробую сделать свою игру на CSS" — отлично! Но помните: это кроличья нора. Вы начнёте с простого toggle. Потом сделаете accordion. Потом табы. Потом dropdown. Потом анимированное меню. Потом 3D-карточку. Потом 3D-куб. Потом 3D-мир. Потом игру. Потом калькулятор.

И в один прекрасный день вы проснётесь с мыслью: "А можно ли сделать операционную систему на CSS?" Ответ: нет, но вы всё равно попробуете.

P.P.S. Спасибо всем CSS-энтузиастам, которые делятся своими безумными проектами на CodePen. Особенно Chris Coyier (CSS-Tricks), Elad Shechter (автор Pure CSS Games), и всем остальным, кто доказывает, что ограничения — это вызов, а не препятствие.

P.P.P.S. Я CSS-программист. И я не извиняюсь за это.

Комментарии (4)


  1. entze
    05.11.2025 14:24

    Сыллок бы к каждому примеру.


  1. NeoCode
    05.11.2025 14:24

    Думаю, можно написать (или уже написаны) какие-нибудь компиляторы, которые просто генерят нужный css-код с какого-нибудь нормального языка высокого уровня.

    Только вот с моей точки зрения и html, и css уже давно перегружены всякой фигней. Превращение веб-страниц в веб-приложения нанесло здравому смыслу и свободе информации непоправимый урон.

    Интересно, кто нибудь уже пытался сделать альтернативы или чистые подмножества html/css, на которых можно только формировать документы, но никакой логики и интерактивности?


    1. k12th
      05.11.2025 14:24

      epub?


  1. Tolnik
    05.11.2025 14:24

    Интересная статья про CSS для программистов.

    А есть еще CSS для дизайнеров и художников. Ссылка для заинтересовавшихся: https://www.thisiscolossal.com/2019/11/css-portraits-diana-smith/