Выбрать главу

Вычисление постоянных

Вот что мы собираемся сделать: пройтись по всем объявлениям стилей и заменить вычисление выражения его постоянным значением. В предыдущем примере, предполагая, что мы используем IE6 в стандартном режиме, нам хотелось бы видеть следующий код:

#myDiv {

border: 10px solid Red;

width: 80px;

}

Итак, как нам убедиться в том, что наше выражение постоянно? Самым простым путем является пометить само выражение, чтобы мы могли его легко обнаружить. Решением в данном случае будет заключение выражения в вызов функции, которая нам известна и заранее объявлена.

function constExpression(x) {

return x;

}

Итак, в нашем CSS-блоке мы напишем следующее:

#myDiv {

border: 10px solid Red;

width: expression(constExpression(ieBox ? "100px" : "80px"));

}

Использование

Во-первых, мы сперва должны подключить библиотеку cssexpr.js (о ней речь чуть ниже) и только потом вызывать нашу функцию constExpression.

<script type="text/javascript" src="cssexpr.js"></script>

После этого можно использовать constExpression в любом задаваемом блоке стилей (<style>), или любом подключаемом файле стилей (<link>), или при использовании директивы @import. Следует заметить, что атрибут style у тегов для ускорения работы не проверяется.

Реализация

Идея заключается в том, чтобы перебрать все объявленные таблицы стилей, а в них — все правила и их конечные объявления. Для этого мы начнем с массива document.styleSheets.

function simplifyCSSExpression() {

try {

var ss = document.styleSheets;

var i = ss.length

while (i-- > 0) {

simplifyCSSBlock(ss[i]);

}

}

catch (exc) {

alert("Обнаружили ошибку при обработке css. Страница будет " +

"работать в прежнем режиме, хотя, возможно, не так “ +

“быстро");

throw exc;

}

}

В таблицах стилей мы пройдемся по массиву импортируемых таблиц (@import), а затем уже по объявлениям стилевых правил. Для того чтобы не совершать пустых телодвижений, будем проверять, что cssText содержит expression(constExpression).

function simplifyCSSBlock(ss) {

// Проходимся по import'ам

var i = ss.imports.length;

while (i-- > 0)

simplifyCSSBlock(ss.imports[i]);

// если в cssText'е нет constExpression, сворачиваемся

if (ss.cssText.indexOf("expression(constExpression(") == -1)

return;

var rs = ss.rules;

var rl = rs.length;

while (rl-- > 0)

simplifyCSSRule(rs[j]);

}

Затем мы уже можем обрабатывать для каждого правила cssText и заменять его, используя функцию simplifyCSSRuleHelper, чтобы текст объявления из динамического становился статическим.

function simplifyCSSRule(r) {

var str = r.style.cssText;

var str2 = str;

var lastStr;

// обновляем строку, пока она еще может обновляться

do {

lastStr = str2;

str2 = simplifyCSSRuleHelper(lastStr);

} while (str2 != lastStr)

if (str2 != str)

r.style.cssText = str2;

}

Вспомогательная функция находит первое возможное выражение и исполняет его, затем заменяет выражение полученным значением.

function simplifyCSSRuleHelper(str) {

var i = str.indexOf("expression(constExpression(");

if (i == -1)

return str;

var i2 = str.indexOf("))", i);

var hd = str.substring(0, i);

var tl = str.substring(i2 + 2);

var exp = str.substring(i + 27, i2);

var val = eval(exp)

return hd + val + tl;

}

Наконец, нам нужно добавить вызов simplifyCSSExpression при загрузке страницы.

if (/msie/i.test(navigator.userAgent) && window.attachEvent != null) {

window.attachEvent("onload", function () {

simplifyCSSExpression();

});

}

Все так просто? Нет, еще проще

А еще можно использовать свойства currentStyle (доступное для чтения) и runtimeStyle (доступное для записи), чтобы переопределять само стилевое свойство при его объявлении (звучит несколько сложно, не так ли?). На самом деле все чрезвычайно просто. Применительно к нашему примеру мы должны будем написать:

#myDiv {

border: 10px solid Red;

width: expression(runtimeStyle.width = (ieBox ? '100px' : '80px'));

}

Например, можно дописать исправление всплывания alt вместо title для картинок:

img {

behavior: expression( (alt&&!title) ? title = '' : '',

runtimeStyle.behavior = 'none'

)

}

Или прозрачность через фильтр:

.button1 { opacity: .1 }

.button2 { opacity: .2 }

.button3 { opacity: .3 }

.button4 { opacity: .4 }

.button1, .button2, .button3, .button4

{ filter: expression( runtimeStyle.filter =

'alpha(opacity='+currentStyle.opacity*100+')' ) }

Таким образом, наше выражение быстро применяется при загрузке страницы и последующем создании новых узлов скриптом. Такой способ оптимизации подходит только для «статичных» элементов, которым не нужно менять свое отображение динамически. Изменение родительского класса, равнение по высоте окна и эмуляция position: static — все это проблемные участки оптимизации. Лучше их не оптимизировать, а использовать пореже.

Еще одним проблемным местом, на мой взгляд, является общее выполнение скриптов при onresize. Ну и еще серьезный совет: используйте CSS-выражения по минимуму. Лучше всего будет, если они вообще не встретятся у нас сайте.

6.2. Что лучше, id или class?

Далее давайте рассмотрим, как использование id или class влияет на скорость отображения страницы в браузере (сейчас речь не идет о множественном использовании одинаковых id — это и так запрещено спецификацией). Если элемент на странице встречается единственный раз (например, «шапка» или «подвал»), то мы можем с равным успехом использовать id и class для его стилизации.