Долой отступы между строчными элементами (и блоками)
Автор: Александр Головко Дата публикации:
Строчные блоки (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; }
Теперь-то все хорошо и красиво? Не тут-то было!
Пришла беда, откуда не ждали
Видать, действительно эти отступы должны быть! В подтверждение этому есть два железных аргумента:
- их не рисует IE6-7;
- их, несмотря на наши старания, все равно рисуют Webkit-браузеры.
Да-да! И Safari и Chrome после всех вышеизложенных ухищрений соизволили просто уменьшить отступы с трех пикселей до одного!
Упрямые webkit’ы не хотят сдаваться!
Update by Nick. Еще один скрытый сюрприз преподнес FF. Если масштабировать страницу иногда наблюдается дополнительный отступ в 1px сверху. Лечится это добавлением правила display: -moz-inline-stack;
Окончательное решение
Окончательный 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
Очистка 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; }
У этого решения есть несколько своих проблем и ограничений:
- Вы не сможете восстановить шрифт для дочерних элементов используя em как размер шрифта
- Пробелы не удаляются на устройствах с Android до Jellybean
- Текст с использование @font-face может потерять сглаживание в Safari 5
- Некоторые браузеры игнорируют font-size: 0, например Китайская версия Chrome, в таком случае font-size сбрасывается до 12px
Так что, это не лучшее решение. Как я уже говорил ранее, скорее всего буду использовать путь с комментирование пробелов. Если для вас он выглядит неудобным, вы можете вернуться к 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
html. Как устранить пробелы между встроенными элементами в CSS?
Задавать вопрос
спросил
Изменено 9 лет, 5 месяцев назад
Просмотрено 43к раз
У меня есть div с кучей тегов изображений внутри, вот пример:
<дел> jpg" alt="Foo1" />
Поскольку между тегами есть пробелы, браузеры будут отображать некоторые пробелы между изображениями (Chrome выбирает 4 пикселя). Как я могу сказать браузеру, чтобы между изображениями не отображалось НИКАКИХ пробелов, не размещая > и < непосредственно рядом друг с другом? Я знаю, что межбуквенный интервал применяется в дополнение к тому, что решит использовать браузер, так что это бесполезно даже с отрицательным значением. По сути, я собираюсь сделать что-то вроде Твиттера в нижней части своей домашней страницы. Я посмотрел на их код, и они используют неупорядоченный список. Я мог бы просто сделать это, но я хотел бы получить техническое объяснение того, почему, по-видимому, нет способа устранить пустое пространство между этими изображениями.
- html
- css
- пробел
- удаление пробелов
2
Если вы по какой-то причине хотите это сделать:
- без использования
float
s, и; - без свертывания пробелов в вашем HTML (что является самым простым решением, и для чего оно стоит, что делает Твиттер)
Вы можете использовать решение отсюда:
Как убрать пробел между элементами встроенного блока?
С тех пор я его немного усовершенствовал.
См.: http://jsfiddle.net/JVd7G/
межбуквенный интервал: -1px
для исправления Safari.
раздел { размер шрифта: 0; межбуквенный интервал: -1px } <дел>