От автора: статья является выдержкой из нашей книги CSS мастер за авторством Tiffany B. Brown. Книгу можно купить в магазинах по всему миру или приобрести цифровую версию. Ранее в этой главе мы уже говорили, что псевдоклассы позволяют задавать стили на основе информации, которую невозможно получить из дерева документа и на которую нельзя сослаться с помощью простых селекторов. К ним относятся логические и лингвистические псевдоклассы типа :not и :lang(), а также псевдоклассы, срабатывающие на пользовательские события, типа :hover и :focus.
В этом разделе мы рассмотрим тайные и малоизвестные псевдоклассы с упором на то, что есть в браузерах: дочерние и типизированные дочерние псевдоклассы, а также псевдоклассы ввода. Дочерние обычные и дочерние типизированные псевдоклассы позволяют выбирать элементы на основе их позиции в поддереве документа. Псевдоклассы ввода выбирают поля форм по их значениям и состояниям.
Выделение фрагментов страницы с помощью :target
Идентификатор фрагмента – это та часть URL, которая идет после символа #. Например, #top или #footnote1. Вы могли их использовать для создания внутренней навигации по странице – так называемые якоря. С помощью :target можно выделить часть документа, относящуюся к этому фрагменту. И тут совсем не нужен JS.
Например, у вас есть несколько комментариев или ветка дискуссионного клуба:
1 2 3 4 5 6 |
<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 и всяких украшений, и страница будет выглядеть примерно так.
У каждого комментария в коде выше есть свой идентификатор фрагмента. То есть на каждый комментарий можно получить прямую ссылку. Например, <a href=»#comment-1146937891″>. Осталось лишь задать стили комментария с помощью псевдокласса :target:
1 2 3 4 |
.comment:target { background: #ffeb3b; border-color: #ffc107 } |
Когда в URL есть идентификатор фрагмента, ссылающийся на комментарий (например, //example.com/post/#comment-1146937891), комментарий будет выделяться желтым фоном, как на скриншоте ниже.
С :target можно использовать любые стили, что позволяет создавать вкладки без подключения JS. Craig Buckler подробно описал эту технику в своем уроке «как создать вкладки на чистом CSS3 с помощью селектора :target». Мы немного освежим его способ, добавим чуть больше CSS3 свойств. Во-первых, давайте взглянем на наш HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<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:
1 2 3 4 5 6 7 8 9 |
[id^=tab] { position: absolute; } [id^=tab]:first-child { z-index: 1; } [id^=tab]:target { z-index: 2; } |
А вот тут и кроется вся магия. Наши вкладки имеют абсолютное позиционирование. Дальше мы помещаем первую вкладку на самый верх с помощью z-index: 1. Данное свойство делает первую вкладку видимой по умолчанию. В конце мы добавляем z-index: 1 к нашей целевой вкладке. Так нужная нам вкладка всегда будет лежать поверх остальных. Результат представлен на скриншоте ниже.
Совет: повышение доступности
Для большей доступности можно использовать JS, с помощью которого будет устанавливаться атрибут hidden или aria-hidden=true в зависимости от видимости вкладок.
Клик по вкладке обновляет идентификатор фрагмента в URL, что в свою очередь вызывает состояние :target.
Вычитание селекторов с помощью :not()
Псевдокласс :not(), возможно, самый мощный из новых. Он возвращает все элементы кроме тех, которые указаны в аргументе. Например, p:not(.message) выберет все теги p без класса message.
Псевдокласс :not() также известен как функциональный псевдокласс. Он принимает один аргумент, как функции в других языках программирования. Передаваемый в :not() аргумент должен быть простым селектором: тип элемента, класс, ID или другой псевдокласс. Псевдокласс не сработает, если будет передан составной селектор типа label.checkbox или сложный селектор типа p img.
Пример формы с текстовыми полями и радиокнопками:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<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 выше лейблы, относящиеся к типу radio, имеют класс .label-radio. С помощью псевдокласса :not() можно выбрать элементы без класса label-radio, как показано на скриншоте ниже:
1 2 3 4 |
label:not(.label-radio) { font-weight: bold; display:block; } |
Этот пример поинтереснее. Давайте стилизуем текстовые поля. К таким полям относятся инпуты с типом number, email, text, password и url. Но давайте сделаем это, исключив из выборки радиокнопки, чекбоксы и ползунки. Первое, что может прийти в голову:
1 2 3 4 5 |
([type=radio]), input:not([type=checkbox]), input:not([type=range]) { ... } |
Но это не сработает, так как каждый селектор будет переписывать предыдущий. Это эквивалент такой записи:
1 2 3 |
input:not([type=radio]){ ... } input:not([type=checkbox]) { ... } input:not([type=range]) {... } |
Вместо этого необходимо сцепить псевдоклассы :not(), чтобы они все фильтровали поля input.
1 2 3 |
input:not([type=radio]):not([type=checkbox]):not([type=range]) { ... } |
Использовать псевдокласс или псевдоэлемент без простого селектора – это то же самое, что использовать его с универсальным селектором. То есть запись :not([type=radio]) равна *:not([type=radio]). В таком случае в выборку попадут все элементы без атрибута type и значения radio, в том числе html и body. Чтобы исключить это, используйте :not() с классом, ID или селектором атрибута. Кстати, это касается и классов, ID и селекторов атрибутов: .warning и [type=radio] равны *.warning и *[type=radio] соответственно.
Спецификация CSS Selectors Level 4 улучшает принцип работы :not(). Теперь он может принимать список аргументов, а не просто селекторы. Вместо сцепки можно использовать запятую в качестве разделителя в аргументе:
1 2 3 |
input:not([type=radio], [type=checkbox], [type=range]) { ... } |
К сожалению, этот синтаксис на данный момент не поддерживается ни в одном браузере. Пока что пользуйтесь сцепкой.
Автор: Tiffany Brown
Источник: //www.sitepoint.com/
Редакция: Команда webformyself.