Задача
Заданы два блочных элемента – один с текстом статьи (ширина 75% от ширины документа), другой с перечнем ссылок для навигации по первому элементу (ширина 25%). Высота элемента содержащего статью задается динамически, в зависимости от наполнения блока текстом. Необходимо сделать так, что бы второй блок с навигацией обладал таким же значением параметра высоты как и первый содержащий основной текст статьи.
Техническое уточнение
Ранее подобные задачи решались с помощью TABLE-TR-TD семейства табличных тэгов, но такой подход нарушал принцип отделения структуры данных в разметке (markup — HTML) от способа их стилизации (styling — CSS), поскольки сами данные по характеру представленной информации вовсе не были табличными, а только использовали сходный табличному метод отображения на странице:
<table>
<tr>
<td id=”navigation”>
...перечень a-href ссылок...
</td>
<td id=”content”>
..содержимое статьи...
</td>
</tr>
</table>
Позже стандарт СSS был расширен дополнительными значениями table, table-cell для параметра display, что позволило использовать привычные DIV, SPAN элементы в html-структуре разметки страницы и задавать для них соответствующие css-правила для отображения в виде таблицы с колонками сообщающимися в процентном соотношении как по ширине так и по высоте:
<div id=”wrapper”>
<div id=”navigation”>
...перечень a-href ссылок...
</div>
<div id=”content”>
...содержимое статьи...
</div>
</div>
#wrapper {
display: table;
}
#navigation, #content {
display: table-cell
}
Казалось бы задача была решена, но к сожалению, такой подход не работал в старших версиях браузеров (IE 6, IE 7) заставляя верстальщиков искать другие подходы. Довольно распространенным стало решение с помощью вложенных элементов-оберток смещение которых относительно друг-друга позволяет добиться визуального эффекта равных по высоте колонок:
<div id="bg-one">
<div id="bg-two">
<div id="navigation">
...перечень a-href ссылок...
</div>
<div id="content">
...содержание...
</div>
</div>
</div>
#navigation, #content {
position: relative;
float: left;
left: -50%;
}
#navigation {
width: 50%;
}
#bg-one, #bg-two {
position:relative;
float: left;
width: 100%;
background-color: #9988ff;
}
#bg-one {
overflow: hidden;
}
#bg-two {
left: 50%;
background-color: #99ff99;
}
Роль колонок здесь выполняют обертывающие тэги (#bg-one, #bg-two) количество которых дублирует вложенные в них тэги с контентом (#content, #navigation). Такая техника работает даже в IE 6, но ее ощутимым недостатком является необходимость добавления большого количества дополнительных элементов (#bg-one, #bg-two) обертывающих тэги с текстом колонок (#content, #navigation). Количество таких элементов оберток (#bg-N) равно количеству фактических блочных-тэгов с колоноками текста. В приведенном выше примере для добавления еще одной колонки (скажем #advertisement) на одном уровне с #navigation и #content придется добавить еще один общий обертывающий элемент bg-three:
<div id="bg-one">
<div id="bg-two">
<div id="bg-three">
<div id="navigation">
..перечень ссылок a href...
</div>
<div id="content">
..содержание статьи....
</div>
<div id="advertisement">
...рекламные объявления...
</div>
</div>
</div>
</div>
#navigation, #content, #advertisement {
position: relative;
float: left;
left: -64%;
}
#navigation,#content {
width: 32%;
}
#bg-one, #bg-two, #bg-three {
position: relative;
float: left;
width: 100%;
background-color: #9988ff;
}
#bg-one {
overflow: hidden;
}
#bg-two {
left: 32%;
background-color: #99ff99;
}
#bg-three {
left: 32%;
background-color: #a0a0a0;
}
В таком случае html-разметка заметно усложняется – причина наличия обертывающих тэгов неочевидна. Таким образом отказываясь от html-таблиц из-за плохой читабельности разметки мы приходим к еще менее читабельному коду. Ситуацию можно улучшить если перенести обертывающие тэги на один уровень с колонками:
<div id="wrapper">
<div id="navigation-bg"></div>
<div id="navigation">
..перечень ссылок с a href..
</div>
<div id="content-bg"></div>
<div id="content">
...содержание статьи...
</div>
</div>
#wrapper{
position: relative;
float: left;
width: 100%;
}
#navigation, #content {
position: relative;
float: left;
width: 50%;
}
#navigation-bg {
position: absolute;
left: 0;
width: 50%;
height: 100%;
background-color: #ffaaaa;
}
#content-bg {
position: absolute;
left: 50%;
width: 50%;
height: 100%;
background-color: #aaffaa;
}
В таком случае элементы c фоном (#navigation-bg, #content-bg) расположены перед тэгами содержащими текст колонок, что заметно улучшает понимание разметки. Но к сожалению IE 6 не понимает процентных значений заданных в параметре высоты для блочных элементов с абсолютным позиционированием, а для более свежие версии браузеров поддерживают display: table правило, которое позволяет избежать добавочных div-элементов содержащих фон колонок (в примере выше #content-bg, #navigation-bg).
Решение
Читая задание становится заметным что разметка текста с прицелом на последующие применение css-правила display: table, также содержит один лишний тэг:
<div id=”wrapper”>
<nav class=”shakespeare”>
...перечень ссылок...
</nav>
<article class=”shakespeare”>
...содержание статьи...
</article>
</div>
#wrapper {
display: table;
}
.shakespeare {
display: table-cell;
background-color: #f0f0f0;
}
Ведь в таком варианте зависимость высоты колонок двунаправлена, то есть высота блока заданного тэгом nav зависит от высоты блока заданного тэгом article и наоборот — блок article зависит от высоты блока nav. Хотя в данном только высота блока nav должна подстраиваться под высоту более длинного тэга article обратная зависимость является лишней:
<article>
<aside>
...перечень ссылок...
</aside>
..содержание статьи
</article>
article {
position: relative;
width: 75%;
left: 25%;
background-color: #fafafa;
}
aside {
position: absolute;
width: 33%;
left: -33%;
height: 100%;
background-color: #f0f0f0;
}
Процентное значения для аболютных элементов также как и display: table работают в браузере IE начиная только с восьмой версии. Значения ширины и длины блока aside берутся из пересчета относительно размеров блока article, так как в CSS координаты и размеры элемента с абсолютным отсчитывается начиная с первого родительского элемента с нестатичным (relative, absolute, fixed) значеним параметра position. То есть ширина блока article (которая составляет 75% от ширины документа) для aside контейнера равна 100%, составляя пропорцию:
75% - 100%
25% - ?
получаем
25% * 100% / 75% = 33.33%
То есть 25% свободного экрана в процентном соотношении блока article.
Таким образом мы можем избавиться от лишнего wrapper элемента, отобразить зависимость одной колонки от другой в коде и не прибегать к методу табличного позиционирования для нетабличных даных.
Автор: SergeiRyabokon