<
  • Главная
Статьи

Абсолютне позиціонування в осередках таблиці, в Firefox - CSS-LIVE

  1. Приклад - Опис товарів
  2. Баг або фіча?
  3. Рішення
  4. Абсолютне позиціонування без контейнера
  5. вертикальне вирівнювання
  6. Ложка дьогтю
  7. резюме

Багато верстальники напевно стикалися з неприємною особливістю, яка стосується абсолютного позиціонування в осередках таблиці, в Firefox. Неприємність полягає в тому, що в браузерах Firefox, аж до останньої версії (Firefox-9 на даний момент) немає підтримки position: absolute як в таблиці, так і в самих її осередках. Тобто ми, наприклад, не зможемо позиціонувати який-небудь блок або елемент, щодо <table> або <td>, ну або будь-яких інших елементів таблиці, типу <tr>, <tbody> і т.д.

За моїми спостереженнями, на форумах, часто задають питання з проханням допомогти у вирішенні цієї проблеми. Так, і мені часом, ця неприємність доставляє масу незручностей, підштовхуючи до винаходу обхідних шляхів і інших милиць. У цій статті, я пропоную все-таки з'ясувати, що це насправді, баг або фіча, і чи можна вважати Firefox неправим в даній ситуації? А так же знайти нарешті рішення цієї проблеми.

Для початку пропоную подивитися одну з ситуацій, де ми зможемо побачити, наскільки корисним може виявитися працює position: absolute в осередках

Приклад - Опис товарів

Уявімо собі ситуацію. Інтернет магазин, таблиця опису товарів, в осередках картинка-товар, його ціна і опис.
Завдання: Зробити роздільники між осередками, але, тільки незвичайні, ну скажімо, щоб вони були різнокольоровими і розтягувалися від 10px зверху комірки і до 10px не доходячи низу. Ось як це виглядає приблизно.

Помаранчеві смужки зверху означають кінець рядка таблиці і початок нової. В іншому, як і планувалося, обтічне зображення, і текст справа. А ось як раз градієнтні роздільники зліва від осередків - це і є те, про що ми говорили, тобто окремі позиційований блоки, які беруть свій початок зверху з відступом 10px і закінчуються майже внизу, не доходячи до низу так само 10px. Для прикладу я зробив псевдоелемент у осередків, він і буде нашим роздільником.

table td {vertical-align: top; padding: 10px; padding-left: 30px; position: relative; } Td: after {background: -webkit-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); background: -moz-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); position: absolute; width: 20px; bottom: 10px; top: 10px; left: 0px; content: ''; border-radius: 5px; }

Решта код, я думаю, показувати сенсу немає, там все просто і зрозуміло.

Загалом все начебто логічно, самим осередкам у нас прописаний position: relative, а для псевдоелемента position: absolute, і останній при цьому прекрасно відчуває першого, відштовхуючись своїми початковими координатами саме від нього. Але, так вважають на жаль не всі ... не всі браузери. У Firefox на цей випадок свій погляд.

За малюнком можна зрозуміти, що в Firefox "абсолютні" блоки перетворилися в один великий блок, батьком якого вже є вікно браузера, а не елемент таблиці. Це прикре явище ясно дає зрозуміти, що нам доведеться або відмовлятися від position: absolute взагалі, або шукати рішення даної проблеми.

Цей приклад не єдиний. Завдань із застосуванням position: absolute в таблиці безліч і всі вони руйнуються в один момент, коли на полі з'являється Firefox. Взяти хоча б звичайний приклад з одним, простим елементом, який потрібно вирівняти щодо елементи таблиці. Зробити, скажімо, кути для осередків або ж просто якісь інші речі, що стосуються абсолютного позиціонування в таблиці. І всі ці спроби відразу ж стають марними, коли на полі з'являється Firefox.
Але, не варто засмучуватися раніше часу, ми ж теж не ликом шиті, чи не так?

Баг або фіча?

Перед тим, як переходити до вирішення даної проблеми, давайте розберемося, що ж насправді відбувається і чому Firefox поводиться не так, як інші браузери.
За відповіддю я відправився в специфікацію і виявив там кілька цікавих витягів, що стосуються нашої ситуації. Насправді ситуація трохи двояка, і зараз ви зрозумієте, чому.
У пунктах 9.3 про position: absolute і в пункті 10.1, частини четвертої говориться наступне.

