Как я * действительно * оправдываю горизонтальное меню в HTML + CSS? - PullRequest
85 голосов
/ 08 сентября 2008

Вы найдете множество учебных пособий по строкам меню в HTML, но для этого конкретного (хотя и ИМХО общего) случая я не нашел никакого достойного решения:

#  THE MENU ITEMS    SHOULD BE    JUSTIFIED     JUST AS    PLAIN TEXT     WOULD BE  #
#  ^                                                                             ^  #
  • Существует разное количество текстовых пунктов меню, а разметка страницы плавная.
  • Первый пункт меню должен быть выровнен по левому краю, последний пункт меню должен быть выровнен по правому краю.
  • Остальные элементы должны быть оптимально распределены в строке меню.
  • Число варьируется, поэтому нет возможности предварительно рассчитать оптимальную ширину.

Обратите внимание, что TABLE и здесь не будет работать:

  • Если вы центрируете все TD, первый и последний элементы не будут правильно выровнены.
  • Если вы выровняли по левому и правому краям первый соотв. последние пункты, интервал будет неоптимальным.

Не странно ли, что не существует очевидного способа реализовать это простым способом с использованием HTML и CSS?

Ответы [ 13 ]

83 голосов
/ 15 марта 2010

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

#menu {
  text-align: justify;
}

#menu * {
  display: inline;
}

#menu li {
  display: inline-block;
}

#menu span {
  display: inline-block;
  position: relative;
  width: 100%;
  height: 0;
}
<div id="menu">
  <ul>
    <li><a href="#">Menu item 1</a></li>
    <li><a href="#">Menu item 3</a></li>
    <li><a href="#">Menu item 2</a></li>
  </ul>
  <span></span>
</div>

Весь мусор внутри селектора #menu span (насколько я нашел) необходим, чтобы понравиться большинству браузеров. Он должен принудительно увеличить ширину элемента span до 100%, что должно вызвать разрыв строки, поскольку он считается встроенным элементом из-за правила display: inline-block. inline-block также делает возможным span правила стилевого уровня, такие как width, что приводит к тому, что элемент не согласуется с меню, и, следовательно, меню разрывается на строки.

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

42 голосов
/ 22 марта 2015

Современный подход - Flexboxes !

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

В этом случае вы просто установите display родительского элемента на flex, а затем измените свойство justify-content на space-between или space-around, чтобы добавить пространство между или вокруг дочерних элементов flexbox.

Использование justify-content: space-between - (пример здесь) :

ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.menu {
    display: flex;
    justify-content: space-between;
}
<ul class="menu">
    <li>Item One</li>
    <li>Item Two</li>
    <li>Item Three Longer</li>
    <li>Item Four</li>
</ul>

Использование justify-content: space-around - (пример здесь) :

ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.menu {
    display: flex;
    justify-content: space-around;
}
<ul class="menu">
    <li>Item One</li>
    <li>Item Two</li>
    <li>Item Three Longer</li>
    <li>Item Four</li>
</ul>
12 голосов
/ 05 марта 2012

Хорошо, это решение не работает в IE6 / 7 из-за отсутствия поддержки :before / :after, но:

ul {
  text-align: justify;
  list-style: none;
  list-style-image: none;
  margin: 0;
  padding: 0;
}
ul:after {
  content: "";
  margin-left: 100%;
}
li {
  display: inline;
}
a {
  display: inline-block;
}
<div id="menu">
  <ul>
    <li><a href="#">Menu item 1</a></li>
    <li><a href="#">Menu item 2</a></li>
    <li><a href="#">Menu item 3</a></li>
    <li><a href="#">Menu item 4</a></li>
    <li><a href="#">Menu item 5</a></li>
  </ul>
</div>

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

8 голосов
/ 17 марта 2010

Получил решение. Работает в FF, IE6, IE7, Webkit и т. Д.

Убедитесь, что вы не ставите пробелы перед закрытием span.inner. IE6 сломается.

При желании можно указать .outer ширину

.outer {
  text-align: justify;
}
.outer span.finish {
  display: inline-block;
  width: 100%;
}
.outer span.inner {
  display: inline-block;
  white-space: nowrap;
}
<div class="outer">
  <span class="inner">THE MENU ITEMS</span>
  <span class="inner">SHOULD BE</span>
  <span class="inner">JUSTIFIED</span>
  <span class="inner">JUST AS</span>
  <span class="inner">PLAIN TEXT</span>
  <span class="inner">WOULD BE</span>
  <span class="finish"></span>
</div>
4 голосов
/ 27 июля 2012

Работает с Opera, Firefox, Chrome и IE

ul {
   display: table;
   margin: 1em auto 0;
   padding: 0;
   text-align: center;
   width: 90%;
}

li {
   display: table-cell;
   border: 1px solid black;
   padding: 0 5px;
}
3 голосов
/ 19 октября 2013

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

Работает в Chrome, Firefox, Safari ... не знаю об IE.

Тест: http://jsfiddle.net/c2crP/1

ul {
  margin: 0; 
  padding: 0; 
  list-style: none; 
  width: 200px; 
  text-align: justify; 
  list-style-type: none;
}
ul > li {
  display: inline; 
  text-align: justify; 
}

/* declaration below will add a whitespace after every li. This is for one line codes where no whitespace (of breaks) are present and the browser wouldn't know where to make a break. */
ul > li:after {
  content: ' '; 
  display: inline;
}

/* notice the 'inline-block'! Otherwise won't work for webkit which puts after pseudo el inside of it's parent instead of after thus shifting also the parent on next line! */
ul > li:last-child:after {
  display: inline-block;
  margin-left: 100%; 
  content: ' ';
}
<ul>
  <li><a href="#">home</a></li>
  <li><a href="#">exposities</a></li>
  <li><a href="#">werk</a></li>
  <li><a href="#">statement</a></li>
  <li><a href="#">contact</a></li>
</ul>
2 голосов
/ 08 сентября 2008

Сделать это <p> с text-align: justify?

Обновление : Неважно. Это совсем не работает, как я думал.

Обновление 2 : в настоящее время не работает ни в одном браузере, кроме IE, но CSS3 поддерживает это в виде text-align-last

1 голос
/ 22 июля 2011

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

CSS:

ul {
  text-align: justify;
  width: 400px;
  margin: 0;
  padding: 0;
  height: 1.2em;
  /* forces the height of the ul to one line */
  overflow: hidden;
  /* enforces the single line height */
  list-style-type: none;
  background-color: yellow;
}

ul li {
  display: inline;
}

ul li.break {
  margin-left: 100%;
  /* use e.g. 1000px if your ul has no width */
}

HTML:

<ul>
  <li><a href="/">The</a></li>
  <li><a href="/">quick</a></li>
  <li><a href="/">brown</a></li>
  <li><a href="/">fox</a></li>
  <li class="break">&nbsp;</li>
</ul>

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

Протестировано в IE7, IE8, IE9, Chrome, Firefox 4.

1 голос
/ 08 сентября 2008

Для браузеров на базе Gecko я придумал это решение. Это решение не работает с браузерами WebKit, хотя (например, Chromium, Midori, Epiphany) они по-прежнему показывают завершающий пробел после последнего элемента.

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

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

Код:

<div style="width:500px; background:#eee;">
 <p style="text-align:justify">
  <a href="#">THE&nbsp;MENU&nbsp;ITEMS</a>
  <a href="#">SHOULD&nbsp;BE</a>
  <a href="#">JUSTIFIED</a>
  <a href="#">JUST&nbsp;AS</a>
  <a href="#">PLAIN&nbsp;TEXT</a>
  <a href="#">WOULD&nbsp;BE</a>
  <img src="/Content/Img/stackoverflow-logo-250.png" width="400" height="0"/>
 </p>
 <p>There's an varying number of text-only menu items and the page layout is fluid.</p>
 <p>The first menu item should be left-aligned, the last menu item should be right-aligned. The remaining items should be spread optimal on the menu bar.</p>
 <p>The number is varying,so there's no chance to pre-calculate the optimal widths.</p>
 <p>Note that a TABLE won't work here as well:</p>
 <ul>
  <li>If you center all TDs, the first and the last item aren't aligned correctly.</li>
  <li>If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.</li>
 </ul>
</div>

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

0 голосов
/ 18 мая 2012

Более простая разметка, протестировано в Opera, FF, Chrome, IE7, IE8:

<div class="nav">
  <a href="#" class="nav_item">nav item1</a>
  <a href="#" class="nav_item">nav item2</a>
  <a href="#" class="nav_item">nav item3</a>
  <a href="#" class="nav_item">nav item4</a>
  <a href="#" class="nav_item">nav item5</a>
  <a href="#" class="nav_item">nav item6</a>
  <span class="empty"></span>
</div>

и css:

.nav {
  width: 500px;
  height: 1em;
  line-height: 1em;
  text-align: justify;
  overflow: hidden;
  border: 1px dotted gray;
}
.nav_item {
  display: inline-block;
}
.empty {
  display: inline-block;
  width: 100%;
  height: 0;
}

Живой пример .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...