Селекторы CSS
В этой главе:
- Селекторы классов и идентификаторов
- Селекторы атрибутов
- Родственные селекторы
- Псевдоклассы
- Псевдоэлементы
- Наследование и каскадирование
В предыдущей главе мы в целом изучили составление правил CSS. Если бы применение таблиц стилей ограничивалось атрибутом STYLE, то этого было бы достаточно для того, чтобы начать использовать CSS. Но поскольку применение таблиц стилей гораздо более гибкое (на то они и каскадные), то для описания порядка применения правил к документу в CSS 2.1 предусмотрен мощный механизм селекторов.
Селекторы классов и идентификаторов
Для определения того, попадает или нет элемент документа под то или иное правило CSS, используется механизм совпадения шаблонов, называемых селекторами. Эти селекторы могут быть как совсем простыми, указывающими лишь на какой-либо элемент, так и весьма сложными, учитывающими механизм наследования в дереве документа, значения атрибутов и т.д. С рядом селекторов мы уже знакомы – это дескрипторы единичных элементов, а так же селекторы классов и идентификаторов:
p {font-face: Arial} /* селектор элементов p */
.extra {font-weight: bold} /* селектор класса extra */
#part1 {font-size: 1pc} /* селектор идентификатора part1 */
Селекторы элементов, классов и идентификаторов можно комбинировать. Например, если мы хотим указать, что определяемое правило для класса «extra» должно распространяться только на элементы P, имеющие этот класс, следует объединить в селекторе элемент и его класс:
p.extra {font-weight: bold}
Такой шаблон совпадет только с элементами P, имеющими указанный класс, но не с другими элементами P или иными элементами с классом extra. Так, если мы применим такую таблицу к документу, приведенному в листинге 3.2, то сможем убедиться, что определенное нами правило было применено только к первому абзацу (рис. 3.1).
Листинг 3.1. Селекторы классов
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN">
<html>
<head>
<title>Селекторы классов</title>
<style type="text/css">
p.extra {font-weight: bold}
</style>
</head>
<body>
<p class="extra">Элемент P с классом extra</p>
<p class="super">Элемент P с другим классом (super)</p>
<p>Элемент P без определенного класса</p>
<div class="extra">Другой элемент (DIV) с классом extra</div>
</body>
</html>
Рис. 3.1. Селектор класса для элемента P
В то же время, если бы мы в селекторе не указали имени класса, то полужирное начертание получили бы все три абзаца, а если бы был указан только лишь класс, то такое начертание получили бы первый абзац и последняя строка, представляющая собой блок DIV.
Аналогичное поведение будет и у селекторов с идентификаторами, с той лишь разницей, что в пределах всего документа может быть лишь один элемент, имеющий указанный идентификатор. С этой точки зрения комбинировать идентификатор с чем-либо не представляется рациональным, однако если создаваемая таблица стилей будет применяться сразу к группе документов, такое дополнительное условие может быть полезным. Кроме того, можно еще больше сузить действие шаблона, совместив в нем и класс, и идентификатор:
p.extra#unicum {font-weight: bold}
Для того чтобы «сработало» заданное таким образом правило, придется несколько изменить документ из листинга 3.1, в частности, два первых абзаца будут такими:
<p class="extra">Элемент P с классом extra</p>
<p class="extra" id="unicum">Элемент P с классом extra и идентификатором unicum</p>
Теперь полужирным будет только второй абзац, поскольку для выполнения правила необходимо совпадение уже трех условий: элементом должен быть P, его класс должен быть extra, а его идентификатор – unicum. Несовпадение любого из условий приведет к тому, что правило применено не будет.
От такого особо выборочного варианта перейдем к наиболее общему: в CSS имеется специальный обобщающий шаблон «*» (звездочка), который подразумевает любой элемент. Таким образом, следующее правило будет применяться абсолютно ко всем элементам документа:
* {background: transparent;}
Здесь мы задали прозрачный фон для всех элементов документа. Строго говоря, присутствие обобщающего шаблона подразумевается и в тех случаях, когда в селекторе указывается только класс или идентификатор:
.extra {font-weight: bold}
*.extra {font-weight: bold}
Обе эти записи эквивалентны, так что ставить или нет в подобных случаях звездочку перед именем класса или идентификатором – решать вам.
Селекторы атрибутов
На самом деле, рассмотренные нами селекторы классов являются не более чем частным случаем селектора атрибута. Иными словами, можно создать шаблон, который будет действителен не только для какого-либо элемента с указанным классом, но и с определенным значения любого атрибута. Таким образом, вместо селектора класса можно использовать селектор атрибута, добиваясь одного и того же результата:
p.major {color: red} /* стандартное применение селектора класса */
p[class="major"] {color: red} /* использование селектора атрибута */
Хотя вторая запись кажется более громоздкой, и в данном случае использование такого синтаксиса – не лучшая идея, в ряде других случаев селекторы атрибута могут быть очень полезными. Так, в данном случае был использован селектор с совпадением значения (т.е. значение атрибута должно совпасть с указанным текстом), однако допустимо указывать и более общий случай – например, для всех элементов, имеющих атрибут class:
p[class] {background: red}
В этом случае для всех элементов P, имеющих атрибут CLASS, вне зависимости от того, какое именно значение имеет этот атрибут, будет установлен красный цвет фона. Собственно, вместо CLASS может быть указан любой другой атрибут, например, TITLE:
a[title] {text-decoration: none;}
Таким образом, все ссылки, имеющие атрибут TITLE не будут подчеркнуты. В данном случае преимущество использования такого селектора очевидно, поскольку в противном случае пришлось бы дополнительно для каждой такой ссылки указывать еще и класс.
ПРИМЕЧАНИЕ
К сожалению, вам, возможно, так и придется поступать еще некоторое время, поскольку в MSIE 6-7 селекторы атрибутов не поддерживаются, как и многие другие новые методы каскадирования, появившиеся в CSS 2. Полную поддержку селекторов CSS уровня 2 имеют лишь современные браузеры Mozilla и Opera.
Помимо проверки на наличие атрибута или на соответствие значения атрибута, допускается и проверка на частичное соответствие значения атрибута. Например, если в качестве значения атрибута используется набор слов, а применить правило следует в том случае, когда встречается одно из них, можно создать такой селектор:
img[title~="Москва"] {border: red}
В этом случае все картинки, имеющие в подписи слово «Москва», будут заключены в красную рамку:
<img src="mos1.jpg" title="Москва днем" />
<img src="mos2.jpg" title="Москва ночью" />
<img src="mos3.jpg" title="Универмаг Москва" />
Другой вариант частичного совпадения – проверка на первую часть значения, разделенного при помощи черточки. Как правило, такие селекторы создают для многоязыковых документов, когда достаточно лишь основной составляющей языка:
div[lang|="en"] { font-style: italic;}
Такой шаблон подойдет к любому блоку с указанным языком, начинающимся на en:
<div lang="en-us">American English</div>
<div lang="en-uk">British English</div>
<div lang="en">English</div>
Все три блока получат курсивное начертание шрифта. Впрочем, ничего не мешает использовать такие шаблоны и для любых других случаев. Допустим, если бы мы изменили в шаблоне Москва «img[title~="Москва"]» на «img[title|="Москва"]», то он был бы применен к такой вот картинке:
<img src="mos4.jpg" title="Москва-река" />
Как и с селекторами классов, с селекторами атрибутов можно использовать обобщения, указывая звездочку, или опуская ее:
*[title] {text-decoration: underline}
[lang|="en"] {font-style: italic;}
Здесь в первой строке мы задали подчеркивание для всех элементов, имеющих атрибут TITLE, а во второй – наклонный шрифт для любых элементов с установленным английским языком.
Резюмируя информацию по селекторам атрибутов, остается сделать две вещи: свести правила совпадения в таблицу 3.2 и высказать сожаление, что они (увы!) не поддерживаются наиболее популярной программой просмотра.
Тип шаблона | Описание |
---|---|
[атрибут] | Совпадает, когда элемент имеет указанный атрибут |
[атрибут=значение] | Совпадает, когда элемент имеет указанный атрибут с указанным значением |
[атрибут~=слово] | Совпадает, когда элемент имеет указанный атрибут, а в его значении имеется указанное слово |
[атрибут|=слово] | Совпадает, когда элемент имеет указанный атрибут, а его значение состоит из разделенных черточкой слов и начинается с указанного слова |
Псевдокласс | Описание |
---|---|
:link | Применяется, если ссылка не была просмотрена пользователем |
:visited | Применяется, если ссылка уже была просмотрена пользователем |
:active | Применяется, когда элемент активизируется пользователем. Например, между моментами, когда пользователь нажимает кнопку мыши и отпускает ее |
:hover | Применяется, когда пользователь выделяет элемент, но не активизирует его. Например, браузер может применять этот псевдокласс, когда курсор (указатель мышки) находится над данным элементом |
:focus | Применяется, когда элемент находится в центре некоторых событий (включая события клавиатуры или другие типы ввода текста) |
Рассмотрим применение основных псевдоклассов на наиболее часто встречающееся примере – ссылках:
a:link {color: red} /* не посещенные ссылки */
a:visited {color: blue} /* посещенные ссылки */
a:hover {color: green} /* во время выделения ссылки */
a:active {color: black} /* в момент щелчка по ссылке */
a:focus {background: yellow} /* на время получения фокуса ввода */
В документе, оформленном при помощи такой таблицы стилей (см. файл links.html), все не посещенные ссылки будут красными, а посещенные – синими. При наведении указателя мышки на ссылку ее текст станет зеленым, а в момент щелчка – черным на желтом фоне. Последний эффект (изменение цвета фона) обусловлен тем, что при щелчке ссылка получает фокус ввода. В то же время, если просто передать фокус ввода ссылке (например, при помощи табуляции), то она так же изменит цвет фона на желтый, сохранив, однако, при этом свой исходный цвет (красный или синий, в зависимости от того, является ли она посещенной).
Псевдокласс :first-child, впервые введенный в CSS уровня 2, сопоставляется элементу, который является первым дочерним элементом некоторого другого элемента. Допустим, мы определили, что все абзацы должны иметь «красную строку» размером в 2 символа:
p {text-indent: 2em}
Но при этом мы хотим, чтобы первый абзац, вложенный в DIV, не имел отступа. Теоретически, можно назначить каждому такому абзацу класс и определить для него собственное правило. Но, к счастью, в нашем распоряжении уже имеется псевдокласс :first-child, который как раз указывает на первый элемент в любом блоке. В таком случае достаточно написать такое правило:
div > p:first-child {text-indent: 0}
К подобному способу нередко прибегают и для выделения первой строки списка:
li:first-child {color: red}
Такое правило распространяется на все нумерованные и ненумерованные списки, если же мы хотим ограничить область применения, скажем, только нумерованными, то укажем порядок наследования, который может быть как непосредственным, так и общим:
ol > li:first-child {color: red} /* только для списков OL */
ol li:first-child {color: red} /* для любого списка, если он вложен в OL */
Пример использования :first-child можно посмотреть в файле pseudocl.html, а в завершение знакомства с псевдоклассами рассмотрим еще один – :lang. Псевдокласс «:lang(X)» сопоставляется элементу, использующему язык «X». Сам язык определяется в документах HTML 4.0 и XHTML 1.0 при помощи атрибута LANG, а в XHTML 1.1 и XML – при помощи XML:LANG. Например, можно определить правило, согласно которому вид кавычек будет изменяться в зависимости от языка, на котором написано окружающее содержимое:
:lang(ru) > q { quotes: '«' '»'}
:lang(en) > q { quotes: '"' '"'}
Результат таких манипуляций пока что можно увидеть лишь в Mozilla-браузерах (рис. 3.4), т.к. MSIE не поддерживает ни псевдоклассов CSS 2, ни элемента Q из HTML 4, а у Opera имеются некоторые затруднения с многоязыковой поддержкой.
Рис. 3.4. Псевдокласс :lang и расстановка кавычек
Псевдоэлементы
В отличие от псевдоклассов, псевдоэлементы формируют абстрактные представления о дереве документа в дополнение к тем, которые определяются языком документа. Например, в HTML не предусмотрено алгоритмов доступа к первой букве или первой строке содержимого элемента, но при помощи псевдоэлементов CSS вы сможете обращаться к таким объектам, доступ к которым нельзя получить другим способом. Кроме того, псевдоэлементы предоставляют различные способы назначения стиля содержимому, не существующему в исходном документе. Так, псевдоэлементы :before и :after предоставляют доступ к генерируемому содержимому.
Всего в CSS уровня 2 определено 4 псевдоэлемента. Это уже упомянутые :before и :after, а так же :first-line и :first-letter, отвечающие за доступ к первой строке и первой букве текста в блочном элементе, соответственно. Начнем с :first-line. В типичном случае его используют для выделения первой строки в абзаце (P):
p:first-line {text-decoration: underline}
Здесь сразу можно раскрыть суть названия «псевдоэлемент». Допустим, только что определенный нами стиль будет применен к такому фрагменту HTML-документа:
<p>Некоторый абзац текста, первая строка которого будет выделена подчеркиванием при помощи псевдоэлемента :first-line.</p>
Представим себе, что при графическом построении браузером этого документа первая строка закончится на слове «подчеркиванием». В таком случае браузер вставит пару виртуальных (или «псевдо») тегов: открывающий – сразу за P и закрывающий – перед обрывом строки:
<p><p:first-line>Некоторый абзац текста, первая строка которого будет выделена подчеркиванием</p:first-line> при помощи псевдоэлемента :first-line.</p>
Если впоследствии ширина абзаца изменится (скажем, пользователь развернет окно браузера на весь экран), то расположение закрывающего «псевдотега» соответствующим образом изменится, чтобы эффект распространялся только на первую строку абзаца. Аналогичным образом работает и псевдоэлемент :first-letter, его отличие от :first-line состоит лишь в том, что он отвечает только за первую букву текстового блока:
p:first-letter: {font-size: 200%}
Таким образом, можно без лишнего форматирования исходного документа добиться таких типографских эффектов, как заглавные буквы или буквица.
Несколько интереснее дело обстоит с псевдоэлементами :before и :after. Их можно использовать для вставки генерируемого содержимого до или после содержимого элемента. Например, чтобы выделить подписью некоторые абзацы (скажем, имеющие класс «special»), можно определить такое правило:
p.special:before {content: "Спецабзац! "}
Таким образом, хотя в самом документе такого слова и не будет, при выводе на экран браузер добавит его, как и любое другое содержимое, определенное при помощи свойства content. Остается заметить, что когда псевдоэлементы :first-letter и :first-line сочетаются с псевдоэлементами :before и :after, они применяются к первой букве или строке элемента, включая вставляемый текст:
p.special:first-letter {color: red}
Пример работы приведенных здесь селекторов можно посмотреть в файле pseudoel.html, а подробнее о генерируемом тексте будет рассказано в соответствующей главе.
ПРИМЕЧАНИЕ
Поддержка псевдоэлементов имеется у Opera 5.0 и выше, всех вариантов Mozilla, и MSIE, начиная с версии 5.5, хотя у последнего генерируемый текст, а, следовательно, и псевдоэлементы :before и :after не поддерживаются до версии 8.0.
Наследование и каскадирование
Завершив таким образом знакомство с селекторами, разберемся с тем, как происходит само назначение стилей. Прежде всего, важно знать, что в процессе обработки таблицы стилей, заданные в ней значения проходят до 4-х этапов обработки. Так, после того, как браузер произвел синтаксический анализ исходного текста и создал дерево документа, он должен присвоить каждому свойству каждого элемента этого дерева некоторое значение. На первом этапе происходит самое интересное – свойствам присваивается заданное значение, которое может быть результатом каскадирования CSS, быть унаследованным от родительского элемента, или же являться начальным значением, заданным в определении элемента. Затем заданное значение, если оно было задано в относительных величинах (например, в процентах), будет преобразовано в вычисляемое, которое, после ряда манипуляций и необходимых аппроксимаций (скажем, линия не может быть шириной 14,5 пикселей, а только 14 или 15), приводится к фактическому. Так вот на первом этапе вычисления значения мы сталкиваемся с двумя основополагающими принципами CSS – наследованием и каскадированием.
Многие значения наследуются дочерними элементами в дереве документа. Каждое свойство определяет, является оно наследуемым или нет. Допустим, у нас имеется таблица стилей, определяющая синий цвет для элемента BODY:
body {color: blue}
Если теперь создать использующий такую таблицу документ HTML, то все его элементы (а все выводимые элементы явно или неявно являются вложенными в контейнер BODY) будут синего цвета, по крайней мере, кроме тех, у которых явно не указано иначе:
<body>
<p>Абзац синего цвета</p>
<div>Тоже синий...
<h1>И заголовок синий</h1>
Здесь <cite>снова</cite> синий.
</div>
</body>
Здесь все вложенные в BODY элементы, включая P, DIV, H1 и CITE унаследовали цвет от родительского элемента BODY. Здесь мы видим наследование абсолютного значения (т.е. явно был задан синий цвет), у процентных же значений наследуется не то, что было задано, а результат вычислений. Например, если для BODY установить размер шрифта 10pt, а для заголовка H1 указать размер шрифта 140%, то вычисляемый размер шрифта заголовка будет 14pt, и именно это значение унаследует любой элемент, вложенный в заголовок (а это может быть любой строчный элемент – EM, SITE и т.п.). Пример такого несложного наследования можно посмотреть в файле inheritance.html.
После того, как мы ознакомились с наследованием, пора разобраться с каскадированием. Для начала отметим, что таблицы стилей всегда имеют три источника: разработчика, пользователя и программы просмотра. В качестве разработчика выступает автор страницы, а пользователя – ее посетитель, который может при помощи настроек своего браузера указать собственные стили (рис. 3.5), что, на самом деле – большая редкость, но знать об этом все равно полезно.
Рис. 3.5. Задание пользовательского файла со стилями в MSIE 6.0
Что касается браузера, то он всегда имеет собственную таблицу стилей (разумеется, если он поддерживает CSS), в которой задано стандартное оформление для всех поддерживаемых им элементов: именно благодаря этим стилям заголовки всегда крупные, цитаты – выделены курсивом, а абзацы – выровнены по левому краю. Поскольку области действия этих таблиц могут пересекаться (скажем, в браузере размер кегля для H1 задан в 18pt, а вы указали 20), то для их правильного взаимодействия используется правило каскада. Каскад CSS назначает каждому правилу стиля определенный приоритет. При выполнении нескольких правил преимущество имеет правило с большим приоритетом. По умолчанию правила в таблицах стилей разработчика имеют больший приоритет, чем правила в пользовательских таблицах стилей.
ПРИМЕЧАНИЕ
Для важных правил («!important») ситуация противоположна, поскольку такие правила наделяется преимуществом перед обычным объявлением. Таблицы стилей как разработчика, так и пользователя могут содержать важные объявления, но пользовательские правила «!important» в CSS 2 имеют приоритет над правилами «!important» разработчика.
Все правила пользователей и разработчиков имеют более высокий приоритет, чем правила таблиц стилей, используемых по умолчанию в браузере. Что касается собственно порядка каскадирования, то он происходит по такому сценарию:
- Из всех доступных источников выбираются все объявления, которые подходят к рассматриваемому элементу.
- Производится первичная сортировка объявлений по приоритету и источнику в следующем порядке (по возрастанию значимости): собственные стили браузера, стили пользователя, стили разработчика, важные стили разработчика, важные стили пользователя.
- Вторичная сортировка производится по специфичности селектора. Более специфичные селекторы имеют приоритет над более общими селекторами (при этом псевдоклассы и псевдоэлементы считаются обычными классами и элементами, соответственно).
- И, наконец, проводится сортировка в соответствии с порядком следования: если два правила имеют одинаковые приоритет, источник и специфичность, то будет использоваться правило, описанное последним.
В принципе, ничего сложного здесь нет: подходящие объявления выбираются по селектору, а изо всех таблиц объявлений практически всего приходится иметь дело лишь с обычными стилями разработчика (стили браузера нами воспринимаются как нечто само собой разумеющееся, и обращать на них внимание мы не будем). Некоторые вопросы могут возникнуть с 3-м пунктом – по части определения специфичности селектора. Рассмотрим этот вопрос на примере листинга 3.4.
Листинг 3.4. Каскадирование таблиц стилей
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html>
<head>
<title>Каскадирование</title>
<style type="text/css">
h1 {color: green}
.special {color: blue}
#urgent {color: red}
</style>
</head>
<body>
<h1>Просто заголовок H1</h1>
<h1 class="special">"Специальный" заголовок H1</h1>
<h1 class="special" id="urgent">"Важный" заголовок H1</h1>
</body>
</html>
Здесь мы определили 3 стиля: зеленый цвет для всех элементов H1, синий цвет – для элементов с классом «special2 и красный – для элементов с идентификатором «urgent». В самом документе имеются три элемента H1, следовательно, правило «зеленый цвет» подходит ко всем им. Однако этот селектор, с точки зрения правил CSS, является более общим, чем селектор класса. Поэтому второй заголовок получит синий цвет. Ну а третий заголовок будет красным, поскольку стиль для него будет получен от наиболее специфичного селектора – имени идентификатора. Теперь можно несколько усложнить задачу, добавив в стили строку:
h1.special {color: black}
Теперь второй заголовок будет черным, поскольку данный селектор является более специфичным благодаря тому, что ссылается не на абстрактный класс, а на класс только для элементов H1. А наиболее высокий приоритет имела бы вот такая запись:
h1.special#urgent {color: orange}
Если добавить такую строку в таблицу стилей, то последний заголовок изменит свой цвет на оранжевый. В то же время, и это еще не является пределом! Помните правила наследования при определении селектора? Они тоже учитываются. Так что и такое правило можно перекрыть, указав явно, что h1 должен быть наследником BODY:
body h1.special#urgent {color: white}
На этот раз заголовок сольется с фоном. Впрочем, даже такое правило не будет самым значимым, поскольку учитывается еще и расположение правила: чем позже оно объявлено (или чем ближе оно к элементу, если угодно), тем выше его приоритет (см. пункт 4!). Соответственно, если после одного объявления поместить точно такое же, но с другими параметрами, то будет выполнено последнее. Ну а «самым последним» по правилам каскадирования является то, что написано в атрибуте STYLE. Таким образом, наивысший приоритет имеет такое объявление:
<h1 class="special" id="urgent" style="color: yellow">Заголовок</h1>
Теперь заголовок будет желтым, и никакие хитрости во внешней (по отношению к самому данному элементу) таблице стилей не смогут изменить его цвет, за исключением использования правила важности (!important), поскольку такие правила выполняются еще до сортировки по специфичности, а следовательно, имеют приоритет над ними. Иначе говоря, если в объявлении стиля написать:
h1 {color: green !important }
После такого объявления изменить цвет любого элемента H1 в документе, использующим данную CSS, возможно, только если определить другое важное правило, с более специфическим селектором.
Возвращаясь к специфичности, выведем три правила, по которому она определяется, и расположим их по убыванию приоритета:
- Наиболее специфичным является идентификатор элемента (указание правил в атрибуте STYLE мы тут опускаем);
- Следом идет совпадение значения атрибутов, в первую очередь – имен классов, а так же псевдоклассов. При этом, чем большее число атрибутов или классов совпадает, тем более специфичным получается селектор;
- Наименее специфичным является имя элемента (или псевдоэлемента), при этом указание «родственности» повышает приоритет.
Примеры каскадирования можно посмотреть в файле cascade.html, и на этом можно завершить знакомство с селекторами и перейти к вопросам собственно оформления – то есть к тому, для чего CSS, собственно и предназначаются.
2011-06-16 // Есть вопросы, предложения, замечания? Вы можете обсудить это на форуме !
Избранное
Copyright © 1999-2020 SNK. Все права защищены.
При использовании материалов с сайта ссылка на источник обязательна.