Применение трансформаций к адаптивному дизайну
Прошлым летом, разработчики браузера Google Chrome сделали заявление, прошедшее незамеченным в тематической прессе, и заключалось оно в прекращении поддержки одного из рабочих стандартов консорциума W3C, который все еще поддерживают все остальные браузеры. Речь идет о языке преобразования XML-документов (Extensible Stylesheet Language Transformations, XSLT).
Большинство подумало: «Ну и что?» И это очень прискорбно.
Трансформация это очень простая и мощная техника разделения контента и представления в веб-приложениях. Тем не менее, за пределами крупных предприятий и процессов обработки данных, трансформации посредством XSLT не смогли завоевать популярность.
В результате, веб-разработчики предвзято думают, что трансформации им не нужны, даже когда они работают с HTML, структурированным форматом, отлично подходящим для трансформации. Благодаря появляющимся сейчас фреймворкам для трансформаций, включая плоды трудов изобретателя Sass, эта тема, скорее всего, обретет второе дыхание.
В данной статье, мы расскажем о трансформациях с новой стороны и откроем их применение для разработки мобильного и адаптивного дизайна.
Это будет не только обучение новым приемам, но и наглядная демонстрация того, что трансформации актуальны для каждого, кто имеет дело с HTML.
Разделение содержимого и представления
Трансформация это просто способ преобразования входных данных в выходные, с помощью неких, заранее определенных правил:

Главное в преобразованиях это не выполняемое действие, а возможности, которые они дают. Трансформации создают абстракцию, которая отделяет контент и функциональность от представления.
Это разделение как раз и является целью многих фреймворков, но трансформации позволяют сделать это легко и изящно:

Трансформированные данные представляют собой разделенный на подзадачи контент.
Наглядным примером такого разделения является Enlive, система преобразований и шаблонизатор в одном лице, написанная в Clojure. Большинство шаблонизаторов используют собственный язык разметки для смешивания HTML с программными конструкциями, такими как циклы и переменные.
Вот пример PHP-кода:
<ul>
<?php foreach ($task_list as $task) { ?>
<li> <?php echo $task ?></li>
<?php } ?>
</ul>
Для сравнения, в шаблонах Enlive используется такой же простой HTML, который можно получить от любого дизайнера или PSD-слайсера.
Например, простейший файл hello-world.html шаблона Enlive может выглядеть так:
<html>
<body>
<h1 id="output">Lorem Ipsum</h1>
</body>
</html>
Вместо внедрения логики специальной разметки, код Clojure, ассоциированный с HTML, преобразует его следующим образом:
(deftemplate helloworld
"hello-world.html"
[]
[:h1#output]
(content "Hello World!"))
Полное понимание выше приведенного кода не столь важно, но возможно вы узнали аргумент h1#output являющийся CSS-селектором. В этом примере, шаблон под названием helloworld, в котором содержимое элемента h1#output заменяется текстом «Hello World!».
При запуске, данный шаблон выдаст следующее:
<html>
<body>
<h1 id="output">Hello World</h1>
</body>
</html>
Для более подробной информации по Enlive, я рекомендую статью David Nolen. Но самым основным моментом является разделение содержимого и представления. Изменения на сайте, A/B тестирование и даже редизайн могут быть произведены очень легко: нужно лишь вставить новый HTML-код, полученный от дизайнера.
От дизайнера не требуется знания языка шаблонизатора, он может использовать привычные HTML-классы и идентификаторы.
Если вы не хотите создавать веб-сайты таким образом, то это то же самое, что делать веб-страницы без таблиц стилей. В действительности, вы можете создать страницу, используя только inline-стили (то есть, используя HTML-атрибут style), что часто делают начинающие разработчики. Однако опытные разработчики знают, что таблицы стилей улучшают производительность.
Похожим образом, с помощью разделения контента и представления, вы можете получить множество преимуществ для своей команды разработки. В результате, трансформации разделяют фронт - и бэк-энд, а также создают удобное рабочее пространство для разработчиков графики, делая их независимыми от программистов.
В сфере, где даже простая вещь вроде цвета кнопки влияет на показатели конверсии, возможность эффективной и независимой работы дизайнеров имеет огромное значение.
Реализация отзывчивого дизайна
Трансформации полезны не только при работе с шаблонизаторами. Разделение контента и представления может быть также применено к существующему сайту, позволяя разработчикам создавать новые представления независимо от внутренней архитектуры сайта.
Разделение содержания и представления существующих сайтов это то, что делает трансформации полезными для широкого круга задач. Я проиллюстрирую это на примере придания свойств отзывчивости дизайну существующего сайта, используя технологию, поддерживаемую всеми (на данный момент) современными браузерами - XSLT.
Технология XSLT была представлена общественности в начале 90-х годов прошлого века как язык для преобразования XML- и XHTML-документов. Во время нарастания популярности формата XML, XSLT был средством разделения представления и содержимого в веб-приложениях, работающих с данными в формате XML.
Консорциум W3C рекомендовал XSLT в качестве стандарта, и почти все основные браузеры вскоре включили в себя его поддержку.
Сейчас же, когда команды разработчиков Google Chrome и Blink заявляют о намерении упразднения поддержки XSLT в своих продуктах, многие возможно будут обеспокоены целесообразностью его использования в ближайшем будущем.
Однако, ко времени написания данной статьи, XSLT основными браузерами, включая и Chrome, а также свежие версии браузеров для iPhone и Android, все еще поддерживается.
Также заметим, что технология XSLT может быть использована как на серверной, так и на клиентской стороне. Реализация серверной части работает независимо от поддержки браузерами. Доступны как коммерческие версии XSLT-движков, так и варианты с открытым кодом.
Существование JavaScript-реализаций XSLT, таких как например Saxon-CE, может заполнить пустое место, если вдруг Google все-таки упразднит поддержку XSLT в своем браузере.
Далее, мы будем говорить о том, как добавить адаптивность к имеющемуся дизайну, который изначально как адаптивный не задумывался. Несмотря на обилие статей и инструкций, посвященных построению адаптивных веб-сайтов с нуля, тема модернизации имеющегося дизайна в сторону адаптивности освящена достаточно слабо, хотя имеет огромную важность.
Существует много старых сайтов, в которые за время их существования было вложено множество сил, времени и денег, так что намного целесообразнее их просто модернизировать.
Долгая работа по модификации дизайна для таких сайтов может «вылететь в копеечку», либо быть неприемлемыми по соображениям временных затрат. Трансформации же предоставляют эффективный способ преобразовать дизайн в адаптивный без особых затрат.
Первым, самым очевидным шагом, будет модернизация через CSS. В интернете, например, имеется набор CSS-файлов от Ben Callahan, позволяющий придать адаптивность имеющемуся сайту. Однако, добавление новых CSS-файлов спасает лишь частично.
Порой, расположение и порядок элементов в оригинальном HTML-файле будет вас ограничивать в применении приведенного выше приема. John Shirrel описывает это как один из изъянов CSS:
«Имеется серьезный недостаток использования таблиц стилей CSS… Они не позволяют преобразовывать структуру документа. Нельзя изменить изначально заданный порядок элементов на странице… Так что, в этом CSS серьезно ограничен».
Вышеприведенная техника в большинстве случаев не позволяет достигнуть желаемого результата, так как CSS и HTML не разделяют содержание и представление полностью.
Всякий раз, сталкиваясь с необходимостью обернуть тот или иной элемент в дополнительный тег div или span, чтобы решить задачу представления, вы сталкиваетесь с этим неполным разделением. Тут-то и приходят на помощь трансформации, позволяя нам управлять структурой документа.
Чтобы это продемонстрировать, я создал простое усовершенствование для главной страницы сайта Hacker News и сделал адаптивным верхнее навигационное меню, используя фреймворк Foundation от ZURB.
На самом деле, кроме этого потребуется внести дополнительные изменения, но для быстрого примера сойдет и так. Почему именно сайт Hacker News? Во-первых, использование кода реального сайта поможет продемонстрировать всю мощь рассматриваемой техники на практическом примере.
Во-вторых, HTML-код этой страницы имеет оптимальный объем: не слишком малый, чтобы не сделать пример непрактичным, но и не слишком большой, чтобы затруднить его разбор:

Верхняя навигационная панель сайта Hacker News, преобразованная с помощью фреймворка Foundation.
Самым важным файлом в этой модификации является таблица стилей XSL transformer.xsl, которую можно скачать тут. Ниже, мы укажем на ключевые места в коде этого файла.
Несмотря на то, что полное раскрытие технологии XSLT выходит за пределы данной статьи, мы все же приведем краткое объяснение для того, чтобы не путаться в терминологии:
- Синтаксис:
Язык программирования XSLT соответствует стандарту XML. Например, условная конструкция if в XSLT выглядит так:<xsl:if> ;
- Параметры:
Параметры для выражений типа <xsl:if> определяются с помощью атрибутов внутри тегов;
- Сравнение элементов:
Один из самых часто используемых параметров это атрибут match, который выбирает теги в соответствии с заданным значением.
Например, если в шаблоне прописано правило <xsl:template match="body/center">, то оно будет применено, когда движок XSLT обнаружит элемент <center>, который является дочерним по отношению к тегу <body>;
- Встраивание HTML:
Наконец, вы можете вставлять чистый HTML в таблицу стилей.
Первым делом, нам нужно сказать браузеру, о необходимости использовать правила, описанные в файле transformer.xsl.
Чтобы это сделать, мы меняем Content-Type документа на text/xml (в некоторых браузерах достаточно просто сменить расширение файла с .html на .xml) и добавляем тег <?xml-stylesheet> в верхнюю часть документа:
<?xml-stylesheet type="text/xsl" href="transformer.xsl"?>
Когда браузер читает этот тег, то перед выводом на экран, документ будет преобразован согласно правилам XSLT, определенным в указанной таблице стилей.
Иначе говоря, трансформация будет произведена самим браузером, то есть на стороне клиента. Но трансформацию можно произвести также и на серверной стороне.
В этом случае, производительность будет выше, но в нашем примере, преобразования производятся на стороне клиента, чтобы сделать пример доступным для разбора всем желающим.
Всем заинтересованным доступны техники оптимизации и инструменты для написания производительных реализаций XSLT.
Другим важным моментом является то, как XSLT обрабатывает неопределенные элементы. По умолчанию, XSLT удаляет все элементы, не указанные в правилах преобразований. Это имеет смысл для XML-документов, которые, как правило, представляют собой данные.
Однако, при трансформации полноценной веб-страницы, обычно требуется изменить лишь относительно небольшую часть документа и определение правил для каждого элемента отнимает много времени и сил. К счастью, мы можем добавить конструкцию под названием identity transform в файл стилей transformer.xsl:
<!-- XSLT identity transform позволяет автоматически пропускать все неизмененные элементы на вывод. -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
Код, приведенный выше, может показаться очень непонятным, но суть его проста: он сообщает XSLT-движку, что нужно скопировать (<xsl:copy>) каждый элемент и атрибут в исходном файле на вывод.
Добавляя этот элемент к нашему файлу стилей, мы изменяем стандартное поведение с вырезания необъявленных данных на полное пропускание их в выходной файл.
Следующим шагом мы добавим фреймворк Foundation в документ. Например, следующий код добавит CSS-файл Foundation (foundation.css) и его зависимости (normalize.css и Modernizr) в секцию <head>:
<!—Установка и инициализация Foundation -->
<!-- Атрибут match указывает на секцию <head> документа -->
<xsl:template match="head">
<link rel="stylesheet" href="normalize.css" />
<link rel="stylesheet" href="foundation.css" />
<script src="custom.modernizr.js"></script>
<xsl:apply-templates select="@* | *"/>
</xsl:template>
Чтобы добавить Foundation в нижнюю часть элемента <body>, напишите следующий код:
<xsl:template match="body">
<xsl:apply-templates select="@* | *"/>
<script src="zepto.js"></script>
<script src="foundation.min.js"></script>
<script>$(document).foundation();</script>
</xsl:template>
Самое главное отличие между двумя приведенными выше примерами это значение атрибута match (head и body, указывающие на место, куда будут вставлены элементы) и расположение тега <xsl:apply-templates>, который определяет, появится ли наше новое содержимое до или после имеющегося контента.
Наконец, чтобы добавить адаптивный заголовок (header), мы вставляем новый HTML-код, который добавляет верхнее меню с помощью фреймворка Foundation. Мы используем команды for-each и copy-of для заполнения меню ссылками из существующей секции header:
<!—Добавление верхнего меню Foundation -->
<xsl:template match="body/center">
<nav class="top-bar">
<!—Boilerplate удален для простоты восприятия -->
<section class="top-bar-section">
<ul class="right">
<!—Перемещение ссылок меню из старого заголовка в новый заголовок Foundation -->
<xsl:for-each select="//span[@class='pagetop']/a">
<li><xsl:copy-of select="." /></li>
</xsl:for-each>
</ul>
</section>
</nav>
<xsl:apply-templates select="@* | *"/>
</xsl:template>
Следует быть в курсе некоторых возможных подводных камней.
Первый из них заключается в том, что в данном примере-модификации все трансформации выполнены браузером, но их запуск на стороне сервера имеет некоторые преимущества. При выполнении преобразований на сервере снижается нагрузка на мобильные устройства, мощность и ресурсы которых на порядок ниже серверных.
Сервер также является подходящим местом для сегментации содержимого, так как позволяет избежать пересылки ненужных данных через сеть и тем самым улучшить производительность.
Наконец, вы всегда можете обновить движок сервера и не иметь проблем с возможной неправильной реализацией XSLT в некоторых браузерах (например, когда технология XSLT 1.0 уже поддерживалась большинством браузеров, разработчики браузера Saxon-CE уже предпринимали попытки реализовать XSLT 2.0 через JavaScript).
Второй подводный камень заключается в функциональной ориентации технологии XSLT, делающей ее недоступной для среднего веб-разработчика. Это значит, что такому среднему веб-разработчику потребуется изучать новый синтаксис.
Помимо этого, XSLT требует изменения мышления в сторону использования рекурсии, что также является непривычным для разработчиков, использующих императивные языки, особенно для дизайнеров, как правило, не имеющих особой подготовки в компьютерной науке.
Наконец, еще большим вызовом является то, что эта техника работает только для XHTML-страниц (это HTML, совместимый со стандартом XML), так как XSLT может преобразовывать только XML, но не HTML. Согласно W3Techs, 55% веб-сайтов интернета сейчас в формате XHTML.
Хотя эта цифра и преимущественная, но она все еще не достаточно большая. Фактически, в данном примере-модификации, я обошел это ограничение, пропустив HTML-код через конвертер HTML to XHTML.
Далее, мы рассмотрим, как эти вопросы решаются с помощью языка преобразований Tritium.
Реализация отзывчивого представления (техника Responsive Delivery)
В примере выше, мы использовали трансформации в браузере, чтобы придать свойства отзывчивости существующему сайту. Однако концептуально, два этих подхода пересекаются. Так как суть отзывчивого дизайна заключается в изменении представления в зависимости от размеров окна браузера, трансформации могут очень помочь в этом.
Вместо простого разделения правил отображения определенных фиксированных HTML-блоков на несколько CSS-файлов, мы можем использовать трансформации для изменения самого HTML-кода в зависимости от устройства отображения.
Как мы разобрались ранее, возможность манипулировать структурой HTML-кода (что недоступно в чистом CSS) не только дает гибкие возможности, но еще и улучшает разделение представления и содержимого. Как результат, работа с сайтом упрощается, так как контент менее привязан к макету. В сущности, это сдвиг от CSS-правил к трансформациям.
В Moovweb, мы используем описанную идею, чтобы реализовать отзывчивое представление, которое черпает вдохновение из отзывчивого и адаптивного дизайна, а также техники RESS (Responsive Design + Server-Side Components, отзывчивый дизайн + компоненты на стороне сервера).
В отзывчивом представлении (responsive delivery), трансформации используются, чтобы адаптировать существующий сайт к ключевым платформам, таким как смартфоны и планшетные компьютеры:

Поток данных в данном отзывчивом представлении (responsive delivery) преобразует HTML-код, предназначенный для «больших» компьютеров, в форму, подходящую для отображения на мобильных устройствах.
Так как преобразованный сайт наследует код напрямую от «полной» версии, отзывчивое представление сохраняет содержимое и функциональность, но меняет внешний вид в заданных ключевых точках – как раз то, что делает типичный отзывчивый макет, но при этом все преобразования происходят на стороне сервера.
Так как трансформации могут использоваться для манипуляции HTML-кодом, мы получаем описанные ранее преимущества: независимость и точный контроль над внешним видом и пользовательским опытом в каждой ключевой точке, благодаря абстракции, разделяющей содержимое и макет.
В некотором смысле, можно говорить об отзывчивом представлении, как о части большого тренда разработки адаптивных методов проектирования в сфере отзывчивого веб-дизайна и перемещении вычислительной нагрузки на сторону сервера с помощью RESS.
Также стоит отметить, что отзывчивое представление может улучшить обычную версию сайта. В идеале, бэк-энд выдает семантически верный, но не стилизованный HTML-код (называемый «wireframe HTML», то есть каркасный HTML), а отзывчивое представление уже трансформирует конечный вывод для каждой ключевой точки:

Отзывчивое представление использует HTML-каркас в качестве исходных данных для трансформации к различным версиям сайта.
Особенная польза от такого подхода ощущается в больших организациях, где существуют отдельные команды разработчиков со своими задачами и спецификой.
Бэк-энд инженеры могут сфокусироваться на функциональности (то есть создании того самого HTML-каркаса), а фронт-энд дизайнеры - на интерфейсе и представлении (то есть на преобразовании каркаса в стилизованную веб-страницу). Каналом связи между обеими командами является HTML, который понимают и там и там.
Пример с простым виджетом автозаполнения. Используя подход отзывчивого представления, бэк-энд инженер может написать API для реализации автозаполнения и вставить соответствующий JavaScript-код в HTML-каркас.
Дизайнер же в свою очередь затем стилизует этот виджет с помощью CSS, трансформирует и, если необходимо, добавит свой JavaScript-код вместо заглушки, оставленной бэк-энд инженером.
Как мы видим, HTML это связующее звено между представлением и функционалом в противовес XML или JSON, которые представляют лишь данные:

На картинке изображена схема преобразования HTML-каркаса в «обычный» и мобильный макеты.
Одним из способов реализации этого подхода, является использование веб-платформы для облачного выполнения трансформаций. Это сервис, который мы создали в Moovweb.
Он предназначен для улучшения мобильных сайтов и приложений (среди клиентов сервиса такие уважаемые компании, как Macy’s и 1-800-Flowers).
Для этого используется наш собственный язык трансформаций с открытым кодом, называемый Tritium. Tritium был разработан Хэмптоном Катлином (Hampton Catlin), изобретателем CSS-препроцессора Sass.
Он использовал свой опыт для создания языка трансформаций, который бы был доступен как веб-дизайнерам, так и программистам.
Вот наиболее важные особенности этого языка:
- Известный синтаксис:
Синтаксис похож на CSS и jQuery, поэтому его легче воспринимать, нежели синтаксис XSLT, который схож с XML;
- Императивный стиль:
Мы хотели использовать императивный стиль программирования вместо функций и рекурсии, как это происходит в модели XSLT;
- Прозрачность ввода:
Введенные данные проходят напрямую на вывод, поэтому нет необходимости в трансформации идентификаторов (как в XSLT);
- Совместимость с HTML:
Tritium был разработан для обработки обычного HTML, поэтому может быть использован для любого веб-сайта, а не только для XHTML (случай с XSLT).
Далее приведен код скрипта на языке Tritium с простейшим примером «Hello World». Он выбирает все HTML-элементы таблиц с идентификатором foo и меняет значение атрибута width в них на 100%:
# Функция $$() использует обычный CSS-селектор
$$("table#foo") {
# и меняет значение атрибута width на "100%"
attribute("width", "100%")
}
Язык Tritium имеет собственный официальный сайт, а Moovweb запланировала сделать код языка открытым в 2014 году. Разработчики заинтересованы в том, чтобы проект получил вклад от сторонних энтузиастов, для чего движок Tritium был размещен в репозитории на GitHub.
Для сравнения с вышеприведенным примером на XSLT, код на Tritium для добавления фреймворка Foundation к HTML-документу, будет таким:
# Добавление фреймворка Foundation в документ
$$("head") {
inject_top('<link rel="stylesheet" href="normalize.css" />
<link rel="stylesheet" href="foundation.css" />
<script src="custom.modernizr.js"></script>')
} $$("body") {
inject_bottom('<script src="zepto.js"></script>
<script src="foundation.min.js"></script>
<script>$(document).foundation();</script>')
}
В случае с XSLT, относительное расположение нового содержания в документе бралось из тега <xsl:apply-templates>. Однако, в примере выше с кодом на Tritium, эту роль выполняют очевидно названные функции inject_top и inject_bottom, которые и подключают фреймворк Foundation к документу.
На практике, Moovweb SDK предоставляет каркас, который помогает вам вставить шаблон Foundation.
Этот каркас также предоставляет и другие удобные функции для использования сторонних компонентов во фреймворке Foundation.
В качестве примера, мы можем использовать следующую функцию для создания отзывчивой верхней навигационной панели на сайте Hacker News:
foundation.tbar() {
foundation.tbar_title("Hacker News", "", "menu-icon")
foundation.tbar_section("right") {
move_here("//span[@class='pagetop']//a"){
wrap("li")
}
}
}
Как и в случае с XSLT, XPath-селектор "//span[@class='pagetop']//a" используется для выбора ссылок меню, а функция foundation.tbar*() это упрощает и избавляет нас от необходимости иметь детальную информацию об HTML-формате верхней навигационной панели.
Полный проект, реализующий модификацию отзывчивости на сайте Hacker News с помощью Tritium доступен на GitHub.
XSLT-версия, использует HTML-код, скачанный с этого же сайта (это сделано так, потому что нужно пропустить этот код через XHTML-конвертер), поэтому вы можете испробовать этот пример с рабочей версией исходного сайта.
Преобразование вашего мышления
Трансформации похоронены в глубинах различных фреймворков, которые чужды среднему разработчику и вся их популярность почти полностью зависит от судьбы технологии XSLT.
Печально это слышать, так как трансформации это скорее новый способ мышления, нежели просто еще одна технология. Они позволяют проводить мощное разделение содержимого и логики от представления, и польза от этого разделения оказывается важной во многих случаях.
Если рассматривать эру Post-PC (время, когда продажи мобильных устройств стали увеличиваться в противовес продажам обычных персональных компьютеров), то трансформации дают возможность удобно представлять сайт на самых различных устройствах.
Более того, это разделение позволило улучшить производительность и скорость разработки графических интерфейсов и представлений. Между тем, для разработчиков, которые занимаются перестраиванием DOM-объектов посредством JavaScript или jQuery, трансформации несут в себе новые возможности для оптимизации и ускорения, такие как трансформации на стороне сервера.
Для индустрии, в которой нет недостатка новых идей, порой полезно попытаться пойти по пути соединения старых и новых концепций, чтобы получить более совершенный продукт. Это как раз тот путь, который был выбран для написания данной статьи о трансформациях.
Надеюсь, мы продемонстрировали вам мощь мышления в терминах трансформаций и показали их значимость для всех, кто работает с HTML.