Долой отступы между строчными элементами (и блоками)

Автор: Александр Головко Дата публикации: 12.11.2010
Последнее обновление: 03.07.2011

Строчные блоки (inline-block) во многих случаях очень удобное средство разметки. Примеры их использования можно посмотреть в статьях Inline-block: простое свойство для непростых задач, Выравнивание навигации из блоков по центру, Центрирование резинового блока по горизонтали.

Вместе с тем, с ними связан подводный камень. Я бы даже сказал целый булыжник. Хочешь его увидеть? Поставь несколько строчных элементов (или строчных блоков) в ряд.

Допустим имеем такой HTML:

	<ul>
		<li>Стороки.</li>
		<li>Просто</li>
		<li>строки</li>
	</ul>

Делаем элементы строчными:

li{
	display:inline;
}

…или строчными блоками:

li{
	display:inline-block;
	/* Следующие две строки для IE6-7 - эмулируем поведение строчного блока*/
	//display:inline; 
	zoom:1;
}

Проблема

Большинство браузеров разделяет строчные блоки (элементы) отступами. Для удобства восприятия я немного раскрасил блоки.

отступы между элементами как бы появились сами собой Опаньки! Что за отступы? Я ничего такого не прописывал!

Давай договоримся, что здесь и далее я буду писать просто «строчный блок», а подразумевать «строчный блок (display:inline-block) или просто строчный элемент (display:inline)», поскольку проблема у них совершенно общая и лечится она тоже одинаково.

Кого лечим?

Итак строчные блоки обзавелись загадочными отступами. Конечно, это касается не только списков. Так же поведет себя и группа расположенных подряд, например, span'ов.

Справедливости ради, следует заметить, что IE6 и IE7 отрисуют все это дело без отступов:

отступов нет Вот так хочу, чтобы все браузеры отображали!

Не будем вдаваться в детали вопроса, кто прав, а кто виноват (читай — криво поддерживает стандарты), просто добьемся кроссбраузерности. Очень удобно, когда поведение предсказуемое — не задавал я никаких отступов, значит и рисовать мне их не нужно!

На самом деле все просто — чтобы убрать отступы, нужно понять, откуда они там вообще взялись!

Откуда отступы-то?

А понять не сложно. Достаточно просто записать теги в одну строку:

	<ul>
		<li>Стороки.</li><li>Просто</li><li>строки</li>
	</ul>

Чудеса! Отступы пропали сами собой! Вывод: порождают их невидимые символы между тегами — перенос или пробел.

Само собой, «писать все в одну строку» хоть и является кроссбраузерным решением проблемы, но тут не рассматривается, по понятным причинам (ну кто ж пишет без отступов?). Ищем другие пути.

Долой отступы!

Раз отступы создают символы из контейнера, здравой мыслью будет эти символы «обезвредить» — задать им font-size:0; (главное, не забыть, что это свойство наследуется и перебить его для самих потомков):

ul{
	font-size:0;
}
li{
	font-size:14px;
	display:inline;
}

Отличное решение! Строчные блоки действительно прижались друг к другу. Осталась еще небольшая косметическая проблема: в некоторых браузерах (например, в Opera 9.5 и младше) замечен отступ сверху или снизу в пределах родителя (родитель на рисунке залит бледным серо-зеленым):

вертикальные отступы в некоторых  браузерах картинка увеличена, чтоб было видно отступы по вертикали

Проблема эта сродни описанной в статье IMG внутри блока — убираем странный отступ, и лечится примерно так же: добавляем line-height:0; (опять не забываем перекрыть у потомка). Итак, получаем:

ul{
	font-size:0;
	line-height:0;
}
li{
	font-size:14px;
	line-height:normal; /* ну или другое подходящее значение */
	display:inline;
}

Теперь-то все хорошо и красиво? Не тут-то было!

Пришла беда, откуда не ждали

Видать, действительно эти отступы должны быть! В подтверждение этому есть два железных аргумента:

  1. их не рисует IE6-7;
  2. их, несмотря на наши старания, все равно рисуют Webkit-браузеры.

Да-да! И Safari и Chrome после всех вышеизложенных ухищрений соизволили просто уменьшить отступы с трех пикселей до одного!

упрямые webkit'ы Упрямые webkit'ы не хотят сдаваться!


Update 3.07.2011 by Nick. Еще один скрытый сюрприз преподнес FF. Если масштабировать страницу иногда наблюдается дополнительный отступ в 1px сверху. Лечится это добавлением правила display: -moz-inline-stack;

Окончательное решение

Побороть webkit'ы получилось с помощью letter-spacing:-1px. При этом никаких вредных побочных эффектов обнаружено не было (если, конечно не забыть перекрыть свойство у потомков).

Окончательный CSS с кроссбраузерным решением для строчных элементов:

ul{
	font-size:0; /* убираем горизонтальные отступы */
	line-height:0; /* ...и вертикальные в некоторых браузерах */
	letter-spacing:-1px; /* переубеждаем webkit'ы */
}
li{
	font-size:14px; /* Не забываем восстановить нормальные значения */
	line-height:normal;
	letter-spacing:normal;	
	display:inline;
}

Для строчных блоков:

ul{
	font-size:0; /* убираем горизонтальные отступы */
	line-height:0; /* ...и вертикальные в некоторых браузерах */
	letter-spacing:-1px; /* переубеждаем webkit'ы */
}
li{
	font-size:14px; /* Не забываем восстановить нормальные значения */
	line-height:normal;
	letter-spacing:normal;
	display: -moz-inline-stack!important;
	display:inline-block;
	//display:inline;
	zoom:1;
}

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

Демонстрационный пример

Проверено в:

  • IE 6-8
  • Firefox 3.5
  • Opera 9.5-10.5
  • Safari 4
  • Chrome 7