css
Основы

Псевдоклассы

CSS
Основы

Обновлено

14.09.2023

Просмотров

230

Время прочтения

40 мин.

Сложность

Псевдоклассы определяют промежуточное, событийное состояние элементов, а также некоторые положения элементов в документе\в родительском элементе. Например, при определении состояний мы можем описать стиль для тега, над которым находится курсор мыши, или тега, на котором находится фокус пользователя, и т.д. При определении положения элемента мы можем выбрать первый\последний элемент в документе\в родителе, или элемент 2-й,3-й по порядку в документе\в родителе, чётный\нечётный и т.д. Сейчас это может звучать немного непонятным, но после просмотра примеров вы, уверен, во всём разберётесь.

Синтаксис написания псевдокласса следующий: указывается имя элемента или класс\идентификатор элемента, а затем с двоеточием указывается псевдокласс:

Как видите, при наведении курсора фон кнопки становится белым. За стиль элемента, над которым находится курсор мыши, отвечает псевдокласс :hover, описанный в примере. То есть мы имеем стиль для кнопки, но не для обычной кнопки, а только для кнопки, над которой находится курсор мыши. В другом состоянии данный стиль к кнопке не применяется.

Псевдокласс :active

Псевдокласс :active отвечает за состояние элемента, когда он становится активным. Это наиболее часто используется для работы с ссылками или кнопками. Когда вы нажимаете на ссылку, но ещё не отпускаете кнопку мыши,- это является состоянием элемента :active. То же самое относится и к кнопке <button>. Ниже находится интерактивная кнопка, которая продемонстрирует работу псевдокласса :active. Кнопка при нажатии на неё изменит свой вид, но на другие события она реагировать не будет.

Псевдокласс :focus

Применяется к элементам, на которых сфокусирован пользователь. Это могут быть поля <input>,<select>,<textarea>,<a> в тот момент, когда пользователь кликнул на них\начал ввод, или когда он сфокусировался при помощи кнопки TAB (для ссылки :active и :focus работают практически одинаково).

Потеря фокуса — тоже событие, и оно ведёт к возвращению обычного состояния элемента. Для потери фокуса элементом достаточно лишь кликнуть в любом другом месте документа. Наглядно работу псевдокласса :focus демонстрирует пример ниже:

Помимо обычного фокуса, существует также псевдокласс :focus-within. Он обрабатывается, когда на выбранном элементе или на любом из его потомков происходит событие focus. Чаще всего это используется в работе с <form>, если мы хотим при фокусировании на любом из полей изменять и стили формы.

В данном примере, если мы будем просто кликать куда-то внутри формы и производить иные действия, никакого эффекта не будет. Но стоит нам сфокусироваться на любом из <input> или на кнопке <button>, мы тут же увидим красивую тень у формы, создаваемую посредством псевдокласса :focus-within.

Хотя этот псевдокласс и является весьма удобным, использовать его нужно с осторожностью, поскольку он ещё не пользуется достаточной браузерной поддержкой: на момент написания урока его понимают до 92% браузеров. Это означает, что вы должны либо согласиться с тем, что этот focus-эффект у некоторых пользователей не будет работать (ничего тут не поделаешь), либо отказаться от него и написать обработку этого фокуса на JavaScript.

Псевдокласс :hover

Бесспорно, это наиболее часто используемый псевдокласс. Как уже говорилось, он появляется у элемента в тот момент, когда курсор мыши находится над элементом. Большая часть визуальных эффектов у ссылок, кнопок, блоков и пр., которые мы видим ежедневно на веб сайтах, являются реализациями псевдокласса :hover. Это самая первая интерактивность, которую вы будете создавать как верстальщики\фронтенд разработчики. Пример, в котором при наведении курсора кнопка изменяет свой внешний вид:

Стоит отметить, что :hover действует всегда на все элементы, над которыми находится курсор. То есть, если мы имеем <main>, а внутри него <div>, а внутри него <button> и наводим курсор на <button>, событие :hover срабатывает соответственно на всех этих элементах. Когда мы просто водим мышкой по веб-странице, мы всегда находимся в состоянии :hover для <html> и <body>. Это даёт нам обширные возможности для стилизации сайта.

