Позиционирование блока по центру с учетом скрола

Автор: Андрей Косяк Дата публикации: 17.06.2010

Задача

javascript позициониование по центру Спозиционировать блок по центру (вертикально и горизонтально).

Требования

  • учет размера самого блока;
  • учет прокрутки окна;
  • без использования 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(ух, возомнил себе!)

Материалы