Псевдоклассы СSS :not() и :target

Сегодня мы рассмотрим менее распространенные псевдоклассы CSS, которые поддерживаются в современных браузерах: child-indexed и typed child-indexed, а также псевдоклассы для элементов ввода input. Псевдоклассы child-indexed и typed child-indexed позволяют выделять элементы по их расположению в дереве документа. Псевдоклассы input определяют поля формы на основе их значений и состояний.

Подсветка фрагментов страницы псевдоклассом :target

В этом случае идентификатор фрагмента является частью URL, который следует после хеша # (например, #top или #footnote1). Такое часто используется для организации навигации по странице при помощи так называемой «jump-link». С помощью псевдокласса :target можно подсветить фрагмент документа:

<section id="comments">
<h2>Comments on this post</h2>
<article class="comment" id="comment-1146937891">...</article>
<article class="comment" id="comment-1146937892">...</article>
<article class="comment" id="comment-1146937893">...</article>
</section>

После нескольких штрихов и работы с CSS получается результат, который приведен ниже:

Подсветка фрагментов страницы псевдоклассом :target

Каждый comment в коде обозначен идентификатором, который позволяет ссылаться на конкретный фрагмент. Например, <a href="#comment-1146937891">. Всё что остаётся – это стилизовать комментарий, используя псевдокласс CSS child :target:

.comment:target {
  background: #ffeb3b;
  border-color: #ffc107
}

Когда идентификатор фрагмента в URL совпадает с комментарием (например, http://example.com/post/#comment-1146937891), он будет подсвечен жёлтым цветом, как показано ниже:

Подсветка фрагментов страницы псевдоклассом :target - 2

Псевдокласс CSS :target позволяет создавать комбинации, что открывает пространство для манёвров и позволяет не использовать JavaScript. Стилизуем наш пример с помощью CSS3. Для начала посмотрите на HTML-код:

<div class="tabbed-widget">
<div class="tab-wrap">
	<a href="#tab1">Tab 1</a>
	<a href="#tab2">Tab 2</a>
	<a href="#tab3">Tab 3</a>
</div>

<ul class="tab-body">
	<li id="tab1">
		<p>This is tab 1.</p>
	</li>
	<li id="tab2">
		<p>This is tab 2</p>
	</li>
	<li id="tab3">
		<p>This is tab 3.</p>
	</li>
</ul>
</div>

Здесь всё просто: три вкладки и контент с привязкой. Добавим CSS:

[id^=tab] {
    position: absolute;
}
[id^=tab]:first-child {
    z-index: 1;
}
[id^=tab]:target {
    z-index: 2;
}

Здесь и начинается волшебство. Сначала мы задаём вкладкам абсолютное позиционирование. Затем располагаем первую вкладку поверх контента при помощи свойства z-index: 1. Это важно, если при первом посещении пользователи должны видеть именно эту вкладку. Добавляем свойство z-index 1 к нашей вкладке target. Это гарантирует, что выделенный слой всегда будет расположен поверх остального контента. Результат представлен ниже:

Улучшаем доступность

В более доступной версии (в том числе и псевдоклассах CSS ссылок) можно использовать JavaScript для переключения атрибутов hidden и aria-hidden=true.

Клик по вкладке обновляет URL с использованием нового идентификатора фрагмента, после чего приводится в действие состояние :target.

Отрицание селекторов при помощи :not()

Одним из самых многофункциональных считается псевдокласс :not(). Он возвращает все элементы, за исключением тех, которые совпадают с аргументом селектора. Например, p:not(.message) выделяет все элементы p без класса message.

Псевдокласс :not() принимает один аргумент, как и большинство функций в других языках программирования. Любой аргумент, заданный в :not(), должен быть простым селектором, названием класса или ID, другим псевдоклассом. Псевдоклассы не работают так, как составные селекторы типа label.checkbox или сложные селекторы типа p img.

Посмотрите на пример формы, в которой используется текстовые элементы ввода и radio buttons:

<form method="post" action="#">
  <h1>Join the Cool Kids Club</h1>
  <p>
	   <label for="name">Name:</label>
	   <input type="text" id="name" name="name" required>
  </p>

  <p>
	  <label for="email">Email:</label>
	  <input type="email" id="email" name="email" required>
  </p>
  <fieldset>
	<legend>Receive a digest?</legend>
	<p>
		<input type="radio" id="daily" name="digest">
		<label for="daily" class="label-radio">Daily</label>                
		<input type="radio" id="weekly" name="digest">
		<label for="weekly" class="label-radio">Weekly</label>
	</p>
  </fieldset>
  <button type="submit">Buy Tickets!</button>
</form>

В HTML label, ассоциированные с элементами типа radio, имеют класс .label-radio. Можно использовать псевдокласс CSS нажатия :not() для выделения элементов, не имеющих класса label-radio, как это показано на картинке ниже:

label:not(.label-radio) {
  font-weight: bold;
  display:block;   
}
Отрицание селекторов при помощи :not()

Рассмотрим более сложный пример. Используем стилизацию текстовых полей. Сюда входят элементы ввода number, email и text, а также password и url. Кроме этого мы исключим элементы radio, checkbox и range. Вам наверняка захочется воспользоваться следующим списком селектора:

([type=radio]),
input:not([type=checkbox]),
input:not([type=range]) {
  ...
}

К сожалению, это не поможет, так как каждый новый селектор переписывает предыдущий. Это всё равно, что писать:

input:not([type=radio]){ ... }
input:not([type=checkbox]) { ... }
input:not([type=range]) {... }

Вместо этого, нужно связать псевдоклассы :not() в цепочку, чтобы они отфильтровывали все элементы input:

input:not([type=radio]):not([type=checkbox]):not([type=range]) {
...
}

Приведённая цепочка селекторов также соответствует элементам [type=image], [type=reset], [type=color] и [type=submit]

Использование псевдоклассов и псевдоэлементов CSS без простого селектора эквивалентно его использованию с универсальным селектором. Другими словами, :not([type=radio]) – то же, что и *:not([type=radio]). В данном случае нашему критерию отвечает любой элемент без атрибута type и значения radio, включая html и body. Чтобы предотвратить это, используйте :not() с названием класса, ID или селектор атрибутов в качестве селектора.

В CSS Class-селекторах Level 4 изменен принцип работы :not(), так что, теперь он принимает в качестве аргумента не только простые селекторы, но и списки. Вместо того чтобы связывать классы, как это делалось раньше, можно указывать аргументы через запятую:

input:not([type=radio], [type=checkbox], [type=range]) {
...
}

К сожалению, пока далеко не все браузеры поддерживают этот вариант, поэтому мы рекомендуем и дальше использовать цепочки.

Валентин Сейидовавтор-переводчик статьи «CSS Pseudo-classes: :not() and :target»

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