absolute
The box's position (and possibly size) is specified with the 'top', 'right', 'bottom', and 'left' properties. These properties specify offsets with respect to the box's containing block.

Що перекладається приблизно, як:
Елемент з position: absolute, якому задані будь-які з властивостей top, right, bottom, або left мають зміщення щодо містить їх контейнера.
І, як можна помітити, ніде не вказано про будь-які винятки. Тобто осередок таблиці - це такий же контейнер для своїх нащадків, як і інші елементи.

Або ось, наприклад

If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed'

Якщо елементу вказано position: absolute, то він позиціонується щодо найближчого предка з position: absolute, relative або fixed.
Що знову говорить про те, що осередок таблиці - не є ніяким винятком з правил, і так само цілком може бути найближчим предком, як і інші елементи.

Але, з іншого боку, якщо знову звернутися до пункту 9.3 по частині relative , То там ми вже можемо побачити наступне ...

The box's position is calculated according to the normal flow (this is called the position in normal flow). Then the box is offset relative to its normal position. When a box B is relatively positioned, the position of the following box is calculated as though B were not offset. The effect of 'position: relative' on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.

Сенс написаного в тому, що, як виявилося, специфікація чітко не визначає, як повинен вести себе position: relative на таблиці і її елементах. Ключова фраза тут:

The effect of 'position: relative' on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.

Іншими словами, ефект від застосування position: relative на табличних елементах не визначений (undefined). А значить немає чіткого правила або вказівки, як він повинен себе вести щодо таблиці і її табличних нащадків. У зв'язку з чим, в цьому випадку, браузерам надана повна свобода дій і трактування своїх правил. Браузери самі вільні вибирати те, як буде вести себе position: relative в осередках таблиці і absolute по відношенню до них. На жаль трактування своїх правил обертається для нас не дуже радісно.

Виходить, що звинувачувати Firefox нема в чому, адже, по суті, він дотримується правил специфікації, не порушуючи їх. Інша справа, що нам - розробникам, від цього не легше. Виходить, що всі браузери вирішили це питання на нашу користь, але ось Firefox - немає. Цікаво, що ж його могло утримати?
Швидше за все, розробники Firefox вважають, що самі осередки не є об'єктом, який може вести себе як вирваний з потоку елемент. Таблиця складний і одночасно простий елемент, там і без relative вистачає проблем.
З одного боку їх звичайно ж можна зрозуміти, але з іншого, чому б не зробити таку можливість і не піти розробникам на поступки? Це питання залишиться для нас загадкою. Сподіваюся лише, що в майбутніх версіях Firefox все ж, змінить свою точку зору щодо цієї проблеми.

Рішення

Забіжу трохи вперед і трохи засмучу вас, сказавши, що на мій погляд, ідеального рішення даної проблеми - не існує. Вирішуючи цю задачу (не один день), я занурився в неї по вуха, намагаючись знайти хоч якусь зачіпку і розвинути її по максимуму. Firefox виявився дуже впертим, в цьому відношенні, браузером, і ні в яку не хотів піддаватися на мої вмовляння. До того моменту, я вже прекрасно розумів, що змусити Firefox ідеально застосовувати relative до осередків таблиці мені не вдасться (частково мені це все ж вдалося), і що, для того, щоб змусити працювати в них absolute (зберігаючи при цьому чітке поведінку осередків) , мені знадобиться, як мінімум додатковий контейнер, який і буде точкою відліку для абсолютного позиціонування.
Але, як ви, можливо, вже здогадалися, що, щоб, наприклад, притиснути блок з position: absolute до низу елементи таблиці, нам необхідно якимось чином розтягнути контейнер всередині неї на 100% по висоті самої комірки.

Такого поведінки легко домогтися, якщо, наприклад, у комірки буде виставлена ​​фіксована висота. Тоді блок-контейнер всередині неї, буде відчувати цю висоту і підхопить її негайно. Але, що робити, якщо висота осередку необмежена і залежить від її вмісту? Ось тут-то вже й приходить довгоочікуваний тупик, вийти з якого, стає практично неможливо. Адже контейнер повинен звідкись брати висоту, точніше у свого батьківського елемента, а якщо вона невідома, то і його висота буде автоматичною, тобто підлаштовуватися під вміст.
Загалом, в результаті, переді мною постало завдання, яким небудь чином змусити контейнер відчувати висоту комірки, при тому, що висота останньої - автоматична і повинна підлаштовуватися під висоту свого контенту. Тобто мені треба було зробити практично неможливе, створити що-небудь таке, застосовуючи тільки CSS.

Повозившись пристойний час з цим завданням, я розумів, що, мабуть без JS тут і справді не обійтися. Але одного чудового днем ​​"чудо" все таки сталося і я випадково натрапив на одне цікаве рішення. І якого було моє здивування, коли я побачив, наскільки простим воно виявилося.

table {border-collapse: collapse; width: 100%;} / * Дивовижне рішення * / table tr {height: 1px;} table td {vertical-align: top; position: relative; / * Розтягуємо осередок на 100% по висоті батька * / height: 100%; } Td: after {background: -webkit-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); background: -moz-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); position: absolute; width: 20px; bottom: 30px; top: 30px; left: 0px; content: ''; border-radius: 5px; } / * Так, так, ви не помилилися. Це брудний хак для Firefox * / @ -moz-document url-prefix () {/ * переважує позиціонування на контейнер. Для Firefox * / .psyPositionContainer {position: relative; height: 100%; padding: 0 10px; padding-left: 30px; } .PsyPositionContainer: after {background: -webkit-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); background: -moz-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); position: absolute; width: 20px; bottom: 30px; top: 30px; left: 0px; content: ''; border-radius: 5px; } Td: after {display: none;} td: first-child .psyPositionContainer: after {background: none;}} / * Додаткові стилі, що не грають роль * / tr {border-top: 5px solid # F60;} td: first-child: after {background: none;} .price {font: bold 14px "Trebuchet MS", Arial, Helvetica, sans-serif; color: # E76D13;} .content {overflow: hidden;} table td img {float: left; margin-right: 10px;}

Відразу наведу скріншот з результатом.

Ну, а тепер, по порядку, що ж ми тут накоїли. Почнемо мабуть з самої родзинки ...

table tr {height: 1px;}

Ви може бути не повірите, але цей рядок коду і є вирішенням даної проблеми! Так, саме проставлення фіксованою висоти рядку, і дає такий ефект. Завдяки цьому трюку, у нашій рядки з'являється фіксована висота, в зв'язку з чим - осередок всередині неї, зможе її відчути. Тобто зробити фактично те, що ми, по суті, і хотіли отримати.
Але, як же це працює? Давайте розберемося…
За відповіддю на це питання я відправився до моєї улюбленої специфікації, і ось що вона змогла мені розповісти .

The height of a 'table-row' element's box is calculated once the user agent has all the cells in the row available: it is the maximum of the row's computed 'height', the computed 'height' of each cell in the row, and the minimum height (MIN) required by the cells.

Якщо сказати нашою мовою, то це звучить приблизно так:
"Висота елемента типу table-row розраховується, коли браузер отримав всі осередки рядка: вона дорівнює максимальному з розрахованої (по каскаду) висоти рядка, розрахованої висоти кожного осередку і мінімальний висоти, необхідної для контенту осередків"
Тобто простіше кажучи, вибирається максимальне з наступного: height самої рядки, height найбільшою осередки і, грубо кажучи, offsetHeight найдовшого контенту. А результат як би заноситься в height рядки.
Ну, а оскільки формально висота tr-шки вказана, td з height: 100% вважає своїм обов'язком підхопити цю висоту і передати далі своїм нащадкам. Мабуть, так зроблено для однаковості обліку батьківської висоти.

Чому цей алгоритм не працює в інших браузерах? Мабуть, справа в тому, що форматування таблиць - взагалі найзаплутаніша і суперечлива частина специфікації CSS, по багатьом пунктам самі стандартісти ще не прийшли до спільної думки, як її трактувати. Але нам цілком достатньо, що Firefox поводиться так, як потрібно.

Далі за списком йде наступний код.

table td {vertical-align: top; position: relative; / * Розтягуємо осередок на 100% по висоті батька * / height: 100%; }

Тут ми задаємо самої комірки відносне позиціонування. Це для того, щоб всі браузери, крім Firefox, при абсолютному позиціонуванні усередині осередку, відштовхувалися саме від неї. Браузеру Firefox цей запис нічого не скаже, він її просто проігнорує.
Ну а так само за допомогою height: 100% ми розтягнули осередок на всю висоту рядка, яка в свою чергу, як ми з'ясували, розтягується в залежності від контенту. І тут якраз навпаки, для Firefox цей запис дасть позитивний ефект, на відміну від інших браузерів, на які ця правило ніяк не вплине.

td: after {...}

Тут я не став копіювати весь код. Тут все просто, ми створюємо абсолютно позиційований псевдоелементи для наших осередків, бачити які будуть все Бразер, крім Firefox. Для нього трохи пізніше ми відключимо це правило. Там же, ви і дізнаєтеся, для чого це потрібно.

@ -Moz-document url-prefix () {/ * переважує позиціонування на контейнер. Для Firefox * / .psyPositionContainer {position: relative; height: 100%; padding: 0 10px; padding-left: 30px; } .PsyPositionContainer: after {background: -webkit-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); background: -moz-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); position: absolute; width: 20px; bottom: 30px; top: 30px; left: 0px; content: ''; border-radius: 5px; } Td: after {display: none;} td: first-child .psyPositionContainer: after {display: none;}}

А ось тут важливий момент. Як ви вже зрозуміли, на жаль нам довелося скористатися націленим хаком для Firefox. Але це скоріше вимушений захід, тому що усередині цього хака ховаються правила, які, по-перше розуміє тільки сам Firefox, а по-друге вішають стилі для контейнера, яких не повинні бачити інші браузери. Перші стилі стосуються самого контейнера, на який ми вішаємо position: relative і height: 100%. Тепер блок буде розтягнутий на всю висоту комірки і його нащадки з абсолютним позиціонуванням будуть танцювати від нього.
Нам не можна було допустити, щоб інші браузери це побачили, тому що, як ми вже з'ясували раніше, height: 100% не дає в них ніякого ефекту, вічками не буде підхоплювати висоту і отже, раз немає чіткої висоти, значить і контейнер всередині осередку так само не буде розтягнутий на 100%. Це загрожує тим, що, якщо, наприклад, в контейнері буде абсолютний блок, який повинен буде притискатися до низу контейнера, а, по суті, осередки, то цей самий "низ" для нього буде відраховуватися від низу самого контейнера, який в свою чергу розтягується лише на висоту свого контенту.

Ну, і далі по курсу йде створення псевдоелемента, але для контейнера, а не для осередку. А так як, ніхто крім Firefox цього не побачить, то і псевдоелемент для контейнера буде створений саме в ньому.

Ну і завершують ці націлені стилі два записи, перша з яких (td: after {display: none;}) вимикає псевдоелемент у комірок таблиць. У Firefox він нам не потрібен, так як його "осередок" - це сам контейнер, ну а другий запис (td: first-child .psyPositionContainer: after {display: none;}) потрібна лише для виключення псевдоелемента в першій клітинці.

Заздалегідь повідомлю, що з даного питання я просунувся набагато далі, але, для того, щоб не заплутатися і піти далі, нам необхідно трохи відпочити і підвести проміжні підсумки.

1. Значить ми з'ясували, що правило tr {height: 1px;} є, по суті, рішенням, і допомагає нам включити чутливість висоти рядка в потрібному нам браузері - Firefox, але повністю ігнорується в інших браузерах. А так же це допомагає осередкам підхоплювати висоту рядка, яка збільшується і фіксується в залежності від найвищого контенту в осередках цієї самої рядки. Тобто, по суті, це і є головне рішення.
2. Так само ми зрозуміли, що, у зв'язку з тим, що відмінні від Firefox браузери - не розтягувати контейнер на всю висоту батьківської комірки, тому що просто не знають її, нам треба було перекласти все позиціонування на контейнер для Firefox і на осередки для інших браузерів. Допоміг нам у цьому брудний, але вимушений хак.

