Документ: навешиваем ярлычки.
Пост следующий, как продолжение темы о документе. Про классы элементов и их применение.
Что такое класс элемента? Кто-то ответит, что это эдакий штуковин, чтобы верстальщики могли стили прикрутить.
На самом деле, все значительно глубже. Класс — это именно класс элемента, то, что отделает его от других и наделяет особыми свойствами, и это касается не только css.
В jQuery-style программировании я часто сталкивался с тем, что нужным элементам присваиваются инлайновые стили, мол, ты, элемент, будешь красный и полужирный Ариала двадцатого с подчеркиванием, а ты, дружок, будешь display: none. А потом состояние проверяется через computedStyle, вызывая лавины reflow в совершенно ненужных местах. А через полгода грядет редизайн сайта, и он начинает пестрить красным ариалом, хотя сам уже давно сделан на черном Мириад Про.
Так вот, меняя элемент, мы должны менять не его отображение, а его роль в документе. То есть, класс или id. И это и есть пресловутая семантика.
А теперь вспомним предыдущий пост и посмотрим, какие же плюсы нам может это дать.
С семантичным кодом удобно и приятно работать. Давайте рассмотрим в комментариях следующий код, который добавляет этой странице подсветку ответной скобки при наведении на скобку в скриптах.
Опять-таки, отслеживаем любое событие и смотрим, чьё оно.
if (!highlightCode) var highlightCode = { /* мухи отдельно, котлеты отдельно. Храним связанные функции в одном объекте */
dispatcher: { /* диспетчер. Собираем до кучи обработчики */
mouseover: function(e){
var trigger = e.srcElement||e.target; /* кто такой? */
if (trigger.className && /(^|\s)+br0(\s|$)+/.test(trigger.className)){ /* у него есть класс br0? */
highlightCode.highlight(trigger); /* запускаем подсветку */
};
},
mouseout: function(e){
var trigger = e.srcElement||e.target; /* кто такой? */
if (trigger.className && /(^|\s)+highlight-[^\s]+(\s|$)+/.test(trigger.className)){ /* уже подсвечен? */
highlightCode.unhighlight(trigger); /* снимаем подсветку */
};
}
},
highlight: function(o){ /* подсветка */
var targetBrace = o.innerHTML; /* а что за скобочка? */
switch (targetBrace){
case "(": var matchingBrace = ")"; var browseForward = true; break; /* если это "(", то ищем ")" дальше по документу */
case ")": var matchingBrace = "("; var browseForward = false; break; /* если это ")", то ищем "(" раньше */
case "{": var matchingBrace = "}"; var browseForward = true; break;
case "}": var matchingBrace = "{"; var browseForward = false; break;
case "[": var matchingBrace = "]"; var browseForward = true; break;
case "]": var matchingBrace = "["; var browseForward = false; break;
default: return; /* это не нужная нам скобочка. Выходим и ничего не делаем */
};
var disbalance = 1; /* баланс скобок. Нарушен */
var testElement = o; /* начинаем поиски от текущего элемента */
while (testElement){ /* условие не должно быть пустым. Правило хорошего тона, не более */
testElement = browseForward?testElement.nextSibling:testElement.previousSibling; /* выбираем следующий элемент, назад или вперед */
if (!testElement) break; /* это не элемент. Кончились? Завершаем цикл. */
if (!testElement.className || !/(^|\s)+br0(\s|$)+/.test(testElement.className)) continue; /* это не скобочка. Ищем другой элемент */
switch (testElement.innerHTML){ /* баланс скобок */
case targetBrace: disbalance++; break;
case matchingBrace: disbalance--; break;
default: continue; /* это не наша скобка, пропускаем */
};
if (disbalance == 0){ /* баланс сошелся? */
o.relatedBrace = testElement; testElement.relatedBrace = o; /* делаем скобки побратимами */
o.className += " highlight-matching"; /* одной ставим класс */
testElement.className += " highlight-matching"; /* и другой */
break; /* выходим из цикла */
};
};
if (!testElement){ /* если после выхода из цикла проверяемый элемент Null, то баланс так и не сошелся */
o.className += " highlight-nonmatching"; /* подсвечиваем одинокую скобку, по-другому */
}
},
unhighlight: function(o){ /* снимаем подсветку */
o.className = o.className.replace(/(^|\s)+highlight-[^\s]+(\s|$)+/, " "); /* убираем класс */
if (o.relatedBrace){ /* и у побратима, если есть, тоже */
o.relatedBrace.className = o.relatedBrace.className.replace(/(^|\s)+highlight-[^\s]+(\s|$)+/, " ");
};
},
init: function(){
if (arguments.callee.runOnce) return false; /* защита от повторного запуска */
else arguments.callee.runOnce = true;
for (var i in this.dispatcher){ /* проходим по всему диспетчеру и привязываем его обработчики */
if (typeof this.dispatcher[i] == "undefined") continue;
if (document.addEventListener) document.addEventListener(i, this.dispatcher[i], false)
else if (document.attachEvent) document.attachEvent('on' + i, this.dispatcher[i]);
};
var myCSS = document.createElement("style"); /* создаем стиль и заполняем его */
myCSS.type = "text/css";
myCSS.innerHTML = "\
.source .highlight-matching {color: red; font-weight: bold}\
.source .highlight-nonmatching {color: darkblue; font-weight: bold}\
";
document.getElementsByTagName("head")[0].appendChild(myCSS) /* ...и прикрепляем */
}
};
highlightCode.init(); /* поехали! */
В этом примере css вставляется через яваскрипт (увы, я не имею доступа к хостингу javascript.ru ), но в Вашем проекте, конечно, стили должны подключаться из файла.
CSS позволяет нам посредством себя же управлять отображением документа. Это не секрет. И это можно использовать в своих коварных целях.
На практике есть два приема для этого: классы-модификаторы и классы-переключатели.
Класс-модификатор — класс, который, будучу добавленным к элементу, незначительно меняет его отображение. Одноименные классы, добавленные к разнотипным элементам, могут менять разные свойства, но логически должны составлять единое целое. Например, логическое выделение. Класс-модификатор — это, например, highlight-matching в предыдущем примере.
Класс-переключатель меняет отображение своих детей. Например, на лету и в одном месте поменять цвет сайта или размер шрифта, почему нет?
Чтобы проиллюстрировать класс-переключатель, немного пошалим и с грязными ногами, но с чистыми намерениями внедримся в шаблон этой самой страницы:
if (!inactiveHandler) var inactiveHandler = {
hareAnimation: function(vector){
var thisFunction = arguments.callee;
if (typeof(vector) == "undefined"){
vector = thisFunction.vector;
} else {
thisFunction.vector = vector;
};
if (!thisFunction.frame) thisFunction.frame = 0;
thisFunction.frame = thisFunction.frame + vector;
if (vector > 0){
if (thisFunction.frame > 4){
thisFunction.frame = 4;
return;
};
} else {
if (thisFunction.frame < 0){
thisFunction.frame = 0;
return;
};
}
document.body.className = document.body.className.replace(/(^|\s)+hare-sprite-frame-\d(\s|$)+/, " ") + "hare-sprite-frame-" + thisFunction.frame;
setTimeout(function(){thisFunction()}, 40);
},
dispatcher: {
mouseover: function(e){
if(!(e.relatedTarget||e.fromElement)) inactiveHandler.hareAnimation(-1);
},
mouseout: function(e){
if(!(e.relatedTarget||e.toElement)) inactiveHandler.hareAnimation(1);
}
},
init: function(){
if (arguments.callee.runOnce) return false;
else arguments.callee.runOnce = true;
for (var i in this.dispatcher){
if (typeof this.dispatcher[i] == "undefined") continue;
if (document.addEventListener) document.addEventListener(i, this.dispatcher[i], false)
else if (document.attachEvent) document.attachEvent('on' + i, this.dispatcher[i]);
};
var myCSS = document.createElement("style");
myCSS.type = "text/css";
myCSS.innerHTML = "\
.hare-logo {width: 336px;height: 76px;background: url(/files/u4363/jssprite1.gif) 0px 0px no-repeat}\
.header-table-login {background: url(/files/u4363/jssprite2.gif) 0px -0px repeat-x}\
.hare-sprite-frame-1 .hare-logo, .hare-sprite-frame-1 .header-table-login {background-position: 0px -76px}\
.hare-sprite-frame-2 .hare-logo, .hare-sprite-frame-2 .header-table-login {background-position: 0px -152px}\
.hare-sprite-frame-3 .hare-logo, .hare-sprite-frame-3 .header-table-login {background-position: 0px -228px}\
.hare-sprite-frame-4 .hare-logo, .hare-sprite-frame-4 .header-table-login {background-position: 0px -304px}";
document.getElementsByTagName("head")[0].appendChild(myCSS)
var images = document.getElementsByTagName("img");
for (var i=0; i<images.length; i++){
if (/\/misc\/logo.gif/.test(images[i].src)){
var image = images[i];
var parent = image.parentNode;
var mylogo = document.createElement("div");
mylogo.className = "hare-logo";
parent.insertBefore(mylogo, image);
parent.removeChild(image);
};
};
}
};
inactiveHandler.init();
Запустили? Ничего не произошло? Пролистайте в самый верх страницы и уведите курсор куда-нибудь со страницы, например, в заголовок окна браузера. Теперь видите?
Это я всё к чему. Рассматривая страницу как документ, а не как разрозненный набор элементов, мы можем работать с ней как со стройной системой, легко и просто. Буквально, подежать в руках и покрутить как кубик Рубика.
|
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.