Опубликован: 16.06.2010 | Доступ: свободный | Студентов: 2352 / 93 | Оценка: 4.39 / 4.00 | Длительность: 17:32:00
ISBN: 978-5-9963-0253-6
Лекция 6:

Оптимизация структуры веб-страниц

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >

5.2. Оптимизация CSS-структуры

Этот раздел написан после прочтения статей Steve Souders — don't use @import (http:/www.stevesouders.com/bLog/2009/04/09/dont-use-import/) и Simplifying CSS Selectors (http://www.stevesouders.com/blog/ 2009/06/18/simplifying-css-selectors/) — и обсуждения с ним производительности CSS-правил. Данный материал подготовлен с помощью Аба-новой Ольги (http://www.getincss.ru/).

5.2.1. <link> vs. ©import

Существует два способа загрузки файлов стилей: использовать тег <link>:

<link rel='stylesheet' href='a.css'/>
или импортировать файлы с помощью @import:
<style type='text/css'>
@import url('a.css');
</style>
Листинг 5.6.

Стоит использовать <link> для удобства, но вы должны помнить, что @import нужно размещать всегда в самом верху блока стилей, в противном случае они не импортируются.

5.2.2. ©import ©import

В приведенном ниже примере подключаются два файла стилей: a.css и b.css. Каждый файл по загрузке занимает ровно 2 секунды, чтобы было удобно отследить влияние на скорость загрузки в дальнейшем. В первом примере применяется @import для загрузки обоих файлов стилей. Здесь HTML-документ содержит следующий блок стилей:

<style type='text/css'> @import url('a.css'); @import url('b.css'); </style>
Листинг 5.7.

Если вы всегда будете использовать только @import для загрузки стилей, то проблем с производительностью не будет, хотя, как мы увидим ниже, это может привести к ошибке с JavaScript. Оба файла загружаются параллельно (рис. 5.1) Но проблемы начинают появляться, если применять @import внутри файла стилей либо вместе с <link>.

Параллельная загрузка стилей. Источник: getincss.ru

Рис. 5.1. Параллельная загрузка стилей. Источник: getincss.ru

5.2.3. <link> ©import

В следующем примере используется тег <link> для загрузки a.css и @import для b.css:

<link rel='stylesheet' type='text/css' href='a.css'/> <style type='text/css'> @import url('b.css'); </style>
Листинг 5.8.

В IE (тестировалось в 6, 7 и 8) это привело к тому, что файлы загружаются последовательно друг за другом, как показано на рис. 5.2. Соответственно, время загрузки страницы в IE увеличится.

@import блокирует <link> в IE. Источник: getincss.ru

Рис. 5.2. @import блокирует <link> в IE. Источник: getincss.ru

5.2.4. <link> с ©import

Тут файл a.css загружается через <link> и содержит внутри правило @import для b.css: В документе:

<link rel='stylesheet' type='text/css' href='a.css'/>
Листинг 5.9.

в a.css:

@import url('b.css');

Этот способ также приводит к тому, что файлы загружаются последовательно (рис. 5.3), а не параллельно, и теперь это происходит не только в IE, но и в остальных браузерах. Если подумать — все логично: браузер загружает a.css и начинает анализировать его. Как только внутри обнаружено правило @import, начинается загрузка файла b.css.

@import блокирует <link> не только в IE. Источник: getincss.ru

Рис. 5.3. @import блокирует <link> не только в IE. Источник: getincss.ru

5.2.5. Блоки <link> с ©import

Незначительное отличие от предыдущего примера привело к удивительным результатам: в IE. <link> используется для вызова a.css и для нового файла proxy.css, который содержит только @import для b.css.

В HTML-коде:

<link rel='stylesheet' type='text/css' href='a.css'> <link rel='stylesheet' type='text/css' href='proxy.css'>
Листинг 5.10.

В proxy.css:

@import url('b.css');

Результаты эксперимента в IE показаны на рис. 5.4. Первый запрос — HTML-документ. Второй запрос — a.css (2 секунды). Третий — proxy.css. Четвертый — b.css (2 секунды). И вот что удивительно, IE не хочет начинать загрузку b.css, пока файл a.css не будет загружен полностью. Во всех других браузерах такого сюрприза не происходит, что приводит к более быстрой загрузке страницы (см. рис. 5.5).

Результаты в IE. Источник: getincss.ru

Рис. 5.4. Результаты в IE. Источник: getincss.ru
Результаты в других браузерах. Источник: getincss.ru

Рис. 5.5. Результаты в других браузерах. Источник: getincss.ru

5.2.6. Много ©import

Применение сразу нескольких правил @import в IE приводит к тому, что файлы загружаются не в том порядке, в котором они указаны в коде. В этом примере используется 6 файлов стилей (каждый из которых загружается по 2 секунды), за которыми следует JS-скрипт (4 секунды для загрузки).

<style type='text/css'>
@import url('a.css'); 
@import url('b.css'); 
@import url('c.css'); 
@import url('d.css'); 
@import url('e.css'); 
@import url('f.css'); 
</style>
Листинг 5.11.
Много @import. Источник: getincss.ru

Рис. 5.6. Много @import. Источник: getincss.ru

