Jump to content
  • 0

Горизонтальное выравнивание блочных элементов


FRUTALITY
 Share

Что предпочитаете вы?  

8 members have voted

You do not have permission to vote in this poll, or see the poll results. Please sign in or register to vote in this poll.

Question

Здравствуйте.

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

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

О чем, собственно, речь.

Есть какой-то макет с кучей элементов. И некоторые элементы надо расположить на одной линии по горизонтали, вписав в какой-нибудь фиксированный контейнер.

3622622.jpg

Итак, какие есть способы сверстать такой "макет"?

1. Старые добрые таблицы.

Думаю, не нужно объяснять, что "таблицы для табличных данных", и вообще, поддерживать более-менее сложный макет, сверстанный таблицами — очень муторно.

2. Способ классический. Использовать float: left/right.

Код:

<!doctype html>
<html>
<head>
<title>Способ классический: float</title>
<meta http-equiv='content-type' content='text/html; charset=utf-8'>
<style>
#container{
border:1px solid #c3c3c3;
padding:40px 0;
width:400px;
}

.block{
background:#c3c3c3;
float:left;
text-align:center;
}

#block-1{
margin:0 16px 0 15px;
width:99px;
}

#block-2{
margin-right:16px;
width:59px;
}

#block-3{
width:180px;
}
</style>
</head>
<body>
<section id='container'>
<div class='block' id='block-1'>1</div>
<div class='block' id='block-2'>2</div>
<div class='block' id='block-3'>3</div>
</section>
</body>
</html>

Плюсы: кроссбраузерно.

Минусы:

  • если нужно вставить элемент ниже, то нужно применять clear:both. А когда макет действительно сложный, становится слишком много усложнений - конструкция превращается в монструозную.
  • если высота элементов не фиксированная, то в достаточно типичных макетах случаются разные неприятности (http://habrahabr.ru/post/117109/ - 3 абзац)

3. "Все правильные ребята уже давно прочитали статью в блоге Мозиллы" (с) Сергей Чикуёнок. Речь о display: inline-block, конечно же.

Способ почти идеальный. Если честно, я предпочитаю именно его, но тут есть свои заморочки. Блок, отмеченный как inline-block, ведет себя как блочный, но если ему указать ширину, то спокойно встает в одну линию с другими элементами.

Перепишу стили для примера выше (разметку не трогаю):

<!doctype html>
<html>
<head>
<title>Способ правильный: inline-block</title>
<meta http-equiv='content-type' content='text/html; charset=utf-8'>
<style>
#container{
border:1px solid #c3c3c3;
padding:40px 0;
width:400px;
}

.block{
background:#c3c3c3;
/*float:left; Это убрали */
display:inline-block; /* Это добавили */
text-align:center;
}

#block-1{
margin:0 16px 0 15px;
width:99px;
}

#block-2{
margin-right:16px;
width:59px;
}

#block-3{
width:180px;
}
</style>
</head>
<body>
<section id='container'>
<div class='block' id='block-1'>1</div>
<div class='block' id='block-2'>2</div>
<div class='block' id='block-3'>3</div>
</section>
</body>
</html>

Взгляните на скриншот, что у нас получилось:

3659473.jpg

(Я использую Firebug для подсветки элементов на странице)

Обратите внимание на зеленые стрелки: первая указывает на зазор в 4 пикселя между inline-block-элементами. Вторая указывает на последствие - из-за этих зазоров уменьшилось расстояние до правой границы контейнера.

А если бы контейнер был более узким, то элемент "3" был бы перенесен на следующую линию, несмотря на то, что ширина элементов не менялась.

Как с этим бороться:

1. Достаточно "вытянуть" в одну строку html-код элементов 1-3 (зазор пропадет)

2. Либо прописывать font-size:0 для контейнера и font-size:%ваше значение% для блоков 1-3

3. Либо использовать для блоков 1-3 margin-right: -0.3em

4. Либо еще какой-нибудь костыль (полный список в комментариях здесь: http://chikuyonok.ru...vertical-align/)

5. Либо "подгонять" margin-ы между элементами.

Итак, плюсы: довольно изящное решение, все максимально понятно

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

4. Абсолютное позиционирование.

Вся соль в использовании position:absolute. Перепишу все тот же несчастный пример (разметку снова не трогаем, меняется только CSS):

<!doctype html>
<html>
<head>
<title>Способ pixel-perfect: position:absolute</title>
<meta http-equiv='content-type' content='text/html; charset=utf-8'>
<style>
#container{
border:1px solid #c3c3c3;
padding:40px 0;
position:relative; /* Добавили */
width:400px;
}

