Содержание

Css расстояние между блоками. Расстановка полей и отступов в CSS

В этой статье я хотел бы рассказать, как правильно расставлять поля (padding) и отступы (margin) в CSS.

Прежде всего давайте вспомним определение полей и отступов согласно спецификации W3C . В боксовой модели (box model) поля — это расстояние между контентом (content) и границей блока (border). А отступы это расстояние между границей блока и границей соседнего или родительского элемента.

Таким образом, если граница и фон элемента не заданы, то нет разницы, использовать свойство padding или margin для задания отступов, но при условии, что ширина (width) и высота (height) элемента не заданы и не изменен алгоритм расчета размеров контента с помощью свойства box-sizing .

В любом случае следует помнить, что поля могут быть как включены в ширину или высоту элемента, так и нет. Отступы же всегда задаются снаружи элемента.

Теперь давайте рассмотрим как правильно расставлять поля и отступы между элементами. Возьмем в качестве примера следующий блок.

Это блок новостей news . Он состоит из заголовка, списка новостей и ссылки «Другие новости». Дадим им следующие названия классов: news__title , news__list и news__more-link .

Новости

Другие новости

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

News { padding: 20px 25px; }

Таким образом, при необходимости изменить значение полей справа и слева это нужно будет сделать в одном месте . А при добавлении нового элемента внутрь блока новостей, он уже будет иметь нужные отступы слева и справа.

Часто бывает так, что все элементы внутри блока имеют одинаковые отступы слева и справа, кроме одного, который вообще не должен иметь отступов, например, из-за фона. В этом случае для элемента можно задать отрицательные отступы. Тогда не придется убирать поля внутри блока для остальных элементов.

Теперь нужно задать вертикальные отступы между элементами. Для этого следует определить какой из элементов является обязательным . Очевидно что блок новостей не может существовать без списка новостей, в то же время ссылки «Другие новости» может и не быть, заголовок тоже может быть убран, например, при изменении дизайна.

Учитывая это, задаем для заголовка отступ снизу, а для ссылки «Другие новости» отступ сверху.

News__title { margin-bottom: 10px; } .news__more-link { margin-top: 12px; }

Мы могли бы достигнуть такого же внешнего результата, добавив отступы сверху и снизу для списка новостей.

News__list { margin: 10px 0 12px 0; }

Теперь нужно задать отступы между отдельными новостями. Опять же, нужно принять во внимание, что количество новостей может меняться, и в списке может быть только одна новость.

Можно задать для каждой новости кроме первой отступ сверху, либо для каждой новости кроме последней отступ снизу. Первый вариант более предпочтителен, поскольку псевдоселектор:first-child был добавлен в спецификации CSS 2.1 и имеет более широкую поддержку, в отличие от псевдоселектора:last-child , который был добавлен только в спецификации CSS версии 3.0 .

News__list-item { margin-top: 18px; } .news__list-item:first-child { margin-top: 0; }

Таким образом, правильная расстановка полей и отступов позволяет гибко менять внешний вид любого блока без внесения изменений в стили и без нарушений в дизайне. Самое главное — определить, какие элементы блока являются основными (обязательными ), а какие

опциональными .

Иногда мы не можем опираться на обязательные элементы. Например, у нас есть всплывающее окошко popup , внутри которого может выводиться какой-то заголовок и текст. Причем в каких-то случаях может не быть текста, а в каких-то и заголовка. То есть оба элемента являются опциональными.

В этом случае можно использовать следующий способ задания отступов.

Popup__header + .popup__text { margin-top: 15px; }

Тогда отступ появится, только если будут использоваться оба элемента. В случае же вывода только заголовка или только текста, лишнего отступа не будет.

Схлопывание вертикальных отступов

Еще один нюанс, о котором не все знают, связан с вертикальными отступами между соседними блоками. В определении отступов, которое я приводил выше, сказано, что отступ — это расстояние между

границами текущего и соседнего блока. Таким образом, если мы расположим два блока друг под другом и зададим одному из них отступ снизу в 30px , а другому отступ сверху в 20px , отступ между ними будет не 50px , а 30px .

То есть произойдет наложение отступов, и отступ между блоками будет равен наибольшему отступу, а не сумме отступов. Этот эффект также назы

crabo.ru

Задать 100% высоту между блоками CSS

Stack Overflow на русском

Loading…

  1. 0
  2. +0
    • Тур Начните с этой страницы, чтобы быстро ознакомиться с сайтом
    • Справка Подробные ответы на любые возможные вопросы
    • Мета Обсудить принципы работы и политику сайта
    • О нас Узнать больше о компании Stack Overflow
    • Бизнес Узнать больше о поиске разработчиков или рекламе на сайте
  3. Войти

ru.stackoverflow.com

«Загадочные отступы» между инлайн-элементами — CSS-LIVE

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

В этой статье мы попытаемся понять, что же из себя представляют эти загадочные «Отступы», что это за звери и с чем их едят. Так же рассмотрим, что такое inline-block, и почему после себя он ставит эти непонятные интервалы. Ну, и, самое главное, мы увидим несколько универсальных решений данного вопроса и ,конечно же, обсудим все их стороны.

Для начала мне хотелось бы пояснить, что же такое inline-block и почему все решения мы будем обсуждать именно с этим значением.

inline-block

Значит, inline-block — представляет собой этакую «коробочку», в которой содержатся буковки, т.е. некий коробок со спичками. Этот коробок представляет из себя блок, с поведением строки, т.е. по сути является строчно-блочным элементом.
Строчное поведение inline-block позволяет ему оставаться в одной строке с другими строчными элементами, например <span>-ом или попусту сливаться с обычными буквами, т.е. вести себя, как текст в строке. Ну а благодаря своим блочным способностям,

inline-block-у можно смело задавать любые свойства, которые присущи блочным элементам: ширину, высоту, верхний и нижний margin, например, уже будет действовать, как у блоков.
Ну и т.д., в общем, эдакий «блок-строка»

Живой пример

Как видно из примера, inline-block чувствует высоту и ширину, которую мы ему прописали. Так же можно заметить одну интересную штуку, наш подопечный выровнялся по вертикали, выровнялся так, как и должны выравниваться большинство инлайн-элементов в html, т.е. по базовой линии (baseline) , т.е. выравнивается наш блок относительно своего текста, который в нём находится. Добавляем текста в блок и смотрим результат.

Блок выровнялся по базовой линии. Чего и следовало ожидать.
Сразу же приведу несколько разных примеров, поведения inline-block с разным вертикальным выравниванием.

Разное выравнивание

Тут я продемонстрировал три разных выравнивания, но на самом деле их намного больше, если интересно, то вот здесь описаны все возможные варианты. В данной статье нет смысла всех их описывать. Просто учитывайте это, при работе с inline-block.

inline-block — как буква

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

Переваривайте эту информацию и идёмте дальше…

Почему в статье я использую именно inline-block?

На самом деле «Проблема» пробелов для inline-block и обычных инлайн элементов — является общей. Т.е. и с теми и с другими происходят идентичные вещи. Ненавистные отступы, появляются у тех и у других. Просто дело в том, что:
Во-первых, inline-block имеет больше возможностей, таких например, как задание ширины или высоты и т.д.
Во-вторых, мне всё-таки хотелось немного объяснить вам, что такое inline-block и что они из себя представляют, всё-же они относятся к строкам, как-никак.
Ну и в-третьих это то, что с inline-block связаны определённые проблемы в браузере Safari, о которых мне бы хотелось, чтобы вы знали.

Так что я думаю, что знакомство с этим поведением строчно-блочного элемента будет для вас полезным делом и, безусловно, расширит ваш кругозор.

Загадочные отступы

Познакомившись поближе со строчно-блочным элементом, мы можем смело двигаться дальше, к демонстрации и ответам на вопрос: «Откуда берутся отступы после инлайн элементов?». Для того, чтобы понять, о чём идёт речь, приведу код и скриншот с проблемой.

<ul>
	<li>Пункт 1</li>
	<li>Пункт 2</li>
	<li>Пункт 3</li>
	<li>Пункт 4</li>
	<li>Пункт 5</li>
</ul>
ul {
	font: 14px Verdana,sans-serif;
}
	ul li {
		display : inline-block ;
		width : 100px;
		border : 1px solid #E76D13;

		/* эмуляция inline-block для IE6-7*/

		//display : inline;
		//zoom : 1;
	}

В итоге мы видим ту самую «неприятность», из-за которой мы все тут и собрались.

На картинке отчётливо видны пробелы между пунктами меню. Откуда же они берутся? Причина кроется в том, что, как мы уже выяснили, inline-block ведет себя, как обычная буква, а значит так же, как и простой текст — имеет пробелы между словами. Эти пробелы можно отчётливо наблюдать в разных веб-инспекторах, например таких как «IE WebDeveloper» для Internet Explorer.

Как мы видим, браузер создаёт пустой текстовый узел, который, по сути, может являться переводом строки, пробелом или, например, табом. Все и эти перечисленные вещи превращаются в один единственный пробел и описывается следующей сущностью: &#x0020;. Так же следует учитывать, что, так как пробел — это обычный символ, то, соответственно, и изменяться этот самый символ будет в зависимости от размера или семейства шрифта, т.е, по сути, вести себя точно также, как и обычная буква в строке. Всё это обязательно следует учитывать при вёрстке.

Наша задача

Перед нами стоит задача каким-то образом избавиться от этого ненавистного расстояния. Убрать, сделать его ширину нулевой, сплющить, спрятать, всё что угодно… в общем придумать какой нибудь способ, который избавит нас от этого межсловного промежутка и соединит наши пункты вплотную.

Материал для работы

Давайте поразмыслим, что же нам сможет помочь для решения этой задачи.

1. margin-left (отрицательный) — свойство, с помощью которого можно сдвинуть пункты влево, как бы друг на друга, «избавившись» так сказать от ненавистного пробела между них.
2. font-size — свойство, задающее размер шрифта, с помощью которого нашему пробелу (символу) можно выставить размер шрифта, равный нулю, и тем самым сделать его настолько маленьким, что его попусту не будет видно.
3. letter-spacing — свойство, определяющее интервал между символами. По умолчанию (normal) задаёт обычный интервал, исходя из размера и типа шрифта.
4. word-spacing — свойство, определяющее интервал между словами. По умолчанию так же, как и letter-spacing, задаёт его в зависимости от размера и типа шрифта.
5. Прижать элементы друг к другу, т.е. вплотную, тег к тегу, и таким образом убрать межссловный интервал.
6. Поставить комментарии между элементами, тем самым убрав между ними отступы.
7. Самое, на мой взгляд, интересное решение из всех… оставлю его пожалуй на закуску… интрига…

Плюс ко всему сделаем тестовый элемент  <div>Ширина = 510px</div>, который будет нашей вспомогательной линейкой. Ширина наших пунктов в сумме составляет 510px. Это боковые границы + их ширина + кол-во самих пунктов ((1+100+1)*5) = 510.

Вроде ничего не забыли, поэтому переходим к рассмотрению всех вышеперечисленных вариантов.

Вариант 1 — margin-left

Первым у нас на очереди выступает левый отрицательный margin. Посмотрим, как он сможет помочь нам. Код CSS для наглядности:

ul {
	font: 14px Verdana,sans-serif;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;
		margin-left: -.36em;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;

		/* margin-left отдельно для  IE6-7 */
		//margin-left: 0;
	}

Из кода видно, что для общего списка я выставил шрифт Verdana и размер шрифта в 14px (в наших примерах будет отталкиваться от этих значений). Ну и ,конечно же, левый отрицательный margin, равный -.36em. Как вы могли заметить, для нашей цели я выбрал именно масштабируемую единицу длины (em), потому что, как мы уже знаем, наш пробел пляшет от размера шрифта, а значит, может масштабироваться в зависимости от него. Долго повозившись со значениями, я определил, что -.36em) подходит для нашего шрифта лучше всего (для иного придётся подбирать другие значения), так что оставим, пожалуй, именно этот масштаб. Посмотрим на результат:

Как мы можем наблюдать из скриншота, наши пункты уехали за левую границу, что в принципе и очевидно, ведь мы же по сути подвинули все пункты влево, а значит, и первый пункт также уехал в левую сторону. Для решения этого «недоразумения», мы можем обнулить margin-left именно у первого пункта меню, добавив в наш код следующую запись ul li:first-child { margin-left: 0;}.
*Стоит заметить, что для IE6-7 мы вообще обнулили margin-left, а почему… мы узнаем чуть позже.

А между делом смотрим результат:

Да, действительно, на данный момент во всех браузерах всё здорово и смотрится одинаково. Хм… неужели мы добились своей цели? Давайте проверим это, сделав размер шрифта, к примеру, в два раза больше.

ul {
	font: 28px Verdana,sans-serif;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;
		margin-left: -.36em;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;

		/* margin-left отдельно для  IE6-7 */
		//margin-left: 0;
	}

	ul li:first-child { margin-left: 0;}.

Как можно видеть, мы достигли своей цели, но это до тех пор, пока мы не поменяли шрифт, например, на Arial (предварительно подогнав под него левый, отрицательный margin)

Выставив фон нашему списку, мы можем заметить, что теперь результаты немного разнятся в браузерах Chrome, Opera 11.53, IE6-8 и Firefox 8, IE 9. В первых всё осталось на своих местах, а вот в последних можно заметить небольшой отступ справа, что говорит о том, что всё-таки есть риск получить немного не ту картину, которую мы задумывали изначально. Как вариант, конечно же, можно подогнать спец. значения для Firefox 8 и IE 9 отдельно, но, опять же, это не очень хорошее решение, так как во-первых, это по сути костыль, а во-вторых, не даёт полной универсальности, ведь никогда не знаешь, при каких размерах и как, поведут себя остальные браузеры.

В общем, я, лично, сделал вывод, что это вполне себе нормальный и жизнеспособный вариант, в фиксированной ситуации можно подогнать размеры и будет всё в порядке. Ряд минусов конечно же тоже есть, в виде обнуления margin-left у первого пункта + подгонка значений для разных браузеров, ну и… конечно же есть доля риска, из-за которой могут быть, хоть и не большие, но какие-то отличия с отступами, при разных шрифтах и их размерах.

Результат с margin-left

Вариант 2 — font-size

Как вы уже знаете, font-size влияет на размер шрифта элемента, делая его больше или меньше, в зависимости от своего значения. Пробел — это символ, который исходит от этого самого размера шрифта, а значит, с помощью font-size мы можем попробовать воздействовать на него, например, выставив его значение в ноль и тем самым, возможно полностью «скрыть» наш ненавистный пробел. Давайте проверим это на деле.

ul {
	font: 14px Verdana, Geneva, sans-serif;

	/* Выставляем родителю значение в ноль */
	font-size: 0;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

Что произошло с символами? Куда они все пропали? На самом деле всё просто. font-size наследуемое свойство, а значит, выставив родителю (в нашем случае UL) какое либо значение, отличное от значения по умолчанию, мы должны возвратить font-size в прежнее состояние, у потомков (в нашем случае у LI).

ul {
	font: 14px Verdana, Geneva, sans-serif;

	/* Выставляем родителю значение в ноль */
	font-size: 0;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* Возвращаем в нормальное состояние у потомков */
		font-size: 14px;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

Отлично! Теперь всё работает! Но везде ли? Проверяем… упс… к сожалению почти…

Как видно из скриншотов, Safari подвёл нас, напрочь отказавшись обнулять наш межсловный символ :(. Почему же так произошло? Не найдя ответа на этот вопрос, я рискнул предположить, что всё-таки это ни что иное, как самый настоящий баг браузера Safari и поэтому, нам нужно, либо искать вменяемое лекарство от этого бага, либо отказываться от этого способа, полностью. Исключать этот способ из списка не очень хочется, потому что, во-первых, этот вариант не работает лишь в Safari, а во-вторых, моя интуиция мне подсказывала, что решение всё же имеется. В итоге спортивный интерес взял вверх и решение всё таки нашлось! Да, и при чём оно оказалось для меня приятной неожиданностью. Ответ кроется в свойстве display: table, которое вешается на контейнер с пунктами (в нашем случае UL). Проверим.

ul {
	font: 14px Verdana, Geneva, sans-serif;

	/* Выставляем родителю значение в ноль */
	font-size: 0;

	/* Лекарство отдельно для Safari */
	display: table;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* Возвращаем в нормальное состояние у потомков */
		font-size: 14px;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

А вот и скриншот из Safari:

Супер! Сработало! Но как же это так? Возможно, при display:table движок воспринимает строку блоков внутри как «что-то вроде table-cell», т.е. ячеек таблицы, в каких-то FF до 3.6, если я ничего не путаю, был похожий баг.

Чем это может нам грозить?

Есть пару мелких недостатков, о которых следовало бы знать.
1. Во всех браузерах, кроме Firefox, точкой отсчёта позиционированных элементов являются ближайший предок с relative, т.е. это может быть та же ячейка (TD). Но у нас тут не TD, а LI, так что в этом плане проблем у нас точно не будет. Но проблемы будут, если мы захотим позиционировать сами LI, внутри UL, а так как UL у нас — это, по сути, таблица, то Firefox откажется позиционировать пункты относительно её. Но тут не стоит беспокоиться, так как в этом случае на помощь к нам придёт обычная обёртка (например div) для элемента UL.
2. Второй нюанс — ширина. display:table по умолчанию не растягивается на доступное пространство, так что может понадобиться еще выставление ширины контейнеру (а при наличии бордеров/паддингов — box-sizing: border-box c нужными префиксами вдобавок).

Это что касалось самого display:table, а что же сам font-size? У него есть минусы? Да, есть, пожалуй, один неприятный недостаток. Из-за нулевого значения font-size у родителя, мы не можем применять масштабируемые единицы длины к потомкам, т.к. они отталкиваются от наследуемого размера шрифта и соответственно от нуля в нашем случае. Ну и плюс ко всему, это то, что всегда надо быть начеку и смотреть, чтобы у потомков был переназначен размер шрифта.

Ну а так в целом способ, вполне себе рабочий, если не считать нюансы. Так что смотрим пример в действии и идём дальше.
Решение с font-size

Вариант 3 — letter-spacing

Третьим номером у нас идёт letter-spacing. Чуть ранее мы выяснили, что это свойство влияет на интервал между символами, а так как наш inline-block по сути и есть один, большой символ, то letter-spacing всё таки должен помочь в решении нашей задачи. Как и в прошлый раз, я повозился с масштабом и выяснил, что -.36em будет как раз то, что нужно для Verdana.
* Да, и ещё стоит учесть, что letter-spacing, как и font-size, наследуемое свойство, поэтому нам придётся проделывать ту же операцию с обнулением потомков, что и во втором варианте.

ul {
	font: 14px Verdana, Geneva, sans-serif;

	/* Выставляем родителю значение -.36em */
	letter-spacing : -.36em;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* Возвращаем в нормальное состояние у потомков */
		letter-spacing: normal;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

Отлично, сами пункты вроде бы состыковались так, как нам нужно. «Вроде бы» — я сказал не случайно, а почему, вы поймёте из следующих скриншотов.

Во всех браузерах, кроме Opera, мы можем наблюдать вполне себе отличную картину, но вот в самой Opera к сожалению всё наоборот. Как оказалось, Норвежцы считают, что letter-spacing может влиять на всё, кроме пробела. Видимо из-за того, что символ пробела означает конец слова, а значит и letter-spacing заканчивает на этом свою работу, так как предназначен для сдвижки/раздвижки букв, именно внутри слова (в т.ч. для кернинга вручную). И тут не имеет значения, что inline-block тоже по сути буква, после неё есть пробел, а значит в любом случае, слово по факту, закончилось.
Считать ли это багом Opera? Ну не знаю, ситуация двоякая, и те и другие по своему правы, так что предлагаю оставить это на совести самой Opera, а самим отправиться на поиски решения этой проблемы.

В общем, повозившись довольно таки приличное время в поисках лекарства для этого случая, я не смог придти ни к чему путному, кроме как воспользоваться предыдущим решением с font-size и добавить его в наши стили.

ul {
	font: 14px Verdana, Geneva, sans-serif;

	/* Выставляем родителю значение -.36em */
	letter-spacing : -.36em;
	font-size : 0;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* Возвращаем в нормальное состояние у потомков */
		letter-spacing: normal;
		font-size : 14px;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

Да, вот теперь всё отлично, font-size действительно смог нам помочь. Из этого я сделал вывод, что по сути можно пользоваться обоими вариантами в равной степени: font-size + display-table или letter-spacing + font-size. Т.е. как в первом, так и во втором случае нам требуются вспомогательные инструменты в виде дополнительных свойств.
Upd: Кстати, пока писал статью, обнаружил странный баг в Safari. Когда выставляешь родителю связку font-size : 0 и letter-spacing в любое значение em, например letter-spacing : -.36em, то в Safari всё сразу же рушится((. Причину этого странного поведения Safari мне так и не удалось выявить. Буду рад услышать ответ на этот вопрос в комментариях. Решением с моей стороны является выставление значений letter-spacing, например в пиксели.

Результат с letter-spacing

Вариант 4 — word-spacing

Сразу же хочется отметить, что word-spacing и letter-spacing похожи друг на друга и отличаются только лишь тем, что первый работает с расстоянием между символами, а второй — между словами. При этом word-spacing так же имеет свои недостатки, но в отличие от letter-spacing, с недостатками word-spacing можно бороться, что не может не радовать.
* Также стоит отметить, что word-spacing тоже наследуемое свойство, поэтому в целом код будет напоминать код с letter-spacing. Так что подбираем значение и в путь.

ul {
	font: 14px Verdana, Geneva, sans-serif;

	/* Выставляем родителю значение -.36em */
	word-spacing: -.36em;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* Возвращаем в нормальное состояние у потомков */
		word-spacing: normal;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

По коду вроде всё уже ясно, переходим к скриншотам:

Ну и конечно же снова не обошлось без происшествий. Но теперь уже оба webkit-a (Chrome и Safari) показали нам свои недостатки. Как мы можем наблюдать, word-spacing в этих браузерах вообще не сработал, как будто бы мы его и не назначали. Поведение webkit-ов в данной ситуации, скорее всего, можно назвать багом, так как свойство, которое мы тут применяли, предназначено именно для межсловных расстояний. Доказательством в пользу бага служит то, что для обычных inline элементов word-spacing как раз таки работает в webkit так, как и должен, а вот для inline-block-ов к сожалению нет.

Первый вопрос, который вы зададите, будет: «А есть ли решение у данной проблемы?». С радостью отвечу вам, что ДА! И, как, ни странно, этим решением является снова наш старый, добрый display:table, который помог нам при проблемах в Safari, во втором варианте с font-size. Так что смело добавляем это правило и смотрим результат.

ul {
	font: 14px Verdana, Geneva, sans-serif;

	/* Выставляем родителю значение -.36em */
	word-spacing: -.36em;

	/* Лекарство для webkit */
	display: table;
}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* Возвращаем в нормальное состояние у потомков */
		word-spacing: normal;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

Да, вы не ошиблись. display: table действительно помог нам решить баг webkit-ов. Недостатки этого лечения, собственно точно такие же, как я приводил во-втором варианте, т.е. это позиционирование и задания ширины в контейнере. В остальном этот способ я лично считаю более уместным, чем все предыдущие предшественники, так как, во-первых, мы всё таки решаем проблемы с межсловным расстоянием (word-spacing как раз и создан для этого), во-вторых, решение для проблемы webkit-ов вполне безобидное, если не считать пару нюансов, ну и в-третьих, я, тестировал этот метод с разными размерами шрифта и даже тут ничего страшного не заметил.
Так что привожу работающий пример, смотрим и идём далее…
Результат с word-spacing

Вариант 5, 6 — Соединение элементов

Эти два решения, я решил объединить в одно целое, так как они схожи по своей сути и делают почти одно и то же, т.е. состыковывают элементы, убирая между ними пробелы.

HTML первого варианта:

<ul><li>Пункт 1</li><li>Пункт 2</li><li>Пункт 3</li><li>Пункт 4</li><li>Пункт 5</li></ul>

Ну и второго соответственно:

<ul><!--
	--><li>Пункт 1</li><!--
	--><li>Пункт 2</li><!--
	--><li>Пункт 3</li><!--
	--><li>Пункт 4</li><!--
	--><li>Пункт 5</li><!--
--></ul>

А CSS для обоих вариантов будет таким:

ul {
	font: 14px Verdana, Geneva, sans-serif;

}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

Ну и конечно же, скриншоты:

Как видно из кода, в первом варианте мы просто пристыковали элементы вплотную, перенеся закрывающие теги вплотную к открывающим. А во втором — поместили между границами элементов комментарии, заменяя ими наши пробелы. Т.е. фактически мы намеренно лишили элементы каких либо отступов между ними, специально соединив их разными способами. При этом, как можно заменить, у этих вариантов есть хороший плюс, для них не требуются никакие спец. свойства и костыли в CSS, они работают сами по себе, при чём во всех браузерах, начиная с IE6+.
Но между тем эти решения несут в себе ряд неких проблем, которые связаны, во-первых, с удобочитаемостью кода, во-вторых, со случайным сбросом одного элемента под другой или убиранием одного комментария возле пункта, что сразу же повлияет на отображения вашего сайта, далеко не в лучшую сторону. Например, ваш сайт, может попросту развалиться или какой-нибудь пункт перескочит на другую строку и т.д.

В общем, можно сделать вывод, что эти варианты, однозначно имеют право на жизнь, но пользоваться ими можно только тогда, когда ты точно знаешь и уверен в том, что делаешь.

Так что пока смотрим рабочий пример и плавно переходим к завершающему методу, самому практичному и интересному, на мой взгляд…
Результат

Вариант 7

Как оказалось, на свете есть ещё более простое, а главное, абсолютно законное решение, которым я хочу поделиться. Дело в том, что любая спецификация HTML (но не XHTML), позволяет нам опускать закрывающие теги у некоторых элементов, т.е. разрешает их отсутствие. В спецификации HTML5 таких элементов целых 18 штук. Это означает, что мы, на вполне законных основаниях, можем пользоваться этим преимуществом. Ведь никто не запрещает нам это сделать, не правда ли?)
В нашем случае элементы <li> попадают в этот список, так что воспользуемся этим.

<ul>
	<li>Пункт 1
	<li>Пункт 2
	<li>Пункт 3
	<li>Пункт 4
	<li>Пункт 5
</ul>
ul {
	font: 14px Verdana, Geneva, sans-serif;

}
	ul li {
		display : inline-block;
		width : 100px;
		border : 1px solid #E76D13;

		/* эмуляция inline-block для IE6-7*/
		//display : inline;
		//zoom : 1;
	}

Т.е. по сути, я просто опустил закрывающие теги </li>, и раз после содержимого первого элемента сразу же идёт открывающий тег второго, то соответственно и интервала между ними быть не должно. Что наглядно демонстрируется на скриншоте.
*Стоит заметить, что в IE6-7, например, опциональные закрывающие теги в списках всё равно игнорируются, поэтому там этот метод получается «автоматом». Именно из-за этого в первом варианте c отрицательным левым margin-ом, мы, отдельно, обнуляли margin-left для этих браузеров.

Этот способ мне кажется наиболее удачным, одновременно лёгким и удобным, чем все остальные, которые мы рассматривали в этой статье. Недостатком лишь стоит назвать то, что такую структуру не воспринимают любые XML-парсеры.

Вывод такой, что этот метод не подходит «фанатикам валидности ради валидности», выбирающим XHTML-доктайп, но практикам, ориентирующимся на современные спецификации и реальный результат, отказываться от такого решения незачем =)
Результат

Резюме:

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

Все варианты воедино:

1. Результат с margin-left (Почти рабочее решение)
2. Решение с font-size (Рабочее решение)
3. Результат с letter-spacing (Работающее решение)
4. Результат с word-spacing (Рабочее решение)
5. Вариант с намеренно прижатыми элементами (Рабочее решение)
6. Решение с незакрытыми тегами (Рабочее решение)

Аналогичную статью я недавно опубликовал на хабре

P.S. Это тоже может быть интересно:

css-live.ru

Расстановка полей и отступов в CSS / Netcracker corporate blog / Habr

В этой статье я хотел бы рассказать, как правильно расставлять поля (padding) и отступы (margin) в CSS.

Прежде всего давайте вспомним определение полей и отступов согласно спецификации W3C. В боксовой модели (box model) поля — это расстояние между контентом (content) и границей блока (border). А отступы это расстояние между границей блока и границей соседнего или родительского элемента.

Таким образом, если граница и фон элемента не заданы, то нет разницы, использовать свойство padding или margin для задания отступов, но при условии, что ширина (width) и высота (height) элемента не заданы и не изменен алгоритм расчета размеров контента с помощью свойства box-sizing.

В любом случае следует помнить, что поля могут быть как включены в ширину или высоту элемента, так и нет. Отступы же всегда задаются снаружи элемента.

Теперь давайте рассмотрим как правильно расставлять поля и отступы между элементами. Возьмем в качестве примера следующий блок.

Это блок новостей news. Он состоит из заголовка, списка новостей и ссылки «Другие новости». Дадим им следующие названия классов: news__title, news__list и news__more-link.

<div>
    <h3>Новости</h3>
    <ul>
        <li>...</li>
        <li>...</li>
        <li>...</li>
    </ul>
    <p><a href="...">Другие новости</a></p>
</div>

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

.news {
    padding: 20px 25px;
}

Таким образом, при необходимости изменить значение полей справа и слева это нужно будет сделать в одном месте. А при добавлении нового элемента внутрь блока новостей, он уже будет иметь нужные отступы слева и справа.

Часто бывает так, что все элементы внутри блока имеют одинаковые отступы слева и справа, кроме одного, который вообще не должен иметь отступов, например, из-за фона. В этом случае для элемента можно задать отрицательные отступы. Тогда не придется убирать поля внутри блока для остальных элементов.

Теперь нужно задать вертикальные отступы между элементами. Для этого следует определить какой из элементов является обязательным. Очевидно что блок новостей не может существовать без списка новостей, в то же время ссылки «Другие новости» может и не быть, заголовок тоже может быть убран, например, при изменении дизайна.

Учитывая это, задаем для заголовка отступ снизу, а для ссылки «Другие новости» отступ сверху.

.news__title {
    margin-bottom: 10px;
}

.news__more-link {
    margin-top: 12px;
}

Мы могли бы достигнуть такого же внешнего результата, добавив отступы сверху и снизу для списка новостей.

.news__list {
    margin: 10px 0 12px 0;
}

Но в этом случае при убирании ссылки «Другие новости» внизу остается лишний отступ. То же самое справедливо и для заголовка. Очевидно, что первый вариант является более правильным, поскольку позволяет гибко изменять внешний вид блока.

Теперь нужно задать отступы между отдельными новостями. Опять же, нужно принять во внимание, что количество новостей может меняться, и в списке может быть только одна новость.

Можно задать для каждой новости кроме первой отступ сверху, либо для каждой новости кроме последней отступ снизу. Первый вариант более предпочтителен, поскольку псевдоселектор :first-child был добавлен в спецификации CSS 2.1 и имеет более широкую поддержку, в отличие от псевдоселектора :last-child, который был добавлен только в спецификации CSS версии 3.0.

.news__list-item {
    margin-top: 18px;
}

.news__list-item:first-child {
    margin-top: 0;
}

Таким образом, правильная расстановка полей и отступов позволяет гибко менять внешний вид любого блока без внесения изменений в стили и без нарушений в дизайне. Самое главное — определить, какие элементы блока являются основными (обязательными), а какие опциональными.

Иногда мы не можем опираться на обязательные элементы. Например, у нас есть всплывающее окошко popup, внутри которого может выводиться какой-то заголовок и текст. Причем в каких-то случаях может не быть текста, а в каких-то и заголовка. То есть оба элемента являются опциональными.

В этом случае можно использовать следующий способ задания отступов.

.popup__header + .popup__text {
    margin-top: 15px;
}

jsfiddle.net/onfv42mz/1

Тогда отступ появится, только если будут использоваться оба элемента. В случае же вывода только заголовка или только текста, лишнего отступа не будет.

Схлопывание вертикальных отступов

Еще один нюанс, о котором не все знают, связан с вертикальными отступами между соседними блоками. В определении отступов, которое я приводил выше, сказано, что отступ — это расстояние между границами текущего и соседнего блока. Таким образом, если мы расположим два блока друг под другом и зададим одному из них отступ снизу в 30px, а другому отступ сверху в 20px, отступ между ними будет не 50px, а 30px.

.block1 {
    margin-bottom: 30px;
}

.block2 {
    margin-top: 20px;
}

jsfiddle.net/j99btnc8

То есть произойдет наложение отступов, и отступ между блоками будет равен наибольшему отступу, а не сумме отступов. Этот эффект также называют «схлопыванием».

Прошу заметить, что горизонтальные отступы, в отличие от вертикальных, не «схлопываются», а суммируются. Поля (padding) также суммируются.

Зная о «схлопывании» отступов, мы можем использовать эту особенность в свою пользу. Например, если нам необходимо расставить отступы для заголовков и текста внутри статьи, то для заголовка первого уровня зададим отступ снизу в 20px, а для заголовка второго уровня отступ сверху 20px и снизу 10px, а для всех параграфов зададим отступ сверху 10px.

h2 {
    margin-bottom: 24px;
}

h3 {
    margin-top: 24px;
    margin-bottom: 12px;
}

p {
    margin-top: 12px;
}

jsfiddle.net/n27fms7s/1

Теперь заголовок h3 можно расположить как после заголовка h2, так и после параграфа. В любом случае отступ сверху не будет превышать 24px.

Общие правила

Подводя итог, я бы хотел перечислить правила, которых я придерживаюсь при расстановке полей и отступов.

  1. Если соседние элементы имеют одинаковые отступы, то лучше задавать их родительскому контейнеру, а не элементам.
  2. При задании отступов между элементами, следует учитывать, обязательный это элемент или опциональный.
  3. Для списка однотипных элементов — не забывать о том, что число элементов может варьироваться.
  4. Помнить о наложении вертикальных отступов и использовать эту особенность там, где она принесет пользу.

habr.com

html — Как уменьшить расстояние между блоками?

Stack Overflow на русском

Loading…

  1. 0
  2. +0
    • Тур Начните с этой страницы, чтобы быстро ознакомиться с сайтом
    • Справка Подробные ответы на любые возможные вопросы
    • Мета Обсудить принципы работы и политику сайта
    • О нас Узнать больше о компании Stack Overflow
    • Бизнес

ru.stackoverflow.com

Внутренние отступы CSS, внешние отступы CSS

В CSS есть два вида отступов — внешние и внутренние.Внутренние отступы — это расстояние от края контента до рамки блока. А внешние отступы — это расстояние от рамки блока до соседнего блока или до края страницы. Если рамки нет, то расстояние определяется от предполагаемой рамки. Для создания внешних отступов в CSS используется свойство margin, а для создания внутренних — свойство padding. Значением этих свойств является расстояние в единицах, доступных в CSS.

Для примера создадим блок и установим ему внутренние отступы 30 пикселей, а внешние 50 пикселей. Чтобы видеть внешний отступ, создадим ещё один блок. Установим блокам рамки для определения края блока.

Стиль:

+

1
2
3
4
5
6

<!DOCTYPE html>
<html>
<head>
<title>Страница</title>
<meta charset="utf-8">
<style>

7
8
9
10

div
  {
  border: 1px solid Red;
  }

HTML код:

14
15

<div>Контент</div>
<div>Соседний блок</div>

Обратите внимание — второй блок, которому не установлены отступы, не касается краёв страницы, а находится от них на определённом расстоянии. Это происходит потому, что у страницы есть свои внутренние отступы.

ВАЖНО: Внешние отступы соседних блоков не суммируются. Расстояние между блоками равно большему отступу. Например, если у одного блока margin равно 20 пикселей, а у второго блока margin равно 10 пикселей, то расстояние между блоками будет 20 пикселей.

Отступы можно установить с каждой стороны по-отдельности. Для установки внешних отступов используются свойства margin-left, margin-right, margin-top, margin-bottom, а для внутренних отступов используются свойства padding-left, padding-right, padding-top, padding-bottom.

Добавим на страницу блок и установим ему внутренние отступы сверху и слева:

16

<div>Контент</div>

Попробуйте установить блоку различные внутренние и внешние отступы, посмотрите, как они работают.

Если нужно указать разные отступы со всех четырёх сторон, то это можно сделать более коротким способом. Для этого свойствам margin и padding указываются четыре значения через пробел — сначала отступ сверху, затем справа, затем снизу, а затем слева. Если какой-то отсуп не нужен, то ему можно указать нулевое значение.

Пример:

17

<div>Контент</div>

basecourse.ru

Проблемы CSS. Часть 1 / Habr

От переводчика

Статья большая решил разбить на две части.


Впервые css был представлен примерно в 1995 году, и был предназначен для стилизации простых текстовых документов. Не веб сайтов. Не приложений. А именно текстовых документов. С тех пор, css, прошел долгий путь. Возможно слишком долгий.

Для многих вещей, css, не был предназначен изначально, например для таких как: многоколоночность, отзывчивый веб дизайн и т.д. Вот почему он стал языком полным хаков и глюков, как какая-то древняя машина с кучей расширений.

В лучшем случае — работу с css можно назвать веселым занятием. И это то, благодаря чему мы имеем работу. Потому что, как я считаю, генерация эффективных и кроссбраузерных css стилей невозможна и не будет возможна в ближайшее время.

Перейдем к сути, ведь я здесь не для того, что бы высказать свое мнение о css. А для того, что бы рассмотреть ряд часто встречающихся в css проблем, и их возможных решений.

Я старался выбрать несколько действительно очень распространенных:

  • Очистка float`ов.
  • Как победить отступы между элементами с inline-block?
  • Понимание абсолютного позиционирования.
  • Когда использовать width / height равный 100% (часть 2)
  • Как не облажаться с z-index. (часть 2)
  • Что такое свертывание границ(margin collapsing)? (часть 2)
Очистка float`ов.

Мне кажется, что это самый распространенный вопрос в css. Он стар как мир, честно, я на тысячу процентов уверен, что каждый, кто хоть когда нибудь писал на css сталкивался с ним.

Простыми словами его можно описать так: когда внутри элемента содержатся только элементы с float, он схлопывается так, как будто в нем вообще нет дочерних элементов. То есть, по факту, элементы с float выпадают из общего потока.

Есть несколько способов для решения этой проблемы. Раньше мы использовали пустой div со стилем «clear: both» в самом низу контейнера. Затем, мы заменили его на тег hr, что не на много лучше.

И наконец Nicolas Gallagher предложил новый путь очистки float`ов без необходимости трогать разметку совсем. После продолжительных дискуссий и тестов, мы получили минимально необходимый, для его работы, набор стилей, вот его последняя версия:

.clearfix:after {
    content: "";
    display: table;
    clear: both;
}

На самом деле я солгал, она не последняя, она самая короткая. Но если вам нужна поддержка IE 6/7, то вам нужно добавить еще вот это:
.clearfix {
    *zoom: 1;
}

Для работы необходимо добавить класс .clearfix в свой проект, а затем применять его к элементам разметки. Это самый простой и чистый способ для работы с float`ами.
Как победить отступы между элементами с inline-block?

Продолжим с размещением элементов в строку, в этот раз не с помощью float, а с помощью inline-blocks. display: inline-block долгое время был недооценен, и все же мы разобрались, как он работает и почему это круто. Сегодня, все больше и больше front-end разработчиков предпочитают использовать inline-block взамен float`ов, когда у них есть такая возможность.

Главный плюс inline-block в том, что нам не приходится отчищать float`ы и мы не сталкиваемся с другими проблемами которые могут возникнуть из-за элементов спозиционированных с помощью float`ов. Просто установив свойство элемента display в значение inline-block получим гибрид строчного элемента и блока. Они могут иметь размер, отступы, но их ширина, по-умолчанию, зависит от контента, а не занимает всю ширину родителького элемента. Таким образом они размещаются горизонтально, а не вертикально.

Вы можете спросить: «В чем же тогда проблема?». А проблема в том, что они на половину строчные, а значит имеют отступ друг от друга размером равным пробелу. Со стандартным шрифтом размером 16px, он составляет 4px. В большинстве случаев размер отступа можно рассчитать, как 25% от размера шрифта. Так или иначе, это может помешать нормальному расположению элементов. Например, возьмем контейнер размером в 600px с тремя элементами внутри, размер которых 200px и задано свойством display: inline-block. Если не убрать отступ, то нам не удастся разместить их в одну линию (200 *3 + 4 * 2 = 608).

Есть несколько путей, как убрать ненужный нам пробел, каждый со своими плюсами и минусами. Если честно, то пока нет идеального решения. Давайте взглянем на все по очереди!

Уровень разметки: удаление пробелов

Для всех наших тестов воспользуемся следующей разметкой.
<div> <!-- 600px -->
    <div>I'm a child!</div> <!-- inline-block 200px -->
    <div>I'm a child!</div> <!-- inline-block 200px -->
    <div>I'm a child!</div> <!-- inline-block 200px -->
</div>

Как я уже говорил ранее, дочерние элементы не станут в одну линию, потому что есть дополнительный символ пробела между каждым из них (в нашем случае перевод строки и 4 пробела). Первый способ решить проблему — полностью удалить пробелы.
<div>
    <div>I'm a child!</div><div>I'm a child!</div><div>I'm a child!</div>
</div>

Это действительно работает, но делает не удобным чтение нашего кода. Хотя, мы можем, немного реорганизовать наши элементы, что бы сохранить читаемость:
<div>
    <div>
        I'm a child!</div><div>
        I'm a child!</div><div>
        I'm a child!</div>
</div>

И если быть уж совсем крутым, можно сделать и так:
<div>
    <div>I'm a child!</div
  ><div>I'm a child!</div
  ><div>I'm a child!</div>
</div>

Да — это работает! Конечно я не рекомендую такой подход, потому что он не интуитивен и делает код уродливым. Давайте, лучше, попробуем, что нибудь еще.
Уровень разметки: комментируем пробелы

Что если закомментировать пробелы вместо того, что бы удалить их?
<div> <!-- 600px -->
     <div>I'm a child!</div><!-- 
--><div>I'm a child!</div><!--
--><div>I'm a child!</div>
</div>

Да, так гораздо лучше! Код читаем и работает. Да, способ выглядит не привычно на первый взгляд, но не так и сложно к нему привыкнуть. Я и сам использую такой способ, когда мне надо удалить пробелы между элементами с inline-block.

Конечно, кто-то скажет, что это не идеальное решение, так как оно работает на стороне разметки, а проблема должна быть решена на уровне css. Действительно. Большинство из нас на самом деле используют css решения.

Уровень css: расстояние между символами

Свойство letter-spacing используется для задания отступов между символами. Идея заключается в том, что бы установить отступ таким, что бы он нивелировал отступ между нашими элементами, затем, нам придется сбросить letter-spacing для дочерних элементов, что бы текст в них выглядил нормально.
.parent {
    letter-spacing: -0.3em;
}
 
.child {
    letter-spacing: normal;
}

Эта техика используется в Griddle — основанной на Sass системе сеток за авторством Nicolas Gallagher, так что, как вы видите, это достаточно серьезное решение. Хотя, честно говоря, мне не нравится тот факт, что мы полагаемся на магичиские числа в стилях. Плюс с некоторыми шрифтами, это число может меняться например на 0.31em и т.д. То есть, его необходимо подгонять под каждый конкретный случай.
Уровень css: отрицательный margin

Еще один подход к решению задачи, очень похож на предыдущий, но с использование отрицательного отступа. Главный его недостаток он не работает в IE 6/7. Плюс нам необходимо убрать отступ с первого элемента, что бы они ровно встали внутри нашего контейнера.
.child {
    margin-left: -0.25em;
}
 
.child:first-of-type {
    margin-left: 0;
}

Если вам не требуется поддержка IE 6/7, я считаю что это достаточно неплохе решение.
Уровень css: font-size

Ну и на последок, вы можете установить размер шрифта родительского блока в 0, что бы сделать пробел равным 0px, а затем восстановить размер шрифта для дочерних элементов.
.parent {
    font-size: 0;
}
 
.child {
    font-size: 16px;
}

У этого решения есть несколько своих проблем и ограничений:

Так что, это не лучшее решение. Как я уже говорил ранее, скорее всего буду использовать путь с комментирование пробелов. Если для вас он выглядит неудобным, вы можете вернуться к float`ам или же вообще использовать flexbox.

Понимание абсолютного позиционирования.

Позиционирование элементов — каверзный процесс и всегда им был. Позиционирование, начинающим, дается с большим трудом. Они часто (не)используют свойство position. Это свойство определяет как элемент может перемещаться с помощью смещений (top, right, bottom and left). И принимает следующие значения:
  • static — по-умолчанию, смещения не действуют
  • relative — смещения двигают визуальный слой, но не сам элемент
  • absolute — смещения двигают элемент внутри контекста (первый не static элемент)
  • fixed — смещения позиционируют элемент внутри viewport`a и не важно где он расположен в документе

Проблемы появляются при использовании position: absolute. И наверняка вы с ними уже сталкивались: вы определили элемент с абсолютным позиционирование, потому что хотите, что бы он был в верхнем правом углу своего родителя (например кнопка закрыть у модального окна).

element {
    position: absolute;
    top: 0;
    right: 0;
}

… а он оказывается в верхнем правом углу документа. У вас промелькает мысль «Какого черта?». На самом деле, это нормальное поведение браузера. Ключевое слово тут контекст.

Код выше просто говорит: «Я хочу что бы мой элемент был спозиционирован в верхнем правом углу контекста». Так что же такое контекст? Это первый элемент со свойством position не равным static. Это может быть непосредственно родительский элемент, или родитель родителя, или родитель родителя родителя. И так до первого элемента с position != static.

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

Небольшая демка иллюстрирующая вышесказанное. Два родителя, в каждом по одному дочернему элементу спозиционированному абсолютно со смещение top: 0 и right: 0. Слева правильный родитель с position: relative, справа неправильный с position: static.

jsFiddle

Продолжение «Проблемы CSS. Часть 2».

habr.com