Классификация, расширяемость и другие странные слова

Марк Пилгрим

Оригинал: http://diveintohtml5.info/extensibility.html

Перевод: Влад Мержевич

В HTML5 свыше 100 элементов. Некоторые из них довольно семантичны, другие же просто являются контейнерами для рисования. На протяжении всей истории HTML зубрилы стандартов спорят о том, какие элементы должны быть включены в язык. Должен ли HTML включать элемент <figure>? А элемент <person>? Как насчёт элемента <rant>? Решения принимаются, спецификации пишутся, авторы создают, разработчики разрабатывают, и веб пошатываясь движется вперёд.

Конечно, HTML не может угодить всем. Но стандарт может. Некоторые идеи не идут с ним вразрез. Например, в HTML5 нет элемента <person> (нет также элемента <rant>, чёрт побери!). При этом ничего не мешает вам включить элемент <person> на страницу, но это не будет валидно и не будет работать корректно в разных браузерах. К тому же может возникнуть конфликт с будущими спецификациями HTML, если мы хотим добавить этот элемент позже.

Итак, если создание собственных элементов не решение, что делать авторам склонным к семантике? Были попытки расширить предыдущие версии HTML. Наиболее популярным методом являются микроформаты, которые используют атрибуты class и rel в HTML4. Другим вариантом является RDFa, который первоначально был предназначен для использования в XHTML, но в настоящее время также перенесён в HTML.

Микроформаты и RDFa имеют свои сильные и слабые стороны. Они содержат принципиально разные подходы с одной целью: расширение веб-страницы дополнительной семантикой, которая не является частью основного языка HTML. Я не намерен превратить эту главу в битву форматов (этого, несомненно, требует элемент <rant>). Вместо этого я хочу сосредоточиться на третьем варианте, который является частью HTML5 и тесно интегрирован с ним — микроданные.

Что за микроданные?

Каждое слово в следующем предложении имеет важное значение, так что будьте внимательны.

Профессор Маркап говорит

Микроданные комментируют DOM в пределах действия пары имя/значение из пользовательских словарей.

Как это теперь понимать? Давайте начнем разбирать от конца к началу. Микроданные крутятся вокруг пользовательских словарей. Подумайте о «множестве всех элементов HTML5» как об одном словаре. Этот словарь включает в себя элементы для представления раздела или статьи, но он не включает в себя элементы для представления персоны или события. Если вы хотите описать человека на веб-странице, вам нужно определить свой собственный словарь. Микроданные позволяют сделать это. Кто угодно может определить словарь микроданных и начать добавление пользовательских свойств на собственные веб-страницы.

Следующее, что нужно знать о микроданных это то, что они работают с парой имя/значение. Каждый словарь микроданных определяет набор именованных свойств. Например, словарь «Персона» может определить такие свойства как имя и фотография. Чтобы вставить специфическое свойство микроданных на веб-страницу, вы определяете имя свойства в специальном месте. В зависимости от того, где вы объявляете имя свойства, микроданные содержат правила о том, как извлечь значение свойства. Подробнее об этом в следующем разделе.

Наряду с именем свойства, микроданные в значительной мере опирается на концепцию «области действия». Простейший способ понять область действия микроданных, это подумать об отношениях элементов вида родитель-ребенок в DOM. Элемент <html> обычно состоит из двух детей, <head> и <body>. Элемент <body> обычно содержит несколько детей, каждый из которых может иметь свои собственные дочерние элементы. Например, страница может включать элемент <h1> внутри <hgroup>, который располагается внутри <header> внутри <body>. Таблица может содержать <td> внутри <tr> внутри <table> (в пределах <body>). Микроданные повторно используют иерархическую структуру DOM, чтобы обеспечить себе способ сказать «все свойства внутри этого элемента взяты из этого словаря». Это позволяет использовать больше, чем один словарь микроданных на одной странице. Вы можете даже вкладывать один словарь внутрь других словарей опять же путём повторного использования исходной структуры DOM. Я покажу несколько примеров вложенных словарей в этой главе.

Раз я уже затронул DOM, позвольте на нём остановиться. Микроданные применяют дополнительную семантику для данных, которые уже видны на вашей веб-странице. Микроданные не задуманы как отдельный формат данных, они лишь являются дополнением к HTML. Как вы увидите в следующем разделе, микроданные работает лучше при использовании корректного HTML, но сам HTML-словарь недостаточно выразителен. Микроданные отлично подходят для тонкой настройки семантики данных, которые уже есть в DOM. Если «семантизируемых» данных нет в DOM, вы должны сделать шаг назад и решить снова, являются ли микроданные верным решением.

Стало ли предложение «Микроданные комментируют DOM в пределах действия пары имя/значение из пользовательских словарей» более понятным? Я надеюсь на это. Давайте посмотрим на это всё в действии.

Модель микроданных

Определить свой собственный словарь микроданных довольно просто. Вначале вам нужно пространство имен, это всего-навсего URL. Этот URL действительно может вести на рабочую веб-страницу, хотя это и не обязательно. Допустим, я хочу создать словарь микроданных, который описывает человека. Если я владею доменом data-vocabulary.org, то буду использовать URL http://data-vocabulary.org/Person как пространство имен для моего словаря микроданных. Это простой способ создать глобальный уникальный идентификатор: выберите URL в домене, которым вы управляете.

В этом словаре мне нужно определить некоторые именованные свойства. Давайте начнём с трёх основных свойств:

  • name (ваше полное имя);
  • photo (ссылка на ваше изображение);
  • url (ссылка на сайт связанный с вами, вроде блога или профиля Google).

Некоторые из этих свойств являются URL, другие же обычным текстом. Каждое из них поддается естественной форме разметки ещё до того, как вы начнёте думать о микроданных, словарях или о чём-то ещё. Представьте, что у вас есть страница профиля или страница «обо мне». Ваше имя, вероятно, задано в качестве заголовка как элемент <h1>. Ваша фотография, вероятно, как элемент <img>, так как вы хотите, чтобы люди увидели её. И любой URL связанный с вашим профилем, вероятно, размечен как ссылка, потому что вы хотите чтобы люди могли перейти по ней. Для обсуждения скажу, что весь профиль также обёрнут в элемент <section>, чтобы отделить его от остального содержимого страницы. Таким образом.

Всё обо мне

<section>
<h1>Марк Пилгрим</h1>
<p><img src="http://www.example.com/photo.jpg" alt="[я улыбаюсь]"></p>
<p><a href="http://diveintomark.org/">блог</a></p>
</section>

Модель микроданных основана на паре имя/значение. Имя свойства (вроде имени человека, его фото или URL в данном примере) всегда объявляется в элементе HTML. Соответствующее значение свойства затем взято из элемента DOM. Для большинства элементов HTML значение свойства это просто текстовое содержимое элемента, но есть несколько исключений.

Откуда берётся значение свойств микроданных?
Элемент Значение
<meta> Атрибут content
<audio>
<embed>
<iframe>
<img>
<source>
<video>
Атрибут src
<a>
<area>
<link>
Атрибут href
<object> Атрибут data
<time> Атрибут datetime
Все остальные элементы Текстовое содержимое

«Добавление микроданных» на вашу страницу состоит в добавлении нескольких атрибутов в уже имеющиеся HTML-элементы. Первое, что вы всегда должны сделать, это объявить, какой словарь микроданных вы используете, путём добавления атрибута itemtype. Второе, что вы всегда должны сделать, это объявить область словаря используя атрибут itemscope. В этом примере все данные, которые мы хотим семантизировать, находятся в элементе <section>, поэтому объявим атрибуты itemtype и itemscope для элемента <section>.

<section itemscope itemtype="http://data-vocabulary.org/Person">

Ваше имя это первый кусочек данных в элементе <section>. Оно обёрнуто элементом <h1>. Элемент <h1> не имеет специальной обработки в модели микроданных HTML5, поэтому он подпадает под правило «все остальные элементы», где значением свойства микроданных выступает текстовое содержимое элемента. Это будет так же хорошо работать, если бы ваше имя было обёрнуто в элемент <p>, <div> или <span>.

<h1 itemprop="name">Марк Пилгрим</h1>

Говоря простым языком: «Словарь свойства name находится здесь: http://data-vocabulary.org/Person, а значением свойства выступает Марк Пилгрим».

Далее идёт свойство photo. Это должен быть URL. В соответствии с моделью микроданных HTML5 , «значением» элемента <img> выступает атрибут src. Эй, смотри, URL фотографии твоего профайла уже в атрибуте src. Всё, что вам нужно сделать, объявить о том, что элемент <img> — это свойство photo.

<p><img itemprop="photo"
src="http://www.example.com/photo.jpg"
alt="[я улыбаюсь]"></p>

Говоря простым языком: «Словарь свойства photo находится здесь: http://data-vocabulary.org/Person, а значением свойства является http://www.example.com/photo.jpg».

И наконец, свойство url это тоже URL. В соответствии с моделью микроданных HTML5, «значением» элемента <a> является атрибут href. И опять же это прекрасно вписывается в существующую разметку. Всё, что вам нужно сделать, это сказать, что существующий элемент <a> принадлежит свойству url:

<a itemprop="url" href="http://diveintomark.org/">мой сайт</a>

Говоря простым языком: «Словарь свойства url находится здесь: http://data-vocabulary.org/Person, а значением свойства выступает http://diveintomark.org/.

Конечно, если ваша разметка выглядит несколько иначе, то это не проблема. Вы можете добавить свойства и значения микроданных в любую HTML-разметку, даже очень упрямую табличную вёрстку XX века (о боже, почему я согласился на это). Хотя я не рекомендую такую разметку, она всё ещё широко распространена, и вы всё равно можете добавить к ней микроданные.

Ради бога, не делайте так

<TABLE>
<TR><TD>Имя<TD>Марк Пилгрим
<TR><TD>Ссылка<TD>
<A href=# onclick=goExternalLink()>http://diveintomark.org/</A>
</TABLE>

Для указания свойства name просто добавьте атрибут itemprop к ячейке таблицы, которая содержит имя. Ячейки не имеют специальных правил в таблице значений свойств микроданных, таким образом они получают значение по умолчанию: «свойством микроданных является текстовое содержимое».

<TR><TD>Имя<TD itemprop="name">Марк Пилгрим

Добавление свойства url выглядит сложнее. Данная разметка неверно использует элемент <a>. Вместо того, чтобы включить ссылку в атрибут href, ничего полезного в этом атрибуте не добавлено и в атрибуте onclick применяется JavaScript для вызова функции goExternalLink (её содержимое здесь не показано), которая извлекает URL и переходит к нему. Ради дополнительных бонусных баллов в рейтинге «пожалуйста, хватит так делать» давайте представим, что функция открывает ссылку в небольшом всплывающем окне без полос прокрутки. Разве Интернет прошлого века не смешон?

В любом случае, вы можете преобразовать этот код в микроданные, вам просто нужно проявить немного творчества. О непосредственном использовании элемента <a> не может быть и речи. Адреса ссылки нет в атрибуте href и нет никакого способа, чтобы изменить правило, которое говорит «внутри элемент <a> смотри значение свойства микроданных в атрибуте href». Но вы можете добавить контейнер вокруг этого беспорядка и использовать его для добавления свойства микроданных url.

Вот что вы получите за разрушение HTML

<TABLE itemscope itemtype="http://data-vocabulary.org/Person">
<TR><TD>Имя<TD>Марк Пилгрим
<TR><TD>Ссылка<TD>
<span itemprop="url">
<A href=# onclick=goExternalLink()>http://diveintomark.org/</A>
</span>
</TABLE>

Так как элемент <span> не имеет специальной обработки, то используется правило по умолчанию «свойством микроданных выступает текстовое содержимое». В данном случае «текстовое содержимое» не означает «вся разметка внутри этого элемента» (как это могло получиться, скажем, со свойством DOM innerHTML). Оно означает «только текст, сэр». В этом случае, текстовым содержимым элемента <a> внутри элемента <span> является http://diveintomark.org/.

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

Разметка людей

Кстати, начальные примеры в предыдущем разделе не закончены полностью. Мы включили словарь микроданных для разметки информации о людях, и это было просто. Давайте завершим начатое.

Самый простой способ интеграции микроданных с личным веб-сайтом — включить микроданные в страницу «Обо мне». У вас есть страница «Обо мне», не так ли? Если нет, то вы можете воспользоваться этим расширенным примером страницы с дополнительной семантикой.

Давайте посмотрим на исходную разметку перед добавлением каких-либо свойств микроданных.

<section>
<img width="204" height="250"
src="http://diveintohtml5.info/examples/2000_05_mark.jpg"
alt="[Марк Пилгрим, около 2000]">
<h1>Контактная информация</h1>
<dl>
<dt>Имя</dt>
<dd>Марк Пилгрим</dd>
<dt>Должность</dt>
<dd>Разработчик в Google, Inc.</dd>
<dt>Почтовый адрес</dt>
<dd>
100 Main Street<br>
Anytown, PA 19999<br>
USA
</dd>
</dl>
<h1>Мои цифровые отпечатки</h1>
<ul>
<li><a href="http://diveintomark.org/">блог</a></li>
<li><a href="http://www.google.com/profiles/pilgrim">профиль Google</a></li>
<li><a href="http://www.reddit.com/user/MarkPilgrim">профиль Reddit.com</a></li>
<li><a href="http://www.twitter.com/diveintomark">Twitter</a></li>
</ul>
</section>

Первое, что вам всегда нужно сделать, это объявить используемый словарь и область свойств, которые вы хотите добавить. Это можно сделать путём включения атрибутов Itemtype и itemscope для внешнего элемента содержащего другие элементы, в которых хранятся фактические данные. В нашем случае это элемент <section>.

<section itemscope itemtype="http://data-vocabulary.org/Person">

Теперь вы можете начать определение свойств микроданных словаря http://data-vocabulary.org/Person. Но что это за свойства? Как обычно, список свойств вы можете просмотреть путём перехода по адресу data-vocabulary.org/Person в вашем браузере. Спецификация микроданных не требует этого, но я бы сказал что это, безусловно, «хорошее решение». В конце концов, если вы хотите разработать актуальный словарь микроданных, необходимо его документировать. А где лучше разместить документацию, как не по адресу самого словаря?

Словарь Person
Элемент Значение
name Имя.
nickname Прозвище.
photo Ссылка на изображение.
title Заголовок персоны (например: финансовый менеджер).
role Роль персоны (например: бухгалтер).
url Ссылка на веб-страницу вроде персонального сайта.
affilation Название организации с которой связана персона (например, как сотрудник).
friend Определяет социальные связи между этой и другой персоной.
contact Определяет социальные связи между этой и другой персоной.
acquaintance Определяет социальные связи между этой и другой персоной.
address Местоположение персоны. Может содержать подсвойства: street-address, locality, region, postal-code и country-name.

Первая вещь в данном примере страницы «обо мне» это моё изображение. Естественно, оно верстается с помощью элемента <img>. Всё, что нужно сделать для объявления того, что этот элемент <img> выступает моей фотографией в профиле, так это добавить itemprop="photo" в <img>.

Где находятся значения свойств микроданных? Они уже здесь, в атрибуте src. Если вы помните из модели микроданных HTML5, «значением» элемента <img> является атрибут src. Каждый элемент <img> содержит атрибут src — в противном случае мы бы просто получили битое изображение — и src это всегда URL. Видите? Если вы используете HTML правильно, с микроданными всё просто.

Кроме того, этот элемент <img> не один на странице. Он является дочерним элементом <section>, который мы только что связали с атрибутом itemscope. Микроданные повторно используют отношения элементов родитель-потомок на странице, чтобы определить область видимости свойств микроданных. Говоря простым языком: «Этот элемент <section> представляет собой персону. Любые свойства микроданных вы можете найти в дочерних элементах <section>, которые являются характеристиками этой персоны». Если это поможет, вы можете подумать об элементе <section> как о фразе. Атрибут itemprop представляет собой глагол , что-то вроде «изобразить как» Значение свойства микроданных представляет собой сказуемое.

Эта персона [явно, из <section itemscope itemtype="...">]

изображена в [явно, из <img itemprop="photo">]

http://diveintohtml5.info/examples/2000_05_mark.jpg [неявно, из атрибута <img src>]

Подлежащее должно быть определено сразу, путём добавления атрибутов itemscope и itemtype в обрамляющий элемент <section>.Глагол определяется добавлением атрибута itemprop="photo" в <img>. Сказуемое в предложении не требует специальной разметки, потому что модель микроданных HTML5 говорит о том, что значением свойства элемента <img> является атрибут src.

Переходя к следующему блоку разметки, мы видим заголовок <h1> и начало списка <dl>. Ни <h1>, ни <dl> не нуждаются в микроданных. Не каждый фрагмент HTML должен выступать свойством микроданных. Микроданные сами должны говорить о себе, а не разметка или заголовки окружающих свойств делают это. <h1> не является таким свойством, это просто заголовок. Кроме того, <dt> который говорит «Имя» не является свойством, это просто название.

Скучно

<h1>Контактная информация</h1>
<dl>
<dt>Имя</dt>
<dd>Марк Пилгрим</dd>

Так где же настоящая информация? Она находится в элементе <dd>, так что мы должны поставить здесь атрибут itemprop. Какое из свойств? Свойство name. Где находится значение свойства? В тексте элемента <dd>. Значит ли это, что надо сделать разметку? Модель микроданных HTML5 говорит нет, элементы <dd> не имеют специальной обработки, поэтому значение свойства это только текст внутри элемента.

Это мое имя

<dd itemprop="name">Марк Пилгрим</dd>

Как это сказать человеческим языком? Имя этой персоны — Марк Пилгрим. Хорошо, поехали дальше.

Следующие два свойства немного сложнее. Вот разметка ещё до микроданных.

<dt>Должность</dt>
<dd>Разработчик в Google, Inc.</dd>

Если вы посмотрите на определение словаря Person, то текст «Разработчик в Google, Inc» на самом деле включает в себя два свойства: название («Разработчик») и принадлежность («Google, Inc»). Как вы можете выразить это в микроданных? Если коротко, то никак. В микроданных нет способа разбить текст на отдельные свойства. Нельзя сказать «первые 18 символов этого текста являются одним свойством микроданных, а последние 12 символов еще одним свойством».

Но не все потеряно. Представьте, что вы хотите выделить текст «Разработчик» другим шрифтом в отличие от текста «Google, Inc». CSS не может такого. Так что бы вы сделали? В первую очередь необходимо включить фрагмент текста в элемент вроде <span>, а затем применить разные правила CSS для каждого элемента <span>.

Эта техника также полезна для микроданных. Есть два разных фрагмента информации: title и affiliation. Если обернуть каждую часть в фиктивный элемент <span>, то можно заявить, что каждый <span> это отдельное свойство микроданных.

<dt>Должность</dt>
<dd><span itemprop="title">Разработчик</span> в
<span itemprop="affiliation">Google, Inc.<span></dd>

Та-да! «Эта персона называется Разработчик. Эта персона работает в Google, Inc». Два предложения, два свойства микроданных. Немного лишней разметки, но оно того стоило.

Аналогичный приём используется для разметки адреса. Словарь Person определяет свойство address, которое само по себе является пунктом микроданных. Это означает, что адрес имеет свой собственный словарь (http://data-vocabulary.org/Address) и определяет собственные свойства. Словарь Address содержит пять свойств: street-address, locality, region, postal-code и country-name.

Если вы программист, то, вероятно, знакомы с нотацией для определения объектов и их свойств. Подумайте о взаимосвязи следующим образом:

  • Person
  • Person.address
  • Person.address.street-address
  • Person.address.locality
  • Person.address.region
  • Person.address.postal-code
  • Person.address.country-name

В этом примере адрес содержится в одном элементе <dd>. Опять же, элемент <dt> просто название, так что он не играет никакой роли в добавлении семантики от микроданных. Описать свойство address легко. Просто добавьте атрибут itemprop к элементу <dd>.

<dt>Почтовый адрес</dt>
<dd itemprop="address">

Но помните, что свойство address само по себе является пунктом микроданных. Это значит, что мы также должны добавить атрибуты itemscope и itemtype.

<dt>Почтовый адрес</dt>
<dd itemprop="address" itemscope
itemtype="http://data-vocabulary.org/Address">

Мы видели всё это раньше, но только для элементов верхнего уровня. Элемент <section> содержит itemtype и itemscope, а все элементы внутри <section> определены свойствами микроданных с «областью действия» конкретного словаря. Но это первый раз когда мы видим вложенные области действия областей — добавление новых itemtype и itemscope (к элементу <dd>) к существующим (у элемента <section>). Эта вложенная область действия работает точно так же как HTML DOM. Элемент <dd> содержит определённое количество дочерних элементов, которые ограничены словарём, заданным для элемента <dd>. Как только элемент <dd> закрывается соответствующим тегом </dd>, область действия возвращается к словарю определённым родительским элементом (<section> в данном случае).

Свойства адреса страдают той же проблемой, с которой мы столкнулись со свойствами title и affiliation. У нас только один длинный текст, но мы хотим его разбить на пять отдельных свойств микроданных. Решение следующее: обернуть каждый отдельный фрагмент информации фиктивным элементом <span>, а затем объявить свойства микроданных для каждого <span>.

<dd itemprop="address" itemscope
itemtype="http://data-vocabulary.org/Address">
<span itemprop="street-address">100 Main Street</span><br>
<span itemprop="locality">Anytown</span>,
<span itemprop="region">PA</span>
<span itemprop="postal-code">19999</span>
<span itemprop="country-name">USA</span>
</dd>
</dl>

Простым языком: «Для этой персоны указан почтовый адрес. Улица — 100 Main Street, местность — Anytown, регион — PA, почтовый индекс — 19999, страна — USA». Реально просто.

Спроси профессора Маркапа

В. Формат почтового адреса специфичен для США?

О. Нет. Свойства словаря Address достаточно общие, поэтому они могут описать большинство почтовых адресов в мире. Не все адреса содержат значения для каждого свойства, но это нормально. Некоторые адреса могут потребовать более одной «строки» в одном из свойств, но это также нормально. К примеру, если ваш почтовый адрес содержит улицу и номер квартиры, они оба пойдут в street-address:

<p itemprop="address" itemscope
itemtype="http://data-vocabulary.org/Address">
<span itemprop="street-address">
100 Main Street
Suite 415
</span>
...
</p>

Осталась ещё одна вещь на странице примера «Обо мне»: список URL. В словаре Person для этого есть свойство с именем url. Это свойство может быть любым, воистину (вообще-то, оно должно содержать URL, но вы об этом наверное уже догадались). Я имею в виду, что свойство url достаточно свободно. Это может быть URL любого типа, который вы хотите связать со словарём Person: блог, фотогалерея, профиль на сайте вроде Facebook или Twitter.

Другая важная вещь о которой надо отметить, это то, что у каждой персоны может быть несколько свойств url. Технически, каждое свойство может быть добавлено несколько раз, но мы до сих пор не пользовались этим. Например, у вас может быть два свойства photo, каждое из которых указывает на свой URL изображения. Здесь я хочу перечислить четыре разных URL: мой блог, мой профиль на Google, мой профиль на Reddit, и мой аккаунт Twitter. В HTML это список ссылок: четыре элемента <a>, каждый в своём элементе <li>. В микроданных каждый элемент <a> получает атрибут itemprop = "url".

<h1>Мои цифровые отпечатки</h1>
<ul>
<li><a href="http://diveintomark.org/"
itemprop="url">блог</a></li>
<li><a href="http://www.google.com/profiles/pilgrim"
itemprop="url">профиль Google</a></li>
<li><a href="http://www.reddit.com/user/MarkPilgrim"
itemprop="url">Профиль Reddit.com</a></li>
<li><a href="http://www.twitter.com/diveintomark"
itemprop="url">Twitter</a></li>
</ul>

В соответствии с моделью микроданных HTML5, элементы <a> имеют специальную обработку. Значением свойства является атрибут href, а не дочерний текст. Текст каждой ссылки микроданными фактически игнорируется. Таким образом, говоря простым языком: «У этой персоны есть URL http://diveintomark.org/. У этой персоны есть другой URL http://www.google.com/profiles/pilgrim. У этой персоны есть другой URL http://www.reddit.com/user/MarkPilgrim. У этой персоны есть другой URL http://www.twitter.com/diveintomark».

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.