Опубликован: 16.02.2009 | Уровень: специалист | Доступ: платный
Лекция 6:

CSS-оптимизация

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

Во-первых, для IE и Firefox (наиболее популярных браузеров) функция эта работает некорректно (в общем случае возвращает неверные данные). Во-вторых, работает она чуть ли не медленнее, чем offsetHeight.

Вообще говоря, рекомендуется не пользоваться такими универсальными функциями ( getStyle есть практически в каждой JavaScript-библиотеке), а реализовывать необходимую функциональность в каждом конкретном случае. Ведь если мы договоримся, что скрытые элементы должны иметь класс hide, то все сведется к определению наличия этого класса у элемента или его родителей.

Оптимизация: определение класса hide

Давайте подробнее остановимся на предложенном мной решении. Предлагаю следующую реализацию:

function isHidden(el)
{
	var p=el;
	var b=document.body;
	var re=/(^|\s)hide($|\s)/;
	while(p && p!=b && !re.test(p.className))
		p=p.parentNode;
	return !!p && p!=b;
}

Предполагается, что корневые элементы DOM скрывать не имеет смысла и поэтому проверки ведутся только до document.body.

Предложенное решение явно не спустит лавину reflow, так как никаких вычислений и измерений не проводится. Однако немного смущает проход до корня документа: что же будет при большой вложенности элементов? Давайте проверим. Тест isHidden проводится для вложенности 2 ( document.body / test_div ), а тест isHidden2 — для вложенности 10 ( document.body / div * 8 / test_div ).

Таблица 6.5. Результаты выполнения функции isHidden. Времена приведены в миллисекундах
IE sp62 Firefox 2.0.0.12 Opera 9.22 Safari 3.04b
offsetHeight 23500 10624 4453 5140
isHidden 231 351 70 71
isHidden2 370 792 212 118
offsetHeight vs. isHidden 102 раза 30 раз 73 раза 92 раза

Как показывают тесты, даже при большой вложенности падение скорости невелико. Таким образом, мы получили универсальное решение, которое быстрее доступа к offsetHeight в 30–100 раз.

Заключение

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

В качестве послесловия: стили или классы?

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

Существует два способа это сделать: при помощи стилей или установив цвет (или фон) напрямую из JavaScript. Для начала немного кода — с помощью класса:

var items = el.getElementsByTagName('li');

for (var i = 0; i < 1000; i++) {
	items[i].className = 'selected'
}

И с помошью стилей:

var items = el.getElementsByTagName('li');

for (var i = 0; i < 1000; i++) {
	items[i].style.backgroundColor = '#007f00';
	items[i].style.color = '#ff0000';
}

Результаты простые и понятные:

Таблица 6.6. Применение стилей и классов к элементам
Метод IE 6 IE 7 Firefox 1.5 Firefox 2.0 Opera 9
element.className 512 187 291 203 47
element.style.color 1709 422 725 547 282

Перерисовка страницы

Однако когда мы изменяем класс элемента, код отрабатывает значительно быстрее, но вот страница обновляется медленно. Это все из-за того, что изменение свойства className не перерисовывает страницу мгновенно, вместо этого браузер просто помещает событие обновления в очередь reflow. Отсюда и огромная скорость, казалось бы, более сложной процедуры. А что по поводу :hover? К сожалению, :hover работает только для ссылок в Internet Explorer 6. Поэтому в любом случае придется пользоваться какой-то его эмуляцией.

Из всего вышеперечисленного можно сделать два ключевых вывода

  • Используйте className везде, где это возможно. Это дает больше гибкости и контроля над внешним видом сайта.
  • Если на странице много элементов в контейнере и необходимо построить очень быстрый интерфейс, стоит устанавливать стили напрямую через свойство style.

Групповое изменение стилей

Если мы уже задумались над максимально быстрым изменением интерфейса нашего веб-приложения (отрисовке) через свойство style, то стоит иметь в виду следующий момент. Мы можем изменять свойство cssText, которое отвечает за компилируемые стили элемента:

element.style.cssText = "display:block;width:auto;height:100px;...";

Таким образом, мы можем дополнительно ускорить наше единовременное обновление стилей у элемента, потому что произойдет всего одно присвоение свойств и всего один reflow (и он случится сразу же после изменения этого свойства, а не в отложенном режиме).

Два слова о таблицах

Таблицы замечательно подходят для организации информации. Однако если в HTML-документе встречается таблица, то браузеру приходится пробежаться по ней дважды: в первый раз — чтобы выбрать все элементы, рассчитать их взаимные размеры, и чтобы отрисовать их все — во второй раз. Если на странице выводятся большие массивы данных (например, параметры товаров или статистические данные), то гораздо быстрее будет визуализировать такие таблицы в один проход.

Давайте рассмотрим, как можно помочь браузерам в их нелегком труде. Следующие действия позволят начать отображение таблицы еще до того, как будет получена вся информация о ней.

  • Необходимо установить для table CSS-атрибут table-layout в значение fixed.
  • Затем явно определить объекты col для каждого столбца.
  • И установить для каждого элемента col атрибут width.

В качестве примера можно привести такой фрагмент кода:

<table style="table-layout: fixed">
<!-- первый столбец имеет ширину 100 пикселей -->
<col width="100"></col>
<!-- второй — 200 -->
<col width="200"></col>
<!-- третий и четвертый — по 250 -->
<col width="250"></col><col width="250"></col>
<thead>...</thead>
<tfoot>...</tfoot>
<tbody>...</tbody>
</table>
< Лекция 5 || Лекция 6: 12345 || Лекция 7 >
Мария Кравцова
Мария Кравцова
Россия, Сочи, РГПУ им. А.И.Герцена, 1997
Екатерина Архангельская
Екатерина Архангельская
Россия, СПбГУАП