Позиционирование блока по центру с учетом скрола
Дата публикации: 17.06.2010
Задача
Спозиционировать блок по центру (вертикально и горизонтально).
Требования
- учет размера самого блока;
- учет прокрутки окна;
- без использования js-библиотек.
- Просчитать размер «рабочей области» (размер окна) с учетом размеров всяких панелей и баров
- При необходимости (в случае, если наш блок «резиновый») снять с него «мерки»
- Составить формулу позиционирования и «приклеить» наш блок в нужное место
- ИЕ6-8 не знают, что такое window.innerWidth⁄innerHeight, зато понимают document.body.clientWidth⁄clientHeight.
Обе конструкции возвращают размеры «рабочего окна», под этим определением следует понимать: размер окна = размер экрана — размер панелей
- (document.body.clientWidth) ? document.body : document.documentElement. Зачем такая «мудрёная» конструкция?
Все дело в quirks mode. В этом режиме ИЕ использует не document.body, а document.documentElement для определения высоты скролла. В целом, если не рассчитывать на quirks mode, условие для ИЕ можно сократить до одной строчки: wwSize= [document.body.clientWidth, document.body.clientHeight];
- В формуле просчета координат присутствует конструкция (document.body.scrollTop || document.documentElement.scrollTop).
Её следует использовать если позиционирование происходит с учётом скролла. Конструкция возвращает кол-во пикселей, на которое прокручен скролл и имеет такой вид по следующей причине:
- document.documentElement.scrollTop — понимают IE7-8, Opera, Firefox
- document.body.scrollTop — понимают Chrome, Safari, IE6(ух, возомнил себе!)
Решение
На самом деле, все было бы не так тяжко, если бы нынешние браузеры (в частности ИЕ) следовали одним стандартам. Но, благо, это решаемо. Итак, алгоритм довольно прост:
К примеру имеем такой блок:
<h1>По клику блок выровняется.</h1> <h2>Можно проскролить и кликнуть где-нибудь внизу.</h2> <div id="testBlock"></div>
…и такой CSS (само собой блок должен быть с абсолютным позиционированием):
html { height: 100%; } body { height: 100%; } .wrap { text-align: center; height: 3000px; /* зададим большую высоту, чтоб появился вертикальный скролл - нужно для теста */ } #testBlock { position: absolute; top: 150px; left: 0; width: 500px; height: 500px; color: #fff; background: #090; }
Заметка
ИЕ снова показал, что он не такой как все, правда на этот раз к 6-му примкнул и 8-й. Они по разному (не только относительно других браузеров, но и относительно друг друга) реагируют на высоту html и body. Чтобы было все тип-топ, необходим элемент (обычно это div), который растянет body и html как минимум на 100% высоты экрана.
И так, сам скрипт:
window.onload = function(){ var wsize = windowWorkSize(), // размеры "рабочей области" testElem = document.getElementById("testBlock"), // ложим наш блок в переменную testElemWid = testElem.offsetWidth, // ширина блока testElemHei = testElem.offsetHeight; // высота блока window.document.onclick = function(){ // цетрируем по событию onclick testElem.style.left = wsize[0]/2 - testElemWid/2 + "px"; // центрируем блок по горизонтали testElem.style.top = wsize[1]/2 - testElemHei/2 + (document.body.scrollTop || document.documentElement.scrollTop) + "px"; // центрируем блок по вертикали + скролл }; // фунция определения "рабочего пространства" function windowWorkSize(){ var wwSize = new Array(); if (window.innerHeight !== undefined) wwSize= [window.innerWidth,window.innerHeight] // для основных браузеров else { // для "особо одарённых" (ИЕ6-8) wwSizeIE = (document.body.clientWidth) ? document.body : document.documentElement; wwSize= [wwSizeIE.clientWidth, wwSizeIE.clientHeight]; }; return wwSize; }; };
Результат. Проверено в:
Вобщем-то весь фокус в функции windowWorkSize(), которая и вычисляет кроссбраузерно высоту и ширину окна. Результат возвращает в виде массива из двух элементов, где элемент[0] — ширина окна, элемент[1] — высота. Дальше остается только прописать формулы для размещения в этой области блока.