Вы можете объединять псевдоклассы с обыкновенными селекторами, например указывать :hover не для вложенного элемента, а для его родителя, да и вообще для любого из элементов в селекторе.
Пример кода ниже поможет вам понять, о чём идёт речь.

Как видите, в первом случае мы изменяем цвет ссылки при ховере на текст. Во втором случае мы изменяем цвет <span> при ховере на ссылке.
Запомните о таких возможностях, в будущем они вам обязательно понадобятся, например при создании карточек продукта. Довольно часто ховер на
такие карточки изменяет цвет фона, текста, тень у различных элементов этих карточек.
Вместе с тем, зная о таких обширных возможностях стилизации, вы не должны забывать, что чрезмерная интерактивность раздражает пользователей.

Касаемо псевдокласса :hover есть ещё кое-что, что вам необходимо знать. Примерно у половины устройств, с которых сейчас пользователи выходят в интернет, у элемента вообще не может быть состояния :hover, поскольку это touch-устройства с сенсорными экранами. Когда мы нажимаем на экран iPad, который является одним из таких устройств, происходит событие touch, оно очень похоже на click, который происходит при использовании компьютера и мыши. Но всё же это разные события. Что касается :hover, то на touch устройствах попросту нет курсора, поэтому :hover таким устройствам недоступен. Однако это не относится к событиям :focus, :active, с которыми всё в порядке.

Главное, что вы должны усвоить из этого — интерфейс не должен терять важную функциональность и доступность с потерей :hover. Если какие-то важные элементы вашего сайта
работают только при :hover, возможно вам стоит предусмотреть какое-то альтернативное решение для touch устройств, например прописать подобное поведение элементов при помощи JavaScript.

Псевдокласс :visited

Псевдокласс определяет уже посещённые ссылки. Если для ссылок не задан пользовательский цвет текста, то ссылка отображается со стилями (в Google Chrome) color: -webkit-link. Это означает, что к ссылке и ко всем её состояниям, в том числе :visited применяются дефолтные стили браузера. Если же вы пропишите в своих авторских стилях любой другой цвет, то ссылка в состоянии :visited будет также отображаться указанным цветом. Разумеется, если вы пропишите для :visited отдельный цвет, посещённая ссылка примет этот цвет.

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

Прежде, когда CSS ещё не был развит и владельцы сайтов не особенно беспокоились насчёт внешнего вида их детища, пользователи отмечали такое отображение ссылок и это было привычно и понятно для многих — часть ссылок, по которым пользователь ещё не переходил, была синего цвета, а другая часть фиолетовая. Хотя это было не красиво и не стильно, может это было немного полезно. В дальнейшем, когда сайты стали внешне выглядеть лучше, данный псевдокласс перестал играть какую-либо роль в дизайне и вёрстке.

Псевдокласс :first-child

Этот псевдокласс работает не совсем очевидным образом. Он выбирает первые дочерние теги. То есть если мы напишем p :first-child, то получим первые дочерние теги всех тегов, вложенных в параграфы, на любых уровнях (в примере вложенность только в 1 уровень):

                
<style> p :first-child{ color: red; } </style> <p><strong>Что-то особенное</strong><br> Далеко-далеко, за, <span>словесными</span> горами в стране гласных и согласных живут рыбные тексты. <span>Языкового</span> над ему обеспечивает осталось решила которой океана его, <span>реторический</span> скатился меня не дорогу домах.</p> <p>Далеко-далеко, за словесными горами в стране <span>гласных</span> и согласных живут <span>рыбные</span> тексты. Злых грустный она ipsum то запятых эта агентство <span>подзаголовок</span> власти, языком пор рыбного, все несколько!</p>

Для первого параграфа первым дочерним тегом будет strong, именно он стал красным. Для второго параграфа первым дочерним тегом будет уже span. Если мы в какой-либо span вложим ещё ссылку, то эта ссылка тоже будет выделена красным, поскольку она тоже будет являться первым дочерним тегом!

Многие начинающие и не очень разработчики думают, что этот тег можно использовать для выбора только первого span в родителе, написав селектор например p span:first-child, однако этот код не сработает ожидаемым образом:

                
<style> p span:first-child{ color: red; } </style> <p> <strong>Что-то особенное</strong><br> Далеко-далеко, за, <span>словесными</span> горами в стране гласных и согласных живут рыбные тексты. <span>Языкового</span> над ему обеспечивает осталось решила которой океана его, <span>реторический</span> скатился меня не дорогу домах.</p> <p>Далеко-далеко, за словесными горами в стране <span>гласных</span> и согласных живут <span>рыбные</span> тексты. Злых грустный она ipsum то запятых эта агентство <span>подзаголовок</span> власти, языком пор рыбного, все несколько!</p>

Как видите, strong в первом параграфе перестал отображаться красным, но и span в нём не стал красным. Это произошло потому, что селектор p span:first-child нашёл все параграфы, затем в каждом нашёл все span и потом проверил, является ли какой-либо из них первым дочерним тегом. Как видите, под это условие подходит только первый span во втором параграфе.

Псевдокласс :first-of-type

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

                
<style> p span:first-of-type{ color: red; } </style> <p> <strong>Что-то особенное</strong><br> Далеко-далеко, за, <span>словесными</span> горами в стране гласных и согласных живут рыбные тексты. <span>Языкового</span> над ему обеспечивает осталось решила которой океана его, <span>реторический</span> скатился меня не дорогу домах.</p> <p>Далеко-далеко, за словесными горами в стране <span>гласных</span> и согласных живут <span>рыбные</span> тексты. Злых грустный она ipsum то запятых эта агентство <span>подзаголовок</span> власти, языком пор рыбного, все несколько!</p>

Если мы не будем указывать span вообще, то в таком случае селектор выберет все первые теги всех типов:

                
<style> p :first-of-type{ color: red; } </style> <p> <strong>Что-то особенное</strong><br> Далеко-далеко, за, <span>словесными</span> горами в стране гласных и согласных живут рыбные тексты. <span>Языкового</span> над ему обеспечивает осталось решила которой океана его, <span>реторический</span> скатился меня не дорогу домах.<br> <a href="#">пример ссылки</a></p> <p>Далеко-далеко, за словесными горами в стране <span>гласных</span> и согласных живут <span>рыбные</span> тексты. Злых грустный она ipsum то запятых эта агентство <span>подзаголовок</span> власти, языком пор рыбного, все несколько!</p>

Обратите внимание на то, что и strong, и первый span, и ссылка стали красными. Если мы добавим внутрь параграфа ещё любой другой новый тег, он тоже попадёт в число :first-of-type. А вот второй span, как видите, не отображается красным цветом. Только первый тег своего типа попадает в число :first-of-type.

Существует довольно много заблуждений, касающихся :first-child и :first-of-type. О первом из этих псевдоклассов уже было немного рассказано. Что касается второго из них,
вы должны понять и запомнить, что он подразумевает ВСЕГДА работу с дочерними тегами, а также то, что он работает именно с тегами, и по очереди «перебирает» все
присутствующие на странице теги, проверяя каждый из них. Чтоб какой-то тег попал в эту выборку, такой тег должен быть дочерним и должен быть первым среди тегов своего типа.
В случае, если вы дополнительно укажете класс, например .my-class:first-of-type, это не будет означать, что псевдокласс найдёт вам первый тег на странице с таким классом!

В примере ниже вовсе не первый тег на странице с классом link станет отображаться красным цветом, а три первых тега с классом link:

                
<style> .link:first-of-type{ color: red; } </style> <a class="link" href="#">Homepage</a><br> <div class="menu"> <a class="link" href="#">Homepage</a><br> <span class="link"> Мобильная версия </span><br> <a class="link" href="#">Homepage</a><br> <a class="link" href="#">Contacts</a><br> <a class="link" href="#">About</a><br> </div>

К слову, в CSS вообще нет селектора, который бы позволял найти первый на всей странице тег с определённым классом, и только его. Если у вас возникла такая необходимость, вам поможет только JavaScript.

Псевдокласс :last-child

Подобно :first-child работает и :last-child, но всё же есть между ними одно тонкое, но важное различие — :last-child находит последние дочерние элементы. Разумеется,
это не обязательно будет последний дочерний элемент именно того тега, в который мы вкладываем данный селектор. Пример ниже найдёт в обоих абзацах теги
<span>:

                
<style> p :last-child{ color: red; } </style> <p> <strong>Что-то особенное</strong><br> Далеко-далеко, за, <span>словесными</span> горами в стране гласных и согласных живут рыбные тексты. <span>Языкового</span> над ему обеспечивает осталось решила которой океана его, <span>реторический</span> скатился меня не дорогу домах.</p> <p>Далеко-далеко, за словесными горами в стране <span>гласных</span> и согласных живут <span>рыбные</span> тексты. Злых грустный она ipsum то запятых эта агентство <span>подзаголовок</span> власти, языком пор рыбного, все несколько!</p>

В данном примере селектор нашёл все параграфы, а потом в каждом из них нашёл последний дочерний элемент (вложенность 1 уровень).
Но так этот селектор работает только до тех пор, пока последний дочерний элемент принадлежит параграфу. Стоит нам создать ещё один
дочерний элемент для любого другого (например вложить ссылку в span), и тогда этот элемент тоже станет последним дочерним:

                
<style> p :last-child{ color: red; } </style> <p>Далеко-далеко, за словесными горами в стране <span>гласных</span> и согласных живут <span>рыбные</span> тексты. Злых грустный она ipsum то запятых эта агентство <span>подзаголовок <a href="#">данного текста</a></span> власти, языком пор рыбного, все несколько!</p>

Как видите, теперь красным отображается не только span, но и ссылка, поскольку span является последним дочерним элементом для параграфа, а ссылка — для span.
Это может показаться весьма запутанно, и, признаться, это действительно необычно. Данный селектор используется не часто, но вы обязательно должны
понимать, как он работает, чтобы случайно не написать его там, где он не сможет вам помочь.

Псевдокласс :nth-child(х)

Этот псевдокласс находит элементы, соответствующие заданному селектору, но находящиеся на определённой позиции в выборке. Например, если у нас есть список с десятью пунктами, мы можем при помощи этого псевдокласса найти 2-й по порядку пункт списка, 5-й, 9-й, или например все чётные\нечётные, и даже можем в качестве аргумента X применить функцию. Пример:

ul li:nth-child(1) вернёт первый элемент списка
ul li:nth-child(5) вернёт пятый элемент списка
ul li:nth-child(2n) вернёт каждый 2-й элемент списка
ul li:nth-child(2n+5) вернёт 5-й, затем 7-й, затем 9-й элемент списка и т.д.
Логика работы функции в данном случае такова: вместо n подставляются значения 0, 1, 2 и т.д., выполняется умножение 2 * n, затем к результату прибавляется 5, и дальше осуществляется поиск элемента с таким порядковым номером.

Помимо чисел, данный псевдокласс может принимать два ключевых слова, even и odd. ul li:nth-child(even) вернёт все чётные, а ul li:nth-child(odd) все нечётные элементы списка:

Как видите, четвёртый пункт списка стал красным, потому что он li:nth-child(4). Третий, шестой, девятый и пр. станут зелёными, поскольку они li:nth-child(3n). Пятый, седьмой, девятый стали сиреневыми, поскольку они li:nth-child(2n+5). Девятый оказался и там и там, как видите, поэтому его итоговый цвет — тот, что описан в стилях ниже, то есть сиреневый.

У вас может возникнуть вопрос: «Зачем такая сложная математика, если можно просто присвоить класс нужному элементу и стилизовать?». В рабочих проектах довольно часто необходимо формировать списки динамически, т.е. в зависимости от того, есть ли какая-нибудь информация в базе данных (список покупок, добавленных в корзину товаров, список консультаций и пр). Когда мы делаем проект, мы порой не знаем, сколько будет данных и какой длины будет необходим список. Поэтому зачастую удобнее вместо того чтобы в шаблоне серверного языка программирования PHP, который генерирует HTML разметку страницы, присваивать каждому второму элементу класс, мы можем просто стилизовать элементы при помощи CSS. К тому же бывают ситуации, когда нам необходимо удалять какие-то элементы списка при помощи JavaScript, при этом необходимо сохранить порядок и стиль отображения. Чтобы не переопределять классы, мы выделяем элементы стилями. Самый простой реальный пример — работа со строками таблицы, цвет которых часто для наглядности чередуется. Если мы при помощи JavaScript удалим из таблицы одну строку, то благодаря :nth-child(even) у нас сохранится чередование цвета строк.

Псевдокласс :checked

Этот псевдокласс, как вы могли догадаться, необходим для работы с элементами, которые могут быть «выбраны», это input type="checkbox", input type="radio", и только. Он выбирает те input, у которых проставлен атрибут checked. Хотя такая выборка может показаться странной, этот приём крайне актуален. Дело в том, что средствами CSS стилизовать checkbox невозможно, и потому разработчики придумали несколько «хаков», один из которых как раз работает при посредстве псевдокласса :checked. Рассматривать сейчас этот способ стилизации мы не будем, однако пример работы данного псевдокласса приведём. Смоделируем ситуацию, в которой нам необходимо менять цвет текста рядом с отмеченным checkbox. Это можно реализовать при помощи JavaScript, но гораздо проще и изящнее при помощи CSS и :checked. Вот пример:

                
<style> input:checked + label{ color: red; } </style> <form action="action.php"> <div> <input id="html" type="checkbox"> <label for="html">HTML</label> </div> <div> <input id="css" type="checkbox"> <label for="css">CSS</label> </div> <div> <input id="js" type="checkbox"> <label for="js">JS</label> </div> </form>

В селекторе мы определили, что label, следующий за отмеченным input, должен быть красным цветом. До тех пор, пока input не отмечен, это правило не применяется и цвет label остаётся чёрным. Примерно так же :checked используется и в реальных коммерческих проектах.

Псевдокласс :not(X)

Селектор исключения из выбранных элементов. Например, мы нашли все span, но хотим убрать из выборки те, у которых есть класс special. Самый удобный способ сделать это является использование :not(). Описанный пример:

                
<style> span:not(.special){ color: red; } </style> <span>Hello</span><br> <span class="special">Ordinary</span><br> <span>World</span>

Мы в стилях выбрали все span на странице, но затем при помощи :not исключили те, у которых есть класс .special. Этот псевдокласс работает не только с классами в качестве аргументов, разумеется, а вообще с любым селектором — с тегами, с атрибутами и даже с другими псевдоклассами. Далее мы выбираем все теги с классом .special, но исключаем из их числа ссылки.:

                
<style> .special:not(a){ color: red; } </style> <span class="special">Hello</span><br> <span class="special">Ordinary</span><br> <a href="#" class="special">World</a>

Пример с псевдоклассом в качестве аргумента для исключения. Мы находим все теги с классом .special, но исключаем из него те, у которых будет состояние :hover. Так, если мы наведём курсор на какой-либо из этих span, цвет его текста вернётся к чёрному:

                
<style> .special:not(:hover){ color: red; } </style> <span class="special">Hello</span><br> <span class="special">Ordinary</span><br> <span class="special">World</span>

Псевдокласс :not можно также конкатенировать, указав его несколько раз:

                
<style> .special:not([lang="it"]):not([lang="ru"]){ color: red; } </style> <span class="special">Hello</span><br> <span class="special">World</span><br> <span class="special" lang="it">Ciao</span><br> <span class="special" lang="it">mondo</span><br> <span class="special" lang="ru">Привет</span><br> <span class="special" lang="ru">Мир</span><br>

Мы нашли все теги с классом .special, затем исключили те, у которых lang="it" и lang="ru", то есть мы отфильтровали найденные теги дважды по разным условиям. Кстати, если вы напишете исключаемые селекторы через запятую внутри одного :not, это тоже сработает:

                
.special:not([lang="it"],[lang="ru"]){ color: red; }

Мы рассмотрели не все псевдоклассы, а лишь самые важные, с которыми вы в любом случае встретитесь в своей работе. Однако псевдоклассов гораздо больше, и вы можете для расширения кругозора почитать о них. Некоторые из них являются до сих пор экспериментальными и не имеют (широкой) браузерной поддержки, некоторые уже устарели, некоторые просто применяются предельно редко. Полный список псевдоклассов вы можете найти, конечно, в справочнике.

Необходимо очков: