Как стать автором
Обновить
2604.11
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Полное руководство по HTML-атрибутам data-*

Время на прочтение8 мин
Количество просмотров99K
Автор оригинала: Chris Coyier
Представляем вашему вниманию перевод статьи, посвящённой использованию атрибутов data-*. Это — атрибуты, которые можно применять для удобного хранения в стандартных HTML-элементах различной полезной информации. Эта информация, в частности, может применяться в JavaScript и CSS.



Общие сведения


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

<!-- Атрибут `class` можно использовать для стилизации в CSS, атрибут `role` используется ассистивными технологиями -->
<div class="names" role="region" aria-label="Names"></div>

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

<!-- `highlight` не является HTML-атрибутом-->
<div highlight="true"></div>

<!-- `large` не является допустимым значением для `width` -->
<div width="large">

Это плохо по многим причинам. HTML-код оказывается неправильно сформированным. И хотя подобное может и не иметь реальных негативных последствий, это лишает разработчика тёплого чувства вызываемого тем, что он создаёт валидный HTML-код. Но главная причина того, что так поступать не следует, заключается в том, что HTML — это язык, который постоянно развивается. В результате, если некий атрибут сегодня в языке не применяется, это не значит, что в будущем ничего не изменится.

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

Синтаксис


Возможность создавать собственные HTML-атрибуты и записывать в них данные может оказаться крайне полезной. Это, как вы понимаете, возможно благодаря атрибутам data-*. Именно для этого такие атрибуты и предназначены. Выглядит это так:

<!-- Этим атрибутам необязательно назначать значения -->
<div data-foo></div>

<!-- ...но они могут содержать значения -->
<div data-size="large"></div>

<!-- Тут мы имеем дело с HTML, поэтому надо экранировать HTML-код, который, возможно, решено будет записать в атрибут -->
<li data-prefix="Careful with HTML in here."><li>

<!-- Если надо - можно создавать длинные имена атрибутов -->
<aside data-some-long-attribute-name><aside>

Эти атрибуты, именно из-за того, что они всегда начинаются с префикса data-, часто называют атрибутами data-* или data-атрибутами. При формировании имён этих атрибутов сначала идёт слово data, потом — тире (-), а потом — оставшаяся часть имени, устроенная так, как нужно разработчику.

Можно ли использовать атрибут, имеющий имя data?


Вот пример кода, в котором используется атрибут с именем data:

<div data=""></div>

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

Чего не стоит делать с атрибутами data-*


В таких атрибутах не стоит хранить содержимое, которое должно быть доступно ассистивным технологиям. Если некие данные должны быть видимы на странице, или должны быть доступны средствам для чтения с экрана, их недостаточно просто поместить в атрибут data-*. Такие данные должны появиться и в обычной HTML-разметке.

<!-- Эти данные не выводятся на странице, они недоступны ассистивным технологиям -->
<div data-name="Chris Coyier"></div>

<!-- Если нужен программный доступ к данным, но они не должны выводиться на странице, есть и другие способы... -->
<div>
  <span class="visually-hidden">Chris Coyier</span>
</div>

Вот материал о том, как скрывать элементы веб-страниц.

Стилизация элементов с использованием атрибутов data-*


В CSS можно выбирать HTML-элементы, основываясь на атрибутах и их значениях.

/* Выбрать элемент с таким именем атрибута, имеющим такое значение */
[data-size="large"] {
  padding: 2rem;
  font-size: 125%;
}

/* Выбор можно ограничить элементом, классом, или чем-то другим */
button[data-type="download"] { }
.card[data-pad="extra"] { }

Это может показаться интересным. Для стилизации в HTML/CSS используются, в основном, классы. И хотя классы — это замечательный инструмент (они отличаются средним уровнем специфичности, с ними можно работать с помощью удобных JavaScript-методов через свойство элементов classList), элемент может либо иметь, либо не иметь некоего класса (то есть, класс в элементе либо «включен», либо «выключен»). При использовании атрибутов data-* в распоряжении разработчика оказываются и возможности классов («включено/выключено»), и возможность выбора элементов, основываясь на значении атрибута, которое он имеет на том же уровне специфичности.

/* Выбор элементов, у которых имеется указанный атрибут */
[data-size] { }

/* Выбор элемента, атрибут которого имеет заданное значение */
[data-state="open"],
[aria-expanded="true"] { }

/* Селектор "начинается с", использование которого приведёт к выбору элементов, атрибут которых содержит "3", а так же - что угодно другое, начинающееся с 3 - вроде "3.14" */
[data-version^="3"] { }
/* Селектор "содержит" указывает на то, что заданная строка должна содержаться где-то в значении свойства */
[data-company*="google"] { }

Специфичность селекторов атрибутов


Специфичность селекторов атрибутов такая же, как у классов. Специфичность часто рассматривают как значение, состоящее из 4 частей:

  • Встроенный стиль
  • ID
  • Классы и атрибуты
  • Теги

В результате, если представить себе значение специфичности для элемента, который стилизуется только с использованием селектора атрибута, то оно будет выглядеть так: 0, 0, 1, 0

А вот ещё один селектор:

div.card[data-foo="bar"] { }

Он уже будет описываться значением 0, 0, 2, 1. Число 2 здесь появляется из-за того, что тут имеется и класс (.card), и атрибут ([data-foo="bar"]). А 1 здесь из-за того, что тут присутствует лишь один тег (div).

