Разделители в меню

05 Nov, 2006

Довольно часто на практике встречаются меню с разделителями - например:
Меню с разделителями
О том как сделать такое меню с минимумом правильного HTML кода и пойдет дальше речь.

HTML

Очевидным HTML для подобных конструкций служит ненумерованный список UL, вот например такой:
  1. <ul id="nav">
  2. <li><a href="#">Главная</a></li>
  3. <li><a href="#">Новости</a></li>
  4. <li><a href="#">Каталог</a></li>
  5. <li><a href="#">Рейтинг</a></li>
  6. </ul>
Конечно если бы мы тупо и цинично рубили бабло © мы могли бы написать что то вроде:
  1. <a href="#">Главная</a> | <a href="#">Новости</a> | <a href="#">Каталог</a> | <a href="#">Рейтинг</a>
Но по причине совсем не циничной рубки (© Flack), а так же истокам проблемы с этим меню, и вдобавок семантики кода так лучше не поступать.

Как обычно делалось

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

Проблема(лень)

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

Решение

Идея простая как 5 копеек. Вот весь код:
  1. #nav{
  2. overflow:hidden;/* что бы UL растянулся до содержимых float во всех броузерах кроме ИЕ, а так же для нашего "обрезания"*/
  3. width:100%;/* что бы UL растянулся до содержимого в ИЕ, к самому трюку имеет косвенное отношение*/
  4. }
  5. #nav li{
  6. margin-left:-1px;/*сдвигаем все элементы влево*/
  7. }
Суть такова. Задаем overflow:hidden для UL - таким образом все что выходит за пределы блока UL отображаться не будет. Затем задаем margin-left:-1px для всех элементов списка, то есть первый элемент выйдет на 1 пиксель за пределы элемента UL, но это как раз и будет тот лишний злополучный первый разделитель! Все же остальные разделители останутся в деле - так как не выйдут за пределы блока. А первый будет скрыт. В результате получим: Меню с разделителями Смотреть пример

Идея

Эта же идея только с заменой на border-top и margin-top:-1px сработает и для таких меню: Меню с горизонтальными разделителями Смотреть пример Более того такой прием можно применять и для графических разделителей. Будь они даже потолще одного пиксела - просто придётся задавать больший отрицателый отступ для элементов списка. Таким образом это работает и для разделителей в виде картинки.

В конце

Хотя прием и довольно узкоприменимый, но мне сэкономил время, да и идея мне понравилась. Тестировалось и работает во всех моих виндошных браузерах(IE5-7, FF, Opera). Думаю работает везде. Буду рад услышать Ваше мнение или приемы которые вы используете!

61 комментариев к “Разделители в меню”

1.StraNNicK | 07 Nov, 2006
Почти оффтопик: не "прийдётся", а "придётся". :)
2.Александр Шабуневич | 06 Nov, 2006
Спасибо за способ. Я сам сталкивался с этой проблемой не раз, но всегда правил для этого HTML. Теперь будем знать.
3.akella | 09 Nov, 2006
Все думал кто же первый уличит :) У меня просто фобия какая то развилась - уже год не менял ни CSS ни HTML на блоге. Тут только зацепись... перфекционизм тут же погубит меня :) Просто вдобавок ко всему это как раз то маленькое-вторичное и не генерируемое из движка меню
4.IDcontent | 06 Nov, 2006
Ай маладэээц, теперь я знаю как мне быстро "умирающие в градиенте" бордеры сделать для нового меню и не париться, сэнкс.
5.Michael Yakovis | 06 Nov, 2006
Да, присоединяюсь к Zigzag -- обычно хочется границы совсем не высоты бордера, а меньше и аккуратнее. Но способ этот я пробовал когда-то.
6.tapazukk | 05 Nov, 2006
Браво! Публика в восхищении! Особенно по радовало,что можно работать с бэгграундами,а еще интересно float:left вместо привычного display:inline, хотя,трюк работает и с display-inline,вот только возможность поиграться с бордерами пропадает.Еще раз-публика в восхищении :)
7.tapazukk | 05 Nov, 2006
upd:поиграться не с бордерами,а с паддингами вверху и внизу
8.Игорь | 05 Nov, 2006
Оригинально! Давно боролся с этим! Теперь буду умнее :))
9.Zigzag | 06 Nov, 2006
хм, интересный подход, но вот если мне нужно сделать разделители меньше чем высота блока, то этот вариант не пройдет =\
10.Mkdir | 05 Nov, 2006
"Конечно если бы мы тупо и цинично рубили бабло мы могли бы написать что то вроде..." )))))))) Классная статья! То, что я давно искал! Спасибо.
11.Flack | 05 Nov, 2006
Твоя обнаглел совсем :))
12.akella | 05 Nov, 2006
Извини, ты прав ) я забыл © добавить
13.Flack | 05 Nov, 2006
Строго говоря: а). я так не делаю :) б). если пунктов мало, то действительно лучше сделать через «|», особенно когда речь идет о вторичной информации (см. футер старого browsing.ru). в). без стилей смотрится ничуть не хуже :)
14.akella | 05 Nov, 2006
Я все же неправильно расставил ударения. Суть не в том что б делать не "цинично", а в том что реализация циничного варианта в данном случае не легче чем class="first". В движке я имею ввиду. Если делать списком как я говорю - все элементы получатся симметричными-одинаковыми. А в "циничном" варианте все равно надо будет различать где первый и последний в движке, что бы по краям не стояли |... Да и что б было понятно откуда ноги - http://horo.ukr.net/ (внизу страницы). Но для маленьких, вторичных и не генерируемых из движка - согласен полностью.
15.akella | 06 Nov, 2006
1) высота блока в данном случае расплывчатое понятие - задавай padding-top меньше и будет меньше высота. Но если ты имел ввиду высоту шрифта то 2) 2) используй фоновую картинку - если она будет шириной в один пиксель - то подход полностью катит. Больше пикселей? больше margin-left:-X Вроде бы ответил?
16.akella | 07 Nov, 2006
2Mourner: Да, спору нет, это просто - но мне нравится какая то изящность что ли, этой идеи. Что то в этом есть. И как видишь не все знали. Я за обмен опытом ;) 2Michael Yakovis: Для маленьких артинок придётся оперировать не границами а фоновыми картинками - но техника вроде бы особо не опирается именно на границы. Просто заменяем border-left на background:.... 0 50%. И дело в шляпе. 2Странник: Спасибо! Действительно провинился! Поправил.
17.Mourner | 07 Nov, 2006
Так всегда и делаю, мне этот трюк казался очевидным. :)
18.Vadim | 09 Nov, 2006
Действительно абсолютно прозрачный метод, в таком применении почему то не додумывался, хотя иногда могло бы стать легче, спасибо. И теперь в подтверждение всему выше сказанному предлагаю переделать меню, находящееся внизу блога на "не для тупого рубежа бабла div#footer > p > a", а листингами ;)
19.ZeT | 14 Nov, 2006
а вот вариант с "|" разделителями и намёком на 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 : '' ): '');}
20.akella | 14 Nov, 2006
Я бы обошелся CSS2: #nav > li + li{border-left:1px solid #ccc} :) Но спасибо за интеерсный вариант для ИЕ )
21.IDcontent | 09 Nov, 2006
Перфекцтонизм- зло.
22.akella | 15 Nov, 2006
MT: спасибо за совет! Я пренебрегал тем одним пикселом :)
23.MT | 15 Nov, 2006
overflow: hidden как инструмент вёрстки — вообще полезная штука. ;-) Правда, ты забыл о _положительном_ поле с противоположной стороны каждого элемента списка — для компенсации циклического сдвига элементов и соответствующего «наезжания» их друг на друга: #nav LI {margin-left: -1px; margin-right: 1px; }
24.FataL | 15 Nov, 2006
Идея супер! Особенно нравится "автоматическое" убирание лишних разделителей слева в случае, если ссылки не помещаются в одну строку. Этого не добиться ни какими CSS3! 5+
25.Иван Сагалаев | 21 Nov, 2006
Когда прочитал: > как сделать такое меню с минимумом правильного HTML кода Долго втыкал: это "правильный код, которого мало" или "минимально правильный код"? :-)
26.akella | 21 Nov, 2006
наверно надо было писануть: "с минимумом максимально правильного" :-)
27.tobto | 24 Nov, 2006
полезная идея!
28.CooperTV | 20 Dec, 2006
Интересно
29.alex | 05 Jan, 2007
каким образом горизонтальное меню выравнять по правому краю? :/
30.akella | 06 Jan, 2007
float:right для LI или display:inline для LI и text-align:right для UL или float:left для LI и float:right для UL
31.Серёга | 27 Jan, 2007
ага!!! лень это проблема всех проблем!!!
32.Jurij Burkanov | 08 Feb, 2007
Клево, спасибо!
33.Vladson | 10 Feb, 2007
Ув. Серёга лень это двигатель прогресса, если бы люди в силу лени не старались всячески упростить свой труд любыми путями прогресс стоял бы на месте... :)
34.Q-Zma | 22 Mar, 2007
есть несколько более сложный метод :) http://q-zma.rajaka.net/2006/11/24/css3-selektory-first-child-i-last-child/
35.Ззаработок в Интернет | 23 Mar, 2007
Да, довольно неплохое меню. Но очень часто приходится делать горизонтальное меню с выпадающим списком, а вот именно с ним и возникают проблемы. Валидности достичь можна, а вот адекватной работы во всех броузерах - практически нет. Приходится выбирать одно из двух - или валидность или нормальную работу. Я лично выбираю второй вариант.
36.ogonkov | 31 May, 2007
а слово "лень" - это не акроним :P а вобще очень интересно, до этого всегда использовал присваивание класса к первому пункту)
37.ScoDi | 08 Jun, 2007
Не скажу что я консерватор, но если в движке сайта присутсвует шаблонизатор, то всё-таки лучше использовать дополнительный класс, ну тольок в том случае если меню содержит не поростой разделитель. Вообще всегда использую класс, т.к. это читабельней и гибче.
38.Евгений | 22 Aug, 2007
А как это меню выровнять по центру страницы для всех браузеров? В частности для IE6? Для FF, Opera'ы и Safari я сделал так: ul { display: table; margin: 0 auto; } li { display: inline; margin: 0 1px 0 -1px; } IE стал показывать у первого пункта меню разделитель :(
39.mihdan | 16 Sep, 2008
Решение весьма элегантное Код семантически верный Спасибо-часто использую этот вариант
40.mihdan | 16 Sep, 2008
2Евгений http://css-tricks.com/examples/CenterHorizontalListItems/
41.оля | 07 Nov, 2008
Отлично!!! Давно хотела узнать как это делается без first и last для li. Автору Респект!
42.Bonch | 14 Nov, 2008
Это все хорошо. Но как быть, если разделители должны быть графические? Думал-думал как сделать и пока только с ужасным нарушением семантики кое-что придумал).
43.Bonch | 14 Nov, 2008
Тьфу, извиняюсь, невнимательно прочитал.
44.INOZ | 26 Jan, 2009
Поднимаю вопрос, заданый Евгением (38 комментарий): а как это меню выровнять по центру страницы для всех браузеров?
45.akella | 26 Jan, 2009
Попробуйте вот этот вариант http://mauzon.com/?p=87
46.INOZ | 29 Jan, 2009
Благодарю! Помогло. Выкладываю решение: Горизонтальное меню | выровненное по центру | с вертикальными разделителями #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/ Но вот замутить вертикальные разделители с помощью этого метода не получится. Во всяком случае, мне не удалось.
47.INOZ | 29 Jan, 2009
Тьфу какая бяка получилась. Юра, можешь сделать, чтобы мой ХТМЛ было видно? А то получилось фиг знает что.
48.Quaze | 17 Aug, 2010
I wish i had a penguin, because i cant understand any of this
49.matros | 24 Sep, 2010
Ну а если я хочу сделать разделители в виде наклонной черты, а не прямой: Главная / Новости / Каталог / Рейтинг Тогда получается тут уже фокусы не проходят и рамки бесполезны и поля? И придется цинично рубить бабло, как замечено в начале поста.
50.akella | 24 Sep, 2010
Ну смотря по ситуации, можно использовать либо :after (он заменяется для ИЕ простым expression) Либо фоновую картинку слэша, либо спан со слешом - его тоже можно будет спрятать через overflow.
51.Modern Separators In Lists Menu &laquo; deniscyriac | 22 Apr, 2012
[...] Here is an another interesting approach: [...]
52.Сергей | 22 Dec, 2011
А как можно сделать вот эти линии (border:1px solid gray) ПУНКТ | ПУНКТ | ПУНКТ вот эти: | , Как можно их из такой ситуации сделать меньше и по центру? если ставить например к li height:10px, то они уменьшаются, но остаются в верху .
53.Сергей | 22 Dec, 2011
то есть уменьшение размера border1px в высоту и равнять по центру
54.Ganpati-Industries.com | 10 Dec, 2011
полезная идея!
55.Using Separators in Lists Menu with CSS | iDearays | BlogiDearays | Blog | 30 Dec, 2012
[...] Here is an another interesting approach: [...]
56.akela | 16 Apr, 2014
Все правильно, но в 2006 году актуальная версия IE была 6. =)
57.Алексей | 16 Apr, 2014
вообще можно использовать li:first-child, но для Internet Explorer это свойство поддерживается начиная с 9 версии
58.Алексей | 16 Apr, 2014
вообще можно использовать li:first-child, но для Internet Explorer это свойство поддерживается начиная с 9 версии :)
59.некто | 09 Jan, 2014
полезное инфо,спасибо
60.Vladson | 18 Apr, 2014
Кстати чем твой блог и интересен что иногда встречаются хаки которые будут работать не только на старых браузерах, но и на новых. В этом хаке например всё работает так как стандарт описывает. А основываясь на некоторых, можно придумать и новые, но уже под современные глюки браузеров (которые к сожалению увы были есть и будут)
61.Vladson | 18 Apr, 2014
Я про глюки, если чо, не про браузеры (браузеры то точно будут, и сожалеть не о чем) =)