«Загадочные отступы» между инлайн-элементами
Каждому, даже самому «молодому» верстальщику известны неприятности (проблемы) с интервалом между элементами, пробелами, которые вставляются между словами. Эти пробелы часто мешают нам при вёрстке того или иного блока. Избавиться от них бывает не так-то просто, а зачастую эти межсловные расстояния и вовсе ставят нас перед выбором, выбором способа решения данной проблемы.
В этой статье мы попытаемся понять, что же из себя представляют эти загадочные "Отступы", что это за звери и с чем их едят. Так же рассмотрим, что такое 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.
Как мы видим, браузер создаёт пустой текстовый узел, который, по сути, может являться переводом строки, пробелом или, например, табом. Все и эти перечисленные вещи превращаются в один единственный пробел и описывается следующей сущностью:  . Так же следует учитывать, что, так как пробел — это обычный символ, то, соответственно, и изменяться этот самый символ будет в зависимости от размера или семейства шрифта, т.е, по сути, вести себя точно также, как и обычная буква в строке. Всё это обязательно следует учитывать при вёрстке.
Наша задача
Перед нами стоит задача каким-то образом избавиться от этого ненавистного расстояния. Убрать, сделать его ширину нулевой, сплющить, спрятать, всё что угодно… в общем придумать какой нибудь способ, который избавит нас от этого межсловного промежутка и соединит наши пункты вплотную.
Материал для работы
Давайте поразмыслим, что же нам сможет помочь для решения этой задачи.
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 у первого пункта + подгонка значений для разных браузеров, ну и… конечно же есть доля риска, из-за которой могут быть, хоть и не большие, но какие-то отличия с отступами, при разных шрифтах и их размерах.
Вариант 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, например в пиксели.
Вариант 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. Это тоже может быть интересно:
Отличная статья , понятно , прям все по полочкам разложил )
Успехов в дальнейшем )
Спасибо!
Присоединяюсь к Максу, не смотря на то, что сам давно занимаюсь версткой, раньше использовал только минусовые маржины, а к этому вопросу снова пришел после собеседования, где задали именно этот вопрос с другими решениями.
В общем спасибо автору.
Спасибо, остановился на обнулении размеров в ul и задании их в чилдах
Спасибо за подробное исследование вопроса. Хотя использую пятый способ, другие могут быть полезны в определенных ситуациях.
Успехов!
У каждого способа есть свои плюсы и минусы. Например, у того же 5-го есть риск:
<li>бла-бла</li
><li>два</li>
тоже работает
Да, но это не очень удобная запись. Особенно в нодпаде(
1) Комментарии писать удобней? :)
2) Запись с незакрывающимися li тоже очень частный вариант, ведь с дивами такое не прокатит.
Почему не прокатит?
Я имею ввиду не конкретно потому, что это див, а если делать верстку, и раскидать блоки на инлайнах, то внутрь мы уже блочного положить ничего не сможем: http://jsfiddle.net/Softlink/YYwsd/
Не потому что это див, а потому что внутрь мы не сможем вложить блочный элемент: http://jsfiddle.net/Softlink/YYwsd/
Я имею ввиду не конкретно див, а проблему, что внутрь мы не сможем вложить блочный элемент: http://jsfiddle.net/Softlink/YYwsd/
Он имел ввиду не конкретно див, а проблему, что внутрь мы не сможем вложить блочный элемент: http://jsfiddle.net/Softlink/YYwsd/
Он имел ввиду не конкретно див, а проблему, что внутрь мы не сможем вложить блочный элемент: http://jsfiddle.net/Softlink/YYwsd/
Ну и эхо на этом сайте :)
Он имел в виду не конкретно эхо, а проблему, что внутрь мы не сможем вложить эхо на этом сайте:
http://jsfiddle.net/Softlink/YYwsd/
Видимо я что-то неправильно понял, но
http://jsfiddle.net/HHQXC/
(это был ответ на коммент 5го уровня)
К слову сказать, я верстаю на php; html, который генерируется, идет в одну строчку.
Еще вариантом убирания отступов можно считать добавлением в сайт заранее подготовленного шрифта с одним лишь пробельным символом нулевой ширины (такой шрифт будет весить совсем мало) и указанием этого шрифта для списка (ul). Естественно после необходимо переобъявить стандартный шрифт для элементов списка (li). Этот вариант позволяет не высчитывать новое значение отрицательного отступа при смене шрифта, позволяет все так же использовать относительные единицы для указания размеров шрифта и пр. вышеописанных минусов.
Если не сложно, покажи пример плз
http://jsfiddle.net/Madman/XPwnP/
Вот пример. Шрифт собрал по быстрому, в нем всего 5 символов, все нулевой длины. Кажется немного промахнулся с символом TENGE и иногда под элементами списка может образовываться зазор в 1рх (мне по крайней мере так показалось). Надо будет его немного подкорректировать. Каждый фаил шрифта весит не более 2.5КБ
Как и говорил, можно использовать относительные размеры, менять безопасно шрифт и пр.
http://jsfiddle.net/Madman/XPwnP/
Вот пример (основан на вашем примере).
Фаил шрифта собрал по быстрому, в нем всего 5 символов, все нулевой длины. Кажется не много промахнулся с символом TENGE и иногда под элементами списка может появляться зазор в 1рх (мне так показалось по крайней мере), надо будет позже его подправить.
Каждый фаил шрифта весит не более 2.5КБ
Как и говорил, можно использовать относительные величины, менять безболезненно шрифт и пр.
Странно, на jsFiddle в FF отрабатывает не правильно, возможно не подтягивает шрифты.
Вот можно глянуть тут:
http://wcart.madman.users.dev.shopxml.biz:8888/zero/
Фаил шрифта собрал по быстрому, в нем всего 5 символов, все нулевой длины. Кажется не много промахнулся с символом TENGE и иногда под элементами списка может появляться зазор в 1рх (мне так показалось по крайней мере), надо будет позже его подправить.
Каждый фаил шрифта весит не более 2.5КБ
Как и говорил, можно использовать относительные величины, менять безболезненно шрифт и пр.
Спасибо большое за идею. Действительно отличный способ.
Надо будет попробовать соорудить какой нибудь шрифт с ещё меньше весом! Если будут результаты, сообщим.
Вот пример (основан на вашем примере) http://jsfiddle.net/Madman/XPwnP/
Фаил шрифта собрал по быстрому, в нем всего 5 символов, все нулевой длины. Кажется не много промахнулся с символом TENGE и иногда под элементами списка может появляться зазор в 1рх (мне так показалось по крайней мере), надо будет позже его подправить.
Каждый фаил шрифта весит не более 2.5КБ
Как и говорил, можно использовать относительные величины, менять безболезненно шрифт и пр.
Update: на jsFiddle в FF отрабатывает не правильно, возможно не подтягивает шрифты.
Вот можно глянуть тут:
http://wcart.madman.users.dev.shopxml.biz:8888/zero/
отличная статья.
вот это немного не по русски «Одно из главных вещей, которые вы должны знать»
Спасибо, поправил.
Psywalker, статья отличная, ее даже на английский переводят (правда в сокращении) :-) http://css-tricks.com/fighting-the-space-between-inline-block-elements/
На самом деле не удивительно. Материал действительно уникальный и очень полезный!
На мой взгляд, в полноценной верстке для разных проектов нельзя ни привязываться к конкретному шрифту, ни использовать фиксированный размер шрифта — все это меняется от проекта к проекту, требует гибкости, относительных единиц измерения и быстроты верстки при этом. Поэтому первые 4 варианта можно отметать. Пересчитывать эти -.36em каждый раз — нереально. Плюс достаточно будет юзеру изменить шрифт локально — и все разъедется. Поэтому 2 последних варианта остаются предпочтительными.
Спасибо! )
про незакрытые теги — хитро придумано
двенадцатая (по крайней мере 12.01, 12.02) Opera сделала подлянку, и теперь вариант с font-size:0; срабатывает в ней в половине случаев, при чём закономерность поведения (на одной машине работает, а на другой, с такой же конфигурацией — нет) абсолютно не понятна, как и причины такого поведения.
вариант 4 — это баг не вебкитов, а как раз ие фф и оперы.
word-spacing влияет на интервал между словами, а поскольку пункты (li) это буквы, то и влиять на них должен letter-spacing
Когда между буквами стоят пробелы — они автоматически становятся коротенькими, но всё же словами. И word-spacing обязан работать. К тому же баг в вебкитах только с инлайн-блоками, c обычным display:inline word-spacing работает и там.
вариант 4 с word-spacing: -.39em; в chrome 28 под linux и windows работает нормально
Да, в 25-й версии баг, о котором говорится в статье, исправили. Но этим поломали немало решений, которые рассчитывали на этот баг.
Самый удобный вариант с коментариями! ИМХО вариант с незакрытыми li подходит только если у вас в нем лежит 1, ну максимум 2 элемента. Этот вариант абсолютно не практичен при верстке многоярусного меню (2 и более уровня вложенности), выводе анонсов новостей или списка товаров на витрине магазина, что тоже часто густо делается inline-block'aми (когда например, в карточке товара лежит картинка, описание, "звездочки", ссылка на отзывы, цены старая и акционная и ещё что-то). В общем удобнее раз привыкнуть к комментариям и все гуд. особенно в N++ и других блокнотах с подсветкой.
Если изначально написать вот так:
<ul>
<li>Пункт 1</li><li>Пункт 2</li><li>Пункт 3</li><li>Пункт 4</li><li>Пункт 5</li>
</ul>
то проблема уже не будет. Это лучше чем оставлять li без закрытия. Ну во всяком случае красивей и более валидно
Это 6-й ввриант из статьи. Кстати, необязательно писать в одну строку весь код — главное, чтобы пробелов не было между </li><li>.
Насчет красоты варианта с незакрытыми (точнее, неявно закрытыми) тегами — вопрос субъективных привычек и принятых в коллективе конвенций (напр. гайдлайны Гугла утверждают, что «байты — деньги» и призывают экономить на всём, что только позволяет стандарт). Насчет «валиднее» — настоятельно рекомендую ознакомиться с этой статьёй (потом можно будет и
похоливоподтскутировать).Вариант номер 2. Я взял код из вашего примера и добавил:
ul li {
float: left;
}
Отспуп исчез.
Вот ссылка на полную версию http://jsfiddle.net/5Yq8u/
Или я вообще не понимаю о чем речь )))) Если что то мой email: web_my_web@ukr.net
…вместе с инлайн-блочным поведением как таковым:). Логично, что если не пользоваться инлайн-блоками, то и их специфических проблем не будет. Но у плавающих блоков свои проблемы.
Ура!!! спасибо автору за статью, как раз такая проблема сейчас возникла, и совершенно случайно наткнулся на эту статью. Почему случайно? потому-что искал я решение совсем для другой проблемы, а тут сюрприз меня ждал. Спасибо…!
Как не было нормального решения, так и нет. Нормальное решение мне видится, или специальный тег, код внутри которого воспринимается одной строкой, или специальное css-свойство для контейнера убивающее все пробелы, ну а самое главное это иметь один движок для всех браузеров.
Незакрытые теги это неправильно, это быдло-код. ИМХО.
Вот еще вариант, нечто среднее между одной строкой и использованием комментов, пустые строки вбил специально
<ul id="ull">
<li>one
</li><li>two
</li><li>three
</li>
</ul>
#ull li {display:inline-block; background:pink;}
С недавних (относительно) пор нормальное решение есть, назвается флексбоксы. Пробелы между инлайн-блоками — не проблема, поэтому ее и «решать» не надо. Проблема была в отсутствии нормального механизма горизонтальной раскладки, вынуждавшая использовать хаки на основе др. механизмов, предназначенных для другого. Теперь такой механизм есть.
Один движок для всех у нас уже был 14 лет назад. Круто было только первых пару лет:). Пусть уж будут разные движки, адекватно реализующие единый, детально и понятно написанный стандарт
в опере пример с font-size не работет
Я принципиален и не могу допустить, чтобы на одной строчке в коде было несколько пунктов, одна строчка — один пункт. Идея с заменой комментарием хороша. Но я буду пользоваться не закрытым тегом. Большое спасибо.
Уважаемый Psywalker, нуждаюсь в вашем совете. Занимаюсь изучением верстки, потому как хочу обрести новую профессию.Поэтому для меня очень важно определиться.Прошла двухнедельные курсы html, css,где обучили элементарной структуре построения сайта и элементарным тегам.Информацию воспринимать было не так уж сложно. Когда читаешь обучающие сайты, тоже понятно, но как только начинаешь применять на практике, возникают огромные проблемы, так как описанного результата часто не получается, в т.ч. и со строчно-блочными элементами.Также столкнулась с проблемой, когда на разных обучающих сайтах принципы действия одних и те же тэгов описываются по разному.Вопрос:это так только мне сложно разобраться?У меня с математикой всегда было хорошо.Или чтобы разобраться в тэге, нужно протестить его со всех сторон, так сказать провести целую исследовательскую работу.Сайт htmlbook.u хорош, но в полной мере не описывает все возможности тэгов.Очень прошу совета, так как не хочется зря потратить время в случае, если профессия не для меня(или я не для нее):)
Ольга, здравствуйте!
Я лично считаю, что если вы ставите себе какую-то цель и упорно её добиваетесь, то в конечном счёте у вас обязательно всё получится. Главное не лениться, влюбиться в своё занятие и никогда не сдаваться.
Что касается строчно-блочных элементов и т.д, я бы посоветовал вам обязательно очень внимательно прочитать нашу книжку: http://css-live.ru/articles/obzor-inlajnovyj-kontekst-formatirovaniya.html
А так же вот эту статью, где я описываю свой путь верстальщика: http://css-live.ru/faq/put-verstalshhika.html
Из этой статьи вы сможете подчерпнуть много полезного.
Удачи вам!:)
Спасибки за труд! Красава!
Друзья, помогите убрать отступы между div. Учусь пока. Сильно не ддосить просьба) http://37.193.79.122/
О каких отступах идёт речь? Покажите на скриншотах пожалуйста.
Режим телепата подсказывает, что вопрос о разрывах между блоками, вызванных «вываливанием» из них верхних margin-ов заголовков (частный случай margin collapsing). Классические решения — добавление контейнеру верхнего padding-а или невидимого border-а, либо добавление к нему ::before с display:table (как в micro clearfix), либо выделение его в отдельный блочный контекст форматирования (напр. overfow:hidden), по ситуации. Если моя телепатилка не глючит, конечно:)
Спасибо автору за полезную статью!
Хорошая статья. Очень помогла. Час бился над своей проблемой, материал помог решить вопрос за 5 минут.
Огонь ! То что искал.
Спасибо, мой внучак иди супчыка налью! Добру статью написал!
Пункт 1Пункт 2Пункт 3Пункт 4Пункт 5
Просто, валидно )
хех, экранировать что ли
<ul
><li>Пункт 1</li
><li>Пункт 2</li
><li>Пункт 3</li
><li>Пункт 4</li
><li>Пункт 5</li
></ul>
По сути это вариант варианта 5. Кстати, скобку от <u;> можно и не переносить. Да, вариант имеет право на жизнь, но читабельность страдает, другие члены команды (напр. программист, прикручивающий шаблон) могут сильно удивиться.
Вообще в 2015-м актуальность проблемы под большим вопросом — есть же флексбоксы, которые умеют всё то же самое, что инлайн-блоки, но не зависят от оформления кода. А для старья, которому всё равно одна дорога на изящную деградацию, и пробелы не особо испортят картину…
Строки внутри ul в исходнике отбиты табуляцией, для повышения читаемости и всего такого. Единственное отличие от «№5» — экономия семи символов на каждый перенос ) А так-то да, прогресс шагает семимильными шагами.
Спасибо за исследования этого вопроса!
А как насчет white-space:nowrap ?
Он не сжимает пробелы, только запрещает переносы. Теоретически, помог бы word-spacing:-100% из CSS Text 3, но его, насколько я в курсе, ни один браузер так и не поддержал, так что эту возможность могут удалить из спецификации.
Печально, с учётом того, что значение по-умолчанию — normal, можно было бы поставить его для потомков и вот оно простое и красивое решение.
А конкретно для символа переноса задать нулевое значение в CSS нельзя?
Насколько мне известно — только сделав свой шрифт, в котором у символа пробела (перенос отображается всё равно как пробел, согласно п. 16.6.1 спеки) нулевая ширина. Чуть выше в комментариях даже был пример.
В черновике CSS Text 4 предлагается text-space-collapse: discard, но с пометкой, что это очень сырая идея и всё (включая имя свойства) еще может поменяться.
Красава! Я минут 20 тупил откуда отступы и почему их не видят инструменты разработчика.
ППц, я в шоке….Потратил почти 2 часа….
Решил просто в троку div и пофик на неудобность правки кода.
Статья супер.
Хороший пост. Очень помог)
Огромное спасибо за статью.
В действительности, статья написана для хорошего продвижения в поисковиках, а не для людей.
Да ладно! Это первая проблема, с которой я зашёл на htmlform и статья мне очень помогла.
Спасибо за возможность сравнить решения и за информацию по их поддержке браузерами.
Спасибо за статью, очень понятно для начинающих!
Только у меня вопрос возник (может из-за моей неосведомленности), почему во 2 варианте, когда мы изменяем размер родительского шрифта на 0, свойство font остается со значением 14px?Нельзя ли сюда подставить значение 0?)
заранее спасибо за ответ!
Можно.
Просто, думаю, такая запись, как в статье — нагляднее.
А вообще, Вы можете сами заниматься экспериментаторством в песочнице, вроде jsfiddle.net.
Спасибо)
Отличная статья. Очень понравился способ с комментариями, меньше всего хлопот с ним!
Аналогичную статью я недавно опубликовал на хабре https://habrahabr.ru/blogs/css/137582/ НЕ РАБОТАЕТ — 404
Отлично, почти без воды. Редко благодарю на просторах сети. Но здесь вот: благодарю!
Огромное спасибо))) Победил отступ между inline-block. Очень не удобно рассчитывать ширину inline-block зная ширину родителя. А так все путем. Автор молодец, полезно)
Лекция на ура! Все внятно, понятно и с душой!
Благодарю!
Всем привет.
Однозначно работать с letter-spacing и word-spacing не стоит
по нормальному в современных браузерах нужно юзать display: flex
а для олдскульных (ie7-8)
ul {
display: table;
font-size: 0;
width: 100%;
}
ul li {
dispay: inline-block;
vertical-align: top;
width: 20%;
}
Почему тут точка?
margin-left: -.36em;
Это -0.36em. Ноль в такой записи разрешается опускать (как и в JS, кстати).
Спасибо, помогло.
Благодарю за подсказку использовать letter-spacing, очень помогло!
А можно ли сделать как-то инлайн блок с буквой внутри, чтоб он не удлинял строчку, в которой лежит? То есть я хочу чтоб он лежал в этой строчке, влиял на её высоту, но, при этом, в идеале, вообще не имел ширины, ну или, чтоб его ширина (с учётом шрифтового отступа между инлайн-блоком и соседним элементом) была не большой и строго заданной (чтоб его можно было учесть при проставлении в марджинах. и в разном окружении (браузер, ОС, что там ещё может влиять), она если и различалась, то очень незначительно).
Последний способ не реализовать, если использовать шаблонизаторы, например Pug.
они все равно закроют теги, правда можно минимизировать html код и тогда пробелы будут удалены автоматически.
Да, с шаблонизаторами и проще, и правильнее всего настроить их на честное убирание пробелов. Остальные способы во многом вынужденные, компромиссные. К счастью, сейчас, в эру общедоступных флексбоксов, решать эту задачу инлайн-блоками (и бороться с их ограничениями) вообще практически не приходится — разве что в качестве фолбэка для 2% ископаемых браузеров..:)
border:-4px;
Помог margin-right: -4px;
Зачетная статья, познакомился с различными вариантами. Как для общего развития, вполне нормально, а так, это уже старые проблемы.