Позиционирование блока по центру с учетом скрола
Задача
Спозиционировать блок по центру (вертикально и горизонтально).
Требования
- учет размера самого блока;
- учет прокрутки окна;
- без использования js-библиотек.
Решение
На самом деле, все было бы не так тяжко, если бы нынешние браузеры (в частности ИЕ) следовали одним стандартам. Но, благо, это решаемо. Итак, алгоритм довольно прост:
- Просчитать размер "рабочей области" (размер окна) с учетом размеров всяких панелей и баров
- При необходимости (в случае, если наш блок "резиновый") снять с него "мерки"
- Составить формулу позиционирования и "приклеить" наш блок в нужное место
К примеру имеем такой блок:
<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] - высота. Дальше остается только прописать формулы для размещения в этой области блока.
Заметки
- ИЕ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(ух, возомнил себе!)