В языке HTML у HTML-элементов есть атрибуты. Некоторые атрибуты есть только у отдельных HTML-элементов, а другие — есть у любого HTML-элемента. Последние называют глобальными атрибутами. К любому HTML-элементу можно привязать один или несколько классов CSS, определяющих разные стили для данного HTML-элемента. Для этого у HTML-элемента существует глобальный атрибут class. Этот атрибут по правилам языка HTML не обязательно определять для всех HTML-элементов на HTML-странице, можно определить только для тех, для которых это будет нужно.

Например (несущественный сейчас код я заменил многоточиями):

...
<head>
  ...
  <style>
    .class-name1 { border: 2px solid blue; }
    .class-name2 { color: red; }
  </style>
</head>
<body>
  <p class="class-name1 class-name2">
    Ночь, улица, фонарь, аптека.
  </p>
</body>
...

В примере выше к HTML-элементу p привязано два класса CSS с названиями class-name1 и class-name2. Первый из этих классов CSS определяет для HTML-элемента p границу (ее толщину, вид линии границы, цвет границы), а второй — цвет текста внутри этого HTML-элемента. Эти же классы CSS можно привязать к другим HTML-элементам на HTML-странице.

Если к одному HTML-элементу привязано несколько классов CSS, то все они указываются в одном и том же атрибуте class данного HTML-элемента. При этом названия классов CSS отделяются друг от друга пробельными символами (пробелами, символами горизонтальной табуляции, символами новой строки).

При разборе кода HTML-страницы возникает вопрос: какие символы можно использовать в названиях классов CSS? Например, можно ли названия классов писать по-русски? Или китайскими иероглифами? Или с помощью эмодзи?

С точки зрения языка HTML

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

  1. С точки зрения синтаксиса языка HTML значение любого атрибута HTML-элемента определяется так (источник цитаты):

Attribute values are a mixture of text and character references, except with the additional restriction that the text cannot contain an ambiguous ampersand.

Грубо говоря, значение атрибута — это смесь текста (символы Юникода) с возможными вкраплениями ссылок на символы вида &#1102; (это пример ссылки на строчную русскую букву «ю»). Там куча всяких ограничений и оговорок, про которые я тут писать не буду, кому интересно — стоит пройти по вышеуказанным гиперссылкам и далее вглубь стандарта.

  1. С точки зрения построения DOM (объектной модели HTML-страницы) значение атрибута class определяется так (источник цитаты):

When specified on HTML elements, the class attribute must have a value that is a set of space-separated tokens representing the various classes that the element belongs to.

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

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

С точки зрения языка CSS

Для языка CSS тоже существует стандарт. Раньше это был один документ, разбитый на разделы, как стандарт языка HTML. Сейчас единый прежде документ разделили на так называемые «модули», каждый из которых может развиваться со своей скоростью. Существует документ, содержащий ссылки на все эти модули (спецификации). Всего этих модулей несколько десятков.

Для вопроса, заданного в названии этой статьи, важны два модуля (спецификации): определяющий селекторы и работу с ними, а также модуль, определяющий синтаксис языка CSS.

В языке CSS стилевые правила задаются с помощью так называемых «селекторов» (по-английски «selector»). Дословно это слово по-русски означает «отборщик» или «выборщик», потому что селектор отбирает (выбирает) из HTML-дерева узлы с указанным условием. Селекторы в CSS бывают очень разные, отбор происходит по разным условиям. Нас сейчас интересуют селекторы по классу (по-английски «class selector»). Селекторы по классу являются подвидом селекторов по атрибуту (по-английски «attribute selector»), так как класс в языке HTML является атрибутом HTML-элементов.

Вот ссылка на определение селектора в стандарте CSS (источник цитаты):

selector represents a particular pattern of element(s) in a tree structure. The term selector can refer to a simple selectorcompound selectorcomplex selector, or selector list. The subject of a selector is any element that selector is defined to be about; that is, any element matching that selector.

Следующий параграф стандарта дает определение «простому селектору» (по-английски «simple selector», источник цитаты):

simple selector is a single condition on an element. A type selectoruniversal selectorattribute selectorclass selectorID selector, or pseudo-class is a simple selector. (It is represented by <simple-selector> in the selectors grammar.) A given element is said to match a simple selector when that simple selector, as defined in this specification and in accordance with the document language, accurately describes the element.

Из этой цитаты видно, что понятие «простой селектор» включает, в частности, понятие «селектора по атрибуту» и «селектора по классу». Это определение отправляет нас в раздел грамматики селекторов.

Пройдем по ссылке и найдем определение селектора по классу:

<class-selector> = '.' <ident-token>

Эта схема читается так: селектор по классу начинается с символа точки, после которого сразу же (без разделяющих пробельных символов) идет идентификатор (название) класса (ident-token).

Вот этот самый «ident-token» (идентификатор) уже определен в другом модуле (спецификации) стандарта CSS, посвященном синтаксису (источник цитаты):

<ident-token><function-token><at-keyword-token><hash-token><string-token>, and <url-token> have a value composed of zero or more code points.

Напомню, под «кодовыми точками» (кодовыми позициями) подразумеваются символы Юникода (определение есть по вышеуказанной ссылке).

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

Конечно, следует иметь в виду, что в языке CSS есть множество служебных символов, вроде скобок разных видов, кавычек разных видов, символа точки и тому подобных. Но их таки можно представить в названии класса с помощью экранирования символов. Экранирование выполняется с помощью символа обратной косой черты (в Юникоде — «reverse solidus») — \. После этого символа можно вписать любой служебный символ и он будет интерпретирован как обычный символ, а не как служебный. Также после символа обратной косой черты можно вписать не сам символ, а его код в шестнадцатеричной системе.

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

Выводы и примеры

Эта статья не является исчерпывающим руководством! В стандартах есть множество разных редких правил и исключений. Все эти исключения невозможно описать в одной статье. В этой статье я просто хотел показать, что актуальные на сегодня стандарты HTML и CSS не ограничивают использование символов в названиях классов только латиницей (в интернетах часто можно встретить такое утверждение даже на относительно надежных ресурсах).

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

Один из примеров такого подхода — методология БЭМ (расшифровывается как «Блок, Элемент, Модификатор»). Цитата из соглашения по именованию этой методологии (это лишь фрагмент, продолжение я заменил многоточием):

– Имена записываются латиницей в нижнем регистре.
– Для разделения слов в именах используется дефис (-).
...

Я согласен, что это правильный подход (по многим причинам, которые я не буду излагать в этой статье). Однако, следует иметь в виду, что это всё-таки рекомендация (или требование корпоративных соглашений), а не требование стандартов HTML или CSS.

Примеры необычных имен классов CSS (не стоит этим злоупотреблять, но полезно знать, что такое возможно):

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8" />
  <title>Тестовая страница</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <style>
    .имя-класса { border: 2px solid blue; }     /* на русском языке */
    .类名 { color: red; }                       /* на китайском языке */
    .\1F60E\1F60D { background-color: yellow; } /* символы-эмодзи */
    .имя-со-служебным\#-символом { font-style: italic; }
    .\31имя-класса-начинающееся-с-цифры { border: 5px solid green; }
  </style>
</head>
<body>
  <p class="имя-класса 类名 ????????
            имя-со-служебным#-символом">
    Ночь. Улица. Фонарь. Аптека.
    Всё как у Блока. В поздний час
    Я встретил злого человека
    И получил фонарь под глаз.
  </p>
  <p class="1имя-класса-начинающееся-с-цифры">
    Потом примочки ставил лекарь,
    Меня в аптеку посылал...
    Ночь, улица, фонарь, аптека —
    Откуда ж Блок всё это знал?!
    (Автор пародии: Сергей Матвеенко.)
  </p>
</body>
</html>

Проверено валидатором HTML (весь этот файл), валидатором CSS (содержимое HTML-элемента style) и работает в браузерах «Microsoft Edge» (на движке «Chromium») и «Google Chrome».

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

Обратите внимание, что в коде на языке CSS символ решетки # (служебный для языка CSS) экранируется символом \, а при использовании этого символа в названии класса в коде на языке HTML — не экранируется (в языке HTML другой состав служебных символов для имен классов и там свой метод экранирования).

Кроме того, в коде на языке CSS цифру 1 в начале названия класса пришлось экранировать последовательностью \31, а не просто последовательностью \1 из-за того, что цифры после символа \ интерпретируются в CSS как шестнадцатеричный код символа Юникода, а не как числовой литерал.

Также в коде на языке CSS пришлось символы-эмодзи представить в виде их шестнадцатеричных кодов. Браузеры справляются, даже если в коде на языке CSS здесь указать символы-эмодзи напрямую, но вышеуказанные валидаторы (и для HTML, и для CSS) показывают ошибку (для шестнадцатеричных кодов ошибку не показывают).

И, наконец, в коде выше продемонстрировано, что названия классов CSS внутри атрибута class можно разделять не только пробелами, но и символом новой строки (или символом горизонтальной табуляции, но это здесь не показано).

Заключение

Информация, изложенная в этой статье, может пригодиться при написании парсера HTML, валидаторов HTML и CSS, просто при написании HTML-страниц. В интернетах по этому поводу много ссылок на устаревшие стандарты HTML и CSS (это и понятно, современные стандарты называют «живыми» (по-английски «living»), потому что они меняются очень быстро по сравнению с тем, как это было устроено раньше).

Комментарии (14)


  1. CoolCmd
    16.08.2022 15:15
    +1

    почему написано только о классах? немного дополню.


    в значение атрибута id тоже можно пихать эмодзи: <div id="????">


    в имена атрибутов тоже можно пихать эмодзи: <div data-????="????">.
    интересно, что A-Z в именах переводятся в нижний регистр, а остальные буквы — нет.


    в именах тегов разрешены только ASCII alphanumerics. печалька…


    зато в имена custom elements можно пихать эмодзи, но первый символ должен быть a-z: <f????-????></f????-????>.


    Проверено валидатором HTML

    я бы не стал доверять этому говну мамонта, который до сих пор HTML5 считает experimental.


    1. andreymal
      16.08.2022 15:39
      +1

      я бы не стал доверять этому говну мамонта, который до сих пор HTML5 считает experimental.

      Nu Html Checker регулярно обновляется и знает о многих (если не всех) фишках современного html, так что, думаю, ему можно доверять


      1. CoolCmd
        16.08.2022 17:28

        значит этот "experimental" там лишний


    1. ilyachalov Автор
      16.08.2022 17:17

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


      1. CoolCmd
        16.08.2022 17:31

        Если писать обо всем, то может получиться дубликат стандарта HTML.

        у меня все уместилось в один комментарий.


  1. Gremlinquisitor
    16.08.2022 17:15

    Страшно представить, во что превратится код, если в нём использовать такое разнообразие. Предлагаю всё же не мешать красивости и закидоны с общим удобством. Не зря во всех языках есть правила хорошего тона, среди которых прописаны и рекомендации по именованию переменных. Имя класса -- та же самая переменная.

    А помойку вместо аккуратного кода разбирать нет никакого удовольствия.


    1. ilyachalov Автор
      16.08.2022 17:33
      +1

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


      1. Gremlinquisitor
        17.08.2022 08:49

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


        1. ilyachalov Автор
          17.08.2022 12:34

          Я, собственно, пишу что-то вроде простого парсера HTML, поэтому читаю стандарты по теме. Да, изложенное усложняет мою работу... это не очень приятно. Однако, что делать, если стандарт это разрешает... Не будете же вы писать к своей программе-парсеру пояснения, что, дескать, товарищ пользователь, мой парсер, ищущий ошибки в твоих HTML-файлах, работает только с «хорошим» кодом, так что соблюдай рекомендации, иначе поищи другой инструмент...


    1. PereslavlFoto
      16.08.2022 23:50

      Разговор про нерусские переменные и нерусские классы идёт уже много лет.

      Почему?

      Потому что они — «общее удобство» только там, где общество говорит на английском языке. А если общество говорит на русском, китайском, арабском или казахском — там «общее удобство» основано на другой письменности и других языках.


      1. Gremlinquisitor
        17.08.2022 08:59

        Не соглашусь.

        Для начала напомню, что языки программирования используются по всему миру. Международный официальный язык - английский. Стандарт же на то и стандарт, что всем понятен. Независимо от того, на каком языке говорит разработчик, он сможет взаимодействовать с кодом: изменять, дополнять, делать что-то на его основе и так далее.

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


        1. PereslavlFoto
          17.08.2022 13:00

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

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

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


          1. Gremlinquisitor
            17.08.2022 16:18

            Разрабатывать и использовать - разные вещи. Представьте APIшник на китайском... Нравится? Интуитивно понятно, какие методы за что отвечают? Модуль, возможно, вообще сторонний, но нужный вашему проекту. С ним надо взаимодействовать. Намного удобнее, если язык будет однозначно понятен всем.


            1. PereslavlFoto
              17.08.2022 16:31

              Представьте APIшник на китайском… Модуль, возможно, вообще сторонний, но нужный вашему проекту.

              Владелец стороннего модуля просто не продаст его для использования в нашем проекте.