Заметки за январь 2014 года

Inline SVG для пиктограмм

В очередном проекте мы пробуем встраивать на страницы графику в виде SVG. Заказчик не требует полной поддержки старых браузеров, но ожидает в них доступность основного контента. Для некоторых пиктограмм мы выбрали inline SVG, так как можем легко управлять их внешним видом через стили и даже трансформировать их.

Все изображения собраны в одном SVG-файле shapes.svg.

<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
  <defs>
    <rect id="shape-rectangle" x="1" y="1" width="30" height="30"/>
    <circle id="shape-circle" cx="16" cy="16" r="24"/>
  </defs>
</svg>

Тут у нас две фигуры: квадрат и круг. Чтобы в дальнейшем мы могли сослаться на них, у каждой фигуры должны быть уникальные значения id. Забегая вперёд скажу, что их уникальность должна быть не только в пределах SVG, но и в пределах всего документа, где в дальнейшем будет отображаться эта иконка.

На заметку:

Все фигуры определены внутри тега <defs>. Они не будут отображаться, если попытаться открыть этот файл в каком-нибудь редакторе или просмотрщике. На них можно только сослаться. Несколько контуров могут быть объединены в одну фигуру с помощью тега <g>.

Затем в HTML можно сослаться на заготовленные контуры

<svg xmlns="http://www.w3.org/2000/svg"
      style="width: 32px; height: 32px;">
  <use xlink:href="shapes.svg#shape-rectangle"></use>
</svg>

Браузер отобразит квадрат в блоке размером 32 на 32 пиксела. Габариты блока, разумеется, нужно задавать с помощью CSS. В данном примере я указал их в атрибуте style только для наглядности.

<svg xmlns="http://www.w3.org/2000/svg"
      viewBox="-9 -9 50 50"
      style="width: 32px; height: 32px;">
  <use xlink:href="shapes.svg#shape-circle"></use>
</svg>

C кругом чуть сложнее так как он не вписывается в желаемые габариты 32 на 32 пиксела. Поэтому inline SVG нужно указать атрибут viewBox. Браузер сам правильно смасштабирует фигуру до размеров блока.

Подводные камни

При использование inline SVG нужно знать и помнить несколько особенностей.

Поддержка

Все современные браузеры прекрасно справляются с базовыми конструкциями SVG. Если вам нужны какие-то особенные фильтры, то стоит протестировать их отдельно.

Internet Explorer

Мы обнаружили, что ссылка на внешний SVG-файл с контурами не работает, если страница отображается в IE. Это известное поведение и исправить хаками его нельзя. Остаётся только явно включить этот SVG в HTML страницу. Соответственно при использовании в <use xlink:href="#shape-rectangle"></use> остаётся один якорь (для этого и нужна была уникальность id).

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

<script id="svg-loader">
  $.ajax({url: "shapes.svg", cache: true, dataType: "html"})
    .done(function (data) {
      $("#svg-loader").before(data);
      $(".svg-icon > use").attr("xlink:href", function (i, href) {
        return href.substr(href.indexOf("#"));
      });
    });
</script>

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

Ещё важно, чтобы в SVG разметке не было самозакрывающихся тегов. Нужно явно указывать закрывающий тег, если нет контента. Старые парсеры HTML-супа допускали лишь ограниченное количество самозакрывающихся тегов (<hr/>, <br/>, <input/> и т.п.) — поэтому мы не можем писать <div/>. Конструкции SVG могут поломать весь документ при определённом стечении обстоятельств.

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

Запрет на перенос текста между колонками

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

Обычное распределение текста между колонками

Можно запретить переносить содержимое элемента списка в следующую колонку, если обернуть его в блок со следующими стилями:

display: inline-block;
vertical-align: top;
width: 100%; /* опционально */

Элементы списка не разбивается между колонками

Ключевым правилом тут является display: inline-block. Вертикальное выравнивание нужно, чтобы маркер списка располагался в правильном месте.

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

Решение без дополнительного элемента

В комментариях были предложены ещё несколько решений этой задачи. Мне нравится вариант без обёртки.

  -webkit-column-break-inside: avoid;
            page-break-inside: avoid; /* Makes effect only in Firefox */
                 break-inside: avoid; /* IE10+, Opera 11.1—12.1 */
Комментарии к заметке: 8

Загрузка всех страниц сайта из sitemap.xml

Если у сайта есть карта в виде файла sitemap.xml, то все страницы, перечисленные в ней, можно загрузить с помощью комбинации нескольких консольных команд.

curl -s http://noteskeeper.ru/sitemap.xml | \
  grep '<loc>' | \
  sed 's/^.*\(http[^<]*\).*$/\1/' | \
  xargs curl >/dev/null -s
  1. Первой командой curl мы загружаем карту сайта.
  2. Затем находим в ней все теги <loc>, которые содержат адреса страниц, командой grep.
  3. Извлекаем URL из найденных тегов командой sed.
  4. Вызываем команду curl для каждой страницы.

В моём примере выполнение загрузки происходит «молчаливо» (ключ -s) и загруженные данные сразу же отправляются в /dev/null.

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

CSS3 transition прозрачности и видимость блока

Плавное появление элементов интерфейса с помощью CSS-анимации прозрачности уже стало обычной практикой. Но такой блок даже с полной прозрачностью перекрывает всё, что окажется под ним.

Устанавливать свойство display: none нельзя потому, что тогда перестанет работать анимация. В этом случае поможет смена значения у свойства visibility. Его, на ряду с другими свойствами, указываем в transition.

.tooltip {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s, visibility 0s linear 0.3s;
}
.widget:hover .tooltip {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

При «затухании» блока значение visibility: hidden применится с задержкой равной длительности анимации прозрачности. Без задержки блок будет скрыт мгновенно. Для фазы «появления» блока такой задержки наоборот не нужно. Блок должен получить видимость сразу и только после этого у него будет меняться прозрачность.

Обновление: В примере исправил «дрожание» блока, когда указатель движется около его нижней границы. Это приводило к тому, что указатель то уходил с блока, то вновь оказывался поверх него.

PS: Разумеется, названия CSS3 свойств transition и transition-delay нужно указывать с браузерными префиксами.

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