Сегодня, во времена готовых решений, библиотек, фреймворков, препроцессоров и множества других, несомненно полезных в умелых руках, инструментов, для большого числа разработчиков механизмы технологий остаются чёрным ящиком. Я не буду занудой и не скажу, что каждый должен понять технологию изнутри, поскольку индустрия также требует низкоквалифицированных рабочих рук, в частности «нарезчиков макетов». Я так же не буду играть в Капитана Очевидность — понятно, что это принципиально важно, если вы планируете стать профессионалом. Делайте ваш выбор сами.
В работе над интерфейсами часто встают вопросы производительности. Существует множество различных инструментов и сервисов для определения узких мест. Один из них — Google Page Speed, который приводит рекомендации по повышению быстродействия JavaScript и скорости загрузки страницы. Перед тем как рассмотреть эти советы, нужно хорошо разобраться с тем, как браузеры работают с CSS.
Как обрабатывается CSS
Стиль элемента применяется при его создании
Мы воспринимаем страницу как единую «картинку», с оформлением и контентом. Но браузеры обрабатывают документы постепенно, потоком. Как только браузер начинает получать документ с сервера, он начинает его обрабатывать, не дожидаясь полной загрузки. Каждый узел обрабатывается и отрисовывается в окне браузера после получения. Рассмотрим простой документ.
<body>
<div id="content">
<div class="module intro">
<p>Lorem Ipsum</p>
</div>
<div class="module">
<p>Lorem Ipsum</p>
<p>Lorem Ipsum</p>
<p>Lorem Ipsum <span>Test</span></p>
</div>
</div>
</body>
Браузер начинает читать документ сверху и встречает элемент body. В этот самый момент браузер считает, что он пустой, поскольку ничего более пока не обработал. Браузер вычисляет стили (фон, шрифт, цвет и т.д.) для элемента и применяет их. После элемент отрисовывается на экране.
Затем браузер встречает элемент div с id="content"
. И снова, в этот момент он считает элемент пустым. Браузер вычисляет стили и элемент отрисовывается на экране. Браузер затем определяет, нужно ли перерисовать body
– например, стал ли он шире или длиннее (изменение геометрических размеров — наиболее частый эффект воздействия потомка на родителя)?
Процесс продолжается до достижения конца документа.
CSS селекторы читаются справа налево
Чтобы определить, нужно ли применять правило к некоторому элементу, селектор читается браузером справа налево.
Если у вас есть, скажем, правило div#content p { color: #003366; }
, тогда для каждого элемента, в момент его обработки браузером, сначала будет проверяться, является ли элемент параграфом. Если он является таковым, тогда браузер пойдёт вверх по DOM дереву и проверит, есть ли div с id="content"
. Если условие верно, тогда браузер продолжит поиск body.
Такой принцип работы выбран не случайно. Браузер определяет стоит ли применять стилевое правило к элементу на момент прорисовки значительно быстрее. Чем меньше узлов нужно обойти, тем быстрее обрабатывается правило.
Хорошие и плохие селекторы
Взгляните на рекомендации Google Page Speed. Они выделили четыре, на их взгляд, наиболее медленных селектора:
Контекстные селекторы, например #content h3
Дочерние селекторы, например #content > h3
Избыточно уточнённые селекторы, например div#content > h3
IE7-8: Псевдокласс :hover
, применяемый не к ссылкам, например div#content:hover
Следует дать некоторые пояснения к использованию вышеуказанного. Как видим, эти парни нам говорят, что использованных составных селекторов — зло, замедляющее ваш интерфейс, следовательно надо использовать только простые селекторы (например, элемента, ID, класса, атрибута и т.д.). Однако эти правила не должны быть прямым руководством к действию, иначе можно дойти до абсурда и вернуться во времена
. Безусловно, на проектах вроде Gmail это полностью оправдано, однако для куда меньших сайтов следует искать баланс между этими рекомендациями и здравым смыслом.
Универсальный селектор * {…}
Говорят, универсальный селектор нельзя использовать, потому что он очень медленный. Чушь собачья! Он медленный только в составе контекстного селектора, например #content p *
. Сам по себе не хуже селектора элемента, класса или id.
Как быть?
Чаще всего в моей практике такая проблема решается сама собой. Поскольку обычно наши проекты подвергаются постоянным изменениям, в подавляющем большинстве случаев мы используем классы. Блокам, внутри которых выводится контент, отредактированный через WYSIWYG редакторы, присваивается определённый класс, от которого посредством контекстных селекторов задаются стили некоторых элементов (параграфы, списки, таблицы и др.)
Вместо заключения
А вообще говоря, так ли важно на практике следовать этим, далеко не очевидным, правилам? Зачем тогда вся оставшаяся армия селекторов, если тру-селекторы можно пересчитать по пальцам одной руки? Как я уже упоминал, во всём должен быть баланс, основанный на здравом смысле. Почему бы не сэкономить пару-тройку сотен миллисекунд, если это ничего не стоит! Однако будет безумием тратить на это часы разработки и тестирования.
В то же время, замечали ли вы когда-нибудь на страницах с новомодными приклеивающимися шапками и колонками тормоза? Это результат большого времени, которое необходимо на перерисовку при скроллинге страницы.