Заметки в категории «Вёрстка» (страница 2)

То, что скрыто комментарием

Содержимое HTML комментариев никогда не разбирается парсером документа. Однако, они не пропадают бесследно в пучине тегов. Все комментарии можно достать с помощью JavaScript.

Каждый элемент DOM-дерева имеет поле noteType, в котором указан его тип. Для комментария значения поля равно 8.

var children = document.getElementsByTagName("head")[0].childNodes;
var comments = Array.prototype.filter.call(children,
  function (node) { return node.nodeType == 8; });
var content = comments.map(function (node) { return node.nodeValue; });

Из-за того, что элементы комментариев нельзя получить с помощью .querySelectorAll(), сначала нужно найти родительский элемент, в котором они находятся, и только потом перебором всех детей получить содержимое нужных узлов.

Практическое применение

Условная загрузка

Шикарная идея применять комментарии для формирования разметки на стороне клиента материализовалась в виде проекта Адама Чамберза — Responsive Comments.

Блокам добавляется атрибут data-responsive-comment-media с медиа запросом или атрибут data-responsive-comment-supports с тестом Modernizr. В зависимости от выполнения указанного условия блоки будет появляться или скрывать. А так как изначально контент обвёрнут в комментарий, то это позволит избежать лишних запросов на сервер и лишних элементов в документе.

Поисковая оптимизация

Эксперимент на основе идеи прятать контент от поисковиков в комментариях и доставать его от туда уже на клиентской стороне полностью провалился. Поисковики не только разбирают HTML, то и запускают все скрипты как это делают настоящие браузеры. Это позволяет им индексировать динамически появляющийся контент.

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

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

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

Данные, которые скрыты от пользователя

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

<title> и <meta name="description">

Эти мета-данные были одними из самых первых, которые помогали роботам понять суть страницы.

В теге <title> размещают заголовок страницы. Для каждой страницы должен быть указан заголовок и лучше всего, если он будет уникальным для всего сайта. На размер строки заголовка нет явных ограничений, но из практических соображений не стоит делать его длиннее 70-80 символов.

В атрибуте content тега <meta name="description"> размещают кратное описание страницы. Длину стоит ограничить 150-160 символами потому, что оно активно используется для построения сниппета в поисковой выдаче и более длинное описание будет автоматически укорочено. Явного ограничения в спецификациях нет. Содержимое, как и в случае с заголовком страницы, должно быть уникальным для всего сайта.

Ещё одним классическим тегом считается <link rel="canonical">. Он нужен для того, чтобы сообщить роботам какая из страниц с одинаковым содержимым, если таковые имеются, считается основной. Адрес задаётся в атрибуте href.

Протокол Open Graph

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

Facebook разработал на основе RDFa упрощенный протокол Open Graph, который работает в одном пространстве имён og и имеет ограниченный набор типов данных (музыка, видео, статья, книга, персона и сайт).

<html prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
<head>
  <title>Больше семантики для логотипа :: Хранитель заметок</title>
  <meta property="og:title" content="Больше семантики для логотипа">
  <meta property="og:type" content="article">
  <meta property="og:url" content="http://noteskeeper.ru/945/">
  <meta property="og:image" content="http://noteskeeper.ru/assets/img/nk-logo-200.png">
  <meta property="og:description" content="Разметке логотипа можно добавить семантики с помощью microdata. Тип Brand позволяет указать логотип для продуктов и людей">
  <meta property="og:site_name" content="Хранитель заметок">
  <meta property="article:published_time" content="2013-08-26T03:31:18+00:00">
  <meta property="article:section" content="Вёрстка">
  <meta property="article:tag" content="microdata">
  ...

Протокол получил поддержку у множества социальных сервисов и поисковых систем. Некоторые из них, например, Twitter и Вконтакте, адаптируют его для своих нужд, используя часть полей Open Graph и дополняя необходимыми данными.

Microdata и RDFa

Почти одновременно в 2009 году появились черновики двух спецификаций, оперирующих со сложными типами объектов и поддерживающие их глубокую вложенность:

Оба формата используют дополнительные атрибуты HTML-элементов, чтобы указать тип объекта и его свойства. Значения свойств за некоторым исключением берётся из текстового содержимого элемента.

RDFa позволяет указывать значение свойства с помощью атрибута content у любого элемента:

<span property="dc:modified"
  content="2013-09-16T15:00:00+00:00"
  datatype="xsd:dateTime">16 сентября 2013 года</span>

В то время как парсерам Microdata требуются дополнительные элементы <meta> или <link>:

<span>16 сентября 2013 года</span>
<meta itemprop="dateModified" content="2013-09-16T15:00:00+00:00">

Разметка с помощью Microdata или RDFa позволяют сообщить роботам о семантике контента независимо от того какими тегами он размечен в HTML. Более того, форматы позволяют обозначить данные, невидимые пользователю в силу внешнего дизайна страницы.

“Shaken, not stirred”

При всём разнообразии мета-данных, которые можно впихнуть на страницу, складывается ситуация, когда одни и те же данные будут повторяться в HTML-коде несколько раз.

Например, описание страниц, которое фигурирует во всех форматах, можно передать в одном теге:

<meta content="Разметке логотипа можно добавить семантики с помощью microdata. Тип Brand позволяет указать логотип для продуктов и людей"
  name="description"
  property="og:description"
  itemprop="description"
  id="_articleDescription">

В этом примере свойство description типа http://schema.org/Article подключается в объект с помощью ссылки по id в атрибуте itemref. Если это позволяет разметка, то тип самого важного объекта на странице можно объявить у корневого элемента документа. Тогда все теги meta естественным образом окажутся в области видимости этого объекта.

<html prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#" itemscope itemtype="http://schema.org/Article">
<head>
  <title>Больше семантики для логотипа :: Хранитель заметок</title>
  <meta property="og:title" content="Больше семантики для логотипа" itemprop="name">
  <meta property="og:type" content="article">
  <meta property="og:url" content="http://noteskeeper.ru/945/" itemprop="url">
  <meta property="og:image" content="http://noteskeeper.ru/assets/img/nk-logo-200.png" itemprop="image">
  <meta property="og:description" content="Разметке логотипа можно добавить семантики с помощью microdata. Тип Brand позволяет указать логотип для продуктов и людей" itemprop="description">
  <meta property="og:site_name" content="Хранитель заметок">
  <meta property="article:published_time" content="2013-08-26T03:31:18+00:00" itemprop="dateCreated">
  <meta property="article:section" content="Вёрстка" itemprop="articleSection">
  <meta property="article:tag" content="microdata" itemprop="keywords">
  ...

Так как привязка нового объекта к «родителю» осуществляется только наличием у него атрибута itemprop, то при его отсутствии новый объект помещается на самый верхний уровень иерархии. Получается, что на странице можно безопасно размещать несколько независимых объектов.

Атрибуты role и aria-*

Особняком стоят атрибуты Web Accessibility Initiative (WAI). Они используются вспомогательными технологиями для обеспечения доступности контента для пользователей с ограниченными возможностями.

Скринридерам часто приходится специально сообщать о назначении элемента (атрибут role), его названии (атрибуты aria-label, aria-labelledby, aria-describedby) или состоянии, так как у него нет другого способа передать эту информацию пользователю.

Заключение

  • Старайтесь сообщить как можно больше полезной информации о содержимом страницы для роботов даже если она останется невидимой для человека.
  • Избегайте повторения одних и тех же мета-данных в разных форматах. Чаще всего их можно объединить, используя разные техники.
  • Проверяйте качество разметки с помощью соответствующих парсеров и валидаторов.
Комментарии к заметке: 6