Исследуем подвалы
15:16 21 Дек. 2007 Автор: Кирилл ХарченкоОдно из достоинств метода старой школы
— табличной верстки — состоит в легкости изготовления растягивающегося макета. Если вы хотите выровнять контент по центру по вертикали или привязать подвал к низу окна браузера, вам достаточно лишь поместить все элементы внутрь одной большой таблицы и присвоить ей значение высоты в 100%.
Согласно веб-стандарту, вы этого сделать более не можете. Свойство высоты таблицы (height) в XHTML не одобряется, и веб-стандарты рекомендуют вам избегать использования таблиц в качестве структуры страницы. Для отделения структурной разметки от изобразительной существует CSS, но для вертикального позиционирования в CSS поддерживаемых популярными браузерами средств вряд ли будет вам достаточно.
Эта статья исследует способы позиционирования подвалов используя только стандартные средства, хотя эти техники могут быть использованы для вертикального позиционирования и других элементов. Во множестве макетов страниц подвал размещен непосредственно под блоком контента, хотя контент и подвал вместе не заполняют всю рабочую область браузера. В этом случае, подвал будет располагаться внизу рабочей области браузера.
Абсолютное позиционирование в относительном блоке
Так как вы позиционируете подвал с помощью CSS? Рисуете контейнер с жесткой шириной. Контейнер состоит из разного количества контента и следующего за ним подвала с жесткой высотой. Когда вы добавляете контент, контейнер увеличивается; когда убавляете — сжимается.
Если вы создадите относительно спозиционированый блок и вложите в него блок с контентом, по умолчанию он будет отображаться в нормальном потоке внутри контейнера, увеличивая или сокращая высоту родительского элемента с его содержимым. Одной из сильных сторон относительного позиционирования является то, что вы можете вкладывать в них элементы, спозиционированные абсолютно. Это делает возможным вложение блока с подвалом и, позиционируя его абсолютно, приклеить
к низу контейнера. Разметка будет выглядеть так:
<div id="container">
<div id="content">...</div>
<div id="footer">...</div>
</div>
А стилевые правила — так:
#container {
position: relative;
}
#footer {
position: absolute;
bottom: 0;
}
Однако, абсолютные элементы выпадают из нормального потока и помещаются поверх элементов в нормальном потоке. Поскольку вам явно не хочется, чтобы ваш подвал перекрывал контент, вы можете добавить отбивку (padding) к нижнему краю блока с контентом, чтобы скомпенсировать высоту подвала. Можете взглянуть на результат на примере 1.
На данном этапе такой метод работает неправильно в Internet Explorer 5.x/Windows. Для этого браузера, абсолютно спозиционированый потомок теряет позицию, если не задана ширина элемента-родителя. Так что на следующем шаге мы сосредоточимся на высоте контейнера.
Присоединяем контейнер к окну броузера
Далее, высота контейнера определятся высотой блока с контентом, что просто замечательно, если контента достаточно, чтобы заполнить окно браузера. В противном случае, подвал должен прилипать к низу страницы.
С помощью CSS этот эффект реализовать просто. Если вы зададите контейнеру минимальную высоту в 100% с помощью атрибута min-height, минимальная высота контейнера будет совпадать с высотой его родительского элемента: элемента body. Вы указываете, что высота элемента body должна равняться высоте окна браузера, устанавливая высоты body и html в 100%.
html, body {
height: 100%;
}
#container {
position: relative;
min-height: 100%;
}
Вы можете увидеть результаты в примере 2. Вот и весь код, необходимый для позиционирования подвала с помощью CSS. К сожалению, эта техника не работает в Internet Explorer и Safari, так как они не поддерживают свойство min-height.
Но подождите-ка, техника срабатывает в Internet Explorer 6, даже несмотря на то, что этот браузер не поддерживает min-height (если и поддерживает, то во всяком случае, не так, как предусмотрено спецификацией W3C).
Оказывается, если установить высоту элемента body в 100%, в Internet Explorer 6 (в режиме совместимости со стандартами) контейнер наследует высоту родителя (в нашем случае, рабочую область браузера). Из-за некорректной реализации значения visible в свойстве overflow в IE контейнер растягивается до высоты блока, который содержит, а не до 100%-ной высоты рабочей области браузера. Эти два бага в сумме удачно имитируют свойство min-height.
Обходим некоторые ограничения
Internet Explorer 5.x/Windows всегда отображает страницу в режиме совместимости (нестандартном). Если вы установите высоту блока в 100%, в режиме совместимости, элемент будет использовать высоту рабочей области браузера. Так что если бы вы задали высоту в 100% только для контейнера, это решило бы проблему из первого примера и сделало эту технику пригодной и для IE5/Windows. Заметьте, что если вы установите высоту контейнера в 100%, в режиме совместимости подвал все равно будет оставаться внизу окна браузера.
Используя хак блочной модели, вы можете задавать правила только для Internet Explorer 5.x/Windows. Нужно задать высоту контейнера следующим образом:
#container {
position: relative;
min-height: 100%;
height: 100%;
voice-family: ""}"";
voice-family: inherit;
height: auto;
}
html>body #container {
height: auto;
}
Вы можете увидеть результат в примере 3. Пример 3 по идее в Internet Explorer 5.x/Mac и Safari работать не должен, но они тормозят
изящно: подвал таки остается привязанным к низу блока с контентом.
Microsoft прекратил разработку Internet Explorer для Mac. Надеюсь, Apple’s Safari в скором времени станет поддерживать свойство min-height. Тем не менее, возможно вам понадобится, чтобы ваш сайт все-таки отображался в Safari или в Internet Explorer 5/Mac (а скорее всего, в обоих). Есть ли альтернативные методы? Хорошо, что вы спросили.
Как насчет тяжелой артиллерии
— W3C DOM?
К сожалению, W3C не создал никаких спецификаций для вычисления ни высоты окна браузера, ни высот элементов документа. А ведь стоило: на то стандарт и существует, чтобы разработчики браузеров не создавали эти спецификации сами. Им приходится создавать собственные оригинальные свойства.
Так что, если вы собираетесь применять скрипты для позиционирования элементов относительно окна браузера, вы обречены на использование нестандартных, уникальных для каждого браузера, методов. Вопрос в следующем: правильно ли мы поступим, если будем использовать эти методы в случаях, не определенных стандартом?
По-моему, все зависит от того, насколько внутренне состоятельны эти техники. Если они способны заполнить дыры в веб-стандарте и используются в соответствующих случаях, я думаю, к ним следует относиться, как к спецификации W3C.
Если у вас стоит выбор между решением, использующим только CSS, и решением, совмещающим CSS и скрипты, стоит использовать первое — чистый CSS. По идее, CSS предназначен для оформления, а JavaScript для описания поведения. Однако именно в тех случаях, где стандарт не поддерживается или поддерживается недостаточно хорошо, использование DOM и JavaScript может значительно обогатить инструментарий оформления вашего сайта. В этом случае, комбинация CSS и скриптовых техник может быть оправдана.
Использование нестандартных методов DOM для вычисления высот
Кажется, разработчики браузеров, создавая собственные спецификации высот, следили друг за другом. В результате DOM позволяет нам вычислять высоту окна браузера и элементов документа. Несмотря на то, что некоторые браузеры используют разные объекты и свойства, следующий скрипт правильно определит высоту окна практически любого современного браузера:
function getWindowHeight() {
var windowHeight=0;
if (typeof(window.innerHeight)=='number') {
windowHeight=window.innerHeight;
}
else {
if (document.documentElement&&document.documentElement.clientHeight) {
windowHeight=document.documentElement.clientHeight;
}
else {
if (document.body&&document.body.clientHeight) {
windowHeight=document.body.clientHeight;
}
}
}
return windowHeight;
}
Свойство window.innerHeight возвращает высоту окна большинства популярных браузеров, за исключением Internet Explorer. В Internet Explorer 6 в режиме совместимости со стандартом, для этого используется свойство document.documentElement.clientHeight. Свойство document.body.clientHeight возвращает высоту окна браузеру Internet Explorer 4+.
С помощью document.getElementById(elementId).offsetHeight можно получить высоту любого элемента во всех современных браузерах.
Теперь, обладая средствами вычисления высоты окна браузера и элементов документа, можно написать функцию правильного позиционирования подвала.
Использование W3C DOM для позиционирования подвала
Если вы взялись использовать JavaScript для позиционирования элементов, это не значит что CSS для этого использовать уже не нужно. W3C DOM позволяет использовать JavaScript в стилевых правилах. То есть вы можете описать JavaScript как CSS, с добавлением вычисления высот и некоторой сравнительной логики.
Начнем с разметки страницы в самой простейшей форме — создадим блок с контентом и подвал:
<div id="content">...</div> <div id="footer">...</div>
Если суммарная высота блока с контентом и подвалом больше высоты рабочей области браузера, подвал должен оставаться в нормальном потоке (статическое позиционирование). В противоположном случае, скрипт должен будет привязать подвал к низу окна. С помощью относительного позиционирования вы можете сдвинуть подвал к низу относительно своей позиции в нормальном потоке (или спозиционировать его абсолютно). Попахивает CSS, не так ли?
Следующая функция выполняет то, что мы сейчас описали:
function setFooter() {
if (document.getElementById) {
var windowHeight=getWindowHeight();
if (windowHeight>0) {
var contentHeight=document.getElementById('content').offsetHeight;
var footerElement=document.getElementById('footer');
var footerHeight=footerElement.offsetHeight;
if (windowHeight-(contentHeight+footerHeight)>=0) {
footerElement.style.position='relative';
footerElement.style.top=(windowHeight-(contentHeight+footerHeight))+'px';
}
else {
footerElement.style.position='static';
}
}
}
}
Режем функцию setFooter()
Функция setFooter() сначала получает высоту рабочего окна браузера и хранит ее в переменной windowHeight:
var windowHeight = getWindowHeight();
Затем получает высоты блока с контентом и подвала:
var contentHeight=document.getElementById('content').offsetHeight;
var footerElement=document.getElementById('footer');
var footerHeight=footerElement.offsetHeight;
Затем выясняет, превосходит ли высота окна сумму высот блока с контентом и подвала:
if (windowHeight-(contentHeight+footerHeight)>=0)
В этом случае переставляет относительный (к своему положению в нормальном потоке) подвал к низу страницы:
footerElement.style.position='relative'; footerElement.style.top=(windowHeight-(contentHeight+footerHeight))+'px';
Если контент и подвал полностью заполняют окно, элемент перепозиционируется в статический, чтоб попасть в нормальный поток:
footerElement.style.position='static';
Чтобы заставить все работать, включим в скрипт функцию getWindowHeight() и добавим две функции, вызывающие setFooter() при срабатывании событий загрузки и изменения размеров окна:
window.onload = function() {
setFooter();
}
window.onresize = function() {
setFooter();
}
Конечную версию вы можете увидеть в примере 4. Однако, есть еще одна заковыка. Safari не сможет спозиционировать элемент относительно или абсолютно при срабатывании события onload. Чтобы обойти этот момент, добавьте такое правило:
#footer {
position: relative;
}
Эта техника работает во всех современных браузерах без использования хаков, что дает ей в данном случае преимущество над техникой чистого CSS. Если браузер не сможет вычислить одну из высот, если JavaScript выключена или браузер не поддерживает JavaScript, подвал будет отображаться в нормальном потоке. Как видите, структурная разметка и стили остаются отделенными друг от друга, а сверстанный код не претерпел никаких усложнений. Возможно, подход со скриптами и более объемен, чем CSS, но не столь значительно.
Многофункциональность концепции
Сделав несколько небольших изменений в логике CSS, можно получить несколько способов позиционирования подвала. Можно использовать только относительно спозиционированые элементы (пример 5) или абсолютное позиционирование (пример 6).
Техника скриптования может быть легко использована и для других задач вертикального позиционирования. Представьте, что вам нужно центрировать блок с контентом по вертикали в окне браузера используя только CSS. Вы можете также добиться того же эффекта с помощью техники скриптования. Взгляните на результат в примере 7.
- Автор: Бобби Ван дер Слуис
- Источник: Exploring Footers
- Перевод: Кирилл Харченко