За этот месяц мне пришлось два раза столкнуться с необходимостью создания разметки с фиксированной боковой панелью со скроллингом и такой же главной панелью на всю оставшуюся ширину страницы.

Как истинный приверженец CSS я обычно пытаюсь избегать динамических разметок, и, конечно, я не приверженец использования Java Script в разметке, но иногда без них не обойтись.

Проще всего создавать такие разметки с помощью специальных JavaScript инструментов, например, DOJO, но результаты его применения мне показались слишком объемными, и в будущем могли привести к дополнительным трудностям.

Конечно, мы можем получить такую разметку с помощью JavaScript, позиционируя div`ы каждый раз при загрузке и изменении размеров страницы. Но в этом случае тоже не обойдется без головной боли, нужно будет сделать выбор между window.innerHeight, document.documentElement.clientHeight, document.body.clientHeight, и использовать кросс-браузерные обработчики событий.

Мне кажется использование JavaScript для создания необходимой нам разметки это возможное, но не самое элегантное решение, поэтому я хочу получить легкое и простое решение на чистом CSS.

Проблема с процентами

Часто мы используем элементы с динамическими размерами, задавая высоту или ширину в процентах, но с процентами есть одна проблема, их трудно сочетать с другими единицами.

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

Природа div`ов

Я обратился к основам блочной модели, чтобы найти подходящее решение вот, что можно утверждать о div`ах:

Во всех браузерах

  1. div это прямоугольник.
  2. Только один угол div может абсолютно позиционироваться на странице.
  3. Положение диагонально противоположного угла должно определяться высотой и шириной элемента.
  4. Если высота и ширина динамические, они должны определятся с помощью JavaScript.

Мне показалось, что утверждение «Только один угол div может абсолютно позиционироваться на странице» очень легко подтвердить или опровергнуть, для этого я задал значения для top, left, bottom, right и, несмотря на мои опасения, получил совершенно валидный CSS.

«Конфликтное» абсолютное позиционирование

Я опасался, что если задать top, left, bottom и right то большинство браузеров будут игнорировать два из этих свойств.

Но мои опасения не подтвердились, во всех браузерах, в которых было протестировано это решение за исключением IE5 и IE6, отлично работали все четыре правила, а div растягивался на всю величину окна.

пример div

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

«В браузерах поддерживающих CSS можно задать все четыре координаты, а ширина и высота будут вычислены автоматически. К несчастью, это не работает в IE», — Autistic Cuckoo

«Технически вы можете задать координаты right и left, а ширина будет вычислена браузером, но IE не поддерживает такую возможность», — css-discuss

В действительности эта возможность CSS была незаслуженно забыта, из-за отсутствия поддержки в IE<5 и IE6, приятно видеть, что в IE7 проблема решена.

Между тем, несовместимость не уменьшает полезности этого решения. Определенная нами в начале статьи природа div остается верной для IE5 и IE6, но для других браузеров в нее нужно внести коррективы.

Во всех браузерах кроме IE

  1. Div это прямоугольник.
  2. Все четыре угла div могут абсолютно позиционироваться на странице.
  3. Если задано положение диагонально противоположных углов, то высота и ширина вычисляются автоматически.

Альтернативное решение для IE

То, что в IE5 и IE6 позиционироваться может только один из углов div, создает нам серьезные проблемы, но Microsoft предлагает нам их решение, это динамические свойства.

Динамические свойства чрезвычайно мощный инструмент, но они поддерживаются только IE, что не позволяет использовать их достаточно широко.

В нашем случае этого достаточно, с их помощью мы можем указать IE, что ширина div равна ширине страницы минус 40px.

В соответствии с этим решением нужно еще раз пересмотреть наши предположения относительно природы div в различных браузерах.

В IE5 и IE6

  1. div это прямоугольник.
  2. Только один угол div может абсолютно позиционироваться на странице.
  3. Положение диагонально противоположного угла должно определяться высотой и шириной элемента.
  4. Ширина и высота элемента могут быть определены с помощью динамических свойств.

Во всех остальных браузерах

  1. div это прямоугольник.
  2. Все четыре угла div могут абсолютно позиционироваться на странице.
  3. Если задано положение диагонально противоположных углов, то высота и ширина вычисляются автоматически.

Теперь все наши предположения соответствуют действительности и можно приступить к созданию разметки используя чистый (почти) CSS.

Собираем все вместе

Необходимая нам HTML разметка предельно проста:

<body>
  <div id="header">
    <p>Our header</p>

  </div>

  <div id="side">
    <p>Our side panel</p>
  </div>

  <div id="right">

    <p>Our main panel</p>
  </div>
</body>

В современных браузерах

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

  1. Высоту и ширину элемента body установим в 100% (Это нужно, чтобы работало наше решение для IE, но от того, что мы установим их в основном файле стилей вреда не будет).
  2. Установим overflow: hidden для body и html чтобы убрать скролл бары.
  3. Установим overflow: auto для левой и правой панелей и overflow: hidden для заголовка.
  4. Заголовку зададим ширину 100% и фиксированную высоту 80px.
  5. Для боковой панели установим координаты top (высота заголовка + отступ), left (отступ слева) и bottom (отступ снизу), и фиксированную ширину 200px.
  6. Для правой панели установим top (высота заголовка + отступ), left (отступ + ширина боковой панели с отступом), right (отступ) и bottom (отступ)

Все это очень просто перевести в CSS:

<style type=”text/css”>

html {
  overflow: hidden;
}

body {
  overflow: hidden;
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100%;
}

#header {
  padding: 0;
  margin: 0;
  position: absolute;
  top: 0px;    
  left: 0px;
  width: 100%;
  height: 80px;
  overflow: hidden;
}

#side {    
  padding: 0;
  margin: 0;
  position: absolute;    
  top: 100px;
  left: 20px;
  bottom: 20px;
  overflow: auto;    
  width: 200px;    
}

#main {
  padding: 0;
  margin: 0;
  position: absolute;    
  top: 100px;
  left: 240px;
  right: 20px;
  bottom: 20px;
  overflow: auto;
}

</style>

Создаем заплатку для IE5 и IE6

В IE5 и IE6 свойства bottom и right для главной и боковой панелей игнорируются, при этом левый верхний угол остается в заданной позиции и все, что нам нужно сделать это задать ширину и высоту панелей.

Высота панелей одинакова и равна, высоте страницы минус высоту заголовка и отступы (100%-80px-20px-20px).

Ширина главной панели равна, ширине страницы минус ширину боковой панели и отступы (100%-200px-20px-20px-20px). Боковая панель имеет фиксированную ширину, которая уже задана в основном файле стилей.

С помощью условных комментариев добавим стили доступные только для IE5 и IE6:

<!--[if lt IE 7]>

<style type="text/css">

#side {
  height:expression(document.body.clientHeight-120);
 /* 80+20+20=120 */  
}

#main {
  height:expression(document.body.clientHeight-120);
/* 80+20+20=120 */  
  width:expression(document.body.clientWidth-260);
/* 200+20+20+20=260 */    
}

</style>

<![endif]-->

Не забывайте о том, что для того чтобы это работало, мы установили ширину и высоту body равной 100% в главном файле стилей.

Заключение

Теперь у нас есть законченное решение.

Конечно, динамические выражения не проходят валидацию, но они скрыты от большинства браузеров, и хотя они задаются в CSS на самом деле это JavaScript, а значит, не работают, если JavaScript отключен (но эта проблема есть у всех альтернативных решений).

Известные проблемы

Есть маленький, но неприятный баг в Opera 8, там боковая панель корректно отображается при загрузке страницы, но не меняет размер при изменении размеров окна. Учитывая то, что баг исправлен в Opera 9, это не большая проблема.