Селектор CSS для первого заголовка самого высокого уровня?

Как я могу выбрать первый из самых высоких h* элементов, присутствующих в DOM?

Что-то типа

(h1, h2, h3, h4, h5, h6):first-of-ordered-set

т.е. если в дереве DOM есть в этом порядке h2, h3, h1, h2, h1, будет выбран первый h1;
а если в DOM есть h3, h3, h2, h2, h4, будет выбран первый h2.
Предположим, что h* элементов не являются вложенными.

Я подозреваю, что CSS не обладает такой силой, верно?

Что-то потенциально полезное: https://css-tricks.com/extremely-handy-nth-child-recipes-sass-mixins/

Изменить: почему я этого хочу: система CMS принимает этот «первый верхний заголовок» как заголовок документа (сообщение, страница, ...). Но он оставляет его на странице. И затем он показывает заголовок дважды - один раз в качестве заголовка сообщения и один раз в теле. JavaScript удален. Верхний уровень h* может отличаться.


person Ondra Žižka    schedule 27.07.2018    source источник
comment
В CSS есть циклы? Я ищу чистое решение CSS.   -  person Ondra Žižka    schedule 28.07.2018
comment
Ни в коем случае в чистом CSS   -  person j08691    schedule 28.07.2018
comment
У меня есть идея, но не уверен, что она охватит все случаи...   -  person Temani Afif    schedule 28.07.2018
comment
В CSS нет способа, но чего вы пытаетесь достичь?   -  person Ibu    schedule 28.07.2018
comment
@Ibu, я добавил мотивацию   -  person Ondra Žižka    schedule 28.07.2018
comment
Я так понимаю, нет никакой гарантии, что заголовок будет первым дочерним элементом определенного элемента, поэтому вы не можете просто использовать селектор первого дочернего элемента? Если это так, кажется, что скрывать это может быть небезопасно, если, скажем, автор сообщения не добавил заголовок до середины заголовка раздела. В этом случае скрытие заголовка раздела может привести к путанице. Как насчет того, чтобы скрыть автоматически сгенерированный заголовок, который предположительно вставляет CMS?   -  person lemoncucumber    schedule 28.07.2018
comment
Вот так. Но тогда автор должен не помещать самый высокий h* в другое место, кроме верхнего :) Скрытие верхнего заголовка нецелесообразно, потому что иногда заголовок исходит из метаданных, которые не отображаются. Так что у него вообще не было бы заголовка.   -  person Ondra Žižka    schedule 28.07.2018


Ответы (2)


Я нашел кое-что. CSS не может этого сделать. Пока.

W3C разрабатывает новые функции:

.post-content:has(h1, h2, h3, h4, h5, h6)

Вместе с :not() это позволит то, что мне нужно:

.post-content:has(h1) h1:first-of-kind,
.post-content:not(:has(h1)) h2:first-of-kind,
.post-content:not(:has(h1,h2)) h3:first-of-kind,
...

Есть одна загвоздка: в настоящее время :not() может иметь только один "простой селектор". Если бы он поддерживал больше, то это было бы достижимо и без :has.

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

person Ondra Žižka    schedule 27.07.2018
comment
Важное примечание: :has() будет доступен в JavaScript. См. это (незначительное) обсуждение в дискурсе WICG, где я явно просил, чтобы мы подтолкнули браузеры к его реализации. - person jhpratt; 28.07.2018

Основная проблема в том, что у нас нет предыдущего селектора в CSS. Например, мы можем получить первый h2, но если позже мы найдем h1, у нас не будет селектора для перехода назад.

Вот лучшее, что вы можете сделать с помощью CSS. Вы можете скрыть все элементы после нужного (чтобы нужный элемент был последним видимым), но вы не можете сделать то же самое с предыдущими элементами.

h1:first-of-type,
h2:first-of-type,
h3:first-of-type,
h4:first-of-type {
  color:red;
}


h1:first-of-type ~ * {
  display:none;
}
h2:first-of-type ~ *:not(h1) {
  display:none;
}
h3:first-of-type ~ h4 {
  display:none;
}


.container {
 border:1px solid;
}
<div class="container">
  <h3>text 3</h3>
  <h1>text 1*</h1>
  <h2>text 2</h2>
  <h1>text 1</h1>
</div>
<div class="container">
  <h3>text 3</h3>
  <h2>text 2*</h2>
  <h2>text 2</h2>
  <h4>text 1</h4>
</div>
<div class="container">
  <h3>text 3</h3>
  <h3>text 2</h3>
  <h2>text 2*</h2>
  <h4>text 1</h4>
</div>
<div class="container">
  <h1>text 3*</h1>
  <h3>text 2</h3>
  <h2>text 2</h2>
  <h4>text 1</h4>
</div>

Затем вы можете объединить с небольшим кодом JS, чтобы сохранить только необходимый элемент:

$('h3:first-of-type').prevAll('h4').hide();
$('h2:first-of-type').prevAll('*:not(h1)').hide();
$('h1:first-of-type').prevAll('*').hide();
h1:first-of-type,
h2:first-of-type,
h3:first-of-type,
h4:first-of-type {
  color:red;
}


h1:first-of-type ~ * {
  display:none;
}
h2:first-of-type ~ *:not(h1) {
  display:none;
}
h3:first-of-type ~ h4 {
  display:none;
}

.container {
 border:1px solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <h3>text 3</h3>
  <h1>text 1*</h1>
  <h2>text 2</h2>
  <h1>text 1</h1>
</div>
<div class="container">
  <h3>text 3</h3>
  <h2>text 2*</h2>
  <h2>text 2</h2>
  <h4>text 1</h4>
</div>
<div class="container">
  <h3>text 3</h3>
  <h3>text 2</h3>
  <h2>text 2*</h2>
  <h4>text 1</h4>
</div>
<div class="container">
  <h1>text 1*</h1>
  <h3>text 2</h3>
  <h2>text 2</h2>
  <h4>text 1</h4>
</div>

Раньше я делал элемент скрытым, но вы можете сделать то же самое с другими стилями:

$('h3:first-of-type').prevAll('h4').addClass('initial');
$('h2:first-of-type').prevAll('*:not(h1)').addClass('initial');
$('h1:first-of-type').prevAll('*').addClass('initial');
h1:first-of-type,
h2:first-of-type,
h3:first-of-type,
h4:first-of-type {
  color:red;
  font-family:cursive;
  font-style:italic;
}


h1:first-of-type ~ *,
h2:first-of-type ~ *:not(h1),
h3:first-of-type ~ h4,
h1.initial,h2.initial,h3.initial,h4.initial{
  color:initial;
  font-family:initial;
  font-style:initial;
}

.container {
 border:1px solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <h3>text 3</h3>
  <h1>text 1*</h1>
  <h2>text 2</h2>
  <h1>text 1</h1>
</div>
<div class="container">
  <h3>text 3</h3>
  <h2>text 2*</h2>
  <h2>text 2</h2>
  <h4>text 1</h4>
</div>
<div class="container">
  <h3>text 3</h3>
  <h3>text 2</h3>
  <h2>text 2*</h2>
  <h4>text 1</h4>
</div>
<div class="container">
  <h1>text 1*</h1>
  <h3>text 2</h3>
  <h2>text 2</h2>
  <h4>text 1</h4>
</div>

person Temani Afif    schedule 27.07.2018
comment
Да, CSS только движется вперед, и я считаю, что это как-то связано с производительностью. Вероятно, CSS обходит дерево только один раз с такими оптимизациями, как индексы для имен элементов, имен классов и идентификаторов. Я считаю, что это также причина разногласий вокруг has(). - person Ondra Žižka; 28.07.2018