Представляем вашему вниманию перевод статьи, посвящённой использованию атрибутов
HTML-элементы могут иметь атрибуты, которые используются для решения самых разных задач — от предоставления данных ассистивным технологиям, до стилизации элементов.
При этом не рекомендуется создавать собственные атрибуты, или применять существующие атрибуты такими способами, на которые они не рассчитаны.
Это плохо по многим причинам. HTML-код оказывается неправильно сформированным. И хотя подобное может и не иметь реальных негативных последствий, это лишает разработчика тёплого чувства вызываемого тем, что он создаёт валидный HTML-код. Но главная причина того, что так поступать не следует, заключается в том, что HTML — это язык, который постоянно развивается. В результате, если некий атрибут сегодня в языке не применяется, это не значит, что в будущем ничего не изменится.
Правда, если кому-то нужно использовать подобные атрибуты, у него есть совершенно нормальный способ это делать. Речь идёт о создании собственных атрибутов, названия которых начинаются с префикса
Возможность создавать собственные HTML-атрибуты и записывать в них данные может оказаться крайне полезной. Это, как вы понимаете, возможно благодаря атрибутам
Эти атрибуты, именно из-за того, что они всегда начинаются с префикса
Вот пример кода, в котором используется атрибут с именем
Атрибут с таким именем, вероятно, никому не повредит, но его применение не позволит пользоваться JavaScript-инструментами, которые мы рассмотрим ниже. В этом примере разработчик, фактически, создаёт некий собственный атрибут, что, как уже было сказано, делать не рекомендуется.
В таких атрибутах не стоит хранить содержимое, которое должно быть доступно ассистивным технологиям. Если некие данные должны быть видимы на странице, или должны быть доступны средствам для чтения с экрана, их недостаточно просто поместить в атрибут
Вот материал о том, как скрывать элементы веб-страниц.
В CSS можно выбирать HTML-элементы, основываясь на атрибутах и их значениях.
Это может показаться интересным. Для стилизации в HTML/CSS используются, в основном, классы. И хотя классы — это замечательный инструмент (они отличаются средним уровнем специфичности, с ними можно работать с помощью удобных JavaScript-методов через свойство элементов
Специфичность селекторов атрибутов такая же, как у классов. Специфичность часто рассматривают как значение, состоящее из 4 частей:
В результате, если представить себе значение специфичности для элемента, который стилизуется только с использованием селектора атрибута, то оно будет выглядеть так:
А вот ещё один селектор:
Он уже будет описываться значением
Вот, чтобы было понятнее, иллюстрированная версия этих рассуждений.
1 тег, 1 класс и 1 атрибут
У селекторов атрибутов специфичность ниже, чем у идентификаторов (
Если нужно, чтобы селекторы выбирали бы атрибуты, значения которых могут содержать строки, записанные с использованием разных комбинаций строчных и прописных букв, можно воспользоваться вариантом селектора, нечувствительным к регистру.
Такое поведение обеспечивает использование в селекторе символа
CSS позволяет извлекать значения атрибутов
Атрибуты
Вот соответствующий CSS-код:
А вот — фрагмент результирующей страницы.
Grid-контейнеры, настройка которых производится с помощью атрибутов data-*
Поэкспериментировать с этим примером можно на CodePen.
К значениям атрибутов
Однако атрибуты
Если имеется ссылка на этот элемент, то читать и записывать значения его атрибутов можно так:
Обратите внимание на то, что в последней строке JS-кода используется запись имени атрибута в верблюжьем (CamelCase) стиле. Система автоматически преобразует имена HTML-атрибутов, записанные в кебаб-стиле, в имена, записанные в верблюжьем стиле. То есть —
Этот API, конечно, не такой удобный, как API classList, поддерживающий понятные методы вроде
В JavaScript можно работать и со встроенными в элементы наборами данных:
А почему бы не записать в атрибут
Идея тут заключается в том, чтобы, пользуясь атрибутами
Распространённый вариант реализации этого сценария направлен на организацию работы с базами данных. Предположим, у нас имеется кнопка
У этой кнопки может быть обработчик нажатия, выполняющий AJAX-запрос к серверу. Обработчик, если пользователь лайкнет что-то с помощью кнопки, увеличивает количество лайков в серверной базе данных. Обработчик знает о том, какую именно запись надо обновить, так как берёт сведения об этом из атрибута
Вот, вот и вот — стандарты, связанные с селекторами атрибутов
Уважаемые читатели! Как вы применяете HTML-атрибуты data-*?
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-*?