Вот, чтобы было понятнее, иллюстрированная версия этих рассуждений.


1 тег, 1 класс и 1 атрибут

У селекторов атрибутов специфичность ниже, чем у идентификаторов (ID), но выше, чем у тегов (элементов). Их специфичность равна специфичности классов.

Значения атрибутов, нечувствительные к регистру


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

/* Всё это соответствует следующему селектору
<div data-state="open"></div>
<div data-state="Open"></div>
<div data-state="OPEN"></div>
<div data-state="oPeN"></div>
*/
[data-state="open" i] { }

Такое поведение обеспечивает использование в селекторе символа i.

Вывод данных, хранящихся в атрибутах data-*


CSS позволяет извлекать значения атрибутов data-* и выводить их на странице.
 
/* <div data-emoji=":-)"> */

[data-emoji]::before {
  content: attr(data-emoji); /* Возвращает ':-)' */
  margin-right: 5px;
}

Примеры использования атрибутов data-* для стилизации элементов


Атрибуты data-* можно использовать для указания того, сколько столбцов должно быть у grid-контейнера. Вот HTML-код:

<div data-columns="2">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

<div data-columns="3">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

<div data-columns="4">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

Вот соответствующий CSS-код:

[data-columns] {
  display: grid;
  grid-gap: 1rem;
  padding: 1rem;
  margin: 0 0 1rem 0;
}

[data-columns] > div {
  height: 100px;
  background: white;
}

[data-columns="2"] {
  background: #64B5F6;
  grid-template-columns: repeat(2, 1fr);
}

[data-columns="3"] {
  background: #9CCC65;
  grid-template-columns: repeat(3, 1fr);
}

[data-columns="4"] {
  background: #FFB74D;
  grid-template-columns: repeat(4, 1fr);
}

А вот — фрагмент результирующей страницы.


Grid-контейнеры, настройка которых производится с помощью атрибутов data-*

Поэкспериментировать с этим примером можно на CodePen.

Работа с атрибутами data-* в JavaScript


К значениям атрибутов data-* можно обращаться, как и к значениям других атрибутов, пользуясь методом getAtribute для чтения данных, и методом setAttribute для записи.

// Чтение значения атрибута
let value = el.getAttribute("data-state");

// Запись значения атрибута.

// В data-state записывается значение "collapsed"
el.setAttribute("data-state", "collapsed");

Однако атрибуты data-* имеют и собственный особый API. Предположим, у нас есть элемент с несколькими атрибутами data-* (что совершенно нормально):

<span 
  data-info="123" 
  data-index="2" 
  data-prefix="Dr. "
  data-emoji-icon=":-)"
></span>

Если имеется ссылка на этот элемент, то читать и записывать значения его атрибутов можно так:

// Чтение
span.dataset.info; // 123
span.dataset.index; // 2

// Запись
span.dataset.prefix = "Mr. ";
span.dataset.emojiIcon = ";-)";

Обратите внимание на то, что в последней строке JS-кода используется запись имени атрибута в верблюжьем (CamelCase) стиле. Система автоматически преобразует имена HTML-атрибутов, записанные в кебаб-стиле, в имена, записанные в верблюжьем стиле. То есть — data-this-little-piggy превращается в dataThisLittlePiggy.

Этот API, конечно, не такой удобный, как API classList, поддерживающий понятные методы вроде add, remove, toggle и replace, но это, всё же, лучше чем ничего.

В JavaScript можно работать и со встроенными в элементы наборами данных:

<img align="center" src="spaceship.png"
  data-ship-id="324" data-shields="72%"
  onclick="pewpew(this.dataset.shipId)">
</img>
<h2><font color="#3AC1EF">JSON-данные в атрибутах data-*</font></h2>
<ul>
  <li data-person='
    {
      "name": "Chris Coyier",
      "job": "Web Person"
    }
  '></li>
</ul>

А почему бы не записать в атрибут data-* JSON-данные? Ведь это всего лишь строки, которые можно отформатировать как валидные JSON-данные (учитывая кавычки и прочее). При необходимости эти данные можно извлечь из атрибута и распарсить.

const el = document.querySelector("li");

let json = el.dataset.person;
let data = JSON.parse(json);

console.log(data.name); // Chris Coyier
console.log(data.job); // Web Person

Об использовании атрибутов data-* в JavaScript


Идея тут заключается в том, чтобы, пользуясь атрибутами data-*, размещать в HTML-коде данные, к которым можно обращаться из JavaScript для выполнения неких действий.

Распространённый вариант реализации этого сценария направлен на организацию работы с базами данных. Предположим, у нас имеется кнопка Like:

<button data-id="435432343">Like</button>

У этой кнопки может быть обработчик нажатия, выполняющий AJAX-запрос к серверу. Обработчик, если пользователь лайкнет что-то с помощью кнопки, увеличивает количество лайков в серверной базе данных. Обработчик знает о том, какую именно запись надо обновить, так как берёт сведения об этом из атрибута data-*.

Итоги


Вот, вот и вот — стандарты, связанные с селекторами атрибутов data-*. Здесь, на сайте Caniuse, можно узнать о поддержке атрибутов data-* браузерами. Если вы раньше не пользовались этими атрибутами, надеемся, этот материал дал вам пищу для размышлений.

Уважаемые читатели! Как вы применяете HTML-атрибуты data-*?

Теги:
Хабы:
Всего голосов 30: ↑29 и ↓1+44
Комментарии18

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds