Что не так с квалификацией тега CSS (например, h1.some-class)?

Может кто-нибудь, пожалуйста, объясните мне причины, по которым проверка тегов является плохой практикой CSS? Почему tag.class является плохим в случаях с самообновленными элементами? Например.

<section class="carousel-item">

  <header class="header of-carousel">
    <h2 class="heading of-carousel">Services</h2>
  </header>
    …
  <footer class="footer of-carousel">
    …
  </footer>

</section>

Почему это должно быть лучше, чем DRY и сжатый код с модификаторами контекста?

<section class="carousel-item">

  <header class="of-carousel">
    <h2 class="of-carousel">Services</h2>
  </header>
    …
  <footer class="of-carousel">
    …
  </footer>

</section>

.of-carousel {
  header.& {…}
  h2.& {…}
  footer.& {…}
}

Или даже

section.carousel-item
  header
    h2
  footer

.carousel-item {
  header {…}
      h2 {…}
  footer {…}
}

Я вижу, что многие люди пристрастились к BEM, но я не понимаю, почему? Их селекторы настолько уродливы, особенно - в-HTTP-2__ времени.

Ответ 1

Соглашение, с которым я знаком, заключается в том, что квалификация является плохим, если селекторы имеют разные уровни специфичности. Это означает, что нет смысла квалифицировать идентификатор с классом или тегом (поскольку идентификатор уже является уникальным) или квалифицировать класс с тегом (поскольку класс должен быть более уникальным, чем тег, и если ваш цель состоит в том, чтобы класс выполнял две разные вещи в двух разных случаях, вы должны повысить удобочитаемость, сделав их двумя разными классами). Мне, однако, никогда не говорили, что использование классификатора класса на классе - это плохая практика (на самом деле я подозреваю, что Bootstrap использует их достаточно широко, основываясь исключительно на синтаксисе).

Эта статья из MDN, которая является одним из лучших результатов поиска для "css tag qualifying", похоже, согласна с моей точкой зрения, по крайней мере, если это плохая практика:

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

Далее говорится:

Предыдущая концепция также применяется [для определения тега с классом]. Хотя классы могут использоваться много раз на одной странице, они по-прежнему более уникальны, чем тег. Одним из условий, которые вы можете использовать, является включение имени тега в имя класса. Однако это может стоить некоторой гибкости; если в тег внесены изменения в конструкцию, имена классов также должны быть изменены. (Лучше всего выбирать строго семантические имена, поскольку такая гибкость является одной из целей отдельных таблиц стилей.)

CSS-трюки, похоже, согласны, говоря:

Идентификаторы уникальны, поэтому им не требуется имя тега, чтобы идти вместе с ним. Это делает селектор менее эффективным. Не делайте этого с именами классов, если вы можете избежать этого. Классы не уникальны, поэтому теоретически вы можете иметь имя класса, которое может быть полезно для нескольких разных элементов. И если вы хотите, чтобы этот стиль был другим, в зависимости от элемента, вам может потребоваться tag-qualify (например, li.first), но это довольно редко, так что вообще не делайте этого.

Я надеюсь, что это поможет ответить на ваш вопрос.

Ответ 2

Вам следует избегать вложенности, что сводит к минимуму вероятность столкновения других правил друг с другом. Убедитесь, что наши CSS-модули будут выглядеть одинаково в любом контексте.

.block__elem - синтаксис модификатора не уродлив, если вы не используете несколько вложенных элементов.

Ответ 3

Принцип BEM заключается в том, чтобы удалить всю фактическую иерархию в документе CSS и иметь только одно явное правило для каждого элемента, который должен быть стилизован. Вот почему он эффективен - рендерингу никогда не приходится проходить через DOM для решения правил для детей или пытаться сопоставить более чем с одним квалификатором (поэтому использование разделителя тегов рядом с селектором классов считается "плохим",). Но я согласен, стандартное соглашение об именах для BEM очень устарело. Вы можете изменить это в соответствии с вашими предпочтениями.

Вам нужно понять, что правила CSS обрабатываются справа налево. Пример:

.carousel-item {
    header {…}
    h2 {…}
    footer {…}
}

Это приведет к тому, что рендеринг будет соответствовать всем элементам <header>, <h2> и <footer>. С помощью этих совпадений он попытается найти подходящий родительский .carousel-item, итерации до корня документа до тех пор, пока он не найдет его. Применение этого стиля к глубоко вложенному документу с несколькими элементами <h2> и <header>, не содержащимися в .carousel-item, означало бы наличие много потерянных поисков. Проще говоря: это не очень эффективно.

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

Реально говоря, это очень незначительная проблема в наши дни, и больше циклов процессора, вероятно, потрачено на работу с клиентским JavaScript, чем неоптимальный CSS. Но хорошо иметь в виду, если вы собираетесь построить что-то большое.