.block{
background:#c3c3c3;
/*float:left; Это убрали */
/*display:inline-block; Это тоже убрали */
position:absolute; /* Добавили */
text-align:center;
}

#block-1{
/*margin:0 16px 0 15px; Убрали */
left:15px; /* Добавили */
width:99px;
}

#block-2{
/*margin-right:16px; Убрали */
left:130px; /* Добавили */
width:59px;
}

#block-3{
left:205px; /* Добавили */
width:180px;
}
</style>
</head>
<body>
<section id='container'>
<div class='block' id='block-1'>1</div>
<div class='block' id='block-2'>2</div>
<div class='block' id='block-3'>3</div>
</section>
</body>
</html>

На этот раз, изменений больше. Способ работает совсем идеально. С точностью до пикселя.

Плюсы: получено именно то, чего хотелось, и без костылей.

Минусы:

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

5. Способ прогрессивный. Верстка по настоящей сетке с использованием display:grid.

Снова поменяю пример:

<!doctype html>
<html>
<head>
<title>Способ прогрессивный: display:grid</title>
<meta http-equiv='content-type' content='text/html; charset=utf-8'>
<style>
#container{
border:1px solid #c3c3c3;
display:-ms-grid; /* Добавили */
-ms-grid-columns:15px 99px 16px 59px 16px 180px; /* Добавили */
padding:40px 0;
/*position:relative; Убрали */
width:400px;
}

.block{
background:#c3c3c3;
/*float:left; Это убрали */
/*display:inline-block; Это тоже убрали */
/*position:absolute; Убрали */
text-align:center;
}

#block-1{
/*margin:0 16px 0 15px; Убрали */
/*left:15px; Убрали */
-ms-grid-column:2; /* Добавили */
width:99px;
}

#block-2{
/*margin-right:16px; Убрали */
/*left:130px; Убрали */
-ms-grid-column:4; /* Добавили */
width:59px;
}

#block-3{
/*left:205px; Убрали */
-ms-grid-column:6; /* Добавили */
width:180px;
}
</style>
</head>
<body>
<section id='container'>
<div class='block' id='block-1'>1</div>
<div class='block' id='block-2'>2</div>
<div class='block' id='block-3'>3</div>
</section>
</body>
</html>

Вот он, способ моей мечты. Подробно можно почитать на Хабре (http://habrahabr.ru/...ft/blog/140715/). Если вкратце: описываем контейнер как сетку. Каждому элементу назначаем место в этой сетке. И все классно.

Но есть существенные минусы:

  • в чистом виде, без префиксов, не работает вообще ни в одном браузере (это еще не стандарт, только черновик)
  • с префиксами работает только в IE 10 и выше

Пока что этот способ - в мечтах. Можно, конечно, использовать JS-библиотеки, реализующие поддержку Grid в браузерах (например, http://ecsstender.org/), но это тоже не очень классное решение.

Теперь, внимание, знатоки. Что используете вы? Есть ли изящные решения без замусоривания кода? Предлагаю обсудить данный вопрос.

Edited by FRUTALITY
  • Like 1
Link to comment
Share on other sites

14 answers to this question

Recommended Posts

  • 0
1. Старые добрые таблицы. Думаю, не нужно объяснять, что "таблицы для табличных данных", и вообще, поддерживать более-менее сложный макет, сверстанный таблицами — очень муторно.

display: table;

UPD можете добавить в голосование. Даже странно про inline-block вы написали, а про table нет.

Edited by wwt
Link to comment
Share on other sites

  • 0

6. (уже упомянули) «Не очень старые не очень добрые CSS-таблицы», в смысле display:table для контейнера и display:table-cell для элементов (плюсы те же, что у нормальных таблиц, но без ущерба для семантики, стандартный CSS2.1, главный минус — неподдержка в IE7-).

7. Модные, но с непростой судьбой флексбоксы (плюсы: специально разработаны для этой задачи, поддерживаются в том или ином виде во всех браузерах, кроме IE9- и Оперы-мини, минусы: в разных браузерах поддерживаются очень разные версии спеки, нужен зоопарк префиксов и разных синтаксисов, реализация старой спеки достаточно тормозная).

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

Немного не так. Такой блок внутри ведет себя как обычный блок, причем с отдельным контекстом форматирования (из него не выпадают float-ы и margin-ы потомков), но сам снаружи живет в инлайновом контексте, т.е. ведет себя как слово или картинка в тексте, подчиняясь св-вам text-align, vertical-align и т.п. Поэтому и пробелы между тегами для него учитываются. А ширина у него по умолчанию подстраивается по ширине контента, как и у float-а.

Link to comment
Share on other sites

  • 0
А если бы контейнер был более узким, то элемент "3" был бы перенесен на следующую линию, несмотря на то, что ширина элементов не менялась.

Я пользуюсь довольно интересным способом, подсказанным здесь ранее. Ставлю text-align:justify и генерирую для главного контейнера псевдоэлемент :after { width: 100%; display:inline-block; content: ""} И контейнеры сами встают на всю ширину и не нужно указывать маргин - они всегда будут у краев и при этом на равноудаленном расстоянии друг от друга.

Link to comment
Share on other sites

  • 0
А если бы контейнер был более узким, то элемент "3" был бы перенесен на следующую линию, несмотря на то, что ширина элементов не менялась.

Я пользуюсь довольно интересным способом, подсказанным здесь ранее. Ставлю text-align:justify и генерирую для главного контейнера псевдоэлемент :after { width: 100%; display:inline-block; content: ""} И контейнеры сами встают на всю ширину и не нужно указывать маргин - они всегда будут у краев и при этом на равноудаленном расстоянии друг от друга.

Видимо вы про что то такое http://css-live.ru/articles-css/ravnomernoe-vyravnivanie-blokov-po-shirine.html

Link to comment
Share on other sites

  • 0

Добавил вариант display:table в опрос.

Действительно, этот момент я как-то упустил. Потому что практически не использовал этот вариант. Насколько я понимаю, суть тут, в отличие от таблиц, в принципе не меняется. Представляем макет в виде таблицы (а сложный макет - в виде огромной таблицы с вложенными таблицами), разметку делаем div'ами, но в CSS отмечаем, по сути, все то же самое, что мы бы отметили тегами table, tr, td (и т.д.).

Чуть проще, но разве в поддержке не сложно?

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

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

Тут вы правы, я упростил :)

Zverushka, вы не могли бы привести пример? Для макета из моего первого поста. Кажется, или я вас не так понял, или вы меня.

Edited by FRUTALITY
Link to comment
Share on other sites

  • 0
а сложный макет - в виде огромной таблицы с вложенными таблицами

Зачем? Речь же идет о частной задаче — выстраивании блоков в ряд по горизонтали, разве нет? Для современных браузеров вполне хватает display: table для контейнера и display: table-cell для «ячеек». Из неупомянутых ранее минусов — невозможность абсолютного позиционирования относительно таких «ячеек» (как и относительно обычных, впрочем), частично решается вложенными обертками.

Сложность поддержки для CSS-таблиц, флоатов и инлайн-блоков, имхо, сопоставима. Всё-таки ни один из трех способов не предназначен напрямую для выстраивания блоков (если на то пошло, CSS-таблицы приспособлены больше других), отсюда необходимость тех или иных хаков (для флоатов — клирфиксы, для инлайн-блоков — обнуление пробелов, и т.п.).

судя по вашему описанию, тоже не подарок

Сами по себе, тем более в последней редакции спеки — именно что подарок. Вещь одного порядка с гридами, если не круче (смотря для каких задач, конечно). Но браузеры, увы... как всегда. Вот хорошая статья о них с примерами.

Link to comment
Share on other sites

  • 0
Зачем? Речь же идет о частной задаче — выстраивании блоков в ряд по горизонтали, разве нет?

Ну, я, конечно, именно такой пример привел. Очень простой. Но реальность состоит из сложных макетов. И я постоянно нахожусь в поисках идеала не для решения задачек в 10 строк, разумеется :)

Возьмем, к примеру, макет профиля во "ВКонтакте". Специально не смотрю, как он сверстан. Но просто присмотритесь: хэдер состоит из рядом стоящих элементов.

Далее - три колонки (меню, колонка с фотографией, колонка с контентом). В каждой колонке (кроме меню) снова элементы, расположенные рядом по горизонтали. По сути, весь макет ими пронизан. И они вложены друг в друга. Вложенность многоуровневая. Мне почему-то не кажется, что макет такой сложности довольно удобно будет верстать с помощью display:table. А особенно поддерживать, добавляя/убирая элементы (или вообще перекомпоновывая). Впрочем, пока у меня это лишь на уровне ощущений. Таких сложных макетов на display:table я не верстал.

За ссылки благодарю. Ознакомлюсь.

Link to comment
Share on other sites

  • 0
Но до сих пор не нашел для себя действительно удобного, идеального метода выравнивания блочных элементов по горизонтали. О чем, собственно, речь. Есть какой-то макет с кучей элементов. И некоторые элементы надо расположить на одной линии по горизонтали, вписав в какой-нибудь фиксированный контейнер. Итак, какие есть способы сверстать такой "макет"?

В зависимости от ситуации. Использую в таких случаях table-cell, inline-block, float'ы. Использовать CSS3 Flexible Box'ы в рабочих проектах пока не решаюсь из-за слабой поддержки браузерами.

Link to comment
Share on other sites

  • 0
Зачем? Речь же идет о частной задаче — выстраивании блоков в ряд по горизонтали, разве нет?

Ну, я, конечно, именно такой пример привел. Очень простой. Но реальность состоит из сложных макетов. И я постоянно нахожусь в поисках идеала не для решения задачек в 10 строк, разумеется :)

Возьмем, к примеру, макет профиля во "ВКонтакте". Специально не смотрю, как он сверстан. Но просто присмотритесь: хэдер состоит из рядом стоящих элементов.

Далее - три колонки (меню, колонка с фотографией, колонка с контентом). В каждой колонке (кроме меню) снова элементы, расположенные рядом по горизонтали. По сути, весь макет ими пронизан. И они вложены друг в друга. Вложенность многоуровневая. Мне почему-то не кажется, что макет такой сложности довольно удобно будет верстать с помощью display:table. А особенно поддерживать, добавляя/убирая элементы (или вообще перекомпоновывая). Впрочем, пока у меня это лишь на уровне ощущений. Таких сложных макетов на display:table я не верстал.

За ссылки благодарю. Ознакомлюсь.

Это вам тогда сетку лучше использовать.

Ваш пример и Вконтакт совсем разные вещи.

Одно дело меню из table-cell сделать, а другое сайт из блоков слепить.

Вы или вопрос не так поставили или начинаете не в ту сторону идти.

Для каждой задачи свое решение. Не ищите велосипед под все дороги, гайки крутить больше придется потом. (пока флекбоксы конечно всеми не станут поддерживаться =)

Edited by npofopr
Link to comment
Share on other sites

  • 0

Да, Flexbox тоже классная штука. Напоминает Grid, которую пропихивает MS. Жаль, что пока ни то, ни другое, не поддерживается всеми браузерами.

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

P.S. SelenIT, почитал у вас в блоге статью про inline-block, пару новых моментов для себя узнал. Спасибо :)

А флексбоксов / сетку ждут многие, как я посмотрю?

Link to comment
Share on other sites

  • 0
сетку

сетку? Или вы опять про что то свое или не понятно.

Сетки уже давно повсеместно используюсь.

Флекбоксы тоже не ждут, кому надо и кому позволяет ТЗ пользуются)

Link to comment
Share on other sites

  • 0

У меня тут вопросик возник. Когда мы выравниваем элементы через inline-block и &:after width 100% конструкцию, у нас остается отступ внизу. Чтобы его убрать ставим ул line-height: 0, fonts-size:0; Проблема, что при font-size:0 блоки в ослике схлопываются вообще без расстояния между друг другом. Как бы то обойти без хаков под ие?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

  • Similar Content

    • By d0ublezer0
      zebra-tara.ru
      на главной странице есть блок с популярными товарами

      чтобы его организовать, мне пришлось делить список на две части. отдельно в своём контейнере выводится большой первый элемент и далее - остальные, тоже в flex контейнере
      можно добиться такого визуального представления как-то иначе (без разделения UL списка), когда первый элемент имеет большой размер?
      мне это потребуется, чтобы на малых разрешениях навесить на этот список owl carousel, а получается, что первый элемент оторван..
      Полагаю, это можно как-то решить с колонками, а не строками, но мне этот фокус не удался
    • By sasha_anto
      Доброго времени суток. Возникла такая проблема, нужно сверстать страницу согласно макету, используя только flex и grid
      Сразу появилась идея разбить страницу на три divа, первый это блок с породами кота, второй это блок с фотками и третий блок с рейтингом.
      <body> <header>Бабуленькины котятки</header> <div class="global"> <div class="menu"> <a class="submenu" href="#" id="abis">Абиссинская</a> <a class="submenu" href="#" rel="brit"">Британская</a> <a class="submenu" href="#" rel="rus">Русская голубая</a> <a class="submenu" href="#" rel="siam">Сиамская</a> </div> <div class="cats"> <img src="http://murkote.com/wp-content/uploads/2014/03/abissinskaya-koshka-foto.jpg" alt="" class="abis"> <img src="http://murkote.com/wp-content/uploads/2015/06/australian-mist-5.jpg" alt="" class="cat"> <img src="http://murkote.com/wp-content/uploads/2015/05/American-Bobtail-Cat.jpg" alt="" class="abis"> <img src="http://murkote.com/wp-content/uploads/2015/06/american-curl-7.jpg" alt="" class="cat"> <img src="http://murkote.com/wp-content/uploads/2015/06/Anatolijskya-koshka-2.jpg" alt="" class="abis"> <img src="http://murkote.com/wp-content/uploads/2015/06/arabian-mau-1.jpg" alt="" class="cat"> <img src="http://murkote.com/wp-content/uploads/2014/03/leopardovaya-bengalskaya-koshka.jpg" alt="" class="cat"> <img src="http://murkote.com/wp-content/uploads/2015/06/Brazilian-Shorthair-cat-2.jpg" alt="" class="cat"> </div> <div class="rating"></div> </div> <footer>Подвал</footer> <style> a { color: #000 !important; text-decoration: none; } body { background-color: gainsboro; display: flex; flex-direction: column; } header { text-align: center; font-size: 40px; font-style: bold; } img { width: 250px; height: 200px; } .global { display: -webkit-flex; display: flex; justify-content: space-around; } footer { color: wheat; background: black; } div.menu { display: flex; width: 250px; flex-wrap: wrap; background: gray; align-content: flex-start; } .submenu { display:flex; justify-content: center; align-items: center; width: 100%; height: 50px; font-size: 25px; border-bottom: white 1px solid; } .cats { display: flex; flex-wrap: wrap; width: 800px; height: 900px; justify-content: space-around; } .cats img:nth-child(2){ width: 500px; } .cats img:nth-child(6) { width: 500px; } .cats img:nth-child(8) { width: 750px; } .rating { width: 250px; background: olive; } </style> Но возникла проблема, надо сделать так, чтобы при выборе категории, кошки данной породы меняли прозрачность. Так как у меня фото и породы в разных блоках, я не понимаю как это сделать. Был вариант не добавлять категории в отдельный блок, но тогда как разметить страницу? Прошу помощи, или хотя бы небольшой подсказки
    • By SnowSilver
      Почему line-height на высоту inline элемента не влияет, а на inline-block влияет ?
      Например изначально, при дефолтном размере шрифта в 16px, высота строки в хроме показывает 18.18px. И если применим line-height: 1; - то высота не изменится.
      А если мы превратим строчный элемент в inline-block, тогда высота уменьшается до 15.45px - и тогда высота строки равняется почти размеру шрифта. Хотя line-height: 1 это множитель шрифта, по идеи в моем понимание высота должна равняться 16px, а не 15.45.
      Эти значения получены у не стандартного шрифта... Но это сути не меняет.
      Небольшая заготовка - https://codepen.io/anon/pen/Qxpgoe. Правда там у строчного  элемента изначально 17px , а у инлайн блока после установки line-height:1 -  16px.
       
       
       
    • By Goreska
      https://artrises.github.io/index.html
      Всем добрый день, это моя первая работа, прошу конструктивно описать какие проблемы есть, какие ошибки допустил (хочу не вырабатывать говнокод), а постепенно реализовывать себя как толкового фронтендера. Поэтому будет важно все - мои косяки, ваши предложения, огрехи которые вы увидели в работе. И прошу помочь с одной проблемой - логотип в шапке - под ним как будто маленький маргин\паддинг, но я обнулил его, через инспектор тоже не нашел в чем проблема, какая то брешь между логотипом и контейнером оберткой.
      Заранее спасибо.
    • By Nailya
      Добрый день)
       
      Хочу узнать мнение опытных верстальщиков. Активно ли вы используете  grid: display: grid, grid-template-columns: 30px 200px auto 100px и т.д.? Или рано еще?
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy