Как стать автором
Обновить
VK
Технологии, которые объединяют

Houdini: один из самых впечатляющих проектов в CSS, о котором вы никогда не слышали

Время на прочтение 11 мин
Количество просмотров 61K
Автор оригинала: Philip Walton


Бывало ли у вас так, что хотелось использовать какую-нибудь фичу из стандарта CSS, но вы этого не делали, потому что она поддерживается не всеми браузерами? Или ещё хуже: её поддерживают все браузеры, но поддержка глючная, противоречивая или вообще несовместимая? Наверняка вы с таким сталкивались, и поэтому рекомендую вам присмотреться к Houdini.

Это новая рабочая группа W3C, которой поставлена амбициозная задача — навсегда решить описанную выше проблему. Сделать это планируется с помощью нового набора API, который впервые даст разработчикам возможность самостоятельно расширять CSS, а также предоставит инструменты для подключения к процессу создания макета и применения стилей в ходе работы браузерного движка.

Но что конкретно кроется за этими обещаниями? Это хотя бы хорошая затея? И как всё вышесказанное поможет нам, разработчикам, создавать сайты сегодня и завтра?

На все эти вопросы я постараюсь дать ответы. Но сначала внесу ясность относительно актуальных сегодняшних проблем и необходимости их решения. А затем уже мы поговорим о том, как Houdini может нам с ними помочь, и рассмотрим ряд его наиболее впечатляющих возможностей, находящихся в процессе разработки. И в завершение я внесу ряд предложений, как сообщество разработчиков может помочь реализоваться проекту Houdini.

Какие проблемы пытается решить Houdini?


Каждый раз, когда я пишу статью или создаю демоприложение для популяризации какой-то новой CSS-фичи, неизбежно получаю комментарии вроде: «Это замечательно! Как жаль, что мы не сможем это использовать ещё лет десять». Хотя такие комментарии неконструктивны и весьма раздражают, я могу понять настроение разработчиков. Так сложилось, что широкое распространение нововведений занимает годы. И главной причиной тому, как учит нас история веба, является получение новых возможностей CSS исключительно через процесс стандартизации.


Этапы процесса стандартизации

Я ничего не имею против стандартизации, но это занимает слишком много времени! К примеру, flexbox был предложен в 2009 году, а разработчики всё ещё объясняют, что они до сих пор не могут его использовать из-за недостаточной поддержки браузерами. К счастью, эта проблема постепенно сходит на нет, поскольку почти все современные браузеры обновляются автоматически. Но даже в этом случае всегда имеется задержка между предложением функциональности и общей готовностью к её использованию. Любопытно, что такая ситуация наблюдается не во всех сферах в Сети. Сравните, например, с JavaScript:


Этапы внедрения полифиллов

В данном случае с момента возникновения идеи до её использования в работе могут проходить дни. Например, я уже использую функции async/await в продакшене, а ведь эта функциональность ещё не реализована ни в одном браузере!

Наверняка вы замечали огромную разницу в настроениях обоих сообществ. В JS-комьюнити вы читаете статью, в которой кто-то сетует на то, что всё меняется слишком быстро. А в CSS все стенают о тщетности изучения новинок, поскольку пройдёт ещё куча времени, пока их можно будет использовать.

Так почему нам просто не написать побольше CSS-полифиллов?


На первый взгляд, это вполне очевидное решение. Благодаря хорошим полифиллам CSS мог бы cтать таким же быстроразвивающимся, как и JavaScript, верно? Увы, не всё так просто. Внедрять полифиллы в CSS невероятно трудно, а во многих случаях это невозможно сделать, не обрушив производительность полностью.

JavaScript — динамический язык, поэтому можно на JS создавать полифиллы для JS. Его невероятная расширяемость является следствием его динамической природы. А CSS редко можно использовать для создания собственных полифиллов. Иногда на этапе сборки можно компилировать код CSS в код CSS (transpile) (это делает PostCSS). Но если вы хотите использовать полифиллы для чего-либо, зависящего от DOM-структуры, либо для позиции или раскладки (layout) элемента, то логику полифилла придётся исполнять на клиентской стороне. К сожалению, браузеры эту задачу не облегчают.

