Как добавить разные иконки к пунктам меню, используя только CSS

Как добавить разные иконки к пунктам меню, используя только CSS

Однажды была у меня такая задача, когда заказчик попросил прикрутить к каждому пункту меню свою иконку, но сами пункты меню выводились чистым HTML-списком, без использования различных class и id. А доступа к PHP-скриптам, выводящим меню у меня не было.

Так как же решить подобную задачу?

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

Задачка

Итак, есть «чистое» меню и набор иконок, которые нужно к нему «прикрутить». Отмечу сразу, что дело довольно простое, потому что в меню не было фоновых подложек, «раздвижных дверей» и прочих вещей, усложнивших бы задачу.

HTML-код меню:

1
2
3
4
5
6
7
8
<ul>
	<li><a href="#home">Главная</a></li>
	<li><a href="#aboutCompany">О компании</a></li>
	<li><a href="#catalogue">Каталог</a></li>
	<li><a href="#photogallery">Фотогалерея</a></li>
	<li><a href="#forPartners">Партнерам</a></li>
	<li><a href="#contact">Контакт</a></li>
</ul>

Теперь дело за CSS и навешиванием фона из спрайтов (фоновая картинка):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
* {
	margin: 0;
	padding: 0;
}
body {
	font: normal small/1.5em arial, verdana, sans-serif;
	background: #fff;
	color: #000;
}
ul {
	margin: 1em auto 1.5em 1em;
	list-style: none;
}
ul li {
	width: 250px;
	height: 2em;
	line-height: 2em;
	padding-left: 2em;
	background: url(menu_icons.gif) 0 50% no-repeat;
}
ul li+li {
	background-position: -300px 50%;
}
ul li+li+li {
	background-position: -600px 50%;
}
ul li+li+li+li {
	background-position: -900px 50%;
}
ul li+li+li+li+li {
	background-position: -1200px 50%;
}
ul li+li+li+li+li+li {
	background-position: -1500px 50%;
}

По-научному, называется все это страшными словами «селекторы сестринских элементов», но на самом деле не всё так сложно и пугающе.

C помощью селектора ul li мы задаем общий стиль всем пунктам меню, а потом просто сдвигаем фоновое изображение, чтобы подставить свою иконку для каждого пункта меню.

При этом селектором ul li+li мы устанавливаем фон для второго пункта меню (второго li), селектором ul li+li+li — для идущего за ним третьего, и так далее, пока меню не закончится.

Всё просто. По традиции — демо-пэйдж.

Работает везде, кроме IE6. Но это его проблемы, не так ли?

Пока большинством браузеров не поддерживается CSSmultiple backgrounds (а поддерживается на сегодня только Safari 4), таким нехитрым способом можно смело разукрашивать меню хотя бы с одним «чистым» для установки фона элементом. Не важно, что это будет, li, span или a.

Какие возможности?

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

* * *

А в это время в соседних галактиках:

Для тех, кто еще рисует «вебдваноль» — подборка из бесплатных шрифтов. Несколько приятных фич для пугающего интерфейса Drupal'а. Продвижение сайта в Google с помощью SemRush.

* * *

* * *

Понравилась статья?

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

* * *

Статьи по теме:

Комментариев: 22

  1. Igor, 12.09.2009 в 16:47

    WOW! That's great!

    Спасибо! Просто офигенное решение.

    Ответить

  2. Сергей М., 12.09.2009 в 19:07

    Да, полноценный мультипл ждем-не дождемся.

    Ответить

  3. Steward, 12.09.2009 в 19:13

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

    нет как пример применения + между селекторами более-менее — но как пример здравого написания css — очень бредовый :)

    и самое главное... в ИЕ6 будет работать без проблем :)

    вот говорят ИЕ6 отстой и т.д... нет вы не подумайте — я с этим согласен... но иногда проблема совсем не в ИЕ6 :)

    Ответить

  4. Green, 12.09.2009 в 19:24

    Да давно знал но ни когда не применял — (теперь есть хорошая подсказка).

    Примерно подобное сделал себе на блоге для оформления комментариев (иконки комментаторов), но с помощью селекторов атрибутов и спрайта. Так как к Blogger gravatar не прикрутить :)

    Ответить

  5. Steward, 12.09.2009 в 19:26

    Ещё для таких уж не любителей ИЕ (в т.ч и ИЕ7, насчёт 8-го не уверен) — так вот... существует такой всевдоселектор :nth-child() — в котором каждму потомку элемента можно задать свой класс... и тогда ваше безобразие с плюсами превращается во вполне красивый код:

    1
    2
    3
    4
    5
    
    ul li:nth-child(1) {background-position: -300px 50%;}
    ul li:nth-child(2) {background-position: -600px 50%;}
    ul li:nth-child(3) {background-position: -900px 50%;}
    ul li:nth-child(4) {background-position: -1200px 50%;}
    ul li:nth-child(5) {background-position: -1500px 50%;}

    красота... да ИЕ не поддерживает... но существуют хаки, правда там всем элементам li придётся задавать свой собственный класс — о чём я собственно написал в первом своём комментарии

    проверил только что — поддерживают все последние версии FF, Opera, Safari, Chrome

    Ответить

  6. rotor, 12.09.2009 в 19:28

    Steward, понавешивать class и id не слабо.

    Вы бы для начала, перед тем, как комментировать, прочитали первый абзац. Там есть ответ на ваше замечание.

    А то, что IE6 на корню убил все самые хорошие начинания в CSS2.1 (те же сестринские или селекторы атрибутов) никак его оправдывает.

    Ответить

  7. rotor, 12.09.2009 в 19:30

    Ок, вариант засчитан. Можно и так.

    Ответить

  8. rotor, 12.09.2009 в 19:44

    Steward, единственное замечу, что на IE8 в вашем случае полагаться не стоит. Не держит он псевдоклассы из CSS3.

    Решение красивое, но, пока еще, не везде применимое.

    Мелкомягкие только-только доросли до CSS2.1, утверждённого больше 10 лет назад :)

    Ответить

  9. Steward, 12.09.2009 в 19:45

    Извините конечно... я бы лично такого заказчика отправил на юх... — вам шашечки или ехать?

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

    подметать плац можно и ломом... можно... только нах...я если есть метла?

    Ответить

  10. Octane, 12.09.2009 в 21:47

    C IE6 все не так безнадежно, достаточно написать одноразовый expression:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    <style type="text/css">
        ul {
            x: expression(function(node) {
                var list = node.childNodes, i = list.length;
                while(i--) {
                    if(list[i].nodeType == 1) {
                        list[i].className = 'item-' + i;
                    }
                }
            }(this));
        }
    .item-0 {}
    .item-1 {}
    …
    </style>
    1
    2
    3
    4
    5
    6
    
    <ul>
    	<li>1</li>
    	<li>2</li>
    	<li>3</li>
    	<li>4</li>
    </ul>

    лучше расположить эту штуку в самом конце (из-за фигурных скобок), ну и скрыть это дело с помощью какого-нибудь хака, типа * html {...}.

    Ответить

  11. Python: Получение последнего сообщения из Twitter, 12.09.2009 в 23:31

    [...] Как добавить разные иконки к пунктам меню, используя т

    Ответить

  12. utz0r2, 13.09.2009 в 15:08

    а зачем плюсы? li li li {}

    Ответить

  13.   Python: Получение последнего сообщения из Twitter by Блог безработного манимейкера., 13.09.2009 в 21:01

    [...] Как добавить разные иконки к пунктам меню, используя т

    Ответить

  14. rotor, 14.09.2009 в 0:14

    @utz0r, считаете, в этом случае будет работать? Я — нет.

    Ответить

  15. Тормоз, 14.09.2009 в 15:56

    Привет! Перешёл от Искариота и он меня не подвёл — такой клёвый блог порекомендовал :) Как мне не забыть? После редизайна обязательно отремонтирую свой активный блогролл и в обязательном порядке добавлю туда rotorweb.ru. Прошу мне напоминть, если это не произойдёт в ближайшие две недели. Желаю удачи!

    Ответить

  16. rotor, 14.09.2009 в 16:24

    @Тормоз, спасибо :)

    Ответить

  17. Чистяков Денис, 19.09.2009 в 7:50

    Спасибо интересная статья, слышал про этот селектор, но в живом применении ни разу не видел )

    Вопрос напросился, а почему спрайт не вертикальный, т.е. не просто все картинки одна под другой, так вы не ограничиваете себя в длине пункта меню, и картинка весит меньше ;) А разницы по сути только вместе X-координаты — Y менять.

    Мне еще очень нравится решение которое использует yandex с <i></i> вложенными в , где для i делается отрицательный маргин, и он вроде не в ссылке но кликабельный — очень удобной, я понимаю что не для вашей «зажатой по условиям» ситуации, а вообще )

    Ответить

  18. Чистяков Денис, 19.09.2009 в 7:51

    Ой, съелся тег li, i естественного в него помещаются.

    Ответить

  19. rotor, 19.09.2009 в 13:44

    @Чистяков Денис, отвечу на вопрос про спрайты.

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

    А про длину пункта меню — я специально делал большие промежутки (прозрачные) между иконками, намного больше, чем ширина сайдбара. Причём, это почти не сказывается на размере GIF.

    Если сайт резиновый, то можно еще больше увеличить расстояния, в расчете на ширину сайдбара на самых-самых широких мониторах.

    Надеюсь, доступно объяснил?

    Ответить

  20. Social Maniak, 18.04.2010 в 12:56

    Блин сказать нечего, а хочется! Спасибо за статейку! Иконки это хорошо! Нужно будет поэкспериментировать!

    Ответить

  21. Андрей, 13.06.2016 в 19:58

    Спасибо, надо будет на своем сайте такое попробовать!

    Ответить

Есть что сказать?