Xiper

Прижимаем подвал к низу

Автор: Евгений Рыжков Дата публикации:

Задача

Прижать футер к низу экрана. Требования:

  • подвал прижат к низу экрана при высоте окна браузера больше высоты страницы не зависимо от контента
  • футер находится на положенном ему месте при объеме контента больше, чем высота окна браузера
  • работает в во всех популярных браузерах
  • надежность — не зависит от сложности верстки

Теория

Хорошим тоном является заполнение сайтом всей доступной области экрана браузера (как минимум по высоте для статичных по ширине дизайнов).

футер не прижат к низуЧасто при не прижатом подвале сайт смотрится странно Подвал прижат к низуСовсем другое дело, когда задумка дизайнера точно передана

Решение

Для примера возьмем простую страницу, состоящую из двух основных блоков: основного (main) и подвала (footer). Сделаем чтобы основной блок занял всю площадь окна браузера независимо от количества контента, при этом футер прижмем к низу экрана так, чтобы в браузере не появилась вертикальная полоса прокрутки. Как делаем:

Шаг 1

Делаем 2 блока: основной (main) и подвал (footer). Основной контейнер растягиваем на всю высоту экрана браузера (min-height), подвалу жестко указываем высоту (height).

Прижимаем подвал к низу - шаг 1

При этом общая высота сайта составит высота экрана + высота подвала.

Шаг 2

Отрицательным отступом (margin-top) "въезжаем" в основной блок, чтобы высота сайта составляла только 100% высоты экрана.

Прижимаем подвал к низу - шаг 2

При таком расположении блоков и при достаточном количестве контента (например, текста) в основном блоке, возможны накладки контента в основном блоке на подвал:

Прижимаем подвал к низу - потенциальная проблема
Шаг 3

Для избежания этой потенциальной проблемы, добавляем в конец основного блока пустой блок, высотой не меньше высоты подвала (а лучше немного больше, чтобы был отступ между контентом и подвалом):

Прижимаем footer к низу - шаг 3

Теперь, если контента будет много, он будет двигать пустой блок вниз. А это будет опускать и подвал, не давая налезть на него контенту.

Смотрим как это выглядит в коде:

<html>
<head>
<title>Футер прижат к низу</title>
<style type="text/css">
* {margin: 0; padding: 0;} /* обнуляем отступы */
body {
background: #fff;
}
html,body {
height: 100%; /* задаем высоту тела документа */
}
.main { /* основной блок, который должен растянуться до подвала */
background: #999; /* цвет фона основного блока (для наглядности) */
min-height: 100%; /* задаем минимальную высоту основного блока */
}
* html .main { /* хак для ie6 */
height: 100%; /* для ие6, т.к. не понимает min-height */
}
.hFooter { /* это распорка в основном блоке - резервируем место для подвала */
height: 40px; /* высота нашего подвала */
}
.footer { /* подвал */
background: #0000CC; /* цвет фона подвала (для наглядности) */
color: #fff;
height: 40px; /* высота подвала */
margin-top: -40px; /* делаем отрицательный отступ по высоте равный высоте подвла, чтобы четко вписаться в размер экрана */
}
</style>
</head>
<body>
<div class="main">
	  Это основной блок
	  <div class="hFooter"></div>
</div>
<div class="footer">Это подвал</div>
</body>
</html>

Результат этого примера.

Заметка: при использовании блочной верстки и плавающих основных блоков (колонок) для .hFooter следует добавить clear: both, чтобы подвал расположился под колонками.:

.hFooter {
clear: both;
height: 40px;
}

Проверено в:

Заметка 1: Если ты уже немного освоил CSS, тогда может возникнуть вопрос: " Зачем использовать дополнительный элемент, если можно воспользоваться padding-bottom?". Ответ — так просто его тут использовать нельзя, т.к. размер блока равен его ширине и высоте + сумме внутренних отступов + сумме толщин бордюров. Связка min-height: 100% и padding-bottom даст высоту сайта больше высоты экрана. В итоге даже при отсутствии контента вовсе, подвал будет за пределами "первого экрана". Как это можно обойти смотри ниже.

Заметка 2. В Opera версии 9.5 и выше при добавлении doctype этот пример не сработает. Варианты обхода:

  • добавить в основной тег-контейнер хотя бы один плавающий блок:
    <body>
    <div class="main">
    	  <div style="float: left;">Это основной блок</div>
    	  <div class="hFooter"></div>
    </div>
    <div class="footer">Это подвал</div>
    </body>
    </html>
    
  • добавить два свойства для html, body:
    html,body {
    height: 100%;
    float: left;
    width: 100%;
    }
    
  • вынести стили в отдельный CSS файл:
    <link rel="stylesheet" type="text/css" href="test.css" />
    

update - Недостаток данного приема

Это использование дополнительного пустого элемента hFooter. В реальных условиях (когда содержимое сайта не пустое и применяется блочная верстка) этого можно избежать применив прием clearfix — этот прим поможет очистить поток без использования дополнительного элемента, а чтобы контент не налез на футер, пропишем в колонках padding-bottom

Прижимаем footer к низу без использования пустого элемента

update — проблемы с z-слоями

В вышеописанном приеме футер поднимали отрицательным отступом вверх. При этом возникаем потенциальная проблема с z-слоями. Например, нам нужно показать всплывающее окно (пускай это будет div class="popup"), которое будет позиционироваться относительно контейнера main.

всплывающее окно в main
<div class="main">
    [...]
    <div class="popup">
        [...]
    </div>
</div>
<div class="footer">
    [...]
</div>

CSS:

.main {
position: relative; /* чтобы дочерние элементы позиционировались относительно этого блока */
z-index: 1; /* z-index меньше чем у футера, чтобы тот был виден */
}
.popup {
position: absolute;
z-index: 100;
[...]
}
.footer {
height: 50px;
margin-top: -50px;
position: relative; /* чтобы можно было задать z-index */
z-index: 2; /* больше, чем у main чтобы быть видимым */
}

Все хорошо до тех пор пока у нас не пересекаются всплывающее окно и подвал (а такая ситуация довольно часто возникает) — вот тут начинаются проблемы. Немотря на то, что у всплывающего окна наибольший z-index, оно будет перекрываться футером, т.к. родитель popup имеет z-index меньший, чем у подвала:

всплывающее окно в main

Вариант 1 — искать возможность позиционировать окно не относительно main, а относительно какого-либо другого дочернего элемента, который расположен в main. Таким образом, избавимся от указания z-index для main и footer. Но такой вариант не всегда возможен, потому рассмотрим второй вариант прижатия футера.

Решение 2 — абсолютное позиционирование

Идея похожа на решение 1:

  1. растягиваем основной блок на всю всот экрана
  2. резервируем место для подвала
  3. относительно основного блока позиционируем подвал в самый низ абсолютным позиционированием
<div class="main">
    [...]
	<div class="footer">
         [...]
    </div>
</div>
html, body {
height: 100%;
}
.main {
min-height: 100%;
position: relative; /* чтобы дочерние элементы позиционировались относительно этого блока */
}
.footer {
height: 50px;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
}
* html .footer {
bottomy:expression(parentNode.offsetHeight % 2 ? style.bottom="-1px" : style.bottom="0px"); /* хак для ие6, у которого есть косяк со смещением на 1px */
}

Такой подход решит проблему с всплывающими окнами, т.к. и footer и popup будут иметь общего родителя, а значит с z-слоями сюрпризов не будет.

Недостаток обоих методов

update: Оба метода годятся только для фиксированного по высоте подвала.

По теме