Ниже представлена базовая схема процесса работы браузера, от получения HTML-документа до вывода пикселей на экран. Синим выделены этапы, на которых JavaScript может влиять на результат:


Доступ JavaScript к конвейеру визуализации браузера

Довольно мрачная картина. Вы как разработчик не контролируете процесс парсинга HTML и CSS с последующим превращением в DOM и объектную модель CSS (CSSOM). Вы не управляете каскадом (cascade). Вы не управляете процессом выбора схемы размещения (layout) элементов в DOM, не управляете их окраской (paint) при выводе на экран. Наконец, вы никак не влияете на работу компоновщика (composite). Только DOM полностью вам подвластен. Какое-то влияние вы имеете на CSSOM, но, согласно сайту Houdini, этот этап «недостаточно определён, различается в зависимости от браузера, а также лишён ряда критически важных возможностей». К примеру, сегодня CSSOM не покажет вам правила из cross-origin таблиц стилей, при этом он просто их отбросит, если не поймёт. А это означает, что если вы хотите написать полифилл, добавляющий функциональности, то будете вынуждены идти в обход CSSOM. Вам придётся через DOM найти теги <style> и/или <link rel="stylesheet">, затем самостоятельно получить CSS, распарсить его, преобразовать и только потом добавить обратно в DOM.

Конечно, обновление DOM обычно означает, что потом браузер должен будет заново пройти через все этапы: каскад, шаблон, окраску и компоновку.


Использование полифиллов JavaScript в конвейере визуализации браузера

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

Подводя итоги всему сказанному: если вы хотите заставить браузер делать что-то, для чего он, по его мнению, не предназначен (включая и скормленный ему вами CSS), то придётся думать, как его обмануть с помощью самостоятельного модифицирования DOM. К другим стадиям конвейера у вас нет доступа.

Но зачем мне вообще хотеть модифицировать внутренний движок браузера?


На мой взгляд, это важнейший вопрос всей статьи. Итак, если вы дошли до этого момента, то дальше читайте медленно и вдумчиво!

После предыдущего раздела кто-то из вас подумал: «Мне это не нужно! Я просто делаю обычные веб-страницы, а не пытаюсь хакнуть внутренности браузера или сделать что-то крайне экстравагантное, экспериментальное или суперсовременное». Если вас посетили подобные мысли, то я настаиваю на том, чтобы вы пока отложили этот текст и тщательно изучили технологии, используемые вами для создания сайтов в последние годы. Желание получить доступ к процессу применения стилей в браузере связано не с созданием причудливых демок, а с предоставлением разработчикам и авторам фреймворков возможности делать две вещи:

  • сглаживать различия между браузерами,
  • придумывать новые возможности или добавлять их с помощью полифиллов, чтобы люди могли использовать их уже сегодня.

Если вы когда-нибудь пользовались jQuery, то сразу получили выгоду от использования её возможностей! Это один из главных доводов в пользу почти всех современных фронтенд-библиотек и фреймворков. Например, пять наиболее популярных JS- и DOM-репозиториев на GitHub — AngularJS, D3, jQuery, React и Ember — прилагают немало усилий для сглаживания различий между браузерами, чтобы нам с вами не приходилось об этом думать. Каждый из этих проектов предлагает единый API, который работает как часы.

А теперь вспомните о CSS и всех этих кросс-браузерных заморочках. Даже популярные фреймворки, вроде Bootstrap и Foundation, заявляющие о своей широкой совместимости, на самом деле не решают проблему кросс-браузерных багов — они их просто избегают. Но все эти баги в CSS — не просто осколки прошлого. Даже сегодня, несмотря на использование новых модулей шаблонов наподобие flexbox, мы постоянно сталкиваемся с несовместимостями. А представьте, насколько легче жилось бы разработчикам, если бы мы могли использовать любые свойства CSS и были уверены в их одинаковой работоспособности в каждом браузере. Или вспомните все замечательные новинки, о которых вы прочитали в блогах или услышали на конференциях и митапах, — например, сетки, точки привязки и «липкое» позиционирование (sticky positioning). Представьте, как бы вы могли использовать их уже сейчас, так же просто, как и нативные возможности CSS. И чтобы для этого нужно было всего лишь скопировать кусок кода с GitHub.

