Чередующиеся цвета
Давно известно, что табличный построчный вывод лучше воспринимается, будучи раскрашен в два цвета, которые идут один за другим по очереди. Подумав, и взяв за пример один из кусочков кода на php, я сделал такую весчицу:
<script language="JavaScript">
coloralternator = 1;
function alternate(col1,col2) {color = (coloralternator++ %2 ? col1 : col2); return color;}
</script>
На входе он получает два аргумента, которые надо чередовать. На выходе он возвращает один из этих двух цветов в зависимости от того, чётный или нечётный раз его вызывали.
В документе его можно использовать примерно так:
<table width="250" border="0" cellspacing="1" cellpadding="5" border="0" bgcolor="#b0b0b0" align="center">
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate('#cccccc','#ffcccc')+'">');
</script>test</td></tr><!--
<tr><td bgcolor="#b0b0b0"><img src="i/0.gif" width="1" height="1" alt="" border="0" class="hid"></td></tr> -->
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate('#cccccc','#ffcccc')+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate('#cccccc','#ffcccc')+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate('#cccccc','#ffcccc')+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate('#cccccc','#ffcccc')+'">');
</script>test</td></tr>
</table>
Теперь верстальщику не нужно думать, что будет, если заказчик захотел поменять две строки местами — цвета построятся автоматически.
Надеюсь, что это будет вам полезно также, как это полезно мне.
Известный недостаток: не продумано, что будет, если таких таблиц будет несколько. Нужно каким-то образом давать понять скрипту, скорее всего указывать ему дополнительно с какой переменной работать, и определять её заранее.
Кстати, коллеги, а возможно в качестве аргумента передать название переменной, которую надо использовать?
И “пожалуйста, не напоминайте.” Я знаю, что есть любители отключать скрипты.
- ну цвета можно было б каждый раз и не передавать, а установить вначале,
- для возможности быстрого изменения цветов на всем сайте лучше чередовать не цвета, а стили.
- не напомнить нельзя: такая штука тока в админском интерфейсе годится, ибо если у клиента отключен JavaScript, то он не просто "не увидит красоты", а может вообще "ничего не увидеть"
(можно защититься от этого так:
<tr><td bgcolor="
<script language="JavaScript">
document.write(alternate('#cccccc','#ffcccc'));
</script>
">test</td></tr>
работать будет, но такой подход противоречит принципам "правильного (well-formed) составления документов"
)
- серверная раскраска предпочтительней, т.к. позволяет централизованно управлять внешним видом интерфейса таблиц
P.S. ответ на вопрос: имя переменной можно передавать - подумай над использованием eval
Немного доработал. :)
- Мне не понравилось указание возможных цветов при каждом вызове функции.
- Цветов может больше двух.
- Две таблицы или более не проблема.
<script language="JavaScript">
coloralternator = 0;
last_c=0;
function alternate() {
colors=["#cccccc","#ffcccc","#ccffcc"];
coloralternator=last_c;
if (coloralternator!=colors.length-1) coloralternator++;
else coloralternator=0;
color = colors[coloralternator];
last_c=coloralternator;
return color;
}
</script>
<table width="250" border="0" cellspacing="1" cellpadding="5" border="0" bgcolor="#b0b0b0" align="center">
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 1</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 1</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 1</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 1</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 1</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 1</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 1</td></tr>
</table>
<br>
<table width="250" border="0" cellspacing="1" cellpadding="5" border="0" bgcolor="#b0b0b0" align="center">
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 2</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 2</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 2</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 2</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 2</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 2</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test 2</td></tr>
</table>
Можно чередовать и стили. Переделать не проблема.
Скрипт максимально обобщён для того, чтобы он мог применяться в виде подключаемого модуля. Именно поэтому в нём не предопределены цвета. Разумеется, в качестве аргументов могут передаваться и стили, и классы, и id, поэтому не возникает никакой проблемы, если на одной странице вам требуется серо-синяя таблица, а на другой - зелёно-коричневая.
Сечас вот я подумал, что можно предопределять именно названия классов в скрипте, а потом использовать подключаемый style sheet, который будет нужен именно для этой страницы. В этом случае действительно будет меньше мороки (из-за отсутствия параметров), но исчезнет возможность “выделить” строку (если вставить вместо цветов два одинаковых цвета/класса, которые служат для “подсветки”).
Сергей Круглов: Это не только и не столько tip, сколько вынесение на обсуждение собственного решения, чтобы его “универсализировать” и улучшить.
Андрей Брайнин: Серверная раскраска предпочтительна, когда вывод идёт с сервера, а не из статики. Данное же решение чисто клиентское, тем и хорошо. И, да, я помню про любителей отключать скрипты. Решение (и ваше и Артёма) помогает этого избежать, остаётся надеяться, что оно будет работать и в следующих версиях броузеров...
Артём, спасибо огромное! Вы прекрасно поняли, что именно я хотел получить. Мои комментарии: Неограниченное количество цветов — это просто превосходно! До хранения их в массиве я ещё не додумался. Две, три и более таблиц по-прежнему представляют проблему, даже расскажу почему:
• Как правило, все таблицы должны начинаться с одинакового цвета. Это проблема и моего, и вашего варианта, потому что они начинаются со следующего (в цикле) цвета. Это всё же немного неправильно;
• Если эти разные таблицы должны будут иметь несколько разных сочетаний цветов, то... что тогда будет с вашим вариантом?
По поводу решений пока молчу, они во мне пока только развиваются.
Алексей: неполноценность - это нераскрашенная таблица :-) Посетители с НН увидят таблицу нераскрашенной, и вот в этом и состоит неполноценность...
По поводу статических таблиц: конечно, их и на сервере раскрашивать не очень-то логично... Вообще нелогично раскрашивать программно статические вещи - на клиенте ли, на сервере ли... Значит, надо раскрашивать статически, раз и навсегда. Если лень это делать вручную - можно написать универсальную программу раскраски в процессе вёрстки. Какое-нибудь специальное приложение. На C++ или на Delphi. Не уверен, правда, что кто-нибудь возьмёт на себя труд - овчинка выделки не стоит :-)
А насчёт "пост-фактум" - это же универсальный метод. Всегда, когда делается страницу, на которой с декоративной целью может располагаться динамическое содержание, в первую очередь следует создавать статическую, информационную часть - ту, которую должны видеть все пользователи. При этом в начале документа располагается небольшой "browser sniffer", который определяет, следует ли загружать и динамическую часть. Если проверка на модель броузера прошла успешно, то в соответствующих местах докуметна программно вписывается динамическая часть:
if (хороший_броузер) document.write(динамическая часть);
По событию же загрузки документа (или загрузки соответствующих динамических частей) осуществляется инициализация динамических элементов - позиционирование меню, загрузка изображений в кеш, раскраска таблиц...
С раскраской таблиц общая идея может быть такой (это самый упрощённый вариант, только для иллюстрации; проверен лишь в ИЕ5.5):
<html>
<head>
<title>Title</title>
</head>
<body>
<table to_paint="1">
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
</table>
<P> </P>
<table>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
</table>
<P> </P>
<table to_paint="1">
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
<tr><td>abcdefghijk</td></tr>
</table>
<script>
colors=["#ff0000", "#00ff00"]
onload=function(){
tabArr=document.getElementsByTagName("table")
for (i=0; i<tabArr.length; i++) {
tabObj=tabArr[i]
if (tabObj.to_paint){
for (j=0; j<tabObj.rows.length; j++)
tabObj.rows[j].bgColor=colors[j%2]
}
}
}
</script>
</body>
</html>
Таблицы, где атрибут to_paint имеется и непустой, подвергаются раскраске "пост-фактум". Для желающих усовершенствовать открыт широкий путь :-)
Алексей, я то как раз думал, что таблица должна начинаться со следующего цвета :)
тогда так. :)
<script language="JavaScript">
coloralternator = 0;
last_c=0;
function alternate(e) {
if (e) last_t=e;
if (e) last_c=0;
colors0=["#cccccc","#ffcccc","#ccffcc"]; //1 вариант цветов
colors1=["#0000ff","#00ff00","#ff0000","#ccffff"]; //2 вариант цветов
colors=[colors0,colors1];
coloralternator=last_c;
if (coloralternator!=colors[last_t].length-1) coloralternator++;
else coloralternator=0;
color = colors[last_t][coloralternator];
last_c=coloralternator;
return color;
}
</script>
<table width="250" border="0" cellspacing="1" cellpadding="5" border="0" bgcolor="#b0b0b0" align="center">
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate('0')+'">');
</script>test 1 три цвета</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
</table>
<br>
<table width="250" border="0" cellspacing="1" cellpadding="5" border="0" bgcolor="#b0b0b0" align="center">
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate('1')+'">');
</script>test 2 четыре цвета</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
<script language="JavaScript">
document.write('<tr><td bgcolor="'+alternate()+'">');
</script>test</td></tr>
</table>
т.е. в первой строчке передается номер цветовой гаммы. По этому номеру определается что это новая таблица и какие цвета взять.
(Только надо что бы в массиве colors название нужногомассива стояло на соотвествуюшем номеру месте.)
А если написать на Perl программку, которая будет принимать статический HTML-файл и в статический же его конвертить, получится вот что:
@!/usr/bin/perl -w
my @Colors=("red","blue","cyan");
my $i=0;
while(<>) {
s/[0-9a-f"]*(#COLOR)/'"'.$Colors[($i++)%scalar(@Colors).'"'.$1]/sge;
print;
}
Запускать так:
> perl convert.pl myfile.html > outfile.html
Заменяет все вхождения #COLOR в исходном файле на последовательно чередующиеся цвета. Например:
<tr bgcolor=#COLOR><td>AAA</td></tr>
<tr bgcolor=#COLOR><td>BBB</td></tr>
преобразуется в
<tr bgcolor="red"#COLOR><td>AAA</td></tr>
<tr bgcolor="blue"#COLOR><td>BBB</td></tr>
Маркер #COLOR не убран для того, чтобы и к результирующему файлу можно было применить эту процедуру еще раз. Наверное, это самое простое решение.
Что мне не нравилось с самого начала - так это способ вызова. Неудобно писать <script> внутри html строк. Но есть способ и получше - можно использовать малоизвестную возможность 4 Навигатора под названием javascript entity. Он понимает и интерпретирует вставленные в html конструкции вида &{некий код}; Тех, кто этого не понимает (msie и mozilla) можно этому научить. Таким образом, Навигатор будет красить таблицу на ходу,
а все остальные - постфактум. Главное - html существенно проще становится.
<style>
.p0 {background-color:green}
.p1 {background-color:red}
</style>
<script>
var k=1;
function c() {
return "p"+(k=1-k);
}
</script>
<table border=1>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
</table>
<script>
function assignClasses() {
if(!document.all && document.getElementsByTagName)
document.all=document.getElementsByTagName("*");
for(var ii=0;document.all && document.all[ii];ii++) {
var el=document.all[ii],cls=el.className||"";
if(cls.charAt(0)=="&")
el.className=eval(cls.substring(1));
}
}
assignClasses()
</script>
Кстати: вы заметили, что Андрей сделал табуляцию? Пустячок, как говорится, а приятно.
Мда... Действительно, получилось удобнее и гораздо компактнее. Осталось только довести это творение до “многотабличности”, и всё, я буду счастлив окончательно.
(Впрочем, я был счастлив уже и после версии Артёма, но теперь, когда у меня целых четыре версии, на выбор... Вы догадываетесь, насколько приятнее мне будет жить? Вот-вот, и я тоже не догадываюсь)
Совемещение идеи Квадра и моего предыдущего скрипта.
Добавлена защита от ошибки вестальщика: если в качестве параметра передать букву, число меньше нуля или большее чем есть вариатнов, возмется любой случайным образом.
<html>
<head>
<title>Красим ячейки.</title>
</head>
<body>
<style>
.p0 {background-color:#cccccc}
.p1 {background-color:#ccccff}
.p2 {background-color:#ccffcc}
.p3 {background-color:#ffcccc}
.p4 {background-color:#ffffcc}
.p5 {background-color:#ffccff}
</style>
<script>
var k=1;
var coloralternator=0;
var last_c=0;
function c(e) {
alert(e)
c0=[0,1,2]; //1 вариант цвета
c1=[5,4,3,2,1,0]; //2 вариант цвета
c2=[2,0,5,1,3,4]; //3 вариант цвета
c3=[5,2,0,4,3,4]; //4 вариант цвета
c4=[1]; //5 вариант цвета
colors=[c0,c1,c2,c3,c4];
if (e) {
last_t=e;
if (isNaN(e) || e<0 || e>colors.length-1) {
last_t=0;
for (i=0;i<colors.length-1;i++)
last_t+=Math.round(Math.random());
}
}
if (e) last_c=0;
coloralternator=last_c;
color="p"+colors[last_t][coloralternator];
if (coloralternator!=colors[last_t].length-1) coloralternator++;
else coloralternator=0;
last_c=coloralternator;
return color;
}
</script>
<table width="100%" border="0" bgcolor="#b0b0b0" align="center">
<tr valign="top"><td>
<table width="150" border="0" align="left">
<tr class="&{c('0')};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
</table>
</td><td>
<table width="150" border="0" align="left">
<tr class="&{c('1')};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
</table>
</td><td>
<table width="150" border="0" align="left">
<tr class="&{c('test')};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
<tr class="&{c()};"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
</table>
</td></tr>
</table>
<script>
function assignClasses() {
if(!document.all && document.getElementsByTagName)
document.all=document.getElementsByTagName("*");
for(var ii=0;document.all && document.all[ii];ii++) {
var el=document.all[ii],cls=el.className||"";
if(cls.charAt(0)=="&")
el.className=eval(cls.substring(1));
}
}
assignClasses();
</script>
</body>
</html>
Проблема только в Опере, несмотря на то, что функция вызывается в ней, ячейки не красятся. При этом прямое указание
<tr class="p0"><td >1</td><td >2</td><td >3</td><td >4</td><td >5</td></tr>
работает. Так что есть еще поле деятельности.
Поводы для размышления:
При выводе цветов, оказывается, что моя любимая манера давать названия классам начиная с 0 (т.е. p00,p01,...,p99), не срабатывает по простой причине — при занесении в массив нули срезаются (что есть нормально). Так как решение должно быть неважно чем, то вариантов выхода есть несколько:
• использовать безнулевую запись. Таким образом, удастся избежать всех проблем.
• использовать строковую запись. c1 = ['01','06']; Чуть замороченнее, но потенциально гибче — на месте 01/06 моут стоять не числа/цифры, а очевидные названия классов ('blue','red')/
• использовать функцию для приведения чисел длиной меньше нужного количества знаков к норме путём добавления правильного количества нулей (на входе 1, на выходе, к примеру, 0001). Самый замороченный путь, поэтому я по нему сначала и пошёл. Поплутал и бросил.
Вот.
Плоды раздумий :)
Если бы задача писалась на каком-нибудь C++, мы бы поступили так:
- завели бы класс AbsctractIterator с методом next()
- от него бы произвели разыне виды итераторов: двоичный, по массиву, по массиву с циклом итп.
- и передавали бы эти итераторы функции рисования:
void drawTableRow(AbstractIterator& theIterator){
sprintf(HTML,"<TR CLASS=%d>", theIterator.next());
......
Но на js надо чего-нибудь попроще (хотя реализовать вышесказанное проблем, в общем, нет).
Заведем две функции:
function inc(){ return window.k=isNaN(window.k)?0:window.k+1;}
function reset(){window.k="-";}
первая возвращает 0,1,2 итд до бесконечности, вторая - сбрасывает этот генератор.
Можно это оформить в виде объекта - не принципиально.
На этой "прочной основе" сочиняем разные виды итераторов:
// 0101010
function flipFlop(){
return inc()%2;}
// массив по кругу
function ring(theArray){
return theArray[inc()%theArray.length];}
// числа с 0 до limit-1 дополненные нулями до длины size
function grow(limit,size){
var p=(inc()%limit)+"";
while(p.length<size)p="0"+p;
return p;
}
Ну и потом всё это используем на практике:
<table>
<tr class=&{reset();"p"+flipFlop()};>...
<tr class=&{"p"+flipFlop()};>...
Типа так...
var last_c=0;
также и
var last_t=0; // или просто var last_t;
Чтобы она была “предварительно” создана, иначе мой пятый ИЕ выдаёт ошибку, не найдя такого объекта ер всё корректно выводя дальше.
![[logo]](/site/images/logo.jpg)