CSS-live.ru

Непростая стилизация строк таблицы и непонятный баг в 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. Это тоже может быть интересно:

12 комментариев

    1. Табличные данные должны быть в таблице. Ради красивой подсветки строки таблицы при навдении нарушать семантику кода считаю нелогичной.

    2. Так CSS-боксы будут теми же самыми. С теми же ограничениями (плюс свои дополнительные, типа невозможности colspan/rowspan). В чем профит?

  1. Если вы нашли подходящее вам решение, но уперлись в border-collapse: collapse, то может стоит тогдла отказаться от collapse?
    А бордюр рисовать ячейкам так: border-right и border-bottom. Первой строке и первому столбцу при помощи first-child`а дорисовать оставшиеся.

    1. Основная ирония момента в том, что решение, которое требует отсутствия collapse (с дополнительной разметкой), всё равно проигрывает решению, не зависящему от него (без лишнего, на псевдоэлементах). Обычно бывает наоборот («дубово, но надежно» vs. «изящно, но с кучей оговорок»), а здесь проблема появилась как раз у «дубового» (на первый взгляд) решения.
      Вариант с выборочными бордерами ячеек интересен (по крайней мере, когда не нужны вертикальные разделители). Но как быть с тенью?

  2. В ие8 кстати, на ховер срабатывает только заливка цветом на tr — бордеры отсутсвуют, да и вобще псевдо элементы в динамике в ие8 к сожалению практически не работают.

  3. что-то как-то кривовато…лучше бы разобрались до конца и выложили нормальное решение….

    1. Нормальное решение — при избыточной стилизации (в данном случае наружняя тень у строки таблицы) использовать блоки, поскольку стилевые правила, применительно к таблицам, каждым браузером интерпретируются по-своему. Таблицы — для табличных данных.

  4. Спасибо, нужно было строчно решение по похожей задаче, ваш вариант очень помог.

  5. Версия для динамической высоты строки, но фиксированной ширины таблицы.

    Псевдокласс генерируется в конце последней ячейки строки — связанно с багом отображения тени (если как у Вас)

    http://jsfiddle.net/Hsw6N/1/

  6. Можно убрать  border-collapse: collapse;  и поставить border-spacing: 0px 10px;
    Ячейки строки и строку покрасить в один цвет. В принципе все, отступ даст пространство для hover. И все браузеры будут довольны

Добавить комментарий для Cypher Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.