Заметки за 2012 год (страница 5)

Фоновый градиент с помощью SVG

Замечательный сервис Ultimate CSS Gradient Generator наряду с CSS3 градиентами для всех браузеров создает SVG файл для IE9. Он внедряется в CSS с помощью Data URI в base64 кодировке.


background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0i
MS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zy
Igd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIg
cHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IG
lkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3Bh
Y2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogIC
AgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzdkN2U3ZCIgc3RvcC1v
cGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3
I9IiMwZTBlMGUiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGll
bnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZm
lsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);

Это сервис всегда создает правила так, чтобы градиент заполнял весь блок. Если поправить CSS3 свойства не составит для градиента фиксированного размера, то с SVG придется проделать некоторые манипуляции.

Раскодируем base64

Затем декодируем последовательность символов, которую нам выдал генератор. Я умышленно обрезал часть данных, чтобы команды не затерялись среди них.


echo PD94bWwgdm…IgLz4KPC9zdmc+ | base64 -d > /tmp/g.svg

Файл g.svg .будет содержать SVG и его можно будет отредактировать в любом текстовом редакторе.


<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"
        viewBox="0 0 1 1" preserveAspectRatio="none">
  <linearGradient id="grad-ucgg-generated" gradientUnits="userSpaceOnUse"
          x1="0%" y1="0%" x2="0%" y2="100%">
    <stop offset="0%" stop-color="#7d7e7d" stop-opacity="1"/>
    <stop offset="100%" stop-color="#0e0e0e" stop-opacity="1"/>
  </linearGradient>
  <rect x="0" y="0" width="1" height="1" fill="url(#grad-ucgg-generated)" />
</svg>

Для декодирования можно воспользоваться любым online-сервисом, коих в интернете великое множество.

Задаем размеры изображения

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

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px"
        viewBox="0 0 1 1" preserveAspectRatio="none">

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

Кодируем SVG в base64

base64 -e /tmp/g.svg

Получившийся в результате набор символов копируем из консоли в CSS файл вместо исходного. После этого нужно удалить все переносы строк, которые могли образоваться внутри закодированных данных. Формат base64 игнорирует пробельные символы, но внутри Data URI пробельные символы недопустимы.

Настраиваем параметры фона

Так как фон уже не заполняет весь блок целиком, то нужно не забыть настроить его позиционирование и повторение.

Комментарии к заметке: 2

Стили для разных версий IE

Чтобы не использовать хаки для IE соответствующие стили стоит вынести в отдельные файлы и подключать их через условный комментарий. Так и основные CSS файлы не будут загромождаться мусором и можно отделить особенные стили для разных версий.

Но можно использовать несколько иной подход.


<!--[if lt IE 7]><html class="ie6"><![endif]-->
<!--[if IE 7]><html class="ie7"><![endif]-->
<!--[if IE 8]><html class="ie8"><![endif]-->
<!--[if IE 9]><html class="ie9"><![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--><html><!--<![endif]-->

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

.block {
    padding-bottom: 0;
}
.ie6 .block,
.ie7 .block {
    padding-bottom: 1em;
}

Например, для всех браузеров нижний отступ у элемента с классом block будет нулевым, а в IE6 и IE7 он будет равен 1em.

Стоит заместить, что IE10 игнорирует любые условные комментарии.

Комментарии к заметке: 6

Простые селекторы для разметки статьи в WordPress

Все браузеры начинают разбор CSS селекторов справа налево. Кстати, так же поступают и популярные библиотеки при поиске DOM элементов по заданному селектору.

Пусть в CSS файле, например, указан селектор section.main .article p { … }. Во время отрисовки проверяется, что текущий элемент p. Если это так, то браузер будет искать в дереве всех предков с классом article, а затем предков section с классом main . Только к элементам, для которых были найдены все требуемые предки, и будут применяться декоративные свойства.

Очевидно, что самые быстрые селекторы – это те, которые требуют меньше проверок: div, .main, #sidebar . Такие селекторы называются простыми. Каскадным селекторам (например, как в предыдущем случае) требуется гораздо больше времени для прохождения таких проверок. Так в БЭМ, по возможности, используются только простые селекторы или последовательности простых селекторов (например, a.menu__item-link:hover ), чтобы обеспечить максимальную скорость отображения страниц.

С обычной вёрсткой проблемы добавить нужные классы не возникает. А вот для контента, создаваемого пользователем, такие классы придётся назначать автоматически. Для своего блога на Вордпрессе я написал небольшой фильтр.


function my_content_filter_callback($parts)
{
    $tag = strtolower($parts[1]);
    $attrs = $parts[2];
    $cls_replacement = ' class="t-' . strtolower($tag);

    if (strpos($attrs, ' class=') === false) {
        $attrs = $cls_replacement . '"' . $attrs;
    } else {
        $attrs = str_replace(' class="', $cls_replacement . ' ', $attrs);
    }

    return '<' . $tag . $attrs . '>';
}

function my_content_filter($content)
{
    if (!is_feed()) {
        $out = preg_replace_callback('#<([a-zA-Z0-9]+)([^>]*)>#',
            'my_content_filter_callback', $content);
    } else {
        $out = $content;
    }
    return $out;
}

add_filter('the_content', 'my_content_filter', 20);

Фильтр вызывается при отображении статьи. Каждому тегу в статье добавляется класс с именем тега. Например, <p> становится <p class="t-p">, а <div class="video"> становится <div class="t-div video">.


<h3 class="t-h3">Элемент article</h3>
<p class="t-p">Новый элемент <em class="t-em">article</em> — это специальный вид
    <em class="t-em">section</em>, который обозначает независимую и самодостаточную
    часть страницы. На его месте можно использовать <em class="t-em">section</em>,
    но <em class="t-em">article</em> добавляет больше семантического значения.</p>

Теперь элементы статьи можно декорировать простыми селекторами не опасаясь, что они будут конфликтовать с оформлением других блоков.

.t-h3 { font-size: 1.5em; font-weight: bold; margin: 1em 0 0.5em; }
.t-p { margin: 1em 0; }
.t-em { font-style: italic; }

Подведу итоги:

  • небольшое увеличение объема HTML кода почти никак не сказывается на трафике для пользователя, так как по сети данные передаются в сжатом виде;
  • нет ручной работы по добавлению классов элементам;
  • при декорировании в CSS используются простые селекторы;
  • максимальная скорость при отрисовке страницы в браузере.
Оставте свой комментарий

Шаблонирование на JavaScript

Динамическое создание и обновление блоков страницы с давних пор принято делать через свойство DOM-элемента innerHTML . Если речь идет о куске HTML, пришедшего с сервера в асинхронном запросе, то другого адекватного варианта просто нет. С другой стороны, когда с сервера получаем только данные, а разметку создаем скриптом на JS, то тут уже появляются варианты.

Различные реализации JS-движка имеют свои сильные и слабые стороны. Долгое время создание DOM-элементов через document.createElement было очень дорогой по времени операцией. Не самый лучший дизайн API требовал многословности при создании увесистой структуры из элементов с атрибутами.


var container = document.createElement("div");
var link = document.createElement("a");
link.setAttribute("href", "http://yandex.ru/");
link.setAttribute("title","Яндекс");
link.appendChild(document.createTextNode("Поиск"));
container.appendChild(link);

Этот фрагмент фактически соответствует:

<div><a href="http://yandex.ru/" title="Яндекс">Поиск</a></div>

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

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

HTML – всегда был и остается результатом сериализации древовидной структуры документа в текстовый формат, который может легко восприниматься и редактироваться человеком. Браузер, получая его на вход из файла или через поле innerHTML, разбирает его, превращая в DOM-дерево, прежде чем примется его отображать.

Современные браузеры достаточно быстро выполняют JavaScript, чтобы дать сборке фрагментов DOM-дерева через соответствующие методы API, ещё один шанс.

Синтаксический сахар

Neil Jenkins сделал «сахарок» для создания отдельных элементов и целых иерархий – Sugared DOM. Однако его код не работает в IE из-за отличной от других движков реализации метода split() у строк. Я переделал работу в этой части кода и добавил unit-тесты.

el("div");

Элементы можно создавать с установленными атрибутами id и class , используя знакомый CSS синтаксис

el("div#id.class1.class2");

Элементу можно установить другие атрибуты. Например,

el("div#id", { tabindex: -1, title: "Контейнер" });

Дочерние элементы передаются в массиве последним аргументом

var container = el("div", [
    el("a", {"href": "http://yandex.ru/", "title": "Яндекс"}, [
        "Поиск"
    ])
]);

Производительность

Тесты показывают превосходство DOM версии во всех браузерах кроме Оперы, где разница в скорости почти не заметна и Интернет Эксплорера, который всё же быстрее работает с полем innerHTML.

Ноутбуки и настольные компьютеры в настоящее время настолько мощные, что разница в скорости создания фрагментов не так уж и важна. С другой стороны, на мобильниках и планшетах – это может быть критичным. Тесты показали, что DOM версия быстрее от 45 до 100% в WebKit браузерах (браузеры в iOS устройствах и браузер по-умолчанию в Android устройствах), и примерно одинакова с innerHTML версией в Opera Mobile.

Заключение

Sugared DOM метод имеет ряд преимуществ перед шаблонизаторами:

  • Прост в отладке (описание шаблона – это и есть исполняемый код).
  • Не нужно дополнительно искать элементы после создания фрагмента – все ссылки на готовые элементы можно получить в процессе построения дерева.
  • Не нужно беспокоиться об экранировании данных. Нулевая вероятность XSS. Текстовая стока явно преобразуется в текстовый узел DOM-дерева.
  • Нет пустых текстовых узлов из-за пробелов между тегами.
  • Среда разработки помогает отслеживать ошибки в таком шаблоне, так как он является обычным JS-скриптом.
  • Гибкость шаблонирования обеспечивается полным доступом к объектам и функциям JS.

PS. Заметка вдохновлена статьёй Building the new AJAX mail UI part 2: Better than templates, building highly dynamic web pages

Комментарии к заметке: 3

Вёрстка независимыми блоками

Кажется, в крупных проектах рунета « БЭМ» становится стандартом де-факто.

Если хочется попробовать и получить некоторые плюсы от разработки в стиле БЭМ, но нет возможности внедрять всю технологическую цепочку, то стоит для начала перенять именование классов. Разумеется, это будет уже не БЭМ. Тем не мене, методом проб и ошибок ребятам из Яндекса удалось выработать хорошую методику именования CSS-селекторов для абсолютно-независимых блоков.

Блок

Канонические имена блоков в БЭМ начинаются с префикса b- и отвечают на вопрос «Зачем нужен это блок?»:


.b-menu {}

Я в своей практике префикс всегда опускаю, так как лично для меня – это лишние символы не несущие никакой смысловой нагрузки.

.menu {}

Элемент

Элемент – часть блока, которая не имеет смысла вне этого блока и не может быть использована вне него.


<nav class="menu">
    <h3 class="menu__head">Menu</h3>
    <ul class="menu__list">
        <li class="menu__item">Item 1</li>
        <li class="menu__item">Item 2</li>
        <li class="menu__item">Item 3</li>
    </ul>
</nav>

Селектор элементов именуем следующим образом: .имя-блока__имя-элемента.

Модификатор

Модификатор служит для изменения внешнего вида (возможно, и поведение) блока или элемента. Селектор записывается в виде: .имя-блока_тип-модификатора_значение-модификатора или .имя-блока__имя-элемента_тип-модификатора_значение-модификатора

Назначив тегу блока или элемента класс модификатора, можно изменить его внешний вид.


<nav class="menu menu_footer">
    <h3 class="menu__head">Menu</h3>
    <ul class="menu__list">
        <li class="menu__item">Item 1</li>
        <li class="menu__item menu__item_state_current">Item 2</li>
        <li class="menu__item">Item 3</li>
    </ul>
</nav>

Модификатор menu_footer у блока menu, например, меняет размер шрифта у меню в подвале страницы

.menu { font-size: 16px; }
.menu_footer { font-size: 12px; }

А модификатор menu__item_state_current у элемента menu__item может поменять цвет фона у текущего раздела


.menu__item { background: black; color: white; }
.menu__item_state_current { background: yellow; color: black; }

Модифицировать можно и контекстом. Например, модификатор блока может влиять на элементы этого блока. Важно запомнить, что это можно делать только, если такие блоки не вкладываются друг в друга, иначе не избежать проблем со специфичностью. Так же никогда не модифицируем блок от контекста другого блока. Это лишает блок независимости.

Дополнительные материалы

Комментарии к заметке: 17