Непростая стилизация строк таблицы и непонятный баг в IE9
Несколько дней назад, у одной моей знакомой верстальщицы возникла задачка по вёрстке, которая касалась необычного раскрашивания строк таблицы при наведении. Во время того, как рассматривались всякие решения, был выявлен странный баг в IE9.
В общем, в этом посте я хочу поделиться найдненными решениями (а возможно узнать и лучше), а заодно и непонятным багом, в надежде что кто-нибудь из заинтересовавшихся комментаторов поможет мне понять его природу.
Начнём с задачи
В принципе, условие задачи очень простое. Есть таблица, состоящая из n-количества строк. При наведении указателем мыши на строку она должна изменять цвет, получать одна-пиксельную границу, а вдобавок ещё и тень. Что касается поддержки браузеров: IE8+, но в IE8 тени может и не быть. Думаю на рисунке ниже всё станет понятно.

Рассуждения вслух
Казалось бы, что может быть проще повесить все стили на сами строки и не париться. Но не всё так-то легко, как кажется. Дело в том, что table-row — непростой бокс, собственно как и сама таблица, поэтому и стилизация строк в браузерах очень хромает. Связываться в этом плане со стоками, мягко говоря… рискованное занятие, и поведение Opera на это недвусмысленно намекает, применяя тень к отдельным ячейкам.
Так как поддержка IE6-7 нам не нужна, мы смело может воспользоваться псевдоэлементами. И первое что пришло в мне в голову, это повесить псевдоэлементы на каждую строку, задав им следующие стили (для примера я задал стили только верхней строке):
table tr:first-child:before {
content: '';
position: absolute;
left: 0px;
height: 31px;
width: 100%;
border: 1px solid #47a9e1;
box-shadow: 0 0 4px #47a9e1;
}
Фактически всю ответственность за стилизацию строки я переложил на псевдоэлемент :before, рассчитывая, что это и будет решением задачи. Но как оказалось, я ошибался.

Вместо того, чтобы просто сгенерировать псевдоэлемент внутри строки и растянуть его на 100% по ширине, в таблице появилась и дополнительная ячейка! Да, вы не ослышались, строка стала больше ровно на две сущности вместо одной:) Вот это чудеса, подумал я, и позвал на помощь своего коллегу Илью Стрельцына.
Илья объяснил мне, что любая нежданная сущность внутри tr, но снаружи td, оборачивается в анонимный table-cell. И неважно, абсолютно позиционированная ли это сущность или нет. Рендереру таблиц всё равно. В нашем случае абсолютно отпозиционированный блочный бокс, который мы видим растянутым на всю ширину таблицы, оказался всё равно внутри «виртуальной» пустой ячейки, присутствие которой мы наблюдаем в первой строке таблицы. Это в общем-то стандартное поведение табличной модели в CSS, в скором будущем мы раскроем эту тему подробнее:)
Ради интереса стоит заменить, что, если бы я поменял :before на :after, то картина бы стала приятнее. Но это не избавило бы нас от ответственности. Ведь, по сути, здесь нам просто повезло, что анонимный table-cell появился в конце строки, а не вначале. Но это же совсем не означает, что его вовсе нет, или что при каких-нибудь манипуляциях с ячейками он бы не проявил себя во всей красе.
Отсюда можно сделать вывод, что не стоит добавлять псевдоэлементы к tr, если явно не планируется ставить им display : table-cell;
Баг в IE9
Перед тем, как переходить к основному решению, давайте рассмотрим один интересный баг в браузере IE9.
После перебора всего вышесказанного я стал искать решение дальше, и подумал, а почему бы мне не засунуть какой-нибудь элемент в первую ячейку строки и не сделать наш бокс с тенью именно из него? Сказано — сделано.
<tr> <td><i class="box-shadow"></i> 07/08/12 11:08 AM</td> <td>Voicemail Transcription A328413</td> <td>IN PROGRESS</td> <td>NA</td> <td>NA</td> </tr>
table tr .box-shadow {
position: absolute;
left: 0px;
margin-top: -10px;
height: 31px;
width: 100%;
border: 1px solid #47a9e1;
box-shadow: 0 0 4px #47a9e1;
pointer-events: none;
}
И этот приём сработал… но только не в IE9. В нём ни в какую не хотела отображаться тень. Как я только не двигал координаты бокса и не игрался с его стилями, победить IE9 мне так и не посчастливилось:(
Методом тыка удалось обнаружить, что если убрать border-collapse у таблицы, то тень в IE9 появляется! Простите, но ведь это же бред и маразм?! Где же логика? Скорее всего ответ кроется в том, что IE через одно место наследует боксовую модель от ячейки, которая при collapse сама становится некроссбраузерной и непредсказуемой.
Поэтому мне ничего не оставалось делать, как продолжить искать решение дальше. Но я не пожалел об этом, потому что я его нашёл и оно оказалось ещё проще:)
Решение
Псевдоэлементы, которые ранее давали сбой у строк, отлично подошли к ячейкам таблицы. Короче говоря, я решил заменить элемент внутри первой ячейки строк на псевдоэлемент для самой ячейки. Выкладываю сразу весь рабочий код:
<table class="table">
<tbody>
<tr>
<td> 07/08/12 11:08 AM</td>
<td>Voicemail Transcription A328413</td>
<td>IN PROGRESS</td>
<td>NA</td>
<td>NA</td>
</tr>
....
</tbody>
</table>
table {
background: #F8F8F8;
color: #666;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
margin: 0 auto;
border-collapse: collapse;
border-spacing: 0;
line-height: 1;
position: relative;
width: 600px;
}
table tr:hover td:first-child:before {
content: '';
position: absolute;
left: 0px;
margin-top: -10px;
height: 31px;
width: 100%;
border: 1px solid #47a9e1;
box-shadow: 0 0 4px #47a9e1;
pointer-events: none;
}
table tr:hover {
background: #d1e9f7;
}
table tr {
border: 1px solid #999;
}
table td, table th {
padding: 10px;
}
И сам результат.
Теперь всё работает так, как нам нужно. И самое удивительное, что это касается и IE9, который ранее почему-то отказывался работать с обычным элементом, но, в данной ситуации, прекрасно повёл себя с псевдоэлементом и стал отображать тень, как и другие браузеры. Чудеса? А кто его знает:) Но скорее всего дело в том, что в отличие от обычного элемента псевдоэлемент не имеет наследственных болезней от наследуемой боксовой модели, т.к. создаётся всегда с нуля. Поэтому и проблем в IE9 с ним в этом плане нет.
Заключение
В завершении этого поста, мне хочется спросить у народа, может у кого-то есть решение получше? Особенно интересует универсальное решение, для резиновой по высоте ячеек таблицы.
Так же буду признателен, если кто-нибудь объяснит мне точную природу бага в IE9.
P.S. Это тоже может быть интересно:
None Found
А если использовать display: table, table-row, table-cell вместо обычной таблицы ?
Табличные данные должны быть в таблице. Ради красивой подсветки строки таблицы при навдении нарушать семантику кода считаю нелогичной.
Так CSS-боксы будут теми же самыми. С теми же ограничениями (плюс свои дополнительные, типа невозможности colspan/rowspan). В чем профит?
Если вы нашли подходящее вам решение, но уперлись в border-collapse: collapse, то может стоит тогдла отказаться от collapse?
А бордюр рисовать ячейкам так: border-right и border-bottom. Первой строке и первому столбцу при помощи first-child`а дорисовать оставшиеся.
Основная ирония момента в том, что решение, которое требует отсутствия collapse (с дополнительной разметкой), всё равно проигрывает решению, не зависящему от него (без лишнего, на псевдоэлементах). Обычно бывает наоборот («дубово, но надежно» vs. «изящно, но с кучей оговорок»), а здесь проблема появилась как раз у «дубового» (на первый взгляд) решения.
Вариант с выборочными бордерами ячеек интересен (по крайней мере, когда не нужны вертикальные разделители). Но как быть с тенью?
В ие8 кстати, на ховер срабатывает только заливка цветом на tr — бордеры отсутсвуют, да и вобще псевдо элементы в динамике в ие8 к сожалению практически не работают.
что-то как-то кривовато…лучше бы разобрались до конца и выложили нормальное решение….
Нормальное решение — при избыточной стилизации (в данном случае наружняя тень у строки таблицы) использовать блоки, поскольку стилевые правила, применительно к таблицам, каждым браузером интерпретируются по-своему. Таблицы — для табличных данных.
Спасибо, нужно было строчно решение по похожей задаче, ваш вариант очень помог.
Версия для динамической высоты строки, но фиксированной ширины таблицы.
Псевдокласс генерируется в конце последней ячейки строки — связанно с багом отображения тени (если как у Вас)
http://jsfiddle.net/Hsw6N/1/
поправочка — работает только в chrome((
Можно убрать border-collapse: collapse; и поставить border-spacing: 0px 10px;
Ячейки строки и строку покрасить в один цвет. В принципе все, отступ даст пространство для hover. И все браузеры будут довольны