Разделители в меню
Довольно часто на практике встречаются меню с разделителями - например:

О том как сделать такое меню с минимумом правильного HTML кода и пойдет дальше речь.
HTML
Очевидным HTML для подобных конструкций служит ненумерованный список UL, вот например такой:
- <ul id="nav">
- <li><a href="#">Главная</a></li>
- <li><a href="#">Новости</a></li>
- <li><a href="#">Каталог</a></li>
- <li><a href="#">Рейтинг</a></li>
- </ul>
Конечно если бы мы тупо и цинично рубили бабло © мы могли бы написать что то вроде:
- <a href="#">Главная</a> | <a href="#">Новости</a> | <a href="#">Каталог</a> | <a href="#">Рейтинг</a>
Но по причине совсем не циничной рубки (© Flack), а так же истокам проблемы с этим меню, и вдобавок семантики кода так лучше не поступать.
Как обычно делалось
Обычно для получения результата - то есть меню с вертикальными разделителями, приходилось задавать левую (или правую) границу для каждого элемента(здесь я опускаю код позиционирующий меню, он есть в примерах):
- #nav li{border-left:1px solid #000}
Таким образом мы получали что то вроде:

Не совсем то что нам надо, так как разделители на то и разделители что бы быть только между пунктами, а они у нас сейчас находятся просто слева от каждого пункта. Ранее эта проблема для меня решалась вставкой класса для первого элемента:
- <ul id="nav">
- <li class="first"><a href="#">Главная</a></li>
- …
И потом добавлением правила:
- #nav li.first{border:none}
И все вроде бы работает как надо. Но. Оба эти подхода(с class=”first” и с текстовыми разделителями “|”) требуют от нас несимметричной генерации элементов - надо различать первый и все остальные LI.
Проблема(лень)
Так как мои меню генерировал движок, то для вставки этого класса пришлось бы менять код движка, а лезть туда мне было лень. Отсюда родилось решение как сделать такие разделители не вставляя никаких классов и оперируя лишь обычным списком.
Решение
Идея простая как 5 копеек. Вот весь код:
- #nav{
- overflow:hidden;/* что бы UL растянулся до содержимых float во всех броузерах кроме ИЕ, а так же для нашего “обрезания”*/
- width:100%;/* что бы UL растянулся до содержимого в ИЕ, к самому трюку имеет косвенное отношение*/
- }
- #nav li{
- margin-left:-1px;/*сдвигаем все элементы влево*/
- }
Суть такова. Задаем overflow:hidden для UL - таким образом все что выходит за пределы блока UL отображаться не будет. Затем задаем margin-left:-1px для всех элементов списка, то есть первый элемент выйдет на 1 пиксель за пределы элемента UL, но это как раз и будет тот лишний злополучный первый разделитель! Все же остальные разделители останутся в деле - так как не выйдут за пределы блока. А первый будет скрыт. В результате получим:

Смотреть пример
Идея
Эта же идея только с заменой на border-top и margin-top:-1px сработает и для таких меню:

Смотреть пример
Более того такой прием можно применять и для графических разделителей. Будь они даже потолще одного пиксела - просто придётся задавать больший отрицателый отступ для элементов списка.
В конце
Хотя прием и довольно узкоспециализированный но мне сэкономил время, да и идея мне понравилась. Тестировалось и работает во всех моих виндошных броузерах(IE5-7, FF, Opera). Думаю работает везде.
- Рабочий пример для горизонтальных разделителей
- Рабочий пример для вертикальных разделителей
- “Навигация по-русски” - пост двухлетней жавности про эту идею
Буду рад услышать Ваше мнение или приемы по этому поводу!
Твоя обнаглел совсем :))
Извини, ты прав ) я забыл © добавить
Строго говоря:
а). я так не делаю :)
б). если пунктов мало, то действительно лучше сделать через «|», особенно когда речь идет о вторичной информации (см. футер старого browsing.ru).
в). без стилей смотрится ничуть не хуже :)
Я все же неправильно расставил ударения. Суть не в том что б делать не “цинично”, а в том что реализация циничного варианта в данном случае не легче чем class=”first”. В движке я имею ввиду.
Если делать списком как я говорю - все элементы получатся симметричными-одинаковыми. А в “циничном” варианте все равно надо будет различать где первый и последний в движке, что бы по краям не стояли |…
Да и что б было понятно откуда ноги - http://horo.ukr.net/ (внизу страницы). Но для маленьких, вторичных и не генерируемых из движка - согласен полностью.
“Конечно если бы мы тупо и цинично рубили бабло мы могли бы написать что то вроде…” ))))))))
Классная статья! То, что я давно искал!
Спасибо.
Браво! Публика в восхищении!
Особенно по радовало,что можно работать с бэгграундами,а еще интересно float:left вместо привычного display:inline, хотя,трюк работает и с display-inline,вот только возможность поиграться с бордерами пропадает.Еще раз-публика в восхищении :)
upd:поиграться не с бордерами,а с паддингами вверху и внизу
Оригинально! Давно боролся с этим! Теперь буду умнее :))
хм, интересный подход, но вот если мне нужно сделать разделители меньше чем высота блока, то этот вариант не пройдет =\
1) высота блока в данном случае расплывчатое понятие - задавай padding-top меньше и будет меньше высота. Но если ты имел ввиду высоту шрифта то 2)
2) используй фоновую картинку - если она будет шириной в один пиксель - то подход полностью катит. Больше пикселей? больше margin-left:-X
Вроде бы ответил?
Ай маладэээц, теперь я знаю как мне быстро “умирающие в градиенте” бордеры сделать для нового меню и не париться, сэнкс.
Да, присоединяюсь к Zigzag — обычно хочется границы совсем не высоты бордера, а меньше и аккуратнее. Но способ этот я пробовал когда-то.
Спасибо за способ. Я сам сталкивался с этой проблемой не раз, но всегда правил для этого HTML. Теперь будем знать.
Почти оффтопик: не “прийдётся”, а “придётся”. :)
Так всегда и делаю, мне этот трюк казался очевидным. :)
2Mourner: Да, спору нет, это просто - но мне нравится какая то изящность что ли, этой идеи. Что то в этом есть. И как видишь не все знали. Я за обмен опытом ;)
2Michael Yakovis: Для маленьких артинок придётся оперировать не границами а фоновыми картинками - но техника вроде бы особо не опирается именно на границы. Просто заменяем border-left на background:…. 0 50%. И дело в шляпе.
2Странник: Спасибо! Действительно провинился! Поправил.
Действительно абсолютно прозрачный метод, в таком применении почему то не додумывался, хотя иногда могло бы стать легче, спасибо.
И теперь в подтверждение всему выше сказанному предлагаю переделать меню, находящееся внизу блога на “не для тупого рубежа бабла div#footer > p > a”, а листингами ;)
Все думал кто же первый уличит :)
У меня просто фобия какая то развилась - уже год не менял ни CSS ни HTML на блоге. Тут только зацепись… перфекционизм тут же погубит меня :)
Просто вдобавок ко всему это как раз то маленькое-вторичное и не генерируемое из движка меню
Перфекцтонизм- зло.
а вот вариант с “|” разделителями и намёком на css3:
хорошие броузеры:
#nav li {display:inline;}
#nav li:before {content:”\007C\00A0″;}
#nav li:first-child:before {content:”";}
он:
#nav li {behavior:expression(!this.before ? (previousSibling != null ? this.before = this.innerHTML = ‘| ‘ + this.innerHTML : ” ): ”);}
Я бы обошелся CSS2:
#nav > li + li{border-left:1px solid #ccc}
:)
Но спасибо за интеерсный вариант для ИЕ )
overflow: hidden как инструмент вёрстки — вообще полезная штука. ;-)
Правда, ты забыл о _положительном_ поле с противоположной стороны каждого элемента списка — для компенсации циклического сдвига элементов и соответствующего «наезжания» их друг на друга:
#nav LI {margin-left: -1px; margin-right: 1px; }
Идея супер! Особенно нравится “автоматическое” убирание лишних разделителей слева в случае, если ссылки не помещаются в одну строку. Этого не добиться ни какими CSS3!
5+
MT: спасибо за совет! Я пренебрегал тем одним пикселом :)
Когда прочитал:
> как сделать такое меню с минимумом правильного HTML кода
Долго втыкал: это “правильный код, которого мало” или “минимально правильный код”?
:-)
наверно надо было писануть:
“с минимумом максимально правильного”
:-)
полезная идея!
Интересно
каким образом горизонтальное меню выравнять по правому краю? :/
float:right для LI
или
display:inline для LI
и text-align:right для UL
или
float:left для LI
и float:right для UL
ага!!! лень это проблема всех проблем!!!
Клево, спасибо!
Ув. Серёга лень это двигатель прогресса, если бы люди в силу лени не старались всячески упростить свой труд любыми путями прогресс стоял бы на месте… :)
есть несколько более сложный метод :)
http://q-zma.rajaka.net/2006/11/24/css3-selektory-first-child-i-last-child/
Да, довольно неплохое меню. Но очень часто приходится делать горизонтальное меню с выпадающим списком, а вот именно с ним и возникают проблемы. Валидности достичь можна, а вот адекватной работы во всех броузерах - практически нет. Приходится выбирать одно из двух - или валидность или нормальную работу. Я лично выбираю второй вариант.
а слово “лень” - это не акроним :P
а вобще очень интересно, до этого всегда использовал присваивание класса к первому пункту)
Не скажу что я консерватор, но если в движке сайта присутсвует шаблонизатор, то всё-таки лучше использовать дополнительный класс, ну тольок в том случае если меню содержит не поростой разделитель. Вообще всегда использую класс, т.к. это читабельней и гибче.
А как это меню выровнять по центру страницы для всех браузеров?
В частности для IE6?
Для FF, Opera’ы и Safari я сделал так:
ul {
display: table;
margin: 0 auto;
}
li {
display: inline;
margin: 0 1px 0 -1px;
}
IE стал показывать у первого пункта меню разделитель :(
Решение весьма элегантное
Код семантически верный
Спасибо-часто использую этот вариант
2Евгений
http://css-tricks.com/examples/CenterHorizontalListItems/
Отлично!!! Давно хотела узнать как это делается без first и last для li.
Автору Респект!
Это все хорошо. Но как быть, если разделители должны быть графические? Думал-думал как сделать и пока только с ужасным нарушением семантики кое-что придумал).
Тьфу, извиняюсь, невнимательно прочитал.
Поднимаю вопрос, заданый Евгением (38 комментарий): а как это меню выровнять по центру страницы для всех браузеров?
Попробуйте вот этот вариант http://mauzon.com/?p=87
Благодарю! Помогло. Выкладываю решение:
Горизонтальное меню | выровненное по центру | с вертикальными разделителями
#navBox {
float: left;
left: 50%;
position: relative;
}
#navBox ul {
position: relative;
left: -50%;
float: left;
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
}
#navBox li {
float: left;
border-left: 1px #000 solid;
margin-left: -1px;
margin-top: 1px;
padding: .3em 1em;
}
#navBox a {
color: #000;
text-decoration: none;
font-weight: bold;
}
#navBox a:hover { text-decoration:underline; }
<ul>
<li><a href="#">Главная</a></li>
<li><a href="#">Новости</a></li>
<li><a href="#">Каталог</a></li>
<li><a href="#">Рейтинг</a></li>
</u>
Я нарыл еще один способ того, как выровнять меню (список) по центу: http://kizu.ru/webdev/inline-block-solved/
Но вот замутить вертикальные разделители с помощью этого метода не получится. Во всяком случае, мне не удалось.
Тьфу какая бяка получилась. Юра, можешь сделать, чтобы мой ХТМЛ было видно? А то получилось фиг знает что.