Выберите первое вхождение тега, игнорируя иерархию, с помощью CSS.

Вопрос или проблема

Я наткнулся на вопрос о селекторе CSS. Как выбрать первое вхождение <span>, игнорируя иерархию. Я знаю, что могу использовать JavaScript с document.querySelectorAll('span'), чтобы получить первый объект DOM и назначить ему класс. Но есть ли способ достичь этого без использования JavaScript?

HTML-структура произвольная, поэтому такие селекторы, как div:first-child > p:first-of-type > div:first-of-type span:first-of-type, слишком специфичны. Я хочу, чтобы селектор работал даже в случае изменения структуры HTML.

Я попробовал что-то вроде этого, но не понимаю, почему MISS ME 4 тоже выбран.

span:first-of-type:not(:has(span):nth-child(n+2 of :has(span)) span) {
  color: red;
  font-weight: bold;
}
<div>
  <h1>Выберите первое вхождение span</h1>
  <p>
    <span>HIT ME</span>
    <div>
      <span>MISS ME 1</span>
      <span>MISS ME 2</span>
      <span>MISS ME 3</span>
    </div>
    <span>MISS ME 4</span>
    <span>MISS ME 5</span>
  </p>
  <p>
    <span>MISS ME 6</span>
    <span>MISS ME 7</span>
  </p>
</div>
<div>
  <p>
    <span>MISS ME 7</span>
    <span>MISS ME 8</span>
  </p>
  <p>
    <span>MISS ME 9</span>
    <span>MISS ME 10</span>
    <span>MISS ME 11</span>
  </p>
  <p>
    <span>MISS ME 12</span>
    <span>MISS ME 13</span>
    <span>MISS ME 14</span>
    <div>
      <span>MISS ME 15</span>
      <span>MISS ME 16</span>
      <span>MISS ME 17</span>
    </div>
  </p>
</div>

Возможно ли это вообще? У меня совсем нет идей.

</div><div class="s-prose js-post-body" itemprop="text">

Чтобы выбрать первый span в документе, выберите элемент span, который:

  • не предшествует соседний элемент span
  • не предшествует соседний элемент, содержащий элемент span
  • не имеет предшествующего предка, который является соседним элементом span
  • не имеет предшествующего предка, который является соседним элементом, содержащим элемент span

Используйте:

span:not(span ~ span):not(:has(span) ~ span):not(span ~ * span):not(:has(span) ~ * span)

span:not(span ~ span):not(:has(span) ~ span):not(span ~ * span):not(:has(span) ~ * span) {
  color: red;
  font-weight: bold;
}
<div>
  <h1>Выберите первое вхождение span</h1>
  <p>
    <span>HIT ME</span>
    <div>
      <span>MISS ME 1</span>
      <span>MISS ME 2</span>
      <span>MISS ME 3</span>
    </div>
    <span>MISS ME 4</span>
    <span>MISS ME 5</span>
  </p>
  <p>
    <span>MISS ME 6</span>
    <span>MISS ME 7</span>
  </p>
</div>
<div>
  <p>
    <span>MISS ME 7</span>
    <span>MISS ME 8</span>
  </p>
  <p>
    <span>MISS ME 9</span>
    <span>MISS ME 10</span>
    <span>MISS ME 11</span>
  </p>
  <p>
    <span>MISS ME 12</span>
    <span>MISS ME 13</span>
    <span>MISS ME 14</span>
    <div>
      <span>MISS ME 15</span>
      <span>MISS ME 16</span>
      <span>MISS ME 17</span>
    </div>
  </p>
</div>

Ответ или решение

Чтобы выбрать первое вхождение тега <span> в HTML-документе, игнорируя иерархию, необходимо использовать подход, который позволяет обойти ограничения стандартных селекторов CSS. Обычно, при использовании селекторов, таких как :first-child или :first-of-type, вы сталкиваетесь с проблемами, когда структура документа меняется, что делает ваш селектор неэффективным.

Проблема:

В представленном вопросе необходимо выбрать первый элемент <span>, независимо от того, в каком родительском элементе он находится. Стандартные селекторы недостаточны для этой задачи, ведь они не дают возможности игнорировать иерархию элементов.

Решение:

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

span:not(:has(span)):nth-of-type(1) {
    color: red;
    font-weight: bold;
}

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

Альтернативный подход:

Для точного выбора первого <span>, игнорируя иерархию и избегая использования JavaScript, можно использовать следующую комбинацию селекторов:

span:not(:has(span)) {
    color: red;
    font-weight: bold;
}

Это позволит выбрать все элементы <span>, которые не содержат другие элементы <span>, но здесь также необходимо будет учитывать контекст, в котором вы работаете. В случае, если структура изменится, может потребоваться дополнительное уточнение селектора.

Примечания:

  1. Следите за совместимостью – Использование селекторов, таких как :has(), не поддерживается всеми браузерами, поэтому важно протестировать решение в разных средах.
  2. Адаптивность – Всегда старайтесь разрабатывать такие селекторы, которые будут адаптивны к изменениям в HTML-структуре. Возможное решение требует тщательной проверки.

Выводы:

Выбор первого тега <span> без учета иерархии с помощью только CSS — это сложная задача. Тем не менее, применение современных селекторов и комбинаций может помочь добиться нужного результата. Важно помнить о разумном использовании возможностей CSS, чтобы избежать проблем с совместимостью и производительностью.

Этот метод далеко не идеален, но дает вам направление для поиска оптимальных решений. Если вы всё же хотите добиться 100% контроля, лучшее решение будет включать в себя JavaScript, который может избирательно модифицировать элементы на странице.

Оцените материал
Добавить комментарий

Капча загружается...