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

Примерами «чего-либо на чистом CSS» сегодня удивить трудно, но обычно это значит лишь «без скриптов», т.е. с хаками в разметке, типа вставленных в строго определенные места невидимых чекбоксов. Отчего разметка становится нелогичной и негибкой. Так что «чистый CSS» — это почти всегда «грязный HTML». Хейдон Пикеринг тоже настолько устал от этого, что высказался в твиттере:

Если вы заявляете, что сделали что-то на «чистом CSS», я даже видеть не хочу HTML. Удачи.

Многие читатели прицепились к фразе «видеть не хочу HTML» буквально. Действительно, хотя CSS-оформление привязано к DOM-элементам, CSS может работать и с минимумом HTML-разметки. А то и вообще без нее! Сразу несколько человек вспомнили старинный пример Матиаса Биненса. Он использует псевдоэлемент для элемента body (для которого необязательны и закрывающий, и открывающий теги, т.е. он присутствует в DOM независимо от наличия соотв. тегов в разметке!) плюс малоизвестный (и поддерживаемый пока только в Firefox и старой Опере) HTTP-заголовок Link, позволяющий браузеру ссылаться на файл стилей без тега <link>. Но сами комментаторы были вынуждены признать, что такой подход слишком ограничен, чтобы быть полезным.

Но кто ж готов мириться с ограничениями, тем более вечером в пятницу! Уж точно не ваш покорный слуга:). Вызов принят: что если не полезное, то по крайней мере интересное/занятное можно сделать в наши дни на чистом CSS, по возможности (в идеале — вообще) не используя разметку?

Итогом моих небольших экспериментов стал нехитрый набросок «ремейка» популярной несколько лет назад игры на реакцию, в которой надо как можно дольше удерживать курсор в игровом поле, избегая «столкновения» с летающими объектами. Время, в течение которого игроку это удавалось, фиксируется секундомером. Вот он:

See the Pen Игра на чистом CSS без JS и HTML-разметки (проверка идеи) by Ilya Streltsyn (@SelenIT) on CodePen.

Чтобы начать игру заново, нужно нажать «Rerun» (а в отдельном примере — обновить страницу).

Использована только стандартная базовая разметка от CodePen. Но та же логика будет работать и без нее. Для работы в Chrome достаточно одного лишь тега <link>, а в Firefox даже он не нужен — его можно заменить HTTP-заголовком. Не верите — убедитесь сами! А заодно оцените такую диковинку, как псевдоэлемент в псевдоэлементе:)

Какие «секретные ингредиенты» тут использованы

  • Элементы html, head и body, которые всегда есть в DOM, даже если в разметке нет соотв. тегов. Справедливости ради, как отметил и Хейдон, это всё-таки HTML-элементы — но без HTML-тегов в разметке мы обошлись.
  • По паре псевдоэлементов ::before и ::after для каждого из них. Как раз хватило на 4 «летающих блока», секундомер и маленький текстовый заголовок.
  • Свойство pointer-events. Оно пришло из SVG, поэтому поддерживается без префикса, но современные браузеры уверенно применяют его и в HTML (правда, со стандартизацией у него есть проблемы, из CSS UI 3-го уровня его выбросили, а в 4-й пока не перенесли… но главное, что работает:). Позволило сделать так, чтобы на наведение курсора реагировали только псевдоэлементы, но не сами элементы.
  • Обычные анимации. Для всех 4 «летающих блоков» в примере использована одна и та же анимация, но с разными периодами. Периоды соотносятся как простые числа, поэтому картина в целом выглядит достаточно хаотичной. Но можно сделать анимацию разной и более сложной. В теории, можно было бы анимировать как сами head и body, так и их псевдоэлементы, чтобы получить еще более хаотичное движение — но не стоит, потому что это потребует перерисовки больших площадей, а значит, может тормозить.
  • Пошаговая (steps) анимация с единицей ch. Основа «секундомера». Идея почерпнута из старого примера Лии Веру.
  • Один из псевдоэлементов приходится использовать в двух качествах сразу — как «летающий блок» и как второй (остановленный) секундомер. И использовать на нем две анимации одновременно (вторую — через наследуемое от родителя свойство). Был бы в CSS родительский селектор (или псевдокласс-функция :has(), как в новых редакциях селекторов 4 уровня), без этого удалось бы обойтись.
  • Сохранение состояния с помощью очень большой задержки при transition (с оговорками, см. ниже).

Что так и не получилось

  • При уводе курсора с поля после окончания игры Chrome и Firefox ведут себя по-разному: первый возобновляет анимацию (отчего секундомер становится похож на скринсейвер времен Windows 95), второй нет. Видимо, дело во взаимодействии анимаций с transition. Интересно, кто из браузеров прав?
  • При анимации сдвига текста Firefox оказался крайне чувствительным к малейшим неточностям размера шрифта: если задать шрифт не точно в пикселях, а в vmin или даже в em, из-за накопления ошибки округления текст постепенно смещался и начинала вылезать следующая цифра.
  • IE11 отказался анимировать смещения в единицах vmin, испортил анимацию секундомера (к сожалению, похоже, единица ch там просто сломана) и, что непонятнее и неприятнее всего, не соблюдает задержку перехода при уводе курсора с поля. Первые две проблемы я почти смог побороть в отдельной версии (хотя анимация в IE там всё равно выглядит странно), последнюю так и не смог. Может быть, у вас получится лучше?
  • При уводе курсора с игрового поля секундомер сбрасывается на 0. Хотя, возможно, это не такой уж баг — ведь такое «бегство» можно расценить как то, что игрок сдался:)

Конечно же, это проверка идеи, сделанная исключительно ради интереса и удовольствия… а также демонстрации возможностей соврменного CSS. Как видите, время, когда чистый CSS сможет быть полезным сам по себе, без необходимости в грязном HTML, возможно, уже не за горами!

P.S. Это тоже может быть интересно:

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

  1. Роман

    Баг. Если навести курсор на поле, после чего убрать с мыши руку(оставить ее без движения) квадраты попадают на область курсора, и игра продолжается.

    1. SelenIT (Автор записи)

      Признаю. Причем в Хроме стабильно, в Фоксе как-то через раз. Надо будет дополнительно поисследовать поведение :hover с анимируемыми элементами. Есть одна задумка, как это можно бы поправить, ближе к концу дня постараюсь проверить. Спасибо за багрепорт!

      1. Роман
  2. Вадим

    Не то, чтобы баг, пожалуй, больше недоработка. В левом нижнем углу, над таймером, «мёртвая зона». Можно там курсор оставить и он будет в целости и сохранности, но это уже конечно больше оффтоп, т.к. основной вопрос не в этом. Отличный результат!

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

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