Xiper

Выравнивание навигации из блоков по центру

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

Задача

Есть навигация (список ul). Каждый элемент списка (li) — блочный. Количество элементов навигации заранее не известно. Список в виде строки (li имеют свойство float: left/right), для того чтоб навигация была в одну строку. Нужно выровнять эту навигацию по середине родителя
пример страничной навигации по середине родителя

Имеем следующий HTML:

<div class="parent">
<ul>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li>3</li>
<li><a href="#">4</a></li>
</ul>
</div>

и CSS:

.parent {
width: 100%;
text-align: center; /*пытаемся выровнять содержимое по центру */
padding: 20px 0;
background: #6699FF; /* для наглядности обозначаем родителя */
float: left; /* чтоб высота родителя была с учетом плавающих потомков */
}
ul {
list-style: none;
font-size: 12px;
margin: 0 auto;
padding: 0;
}
li {
float: left; /* выстраиваем блочные элементы в ряд */
margin-right: 4px;
width: 23px;
height: 19px;
overflow: hidden;
text-align: center;
color: #fff;
font-weight: bold;
position: relative; /* для удобного размещения ссылки внутри */
background:url(images/testFonNeactiv.png); /* фоновая картинка текущей страницы*/
cursor: default;
padding-top: 3px;
}
li a {
color: #fff;
text-decoration: none;
position: absolute;
top: 0;
left: 0;
display: block;
background:url(images/testFonActiv.png);
text-align: center;
width: 23px;
height: 22px;
padding-top: 3px;
}

Как видно на примере обычное выравнивание блока по центру относительно родителя в этом случае не срабатывает, т.к. нет четко заданной ширины блока навигации.

Решение

Для решения этой проблемы используем конструкцию:

<div class="parent">
<span><!--или любой другой элемент уровня inline (строчный)-->
<ul>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
</ul>
</span>
</div>

CSS:

.parent {
width: 100%; /* ширина нужна, только если блок плавающий (float) */
text-align: center; /* обязательно делаем выравнивание по центру */
float: left; /* в данном примере float нужен чтобы высота блока была с учетом плавающего содержимого */
padding: 20px 0;
background: #6699FF;
}
ul {
display: table; /* элемент типа таблицы имеет ширину, зависящую от содержимого */
width: auto; /* для уверенности что ширина будет зависеть от содержимого*/
margin: 0 auto; /* устанавливаем отступ слева и справа в auto */
list-style: none;
font-size: 12px;
padding: 0;
}
* html .parent span {/*хак для IE6, который не понимает display: table*/
display: inline-block;
}
*:first-child+html .parent span {/*хак для IE7, который не понимает display: table */
display: inline-block;
}
li {
float: left;
margin-right: 4px;
width: 23px;
height: 19px;
overflow: hidden;
text-align: center;
color: #fff;
font-weight: bold;
position: relative;
background:url(images/testFonNeactiv.png);
cursor: default;
padding-top: 3px;
}
* html li {
height: 22px;
}
li a {
color: #fff;
text-decoration: none;
position: absolute;
top: 0;
left: 0;
display: block;
background:url(images/testFonActiv.png);
text-align: center;
width: 23px;
height: 22px;
padding-top: 3px;
}

Результат. Проверено в:

В боевых условиях лучше использовать условные комментарии вместо хаков.

HTML код не пройдет проверку корректности (валидацию), т.к. элементы уровня inline (строчные) не могут содержать элементы уровня блок (блочные). Заменить в этом коде <span> на блочный элемент (например <div>) не получится — в IE навигация останется прижата влево.

Альтернативное решение (валидный код)

Если отказаться от использования списка, можно сделать и по стандартам:

HTML:

<div class="parent">
<span>
<a href="#">1</a>
<a href="#">2</a>
<b>3</b>
<a href="#">4</a>
</span>
</div

CSS:

.parent {
width: 100%;
text-align: center;
padding: 20px 0;
background: #6699FF;
}
span {
font-size: 12px;
margin: 0 auto;
padding: 0;
width: auto;
display: table;
}
* html .parent span {
display: inline-block;
}
*:first-child+html .parent span {
display: inline-block;
} a, b {
float: left;
margin-right: 4px;
width: 23px;
height: 19px;
overflow: hidden;
text-align: center;
color: #fff;
font-weight: bold;
background:url(images/testFonActiv.png);
padding-top: 3px;
display: inline;
}
* html a, * html b {
height: 22px;
}
b {
background:url(images/testFonNeactiv.png);
cursor: default;
}

Результат. Проверено в:

Заметка

Для более точного центрирования нужно убрать у последнего элемента отступ справа. Или же, если отступы для элементов навигации заданы слева, нужно убрать отступ у первого.

Решение без дополнительных элементов с валидным HTML

update: by Александр Головко.

Это решение не требует дополнительных элементов, является семантичным и оставляет программистам чистый, валидный HTML код. Решение построено на использовании CSS свойства display:inline-block. Навигация реализована списком:

	<div class="parent">
		<ul>
			<li><a href="#">1</a></li>
			<li><a href="#">2</a></li>
			<li><a href="#">3</a></li>
			<li>4</li>
			<li><a href="#">5</a></li>
			<li><a href="#">6</a></li>
		</ul>
	</div>
.parent {
	text-align: center;/*все строчные элементы будут выравниваться по центру*/
}
ul {
	display: inline-block; /*превращаем элемент в строчный блок*/
	//display: inline; /*для IE6-7 превращаем элемент в строчный*/
	zoom: 1; /*присваиваем ему layout*/
	font-size: 12px;/*устанавливаем размер шрифта*/
}
li {
	float: left;/*делаем блок плавающим*/
	display: inline;/*убираем двойные отступы у плавающих блоков в IE6*/
	margin-right: 4px;
	width: 23px;
	height: 22px;
	overflow: hidden;
	text-align: center;/*для того, чтобы центрировать надписи в элементах списка по горизонтали*/
	color: #fff;
	font-weight: bold;
	background: url(/path-to/nvigatsiya-def.gif) no-repeat;
	cursor: default;/*для активной страницы*/
	line-height: 22px;/*для того, чтобы центрировать надписи в элементах списка по вертикали*/
}
li a {
	color: #fff;
	text-decoration: none;
	display: block;
	width: 23px;
	height: 22px;
	background: url(/path-to/nvigatsiya-href.gif) no-repeat;
}

Как обычно, невалидный zoom и хак для IE прячем с помощью условных комментариев.

Демо-пример

Проверено в: