5 ноября, 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>

И потом добавлением правила:

  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). Думаю работает везде.

Буду рад услышать Ваше мнение или приемы по этому поводу!

XHTML/CSS

Комментарии(38) к “Разделители в меню”

1. 5 ноября | Flack

Твоя обнаглел совсем :))

2. 5 ноября | akella

Извини, ты прав ) я забыл © добавить

3. 5 ноября | Flack

Строго говоря:
а). я так не делаю :)
б). если пунктов мало, то действительно лучше сделать через «|», особенно когда речь идет о вторичной информации (см. футер старого browsing.ru).
в). без стилей смотрится ничуть не хуже :)

4. 5 ноября | akella

Я все же неправильно расставил ударения. Суть не в том что б делать не “цинично”, а в том что реализация циничного варианта в данном случае не легче чем class=”first”. В движке я имею ввиду.
Если делать списком как я говорю - все элементы получатся симметричными-одинаковыми. А в “циничном” варианте все равно надо будет различать где первый и последний в движке, что бы по краям не стояли |…

Да и что б было понятно откуда ноги - http://horo.ukr.net/ (внизу страницы). Но для маленьких, вторичных и не генерируемых из движка - согласен полностью.

5. 5 ноября | Mkdir

“Конечно если бы мы тупо и цинично рубили бабло мы могли бы написать что то вроде…” ))))))))

Классная статья! То, что я давно искал!
Спасибо.

6. 5 ноября | tapazukk

Браво! Публика в восхищении!
Особенно по радовало,что можно работать с бэгграундами,а еще интересно float:left вместо привычного display:inline, хотя,трюк работает и с display-inline,вот только возможность поиграться с бордерами пропадает.Еще раз-публика в восхищении :)

7. 5 ноября | tapazukk

upd:поиграться не с бордерами,а с паддингами вверху и внизу

8. 5 ноября | Игорь

Оригинально! Давно боролся с этим! Теперь буду умнее :))

9. 6 ноября | Zigzag

хм, интересный подход, но вот если мне нужно сделать разделители меньше чем высота блока, то этот вариант не пройдет =\

10. 6 ноября | akella

1) высота блока в данном случае расплывчатое понятие - задавай padding-top меньше и будет меньше высота. Но если ты имел ввиду высоту шрифта то 2)
2) используй фоновую картинку - если она будет шириной в один пиксель - то подход полностью катит. Больше пикселей? больше margin-left:-X

Вроде бы ответил?

11. 6 ноября | IDcontent

Ай маладэээц, теперь я знаю как мне быстро “умирающие в градиенте” бордеры сделать для нового меню и не париться, сэнкс.

12. 6 ноября | Michael Yakovis

Да, присоединяюсь к Zigzag — обычно хочется границы совсем не высоты бордера, а меньше и аккуратнее. Но способ этот я пробовал когда-то.

13. 6 ноября | Александр Шабуневич

Спасибо за способ. Я сам сталкивался с этой проблемой не раз, но всегда правил для этого HTML. Теперь будем знать.

14. 7 ноября | StraNNicK

Почти оффтопик: не “прийдётся”, а “придётся”. :)

15. 7 ноября | Mourner

Так всегда и делаю, мне этот трюк казался очевидным. :)

16. 7 ноября | akella

2Mourner: Да, спору нет, это просто - но мне нравится какая то изящность что ли, этой идеи. Что то в этом есть. И как видишь не все знали. Я за обмен опытом ;)

2Michael Yakovis: Для маленьких артинок придётся оперировать не границами а фоновыми картинками - но техника вроде бы особо не опирается именно на границы. Просто заменяем border-left на background:…. 0 50%. И дело в шляпе.

2Странник: Спасибо! Действительно провинился! Поправил.

17. 9 ноября | Vadim

Действительно абсолютно прозрачный метод, в таком применении почему то не додумывался, хотя иногда могло бы стать легче, спасибо.
И теперь в подтверждение всему выше сказанному предлагаю переделать меню, находящееся внизу блога на “не для тупого рубежа бабла div#footer > p > a”, а листингами ;)

18. 9 ноября | akella

Все думал кто же первый уличит :)

У меня просто фобия какая то развилась - уже год не менял ни CSS ни HTML на блоге. Тут только зацепись… перфекционизм тут же погубит меня :)

Просто вдобавок ко всему это как раз то маленькое-вторичное и не генерируемое из движка меню

19. 9 ноября | IDcontent

Перфекцтонизм- зло.

20. 14 ноября | ZeT

а вот вариант с “|” разделителями и намёком на 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 : ” ): ”);}

21. 14 ноября | akella

Я бы обошелся CSS2:
#nav > li + li{border-left:1px solid #ccc}
:)
Но спасибо за интеерсный вариант для ИЕ )

22. 15 ноября | MT

overflow: hidden как инструмент вёрстки — вообще полезная штука. ;-)

Правда, ты забыл о _положительном_ поле с противоположной стороны каждого элемента списка — для компенсации циклического сдвига элементов и соответствующего «наезжания» их друг на друга:

#nav LI {margin-left: -1px; margin-right: 1px; }

23. 15 ноября | FataL

Идея супер! Особенно нравится “автоматическое” убирание лишних разделителей слева в случае, если ссылки не помещаются в одну строку. Этого не добиться ни какими CSS3!
5+

24. 15 ноября | akella

MT: спасибо за совет! Я пренебрегал тем одним пикселом :)

25. 21 ноября | Иван Сагалаев

Когда прочитал:

> как сделать такое меню с минимумом правильного HTML кода

Долго втыкал: это “правильный код, которого мало” или “минимально правильный код”?

:-)

26. 21 ноября | akella

наверно надо было писануть:
“с минимумом максимально правильного”
:-)

27. 24 ноября | tobto

полезная идея!

28. 20 декабря | CooperTV

Интересно

29. 5 января | alex

каким образом горизонтальное меню выравнять по правому краю? :/

30. 6 января | akella

float:right для LI
или
display:inline для LI
и text-align:right для UL
или
float:left для LI
и float:right для UL

31. 27 января | Серёга

ага!!! лень это проблема всех проблем!!!

32. 8 февраля | Jurij Burkanov

Клево, спасибо!

33. 10 февраля | Vladson

Ув. Серёга лень это двигатель прогресса, если бы люди в силу лени не старались всячески упростить свой труд любыми путями прогресс стоял бы на месте… :)

34. 22 марта | Q-Zma

есть несколько более сложный метод :)
http://q-zma.rajaka.net/2006/11/24/css3-selektory-first-child-i-last-child/

35. 23 марта | Ззаработок в Интернет

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

36. 31 мая | ogonkov

а слово “лень” - это не акроним :P

а вобще очень интересно, до этого всегда использовал присваивание класса к первому пункту)

37. 8 июня | ScoDi

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

38. 22 августа | Евгений

А как это меню выровнять по центру страницы для всех браузеров?
В частности для IE6?

Для FF, Opera’ы и Safari я сделал так:

ul {
display: table;
margin: 0 auto;
}

li {
display: inline;
margin: 0 1px 0 -1px;
}

IE стал показывать у первого пункта меню разделитель :(

Оставить комментарий

Комментировать

Обязательные поля

Ссылки

Последние 5