Всё это — мечта команды разработчиков Houdini. Это то будущее, которое они пытаются создать. И даже если вы не планируете писать CSS-полифиллы или разрабатывать экспериментальные функциональности, то наверняка захотите, чтобы это могли делать другие. Ведь если появятся такие полифиллы, то от этого все только выиграют.

Какая функциональность Houdini сейчас находится в разработке?


Выше я упоминал, что у нас очень мало точек входа в браузерный конвейер отображения страницы. По сути, это только DOM и, с натяжкой, CSSOM. Группа разработчиков Houdini представила несколько новых спецификаций, которые на первое время обеспечат разработчикам доступ и к остальным стадиям конвейера. Эти спецификации отражены на схеме (серым выделены запланированные, но ещё не реализованные).


Новые спецификации Houdini для работы с конвейером визуализации

В следующих разделах мы кратко рассмотрим каждую из этих новых спецификаций, разберём предоставляемые ими возможности. Ряд спецификаций в этой статье не упомянут, с полным списком вы можете ознакомиться в репозитории проекта.

CSS Parsing API


Эта спецификация пока не реализована, поэтому всё нижесказанное ещё может измениться. Основная идея в том, чтобы разрешить разработчикам расширять CSS-парсер и сообщать ему о новых конструкциях. Например, о новых медиаправилах (media rules), новых псевдоклассах, о вложенности, @extends, @apply и т. д. Как только парсер о них узнает, он сможет помещать их в нужное место в CSSOM, а не отбрасывать.

CSS properties and values API


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

Посмотрите пример:

body {
  --primary-theme-color: tomato;
  transition: --primary-theme-color 1s ease-in-out;
}
body.night-theme {
  --primary-theme-color: darkred;
}

Класс night-theme добавляется к элементу <body>, и теперь цвет всех отдельных элементов на странице, которые ссылаются на значение свойства --primary-theme-color, будет медленно переходить от tomato до darkred. Пока что для этого приходится вручную прописывать цветовой переход для каждого элемента, поскольку нельзя описать переход для самого свойства.

Другая многообещающая возможность этого API заключается в регистрации хуков (apply hook), что позволяет разработчикам модифицировать финальное значение кастомного свойства элемента после завершения этапа каскадирования. Это очень полезно с точки зрения использования полифиллов.

CSS typed OM


Эту функциональность можно рассматривать в качестве второй версии текущей CSSOM. Она предназначена для решения многочисленных проблем, связанных с текущей моделью, и включает в себя возможности, добавляемые новыми API парсинга и API свойств и значений. Также типизированная ОМ призвана улучшить производительность. Преобразование строковых значений CSSOM в типизированные JS-представления может приводить к существенным провалам в производительности.

CSS Layout API


Этот API позволяет разработчикам писать свои собственные модули макетирования. И под «модулем макетирования» я подразумеваю всё, что может быть передано свойству display. Это позволит создавать макет так же быстро, как и с помощью нативных модулей, наподобие display: flex и display: table. В качестве примера можно привести библиотеку Masonry. Разработчикам приходится прибегать к подобным инструментам, если они хотят создавать сложные макеты, которые невозможно реализовать средствами одного лишь CSS. И хотя все эти макеты выглядят очень впечатляюще, их производительность оставляет желать лучшего, особенно на не самых мощных устройствах.

API макетирования предоставляет метод registerLayout, который получает имя макета (позднее используемое в CSS) и JS-класс, включающий в себя всю логику макета. Вот простой пример того, как можно определить 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');
}

CSS Painting API


Этот API очень похож на предыдущий. Он предоставляет метод registerPaint, работающий так же, как и registerLayout. После этого можно использовать функцию paint() в 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 будет отображаться на фоне синего круга. Этот круг будет центроваться по элементу и подгоняться под его размер, что бы ни происходило.