На рис. 5.6 мы увидим, что самый долгий по загрузке — это скрипт. Несмотря на то, что он указан после стилей, в IE он загружается первым. Если в скрипте содержится код, который зависит от применяемых стилей ( getElementsByClassName, и т. п.), это может привести к ошибкам работы скрипта, так как он загружается раньше, чем стили.

5.2.7. <link> <link>

Проще и безопасней задействовать <link> для загрузки стилей:

<link rel='stylesheet' type='text/css' href='a.css'>
<link rel='stylesheet' type='text/css' href='b.css'>

Использование <link> обеспечивает параллельную загрузку файлов во всех браузерах (см. рис. 5.7). Применение <link> также гарантирует, что файлы будут загружены именно в том порядке, который указан в коде документа.

Использование <link>. Источник: getincss.ru

Рис. 5.7. Использование <link>. Источник: getincss.ru

Для нас особенно плохо то, что ресурсы могут быть загружены в другом порядке, нежели указано в документе. Все браузеры должны заглядывать вперед перед загрузкой стилей для извлечения правил @import и начинать их загрузку немедленно. До тех пор, пока браузеры не реализуют это, стоит избегать использования @import и загружать стили только с помощью <link>.

5.2.8. Упрощаем CSS-селекторы

Для большинства сайтов возможный выигрыш в производительности после оптимизации CSS-селекторов будет крайне незначительным и не будет стоить потраченного времени. Есть несколько типов CSS-правил (например, expression для IE) и взаимодействий с JavaScript, которые могут существенно замедлить страницу. Именно на них и нужно концен-тировать усилия.

Большая часть информации о быстродействии CSS-селекторов может быть получена из статьи David Hyatt Пишем эффективный CSS для интерфейсов в MoziLLa (https://deveLoper.moziLLa.org/en/Writing Efficient CSS). Стоит привести оттуда одну цитату:

"Система стилей находит элемент, соответствующий CSS-правилу, начиная с правого конца селектора и двигаясь налево. Пока мы еще находим элементы, соответствующие селектору, мы продолжаем двигаться. Остановка возможна только в случае нахождения элемента, соответствующего всему CSS-селектору, или невозможности такой элемент найти для какой-то части селектора".

Не очень понятно, как устроен движок CSS-селекторов в других браузерах, например, в IE (а если принять во внимание тесты CSS-производи-тельности из книги "Разгони свой сайт", то возникает предположение, что в Opera движок разбора CSS-селекторов работает как раз слева направо). Может быть, он использует комбинированный подход: как справа налево, так и слева направо. Переключение может происходить по какому-то признаку (например, по наличию #id).

Однако по заявлению Виталия Харисова, руководителя группы HTML-верстки в Яндексе, тесты показывают (http://clubs.ya.ru/yacf/ replies.xml?item no=338&ncrnd=3604), что все браузеры применяют селекторы одинаково — справа налево.

Благодаря вышесказанному мы можем теперь сфокусировать оптимизационные усилия на тех CSS-селекторах, правая часть которых будет соответствовать большому числу элементов на странице. Давайте рассмотрим для примера DIV DIV DIV P A.class0007 {}. У этого селектора присутствует 5 уровней вложенности потомков, для которых необходимо найти соответствие в DOM-дереве. Это выглядит очень ресурсоемко, однако при взгляде на самую правую часть этого селектора, A.class0007, мы прекрасно понимаем, что ей соответствует только 1 элемент на странице, поэтому браузеру очень легко установить точное соответствие.

Ключевым моментом в оптимизации CSS-селекторов является самая правая часть, часто также называемая "ключевым селектором". Вот пример гораздо более ресурсоемкого селектора: A.class0007 * {}. Хотя он может и выглядеть просто, но для браузера очень тяжело его вычислить. Поскольку браузер будет двигаться справа налево, он начнет со всех элементов, которые подходят под ключевой селектор (*). Это означает, что браузер попытается проверить все элементы на странице и установить, нужно ли к ним применить этот стиль. На следующей диаграмме показана разница во времени между тестами для универсального селектора и прошлыми тестами для наследственных селекторов.

Разница во времени загрузки (в мс) для универсального селектора. Источник: stevesouders.com

Рис. 5.8. Разница во времени загрузки (в мс) для универсального селектора. Источник: stevesouders.com

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

A.class0007 DIV {} #id0007 > A {} .class0007 [href] {} DIV:first-child {}

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

Некоторой проблемой является то, что почти все известные JavaScript-библиотеки разбирают селекторы слева направо. Таким образом, мы должны писать два вида селекторов: оптимизированных под браузеры и оптимизированных под JavaScript-библитеки. На данный момент только немногие поддерживают нотацию справа налево, например, CSS1-ветка YASS (http://yass.webo.in/).

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >
Ольга Артёмова
Ольга Артёмова

Доброго времени суток!

Прошла курс, но почему-то диплом получить не могу, хотя курс значится завершенным, хотя обязательные два модуля пройдены. Как решить эту проблему?

Сертификация: оптимизация и продвижение web-сайтов.

Алексей Дмитриев
Алексей Дмитриев
Россия, Москва, МГУ, 2007