Синтаксис CSS несложен, и для понимания его совсем ненужно иметь степень доктора в области IT. Однако, это один из немногих популярных языков, который не является логичным в самом прямом смысле этого слова. В отличие от других языков веб-программирования, таких как JavaScript и PHP, в CSS проблемы не решаются с помощью обычной логики. Алгоритмы типа «если X, то сделать Y, в противном случае сделать Z» или «выбрать все Y, затем сделать с ними X» не могут быть осуществлены в таком языке, как CSS. Проще говоря, это язык, созданный для оформления, язык для дизайнеров, а не девелоперов. Некоторые из опытных программистов, с которыми я работал, именно по этой причине тратили много усилий на то, чтобы освоить CSS.
Обучение CSS начинается с классов и ID, а также с использования . и # для непосредственного обозначения элементов. Этого достаточно чтобы построить полнофункциональный веб-сайт, но это не достаточно гибкое решение в случае полной смены дизайна. Давайте взглянем на альтернативный подход к управлению такими труднодоступными элементами.
Соседний родственный комбинатор
Начнём с селектора, который удобен в сложных ситуациях, — с соседнего родственного комбинатора. Соседний родственный комбинатор обозначается соединением двух элементов с помощью знака +:
h1 + p
Это выделяет следующий p-элемент, расположенный сразу после h1-элемента в DOM. Типографическая теория предполагает, что мы должны использовать отступы в параграфах текста, но только если они следуют за другим параграфом. На практике это может быть использовано, чтобы сделать отступы во всех параграфах, кроме первого:
p + p { text-indent:1em; }
Это гораздо удобней, чем выделять первый параграф с помощью class=«first». Три строки, никаких классов и полная поддержка браузеров. Если вы располагаете тэги img, относящиеся к наполнению сайта, внутри тэгов p (как, собственно, и следует делать), можно просто отодвинуть их левые поля обратно с помощью негативного значения -1em:
p + p img { margin-left:-1em; }
Довольно просто, правда? А что, если нам захочется выделить первую строку всех параграфов, которые стоят сразу после заголовков, не изменяя всех остальных параграфов? Опять-таки мы можем использовать класс представления. Простой селектор, сделанный из соседнего составного комбинатора, и псевдо-элемент справятся с задачей:
h1 + p::first-line { font-variant:small-caps; }
Примечание: псевдо-элемент :first-line принят в CSS 2.1, в CSS 3 используется запись ::, с целью установить различие между псевдо-классами и псевдо-элементами.
Наследственный комбинатор
Обычный протокол разметки – это помещение разделов в как-либо названном элементе в #page или #wrap:
Вне зависимости от того, используете ли вы синтакис HTML 5 или XHTML 1.1, этот основной формат должен выглядеть для вас знакомо. Если ваш документ имеет фиксированную ширину в 960px, выровнен по центру и каждый элемент расположен горизонтально, ваш CSS скорее всего напоминает:
Есть способ получше. Мы все знакомы с универсальным селектором *. Если комбинировать его употребление с наследственным селектором, можно выбрать все элементы, являющиеся прямыми потомками #page, без какого-либо влияния на «внучатые» элементы:
#page>*{ width:100%; }
В будущем это поможет вам добавлять или удалять элементы верхнего уровня в документе. Возвращаясь к нашей начальной схеме разметки, это повлияет на элементы header, article и footer, но никак не коснется #main и всего остального внутри элемента article.
Селекторы атрибутов строки и подстроки
Селекторы атрибутов – одни из самых действенных. Они также существовали в CSS 2.1 и обычно использовались в форме input[type=«text»] или [href="#top"]. Но CSS3 предлагает более глубокий уровень контроля в форме строк и подстрок.
Примечание: до сих пор все, что мы обсуждали, относилось к стандарту CSS 2.1, но теперь мы вступаем на территорию CSS3.
Существует четыре основных селектора атрибутов строки, где ‘v’ = значение, ‘a’ = атрибут. v – одно из списка значений, разделенных пробелом: element[a~=«v»] a начинается с v: element[a^=«v»] a заканчивается на v: element[a$=«v»] a содержит значение: element[a*=«v»]
Потенциал селекторов атрибута строки фактически бесконечен, но отличным примером являются иконки. Скажем, у вас есть неупорядоченный список ссылок на профайлы в соцсетях:
<ul id="social"> <li><a href="http://facebook.com/designfestival">Like on Facebook</a></li> <li><a href="http://twitter.com/designfestival">Follow on Twitter</a></li> <li><a href="http://feeds.feedburner.com/designfestival">RSS</a></li> </ul>
Привести их в порядок так же просто, как сделать запрос через их href атрибут, чтобы найти ключевое слово. Мы можем расположить их таким образом:
#social li a::before { content:''; background:left50%no-repeat; width:16px; height:16px; } #social li a[href*="facebook"]::before { background-image:url(images/icon-facebook.png); } #social li a[href*="twitter"]::before { background-image:url(images/icon-twitter.png); } #social li a[href*="feedburner"]::before { background-image:url(images/icon-feedburner.png); }
Аналогичным образом, можно выбрать все ссылки в PDF документах селектором атрибута Suffix:
Браузеры, не поддерживающие атрибуты подстрок в CSS3, не покажут эти иконки, но это не так важно – они всего лишь красивое дополнение, без особой функциональности.
Структурные псевдо-классы
Наконец, мне хочется обрисовать выгодность использования псевдо-классов (не путать с псевдо-элементами и псевдо-классами link и state). Мы можем использовать их для выделения элементов по их позиции в DOM. Хорошим примером использования структурного псевдо-класса является выделение первого (или последнего) элемента в дереве элементов, или выбор между четными и нечетными элементами.
<ul>
<li>List Item 1</li>
<li>List Item 2</li>
<li>List Item 3</li>
<li>List Item 4</li>
<li>List Item 5</li>
<li>List Item 6</li>
</ul>
ul li { border-top:1pxsolid#DDD; }
ul li:last-child { border-bottom:1pxsolid#DDD; }
ul li:nth-child(even){ background:#EEE; }
Примечание: единственный доступный в CSS 2.1 псевдо-элемент — :first-child. Все остальные псевдо-элементы, включая :last-child, относятся к стандарту CSS3.
Однако необходимо знать, когда НЕ надо использовать структурные псевдо-элементы. Они должны быть использованы исключительно для выделения элемента по его позиции, а не по содержанию. Если требуется провести какое-либо действие над элементом вне зависимости от его расположения в DOM, используйте более многозначные семантические селекторы, например, class, ID или string.
Возможно, вы уже используете некоторые из вышеуказанных комбинаторов и селекторов – может, правильно, а может и нет, — но лишнее напоминание, в каких случаях они удобнее, чем class или ID, не повредит. Даже лучшие из нас часто ошибаются в подобных вещах.