Worklet’ы


Для многих описанных спецификаций приведены образцы кода (например, registerLayout и registerPaint). Этот код нужно будет помещать в скрипты-worklet’ы. Это аналоги «веб-воркеров» (web workers), позволяющие импортировать файлы скриптов и исполнять JS-код, который может быть выполнен на разных стадиях конвейера визуализации независимо от основного потока.

Допустимые типы операций в ворклетах будут жёстко ограничиваться ради поддержания высокой производительности.

Composited Scrolling and Animation


Хотя официальной спецификации пока не существует, но это уже одна из наиболее известных и ожидаемых функций Houdini. Вероятно, эти API позволят исполнять логику в ворклете компоновщика, вне основного потока, с поддержкой модифицирования ограниченного набора свойств элемента DOM. В этот набор войдут только те свойства, которые могут быть считаны или изменены без необходимости заставлять движок пересчитывать раскладку или стили (например, трансформация, прозрачность, сдвиг прокрутки). Всё это позволит реализовывать очень быструю анимацию, основанную на прокрутке или пользовательском вводе, наподобие прилипающих при прокручивании заголовков и эффекта параллакса. Подробнее о способах применения этих API вы можете почитать на GitHub.

Несмотря на отсутствие официальной спецификации, команда разработчиков Chrome уже начала экспериментировать. С помощью примитивов, предоставляемых этими API, они реализовали точки привязки CSS и «липкое» позиционирование. Это означает, что API Houdini работают достаточно быстро, чтобы на их основе создавать новую функциональность в Chrome. Этот факт должен окончательно развеять ваши возможные сомнения относительно производительности Houdini в сравнении с нативными средствами.

Можете посмотреть видеоролик, сделанный с помощью внутренней сборки Chrome. Там показано поведение заголовка при прокрутке, аналогичное реализованному в нативном мобильном приложении Twitter. Также доступен исходный код.

Что можно сделать сейчас?


Как я уже говорил, мне кажется, что Houdini будет интересен всем, кто занимается веб-разработкой. Этот проект способен в будущем сильно облегчить нам жизнь. Даже если вы никогда не станете напрямую использовать эти спецификации, то наверняка будете применять построенные на их базе инструменты. И хотя завтра светлое будущее не наступит, всё же оно ближе, чем кажется многим из вас. Представители всех основных разработчиков браузеров в этом году собирались на встречу с командой Houdini в Сиднее, и среди них почти не было разногласий на тему того, что или как реализовывать. Насколько мне известно, вопрос заключается лишь в сроках завершения работ над Houdini.

Как и все разработчики ПО, создатели браузеров должны уделять особое внимание новым возможностям своих продуктов. И подобные приоритеты зачастую зависят от степени востребованности новых функций. Так что если вас заботит расширяемость стилей и макетов веб-сайтов, если вы хотите жить в мире, где можно использовать новые возможности CSS без многолетнего ожидания стандартизации, сообщите об этом тем, кто связан с командами разработчиков используемых вами браузеров.

Также вы можете помочь делу, поделившись с сообществом возможными способами применения новинок. Расскажите, что вы хотели бы сделать со стилями и макетами, что сегодня сделать трудно или невозможно. Для некоторых черновиков на GitHub доступны описания use-case, но вы, конечно же, можете создать pull request, поделившись своими идеями. Если подходящего документа нет, можно создать новый.

Команде разработчиков Houdini (и W3C в целом) действительно важно получить информативный отклик от сообщества веб-разработчиков. Многие из тех, кто участвует в процессе формирования спецификаций, — инженеры, работающие над браузерами. Зачастую они не являются профессиональными веб-разработчиками и не всегда знают о наших насущных потребностях и трудностях.

Сообщите им своё мнение.

Полезные ссылки


Теги:
Хабы:
+42
Комментарии 26
Комментарии Комментарии 26

Публикации

Информация

Сайт
team.vk.company
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия
Представитель
Руслан Дзасохов