Так що, за допомогою невеликих маніпуляцій з кодом, ми, нарешті, отримали непогане рішення. Так, і не варто забувати, що в нашому випадку, для демонстрації процесу, ми використовували згенерований псевдоелемент: after. На його місці міг би опинитися безліч інших, абсолютно позиціонуються блоків.
Загалом, це рішення - було скоріше загальним, як би знайомством з самою суттю, головною частиною. Але, як уже було сказано вище, я просунувся трохи далі і виявив ще трохи корисних, і в той же час, цікавих речей.

Загальне рішення

Абсолютне позиціонування без контейнера

Як виявилося, все таки є одне рішення, яке дозволило б нам відмовитися від контейнера і застосовувати елементи таблиці в якості точки відліку для абсолютного позиціонування, в Firefox.

Чому я не застосував його в якості основного? Справа в тому, що це рішення підходить скоріше для окремого випадку і має ряд недоліків. Загалом перейдемо відразу до коду.

<Table> <tbody> <tr> <td class = "through-one"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price" > 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ td> <td> <img src = "../ img-td.jpg" /> < div class = "content"> <div class = "price"> 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ td> <td class = "through -one "> <img src =" ../ img-td.jpg "/> <div class =" content "> <div class =" price "> 12000 рублів </ div> <p> Опис товару, Опис товару , Опис товару </ p> </ div> </ td> </ tr> <tr> <td class = "through-one"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price"> 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ td> ....... ......... </ tr> </ tbody> </ table> table {border-collapse: collapse; width: 100%;} / * Дивовижне рішення * / table tr {height: 1px;} table td {position: relative; height: 100%; } .Through-one {display: block;} td.through-one: after {background: # 303; background: -moz-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); position: absolute; width: 20px; bottom: 30px; top: 20px; left: 0px; content: ''; border-radius: 5px; } / * Додаткові стилі, що не грають роль * / tr {border-top: 5px solid # F60;} .price {font: bold 14px "Trebuchet MS", Arial, Helvetica, sans-serif; color: # E76D13;} .content {overflow: hidden;} table td img {float: left; margin: 0 10px 0 30px;}

Ну, почнемо з того, що, як ви могли бачити, я трохи поміняв структуру коду, прибравши контейнери і повісивши класи (through-one) на деякі осередки. Чому на деякі, ви зрозумієте трохи пізніше, а зараз сама суть. Справа в тому, що, виявляється, за допомогою display: block комірок таблиці можна задавати блочне поведінку, що з одного боку залишить їх такий же осередком, а з іншого - дозволить їм застосувати по відношенню до себе position: relative, що зробить їх точкою отсёта для абсолютно позиціонуються нащадків, тобто такими ж, як і звичайний блоковий елемент. І відповідно, в цьому випадку, браузеру Firefox - вже не знадобляться ніякі контейнери та інші допоміжні блоки. Як видно з скріншоту, в ньому цей прийом працює чудово.

А тепер, як це працює. Суть в тому, що при постановці display: block осередкам (table-cell-ам), які ще при цьому знаходяться в рядках (table-row), вони автоматично обертаються анонімним table-cell'ом, і тим самим, знову стають в ряд зі своїми сусідськими осередками. Але тут є один важливий момент! На жаль не можна вішати display: block на дві, (і більше) йдуть підряд осередки, так як в цьому випадку анонімний table-cell огорне не кожного осередок окремо, а відразу обидві, що призведе до руйнування всієї таблиці. Ось чому я і використовував класи тільки у кожної другої комірки. Мені було потрібно, щоб сусідні осередки завжди були рідними.

У цього способу є ще ряд особливостей, про які слід знати.
1. Для даного прийому довелося так само використовувати націлений хак для Firefox. Інакше, в зв'язку з блоковим поведінкою осередки, інші браузери стиснули б її до висоти контенту, що призвело б до неправильного позиціонування всередині неї, а точніше блок з position: absolute всередині осередку не зміг би розтягнутися на всю її висоту, а тільки лише на висоту вмісту. Адже саме так і працює звичайний блоковий елемент з автоматичною висотою.
2. Вертикальне вирівнювання в перероблених осередках просто перестає працювати, як і в звичайних елементах блочного рівня.
* До речі, варто зауважити, що, і в попередньому, загалом прикладі, в зв'язку з контейнером всередині осередку, вертикальне вирівнювання так само відмовляється працювати. Трохи пізніше ми спробуємо вирішити цю проблему.

Загалом цей метод цілком підійде для якого-небудь окремого випадку, але, думаю, не більше, так як факт перетворення осередку "через одну" + відмова від вертикального вирівнювання, не дає нам повною мірою використовувати його в наших проектах.
Так, і так само слід мати на увазі, що замість display: block цілком підійде і display: inline-block або float: left.

Варіант з чергуванням осередків

вертикальне вирівнювання

Ось тут вже трохи складніше, але почнемо по порядку. Спочатку було ясно, що з появою будь-яких видів контейнерів або зі зміною поведінки осередків (я маю на увазі все те, що ми пройшли вище), про вертикальному вирівнюванні через vertical-align варто забути. Це жертва, яку довелося принести за рішення іншого, і вже важливою проблеми - розтягування комірки по висоті. Ну добре, віддали, але що ж тепер робити? Як же при таких розкладах повернути вертикальне вирівнювання?

На цьому етапі переді мною постало тільки одне питання "Які у нас ще є способи вирівняти вміст по вертикалі?" table-cell із зрозумілих причин відпадає. Це повернення до витоків, туди, звідки ми почали. position: absolute ... ммм ... ні, теж не підходить, інакше пропадає висота по вмісту. Загалом розмірковуючи на цю тему, я прийшов до висновку, що допомогти нам у вирішенні цього завдання може тільки одна річ, це емуляція рядки за допомогою display: inline-block. Адже, як відомо, vertical-align: middle добре працює з інлайновимі елементами, так що варто спробувати, тому підемо по наростаючій.

Емуляція рядків з одним контейнером

Перший на черзі варіант з чергуванням і перетворенням осередків.

<Table> <tbody> <tr> <td> <div class = "wrapper"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price "> 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ div> </ td> <td class =" through-one "> <div class =" wrapper "> <img src =" ../ img-td.jpg "/> <div class =" content "> <div class =" price "> 12000 рублів </ div> <p> Опис товару, Опис товару, опис товару </ p> <p> опис товару, опис товару, опис товару </ p> <p> опис товару, опис товару, опис товару </ p> </ div> </ div> </ td> <td > <div class = "wrapper"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price"> 12000 рублів </ div> <p> опис товару, опис товару, опис товару </ p> </ div> </ div> </ td> </ tr> <tr> <td class = "through-one"> <div cla ss = "wrapper"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price"> 12000 рублів </ div> <p> Опис товару, опис товару, опис товару </ p> </ div> </ div> </ td> <td> <div class = "wrapper"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price"> 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ div> </ td> <td class = "through-one"> <div class = "wrapper"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price"> 12000 рублів < / div> <p> Опис товару, Опис товару, Опис товару </ p> <p> Опис товару, Опис товару, Опис товару </ p> <p> Опис товару, Опис товару, Опис товару </ p> <p > Опис товару, Опис товару, Опис товару </ p > </ Div> </ div> </ td> </ tr> </ tbody> </ table> table {border-collapse: collapse; width: 100%;} / * Дивовижне рішення * / table tr {height: 1px;} table td {position: relative; height: 100%; vertical-align: middle; } @ -Moz-document url-prefix () {table td {white-space: nowrap;} table td: before {display: inline-block; height: 100%; width: 5px; background: green; content: ''; vertical-align: middle; } .Wrapper {white-space: normal; display: inline-block; vertical-align: middle; position: relative; margin-right: 8px; border: 1px solid # 000; } Td.through-one {display: block;}} td.through-one: after {background: # 303; background: -webkit-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); background: -moz-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); position: absolute; width: 20px; bottom: 30px; top: 20px; left: 0px; content: ''; border-radius: 5px; } / * Додаткові стилі, що не грають роль * / tr {border-top: 5px solid # F60;} .price {font: bold 14px "Trebuchet MS", Arial, Helvetica, sans-serif; color: # E76D13;} .content {overflow: hidden;} table td img {float: left; margin: 0 10px 0 30px;}


Як видно з малюнка, в нашій таблиці непогано працює вертикальне вирівнювання і до того ж абсолютне позиціонування. Звичайно ж, не у всіх осередках, а через одну, так як в даній ситуації ми скористалися варіантом для окремих випадків. Але, давайте по порядку.
Кожна клітинка, по суті, складається з двох, непереносящіхся, за рахунок white-space: nowrap, малих блоків. Крок зі скасуванням перенесення зроблений для того, щоб головний контейнер (.wrapper) при переповненні ширини не переносять на інший рядок, під лівий, допоміжний інлайн-блок. Сам лівий блок, для наочності, я вирішив зробити 5px ширини і зеленого кольору, щоб ви могли бачити, як все це працює. А так же, щоб не писати зайву розмітку, я скористався псевдоелементи: before. Цей елемент розтягнутий на висоту комірки, тобто на 100% і вирівняний по середині, по вертикалі. Головний контейнер знаходиться праворуч, і фактично містить в собі все основний вміст комірки, тобто її контент. Він так само вирівняний по вертикалі, як і перший.
Так як наші блоки є малими, а перший розтягнутий на 100%, то другий, головний блок, відмінно взаємодіє з vertical-align і вирівнюється по середині цього рядка. При цьому варто зауважити, що позиціювання і вирівнювання працюють окремо і ніяк не заважають один одному.

Так, природно варто врахувати, що випадок приватний і тому цей прийом не працюватиме з осередками, що йдуть підряд. Тому виставляю демонстраційний приклад і йду далі.

Емуляція рядків з двома контейнерами

Полуобрезанний варіант мало кого влаштує, і тому я вирішив піти далі, в пошуках надійного і повністю працює варіанту. У підсумку він знайшовся, схожий на попередній, але з додаванням всього одного контейнера.

<Table> <tbody> <tr> <td> <div class = "wrapper"> <div class = "wrapper-content"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price"> 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ div> </ div> </ td> < td> <div class = "wrapper"> <div class = "wrapper-content"> <img src = "../ img-td.jpg" /> <div class = "content"> <div class = "price "> 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ div> </ div> </ td> <td> <div class = "wrapper"> <div class = "wrapper-content"> <img src = "../ img-td.jpg" /> <div class = "content"> < div class = "price"> 12000 рублів </ div> <p> Опис товару, Опис товару, Опис товару </ p> </ div> </ div> </ div> </ td> </ tr> <tr > ................ </ tr> </ tbody> </ table> table {border-collapse: collapse; width: 100%;} / * Дивовижне рішення * / table tr {height: 1px;} table td {position: relative; height: 100%; vertical-align: middle; } @ -Moz-document url-prefix () {.wrapper {height: 100%; position: relative; } Table td {white-space: nowrap;} .wrapper: before {display: inline-block; height: 100%; width: 5px; background: green; content: ''; vertical-align: middle; } .Wrapper-content {white-space: normal; display: inline-block; vertical-align: middle; position: relative; margin-right: 8px; border: 1px solid # 000; }} .Wrapper: after {background: # 303; background: -webkit-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); background: -moz-linear-gradient (top, rgba (231,109,19,1) 0%, rgba (0,0,0,1) 100%); position: absolute; width: 20px; bottom: 30px; top: 20px; left: 0px; content: ''; border-radius: 5px; } / * Додаткові стилі, що не грають роль * / tr {border-top: 5px solid # F60;} .price {font: bold 14px "Trebuchet MS", Arial, Helvetica, sans-serif; color: # E76D13;} .content {overflow: hidden;} table td img {float: left; margin: 0 10px 0 30px;}

А ось тепер все в повному порядку, у всіх осередках. Але якою ціною? Насправді невеликий. Всього лише одним зайвим контейнером ми змусили працювати вертикальне вирівнювання разом з абсолютним позиціонуванням в осередках таблиці. Чому ж це працює? Все просто. Тепер замість осередку ми використовуємо контейнер (.wrapper), який розтягується на всю висоту першої. Усередині нього ми вже робимо все ті ж дії, які ми робили раніше в натуральних осередках. Тобто емулюючи пару малих блоків, за рахунок чого відбувається потрібне нам вертикальне виравніваініе. Ну, і position: absolute, працює так само ідеально, за рахунок цієї ж додаткової обгортки.

По суті, ось це останнє рішення, є майже: повністю працездатним, кросбраузерності (якщо замінити псевдоелементи на справжні, буде працювати і в IE6-7) і закінченим. Я зробив акцент на слові "Майже", тому що все таки є дещо, що заважає нам поставити крапку в цій статті. Але про це трохи пізніше ...
До речі, можливо хтось помітив, на скріншоті видно дивний баг. У деяких осередках не відображається лівий, допоміжний блок, який я спеціально пофарбував в зелений колір. Він просто зникає, і відбувається це в тому випадку, якщо висота обгортки (внутрішнього контейнера) стає рівною або вище висоти самої комірки. Пояснення цьому, на жаль, знайти так і не вдалося, у зв'язку з чим, я прийшов до висновку, що це звичайний баг. В принципі, нема чого бити на сполох, цей баг може і ховає контейнер, але, на щастя, на функціональність ніяк не впливає. Залишимо його на совість розробників Firefox.

вертикальне вирівнювання

Ложка дьогтю

На жаль в кожній бочці меду обов'язково присутній ложка дьогтю, і тут цієї ложкою став, як не дивно - IE9. При чому не IE7 і ні IE8, а саме Internet Explorer 9. У цьому браузері, чомусь, вимикається чутливість висоти комірки, і саме в двох наступних випадках:
1. Якщо ми виставляємо 100% -у висоту будь-якого блоку в осередку, будь то статичний або абсолютний. Він перестає відчувати висоту і підлаштовується під висоту самого контенту в осередку.
2. При одночасному завданні абсолютного блоку таких властивостей, як top і bottom. В такому випадку елемент так само, як і в першому варіанті, відчуває висоту тільки контенту, але не комірки в цілому.
Щоб було ясно, про що йде мова, надам скріншот.

На малюнку чітко видно, що два правих абсолютних блоку розтягуються тільки на висоту контенту, того осередку, якої вони належать, але не на її висоту, як відбувається в інших браузерах.

Причому дивно те, що, наприклад, якщо задати окремо одну з координат: top або bottom, то все відмінно, елемент з position: absolute виявляється в цих координатах в лічені секунди. Чому це відбувається? Я, якщо чесно - не зрозумів. Але, ця неприємність, явно впливає на кроссбраузерность і змушує шукати рішення, знайти яке, на жаль, мені не вдалося, як я тільки не намагався (сподіваюся хто небудь пнёт в потрібну сторону). Просто враховуйте цей момент під час верстки.

резюме

У цій статті нам вдалося знайти унікальне рішення, завдяки якому position: absolute в осередках таблиці став кросбраузерності, якщо не брати до уваги капризи IE9. Звичайно ж, не обійшлося без брудних хаков і окремих правил для Firefox, але зате результат виявився відмінним. Якщо не брати до уваги завдання, які пов'язані з проблемами IE9 (або є можливість зробити для нього свої стилі), то у нас є повністю працююче рішення, яке можна сміливо застосовувати на будь-яких проектах.

PS Це теж может буті цікаво:

Але, не варто засмучуватися раніше часу, ми ж теж не ликом шиті, чи не так?
Баг або фіча?
Цікаво, що ж його могло утримати?
З одного боку їх звичайно ж можна зрозуміти, але з іншого, чому б не зробити таку можливість і не піти розробникам на поступки?
Але, що робити, якщо висота осередку необмежена і залежить від її вмісту?
Але, як же це працює?
Чому цей алгоритм не працює в інших браузерах?
Чому я не застосував його в якості основного?
Ну добре, віддали, але що ж тепер робити?
Як же при таких розкладах повернути вертикальне вирівнювання?


Новости
  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью