254 lines
10 KiB
Markdown
254 lines
10 KiB
Markdown
# Знаете ли вы селекторы?
|
||
|
||
CSS3-селекторы -- фундаментально полезная вещь.
|
||
|
||
Даже если вы почему-то (старый IE?) не пользуетесь ими в CSS, есть много фреймворков для их кросс-браузерного использования CSS3 из JavaScript.
|
||
|
||
Поэтому эти селекторы необходимо знать.
|
||
[cut]
|
||
|
||
## Основные виды селекторов
|
||
|
||
Основных видов селекторов всего несколько:
|
||
|
||
<ul>
|
||
<li>`*` -- любые элементы.</li>
|
||
<li>`div` -- элементы с таким тегом.</li>
|
||
<li>`#id` -- элемент с данным `id`.</li>
|
||
<li>`.class` -- элементы с таким классом.</li>
|
||
<li>`[name="value"]` -- селекторы на атрибут (см. далее).</li>
|
||
<li>`:visited` -- "псевдоклассы", остальные разные условия на элемент (см. далее).</li>
|
||
</ul>
|
||
|
||
**Селекторы можно комбинировать, записывая последовательно, без пробела:**
|
||
|
||
<ul>
|
||
<li>`.c1.c2` -- элементы одновременно с двумя классами `c1` и `c2`</li>
|
||
<li>`a#id.c1.c2:visited` -- элемент `a` с данным `id`, классами `c1` и `c2`, и псевдоклассом `visited`</li>
|
||
</ul>
|
||
|
||
## Отношения
|
||
|
||
В CSS3 предусмотрено четыре вида отношений между элементами.
|
||
|
||
Самые известные вы наверняка знаете:
|
||
<ul>
|
||
<li>`div p` -- элементы `p`, являющиеся потомками `div`.</li>
|
||
<li>`div > p` -- только непосредственные потомки</li>
|
||
</ul>
|
||
|
||
Есть и два более редких:
|
||
<ul>
|
||
<li>`div ~ p` -- правые соседи: все `p` на том же уровне вложенности, которые идут после `div`.</li>
|
||
<li>`div + p` -- первый правый сосед: `p` на том же уровне вложенности, который идёт сразу после `div` (если есть).</li>
|
||
</ul>
|
||
|
||
Посмотрим их на примере HTML:
|
||
|
||
```html
|
||
<h3>Балтославянские языки</h3>
|
||
|
||
<ol id="languages">
|
||
...Вложенный OL/LI список языков...
|
||
</ol>
|
||
```
|
||
|
||
CSS-селекторы:
|
||
|
||
```css
|
||
/*+ no-beautify */
|
||
#languages li {
|
||
color: brown; /* потомки #languages, подходящие под селектор LI */
|
||
}
|
||
|
||
#languages > li {
|
||
color: black; /* первый уровень детей #languages подходящих под LI */
|
||
}
|
||
|
||
#e-slavic { font-style: italic; }
|
||
|
||
*!*
|
||
#e-slavic ~ li { /* правые соседи #e-slavic с селектором LI */
|
||
color: red;
|
||
}
|
||
*/!*
|
||
|
||
#latvian {
|
||
font-style: italic;
|
||
}
|
||
|
||
#latvian * { /* потомки #latvian, подходяще под * (т.е. любые) */
|
||
font-style: normal;
|
||
}
|
||
|
||
*!*
|
||
#latvian + li { /* первый правый сосед #latvian с селектором LI */
|
||
color: green;
|
||
}
|
||
*/!*
|
||
```
|
||
|
||
Результат:
|
||
[iframe src="relation" border="1" edit link]
|
||
|
||
|
||
## Фильтр по месту среди соседей
|
||
|
||
При выборе элемента можно указать его место среди соседей.
|
||
|
||
Список псевдоклассов для этого:
|
||
|
||
<ul>
|
||
<li>`:first-child` -- первый потомок своего родителя.</li>
|
||
<li>`:last-child` -- последний потомок своего родителя.</li>
|
||
<li>`:only-child` -- единственный потомок своего родителя, соседних элементов нет.</li>
|
||
<li>`:nth-child(a)` -- потомок номер `a` своего родителя, например `:nth-child(2)` -- второй потомок. Нумерация начинается с `1`.</li>
|
||
<li>`:nth-child(an+b)` -- расширение предыдущего селектора через указание номера потомка формулой, где `a,b` -- константы, а под `n` подразумевается любое целое число.
|
||
|
||
Этот псевдокласс будет фильтровать все элементы, которые попадают под формулу при каком-либо `n`. Например:
|
||
<ul>
|
||
<li>`:nth-child(2n)` даст элементы номер `2`, `4`, `6`..., то есть чётные.</li>
|
||
<li>`:nth-child(2n+1)` даст элементы номер `1`, `3`..., то есть нечётные.</li>
|
||
<li>`:nth-child(3n+2)` даст элементы номер `2`, `5`, `8` и так далее.</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
Пример использования для выделения в списке:
|
||
[iframe src="nthchild" border="1" edit link]
|
||
|
||
```css
|
||
/*+ hide="CSS к примеру выше" no-beautify */
|
||
li:nth-child(2n) { /* чётные */
|
||
background: #eee;
|
||
}
|
||
|
||
li:nth-child(3) { /* 3-ий потомок */
|
||
color: red;
|
||
}
|
||
```
|
||
|
||
<ul>
|
||
<li>`:nth-last-child(a)`, `:nth-last-child(an+b)` -- то же самое, но отсчёт начинается с конца, например `:nth-last-child(2)` -- второй элемент с конца.</li>
|
||
</ul>
|
||
|
||
## Фильтр по месту среди соседей с тем же тегом
|
||
|
||
Есть аналогичные псевдоклассы, которые учитывают не всех соседей, а только с тем же тегом:
|
||
|
||
<ul>
|
||
<li>`:first-of-type`</li>
|
||
<li>`:last-of-type`</li>
|
||
<li>`:only-of-type`</li>
|
||
<li>`:nth-of-type`</li>
|
||
<li>`:nth-last-of-type`</li>
|
||
</ul>
|
||
|
||
Они имеют в точности тот же смысл, что и обычные `:first-child`, `:last-child` и так далее, но во время подсчёта игнорируют элементы с другими тегами, чем тот, к которому применяется фильтр.
|
||
|
||
Пример использования для раскраски списка `DT` "через один" и предпоследнего `DD`:
|
||
|
||
[iframe src="nthchild-type" border="1" edit link]
|
||
|
||
```css
|
||
/*+ hide="CSS к примеру выше" no-beautify */
|
||
dt:nth-of-type(2n) {
|
||
/* чётные dt (соседи с другими тегами игнорируются) */
|
||
background: #eee;
|
||
}
|
||
|
||
dd:nth-last-of-type(2) {
|
||
/* второй dd снизу */
|
||
color: red;
|
||
}
|
||
```
|
||
|
||
Как видим, селектор `dt:nth-of-type(2n)` выбрал каждый второй элемент `dt`, причём другие элементы (`dd`) в подсчётах не участвовали.
|
||
|
||
## Селекторы атрибутов
|
||
|
||
<dl>
|
||
<dt>На атрибут целиком</dt>
|
||
<dd>
|
||
<ul>
|
||
<li>`[attr]` -- атрибут установлен,</li>
|
||
<li>`[attr="val"]` -- атрибут равен `val`.</li>
|
||
</ul>
|
||
</dd>
|
||
<dt>На начало атрибута</dt>
|
||
<dd>
|
||
<ul>
|
||
<li>`[attr^="val"]` -- атрибут начинается с `val`, например `"value"`.</li>
|
||
<li>`[attr|="val"]` -- атрибут равен `val` *или* начинается с `val-`, например равен `"val-1"`.</li>
|
||
</ul>
|
||
</dd>
|
||
<dt>На содержание</dd>
|
||
<dd>
|
||
<ul>
|
||
<li>`[attr*="val"]` -- атрибут содержит подстроку `val`, например равен `"myvalue"`.</li>
|
||
<li>`[attr~="val"]` -- атрибут содержит `val` как одно из значений через пробел.
|
||
Например: `[attr~="delete"]` верно для `"edit delete"` и неверно для `"undelete"` или `"no-delete"`.</li>
|
||
</ul>
|
||
</dd>
|
||
<dt>На конец атрибута</dt>
|
||
<dd>
|
||
<ul>
|
||
<li>`[attr$="val"]` -- атрибут заканчивается на `val`, например равен `"myval"`.</li>
|
||
</ul>
|
||
</dd>
|
||
</dl>
|
||
|
||
## Другие псевдоклассы
|
||
|
||
<ul>
|
||
<li>`:not(селектор)` -- все, кроме подходящих под селектор.</li>
|
||
<li>`:focus` -- в фокусе.</li>
|
||
<li>`:hover` -- под мышью.</li>
|
||
<li>`:empty` -- без детей (даже без текстовых).</li>
|
||
<li>`:checked`, `:disabled`, `:enabled` -- состояния `INPUT`.</li>
|
||
<li>`:target` -- этот фильтр сработает для элемента, `ID` которого совпадает с анкором `#...` текущего URL.
|
||
|
||
Например, если на странице есть элемент с `id="intro"`, то правило `:target { color: red }` подсветит его в том случае, если текущий URL имеет вид `http://...#intro`.
|
||
</li>
|
||
</ul>
|
||
|
||
## Псевдоэлементы ::before, ::after
|
||
|
||
"Псевдоэлементы" -- различные вспомогательные элементы, которые браузер записывает или может записать в документ.
|
||
|
||
При помощи *псевдоэлементов* `::before` и `::after` можно добавлять содержимое в начало и конец элемента:
|
||
|
||
```html
|
||
<!--+ autorun -->
|
||
<style>
|
||
li::before {
|
||
content: " [[ ";
|
||
}
|
||
|
||
li::after {
|
||
content: " ]] ";
|
||
}
|
||
</style>
|
||
|
||
Обратите внимание: содержимое добавляется <b>внутрь</b> LI.
|
||
|
||
<ul>
|
||
<li>Первый элемент</li>
|
||
<li>Второй элемент</li>
|
||
</ul>
|
||
```
|
||
|
||
Псевдоэлементы `::before`/`::after` добавили содержимое в начало и конец каждого `LI`.
|
||
|
||
[smart header="`:before` или `::before`?"]
|
||
Когда-то все браузеры реализовали эти псевдоэлементы с одним двоеточием: `:after/:before`.
|
||
|
||
Стандарт с тех пор изменился и сейчас все, кроме IE8, понимают также современную запись с двумя двоеточиями. А для IE8 нужно по-прежнему одно.
|
||
|
||
Поэтому если вам важна поддержка IE8, то имеет смысл использовать одно двоеточие.
|
||
[/smart]
|
||
|
||
## Практика
|
||
|
||
Вы можете использовать информацию выше как справочную для решения задач ниже, которые уже реально покажут, владеете вы CSS-селекторами или нет.
|
||
|