Houdini: возможно, самая захватывающая разработка в CSS, о которой вы никогда не слышали
Опубликовано: 2022-03-10Вы когда-нибудь хотели использовать определенную функцию CSS, но не использовали ее, потому что она не полностью поддерживалась во всех браузерах ? Или, что еще хуже, он поддерживался во всех браузерах, но поддержка была глючной, непоследовательной или даже полностью несовместимой? Если это случилось с вами — а я держу пари, что так и было — то вы должны побеспокоиться о Гудини.
Houdini — это новая целевая группа W3C, чья конечная цель — навсегда избавиться от этой проблемы. Он планирует сделать это, представив новый набор API-интерфейсов, которые впервые дадут разработчикам возможность расширять сам CSS и инструменты для подключения к процессу стилизации и компоновки механизма рендеринга браузера .
Дальнейшее чтение на SmashingMag:
- Почему вам следует прекратить локальную установку среды WebDev
- Будущее CSS: экспериментальные свойства CSS
- 53 техники CSS, без которых вы не сможете жить
Но что конкретно это означает? Это вообще хорошая идея? И как это поможет нам, разработчикам, создавать веб-сайты сейчас и в будущем?
В этой статье я постараюсь ответить на эти вопросы. Но прежде чем я это сделаю, важно прояснить, в чем сегодня заключаются проблемы и почему так необходимы перемены. Затем я более подробно расскажу о том, как Houdini решит эти проблемы, и перечислю некоторые из наиболее интересных функций, которые в настоящее время находятся в разработке. Наконец, я предложу некоторые конкретные вещи, которые мы, как веб-разработчики, можем сделать сегодня, чтобы помочь воплотить Houdini в реальность.
Какие проблемы пытается решить Houdini?
Каждый раз, когда я пишу статью или создаю демонстрацию, демонстрирующую какую-то совершенно новую функцию CSS, неизбежно кто-нибудь в комментариях или в Твиттере скажет что-то вроде: «Это потрясающе! Жаль, что мы не сможем использовать его еще 10 лет».
Какими бы раздражающими и неконструктивными ни были подобные комментарии, я их понимаю. Исторически сложилось так, что для того, чтобы предложения функций получили широкое распространение, требовались годы. И причина в том, что на протяжении всей истории Интернета единственным способом добавить новую функцию в CSS было пройти процесс стандартизации.

Хотя я абсолютно ничего не имею против процесса стандартизации, нельзя отрицать, что это может занять много времени!
Например, flexbox был впервые предложен в 2009 году, и разработчики до сих пор жалуются, что не могут использовать его сегодня из-за отсутствия поддержки браузеров. Конечно, эта проблема постепенно уходит, потому что почти все современные браузеры теперь обновляются автоматически; но даже в современных браузерах всегда будет отставание между предложением и общедоступностью функции.
Интересно, что это не относится ко всем областям Интернета. Посмотрите, как обстоят дела в JavaScript в последнее время:

В этом сценарии время между появлением идеи и ее использованием в производстве иногда может составлять несколько дней. Я имею в виду, что я уже использую функции async
/ await
в производстве, и эта функция не была реализована ни в одном браузере!
Вы также можете увидеть огромную разницу в общих настроениях этих двух сообществ. В сообществе JavaScript вы читаете статьи, в которых люди жалуются, что все происходит слишком быстро. С другой стороны, в CSS вы слышите, как люди жалуются на бесполезность изучения чего-либо нового из-за того, сколько времени пройдет, прежде чем они действительно смогут его использовать.
Итак, почему бы нам просто не написать больше CSS-полифиллов?
На первый взгляд может показаться, что ответом может стать написание большего количества полифиллов CSS. С хорошими полифилами CSS может двигаться так же быстро, как JavaScript, верно?
К сожалению, это не так просто. Полифиллирование CSS невероятно сложно и, в большинстве случаев, невозможно сделать таким образом, чтобы полностью не снизить производительность.
JavaScript — это динамический язык, а это значит, что вы можете использовать JavaScript для полифилла JavaScript. И поскольку он такой динамичный, он чрезвычайно расширяемый. CSS, с другой стороны, редко можно использовать для полифилла CSS. В некоторых случаях вы можете преобразовать CSS в CSS на этапе сборки (PostCSS делает это); но если вы хотите полифилить что-либо, что зависит от структуры DOM или от макета или положения элемента, вам придется запускать логику вашего полифилла на стороне клиента.
К сожалению, браузер не упрощает эту задачу.
На приведенной ниже диаграмме показано, как ваш браузер переходит от получения HTML-документа к отображению пикселей на экране. Шаги, выделенные синим цветом, показывают, где JavaScript может управлять результатами:

Картина довольно мрачная. Как разработчик, вы не можете контролировать, как браузер анализирует HTML и CSS и превращает их в объектную модель DOM и CSS (CSSOM). У вас нет контроля над каскадом. Вы не можете контролировать, как браузер выбирает расположение элементов в DOM или как он визуально рисует эти элементы на экране. И у вас нет контроля над тем, что делает композитор.
Единственная часть процесса, к которой у вас есть полный доступ, — это DOM. CSSOM несколько открыт; однако, цитируя веб-сайт Houdini, он «недостаточно конкретизирован, несогласован в разных браузерах и в нем отсутствуют важные функции».
Например, CSSOM в современных браузерах не покажет вам правила для таблиц стилей разных источников и просто отбросит любые правила или объявления CSS, которые он не понимает. который не поддерживает его, вы не можете использовать CSSOM. Вместо этого вам нужно просмотреть DOM, найти теги <style>
и/или <link rel=“stylesheet”>
, самостоятельно получить CSS, разобрать его, переписать, а затем добавить обратно в DOM.
Конечно, обновление DOM обычно означает, что браузер должен пройти весь каскад, компоновку, отрисовку и составные шаги снова и снова.

Хотя необходимость полного повторного рендеринга страницы может показаться не таким уж большим ударом по производительности (особенно для некоторых веб-сайтов), подумайте, как часто это может происходить. Если логика вашего полифилла должна работать в ответ на такие вещи, как события прокрутки, изменение размера окна, движения мыши, события клавиатуры — на самом деле в любое время вообще что-либо меняется — тогда все будет заметно, а иногда даже ужасно медленно.
Это становится еще хуже, когда вы понимаете, что большинство современных полифилов CSS включают в себя собственный парсер CSS и собственную каскадную логику. А поскольку синтаксический анализ и каскадирование на самом деле очень сложные вещи, эти полифилы обычно либо слишком велики, либо содержат слишком много ошибок.
Подводя итог всему, что я только что сказал, более кратко: если вы хотите, чтобы браузер делал что-то отличное от того, что, по его мнению, он должен делать (учитывая предоставленный вами CSS), вам нужно найти способ подделать его, обновив и изменив ДОМ сами. У вас нет доступа к другим шагам конвейера рендеринга.
Но зачем мне когда-либо изменять внутренний движок рендеринга браузера?
Для меня это самый важный вопрос, на который нужно ответить во всей этой статье. Итак, если вы до сих пор бегло пролистывали материал, читайте эту часть медленно и внимательно!
После просмотра последнего раздела, я уверен, некоторые из вас подумали: «Мне это не нужно! Я просто создаю обычные веб-страницы. Я не пытаюсь взломать внутренности браузера или создать что-то сверхпричудливое, экспериментальное или передовое».
Если вы так думаете, то я настоятельно призываю вас на секунду отступить и по-настоящему изучить технологии, которые вы использовали для создания веб-сайтов на протяжении многих лет. Желание получить доступ и зацепиться за процесс стилизации браузера — это не просто создание причудливых демонстраций — это предоставление разработчикам и авторам фреймворков возможности делать две основные вещи:
- для нормализации межбраузерных различий,
- изобретать или заполнять новые функции, чтобы люди могли использовать их сегодня.
Если вы когда-либо использовали библиотеку JavaScript, такую как jQuery, то вы уже воспользовались этой возможностью! На самом деле, сегодня это одно из основных преимуществ почти всех интерфейсных библиотек и фреймворков. Пять самых популярных репозиториев JavaScript и DOM на GitHub — AngularJS, D3, jQuery, React и Ember — проделали большую работу по нормализации межбраузерных различий, чтобы вам не приходилось об этом думать. Каждый предоставляет один API, и он просто работает.
Теперь подумайте о CSS и всех его кросс-браузерных проблемах. Даже популярные фреймворки CSS, такие как Bootstrap и Foundation, заявляющие о кроссбраузерной совместимости, на самом деле не нормализуют кроссбраузерные ошибки — они просто избегают их. И кросс-браузерные ошибки в CSS не просто ушли в прошлое. Даже сегодня, с новыми модулями компоновки, такими как flexbox, мы сталкиваемся со многими несовместимостями между браузерами.
Суть в том, что представьте, насколько приятнее была бы ваша жизнь при разработке, если бы вы могли использовать любое свойство CSS и точно знать, что оно будет работать одинаково во всех браузерах. И подумайте обо всех новых функциях, о которых вы читали в блогах или слышали на конференциях и встречах, — такие вещи, как сетки CSS, точки привязки CSS и фиксированное позиционирование. Представьте, если бы вы могли использовать их все сегодня и так же эффективно , как нативные функции CSS. И все, что вам нужно сделать, это взять код с GitHub.

Это мечта Гудини. Это будущее, которое целевая группа пытается сделать возможным.
Таким образом, даже если вы никогда не планируете писать полифилл CSS или разрабатывать экспериментальную функцию, вы, вероятно, захотите, чтобы другие люди могли это сделать, потому что, как только эти полифиллы существуют, от них выигрывают все.
Какие функции Houdini сейчас находятся в разработке?
Выше я упоминал, что у разработчиков очень мало точек доступа к конвейеру рендеринга браузера. На самом деле единственными местами являются DOM и, в некоторой степени, CSSOM.
Чтобы решить эту проблему, целевая группа Houdini представила несколько новых спецификаций, которые впервые предоставят разработчикам доступ к другим частям конвейера рендеринга. На приведенной ниже диаграмме показан конвейер и новые спецификации, которые можно использовать для изменения шагов. (Обратите внимание, что спецификации, выделенные серым цветом, запланированы, но еще не написаны.)

Следующие несколько разделов дают краткий обзор каждой новой спецификации и тех возможностей, которые она предлагает. Я также должен отметить, что другие спецификации не упоминаются в этой статье; полный список см. в репозитории черновиков Houdini на GitHub.
API парсера CSS
CSS Parser API в настоящее время не написан; Итак, многое из того, что я говорю, может быть легко изменено, но основная идея заключается в том, что это позволяет разработчикам расширять синтаксический анализатор CSS и рассказывать ему о новых конструкциях — например, о новых правилах мультимедиа, новых псевдоклассах, вложенности, @extends
, @apply
и др.
Как только синтаксический анализатор узнает об этих новых конструкциях, он может поместить их в нужное место в CSSOM, а не просто отбросить.
API свойств и значений CSS
В CSS уже есть настраиваемые свойства, и, как я уже говорил, я очень рад возможностям, которые они открывают. CSS Properties and Values API продвигает настраиваемые свойства на шаг вперед и делает их еще более полезными, добавляя типы.
Есть много замечательных вещей в добавлении типов к пользовательским свойствам, но, возможно, самым большим преимуществом является то, что типы позволят разработчикам переходить и анимировать пользовательские свойства, чего мы не можем сделать сегодня.
Рассмотрим этот пример:
body { --primary-theme-color: tomato; transition: --primary-theme-color 1s ease-in-out; } body.night-theme { --primary-theme-color: darkred; }
В приведенном выше коде, если к элементу <body>
добавить класс night-theme
, то каждый отдельный элемент на странице, который ссылается на –primary-theme-color
, будет медленно переходить от tomato
к darkred
. Если бы вы захотели сделать это сегодня, вам пришлось бы написать переход для каждого из этих элементов вручную, потому что вы не можете выполнить переход для самого свойства.
Еще одна многообещающая функция этого API — возможность зарегистрировать «применить хук», который дает разработчикам возможность изменять конечное значение пользовательского свойства элементов после завершения шага каскада, что может быть очень полезной функцией для полифиллов.
Типизированный CSS OM
CSS Typed OM можно рассматривать как версию 2 текущей CSSOM. Его цель — решить множество проблем с текущей моделью и включить функции, добавленные новым API синтаксического анализа CSS и API свойств и значений CSS.
Другой важной целью Typed OM является повышение производительности. Преобразование текущих строковых значений CSSOM в осмысленно типизированные представления JavaScript приведет к значительному увеличению производительности.
API макета CSS
CSS Layout API позволяет разработчикам писать свои собственные модули макета. И под «модулем макета» я подразумеваю все, что может быть передано свойству display
CSS. Это впервые даст разработчикам способ компоновки, который так же эффективен, как собственные модули компоновки, такие как display: flex
и display: table
.
В качестве примера использования библиотека макетов Masonry показывает, на что сегодня готовы пойти разработчики для создания сложных макетов, которые невозможно реализовать с помощью одного только CSS. Хотя эти макеты впечатляют, к сожалению, они страдают проблемами с производительностью, особенно на менее мощных устройствах.
CSS Layout API работает, предоставляя разработчикам метод registerLayout
, который принимает имя макета (которое позже используется в CSS) и класс JavaScript, который включает всю логику макета. Вот базовый пример того, как вы можете определить masonry
с помощью registerLayout
:
registerLayout('masonry', class { static get inputProperties() { return ['width', 'height'] } static get childrenInputProperties() { return ['x', 'y', 'position'] } layout(children, constraintSpace, styleMap, breakToken) { // Layout logic goes here. } }
Если в приведенном выше примере ничего не понятно для вас, не беспокойтесь. Главное, на что следует обратить внимание, это код в следующем примере. После того, как вы загрузили файл masonry.js
и добавили его на свой веб-сайт, вы можете написать такой CSS, и все будет работать:
body { display: layout('masonry'); }
API рисования CSS
CSS Paint API очень похож на Layout API выше. Он предоставляет метод registerPaint
, который работает точно так же, как метод registerLayout
. Затем разработчики могут использовать функцию paint()
в CSS везде, где ожидается изображение CSS, и передавать зарегистрированное имя.
Вот простой пример, который рисует цветной круг:
registerPaint('circle', class { static get inputProperties() { return ['--circle-color']; } paint(ctx, geom, properties) { // Change the fill color. const color = properties.get('--circle-color'); ctx.fillStyle = color; // Determine the center point and radius. const x = geom.width / 2; const y = geom.height / 2; const radius = Math.min(x, y); // Draw the circle \o/ ctx.beginPath(); ctx.arc(x, y, radius, 0, 2 * Math.PI, false); ctx.fill(); } });
И это можно использовать в CSS следующим образом:
.bubble { --circle-color: blue; background-image: paint('circle'); }
Теперь элемент .bubble
будет отображаться с синим кругом в качестве фона. Круг будет центрирован и того же размера, что и сам элемент, каким бы он ни был.
Ворклеты
Многие из перечисленных выше спецификаций содержат примеры кода (например, registerLayout
и registerPaint
). Если вам интересно, куда бы вы поместили этот код, ответ находится в сценариях рабочих лет.
Ворклеты похожи на веб-воркеры и позволяют импортировать файлы сценариев и запускать код JavaScript, который (1) может вызываться в различных точках конвейера рендеринга и (2) не зависит от основного потока.
Сценарии рабочих лет сильно ограничивают типы операций, которые вы можете выполнять, что является ключом к обеспечению высокой производительности.
Составная прокрутка и анимация
Хотя официальной спецификации для составной прокрутки и анимации пока нет, на самом деле это одна из наиболее известных и долгожданных функций Houdini. В конечном итоге API-интерфейсы позволят разработчикам запускать логику в рабочем наборе компоновщика вне основного потока с поддержкой модификации ограниченного подмножества свойств элемента DOM. Это подмножество будет включать только свойства, которые можно прочитать или установить, не заставляя механизм визуализации пересчитывать макет или стиль (например, преобразование, непрозрачность, смещение прокрутки).
Это позволит разработчикам создавать высокопроизводительные анимации на основе прокрутки и ввода, такие как липкие заголовки прокрутки и эффекты параллакса. Вы можете прочитать больше о вариантах использования, которые эти API пытаются решить на GitHub.
Хотя официальной спецификации пока нет, в Chrome уже началась экспериментальная разработка. Фактически, команда Chrome в настоящее время реализует точки привязки CSS и фиксированное позиционирование, используя примитивы, которые в конечном итоге будут доступны этим API. Это удивительно, потому что это означает, что API-интерфейсы Houdini достаточно производительны, чтобы новые функции Chrome были созданы поверх них. Если у вас все еще были какие-то опасения, что Houdini будет не таким быстрым, как родной, один этот факт должен убедить вас в обратном.
Чтобы увидеть реальный пример, Сурма записал демо-видео, работающее на внутренней сборке Chrome. Демонстрация имитирует поведение заголовка прокрутки, наблюдаемое в родных мобильных приложениях Twitter. Чтобы увидеть, как это работает, ознакомьтесь с исходным кодом.
Что вы можете сделать сейчас?
Как уже упоминалось, я думаю, что каждый, кто создает веб-сайты, должен заботиться о Houdini; это сделает нашу жизнь намного проще в будущем. Даже если вы никогда не используете спецификацию Houdini напрямую, вы почти наверняка будете использовать что-то, созданное поверх нее.
И хотя это будущее может быть не ближайшим, оно, вероятно, ближе, чем многие из нас думают. Представители всех основных поставщиков браузеров присутствовали на последней личной встрече Houdini в Сиднее в начале этого года, и было очень мало разногласий по поводу того, что создавать и как действовать дальше.
Из того, что я мог сказать, вопрос не в том, будет ли Гудини чем-то особенным, а в том, когда, и вот где вы все придете.
Поставщики браузеров, как и все, кто создает программное обеспечение, должны отдавать приоритет новым функциям. И этот приоритет часто зависит от того, насколько сильно пользователям нужны эти функции.
Так что, если вы заботитесь о расширяемости стилей и макетов в Интернете, и если вы хотите жить в мире, где вы можете использовать новые функции CSS, не дожидаясь, пока они пройдут процесс стандартизации, поговорите с членами группы по связям с разработчиками для браузеров, которые вы используете, и скажите им, что вы этого хотите.
Вы также можете помочь, предоставив реальные варианты использования — то, что вы хотите сделать со стилем и макетом, которые трудно или невозможно сделать сегодня. Несколько черновиков на GitHub содержат документацию по прецедентам, и вы можете отправить запрос на извлечение, чтобы поделиться своими идеями. Если документ не существует, вы можете создать его.
Члены рабочей группы Houdini (и W3C в целом) действительно хотят получить вдумчивый вклад от веб-разработчиков. Большинство людей, участвующих в процессе написания спецификаций, — инженеры, работающие над браузерами. Часто они сами не являются профессиональными веб-разработчиками, а это значит, что они не всегда знают, в чем болевые точки.
Они зависят от нас, чтобы сказать им.
Ресурсы и ссылки
- CSS-TAG Houdini Editor Drafts, W3C Последняя общедоступная версия всех проектов Houdini
- CSS-TAG Спецификации целевой группы Houdini, GitHub Официальный репозиторий Github, где происходят обновления и разработка спецификаций.
- Образцы Houdini, примеры кода GitHub, демонстрирующие и экспериментирующие с возможными API
- Список рассылки Houdini, W3C Место, где можно задать общие вопросы
Особая благодарность членам Houdini Яну Килпатрику и Шейну Стивенсу за рецензирование этой статьи.