Карты изображений на CSS
Вторник, 8 июля 2008
В этом посте хочу показать, как создать карту изображений средствами только CSS, не прибегая к помощи устаревших тегов <map>, <area>, JavaScript или Flash. Подход давно испробованный и изученный у них, но почему-то совершенно не распространенный у нас.
Подготовка к работе
Для примера возьму карту одной никому неизвестной страны :) При наведении курсора мыши на одну из областей, должен измениться ее цвет и появиться краткое описание под картой.
Все проблемы буду кратко описывать и решать по ходу их возникновения. Самые нетерпеливые могут посмотреть финальную версию того, что у меня получилось.
Итак, для работы понадобится одно фоновое изображение, с несколькими рисунками, чтобы загружать всю карту сразу и избежать эффекта мигания фона при наведении мыши. Например, такое (в уменьшенном варианте):
Реализация
Вся карта будет базироваться на нескольких CSS-принципах: абсолютная позиция элементов, замена фоновых изображений при наведении мыши и изменение видимости display.
Структуру карты изображений можно построить с помощью ненумерованного списка <ul> или списка определений <dl>. Для примера я выбрал первое.
Для начала создадим контейнер для карты и укажем его основные свойства:
XHTML:
<div id="map"></div>CSS:
1 2 3 4 5 6 7 | #map { border: 1px solid black; width: 401px; height: 328px; background: url(cities.gif) left bottom no-repeat; position: relative; } |
Сейчас у нас есть <div> нужной нам ширины и высоты, с фоновым изображением карты. Создадим структуру для карты (XHTML):
1 2 3 4 5 6 7 8 9 10 | <div id="map"> <ul> <li id="brest"><a href="#brest"><span>Бресткая область. Площадь 32 700 км<sup>2</sup>, население 1 471 000 чел.</span></a></li> <li id="vitebsk"><a href="#vitebsk"><span>Витебская область. Площадь 40 100 км<sup>2</sup>, население 1 369 100 чел.</span></a></li> <li id="gomel"><a href="#gomel"><span>Гомельская область. Площадь 40 400 км<sup>2</sup>, население 1 516 000 чел.</span></a></li> <li id="grodno"><a href="#grodno"><span>Гродненская область. Площадь 25 000 км<sup>2</sup>, население 1 173 900 чел.</span></a></li> <li id="minsk"><a href="#minsk"><span>Минская область. Площадь 40 200 км<sup>2</sup>, население 1 479 400 чел.</span></a></li> <li id="mogilev"><a href="#mogilev"><span>Могилевская область. Площадь 29 000 км<sup>2</sup>, население 1 208 600 чел.</span></a></li> </ul> </div> |
Лишние <span> в ссылках понадобятся позже для реализации подписей к изображениям.
Задаем стили для списка и прячем пока ненужные ссылки (CSS):
ul {
list-style: none;
margin: 0;
padding: 0;
}
ul li {
position: absolute; /* чтобы элементы li не "мешали" в IE6 */
}
a:link, a:visited, a:hover {
text-decoration: none;
}
a span {
display: none;
font: normal x-small/1.4em verdana, tahoma, sans-serif;
width: 395px;
color: #fff;
background: #000;
padding: 0 4px 2px 4px;
}
Теперь поясняю. У списка сбрасываем стандартные установки отступов (конечно лучше сбрасывать через reset.css или универсальный селектор *, но тут я так, для наглядности), «убираем» появляющиеся в IE6 над картой элементы списка <li> и прячем с помощью display:none ссылки. Еще обратите внимание на ширину <span>, она указана меньше ширины самой карты (<div id="map">), так как в ней теперь есть внутренние отступы padding.
Далее начнется самое долгое, но совсем не сложное занятие — нужно задать всем ссылкам абсолютную позицию над картой, используя CSS (покажу на одном примере):
#brest a {
position: absolute;
width: 176px;
height: 133px;
visibility: hidden;
left: 7px;
top: 185px;
}
Здесь ширина и высота для ссылки равны размерам фонового изображения для этой ссылки. Так как для <div id="map"> задано позиционирование relative, то все элементы списка будут оставаться в этом контейнере. Позиции left и top рассчитаны так, чтобы цветная версия изображения совпадала с серой фоновой.
Дальше все просто, при наведении курсора подставляем фоновое изображение и делаем ссылку видимой через CSS:
#brest a:hover {
background: url(cities.gif) -137px 0 no-repeat;
display: block;
}
Теперь при наведении мыши на карте подсвечивается нужная облать. Осталось только вывести описание для каждой ссылки. Опять же, в этом нам поможет абсолютное позиционирование и отрицательные margin'ы, чтобы вывести описание за пределы родительского контейнера (в моем случае — под блок с картой).
Пишем CSS для всех <span>:
a:hover span {
position: absolute;
left: 0;
top: 0;
display: block;
}
И затем настраиваем отдельные ссылки:
#brest a:hover span {
margin-top: 144px;
margin-left: -8px;
}
Все настройки нужно повторить для остальных пяти ссылок, высчитывая отдельно для каждой абсолютное позиционирование над картой и расположение фонового рисунка в background. На самом деле это не так долго, как кажется, у меня на это ушло всего полчаса. Высчитавать положение проще всего на скриншоте в Photoshop, с помощью линеек (Ctrl+R) и направляющих (Ctrl+H), а потом уже корректировать погрешность на пару пикселей «вживую».
Рабочий код
Дальше приведу код моего примера полностью (XHTML):
<div id="map"> <ul> <li id="brest"><a href="#brest"><span>Бресткая область. Площадь 32 700 км<sup>2</sup>, население 1 471 000 чел.</span></a></li> <li id="vitebsk"><a href="#vitebsk"><span>Витебская область. Площадь 40 100 км<sup>2</sup>, население 1 369 100 чел.</span></a></li> <li id="gomel"><a href="#gomel"><span>Гомельская область. Площадь 40 400 км<sup>2</sup>, население 1 516 000 чел.</span></a></li> <li id="grodno"><a href="#grodno"><span>Гродненская область. Площадь 25 000 км<sup>2</sup>, население 1 173 900 чел.</span></a></li> <li id="minsk"><a href="#minsk"><span>Минская область. Площадь 40 200 км<sup>2</sup>, население 1 479 400 чел.</span></a></li> <li id="mogilev"><a href="#mogilev"><span>Могилевская область. Площадь 29 000 км<sup>2</sup>, население 1 208 600 чел.</span></a></li> </ul> </div>
CSS:
#map {
border: 1px solid black;
width: 401px;
height: 328px;
background: url(cities.gif) left bottom no-repeat;
position: relative;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
ul li {
position: absolute; /* чтобы элементы li не "мешали" в IE6 */
}
a:link, a:visited, a:hover {
text-decoration: none;
}
a span {
display: none;
font: normal x-small/1.4em verdana, tahoma, sans-serif;
width: 395px;
color: #fff;
background: #000;
padding: 0 4px 2px 4px;
}
a:hover span {
position: absolute;
left: 0;
top: 0;
display: block;
}
#brest a {
position: absolute;
width: 176px;
height: 133px;
visibility: hidden;
left: 7px;
top: 185px;
}
#brest a:hover {
background: url(cities.gif) -137px 0 no-repeat;
display: block;
}
#brest a:hover span {
margin-top: 144px;
margin-left: -8px;
}
#vitebsk a {
position: absolute;
width: 205px;
height: 129px;
visibility: hidden;
left: 129px;
top: 0;
}
#vitebsk a:hover {
background: url(cities.gif) -542px 0 no-repeat;
display: block;
}
#vitebsk a:hover span {
margin-top: 329px;
margin-left: -130px;
}
#gomel a {
position: absolute;
width: 201px;
height: 145px;
visibility: hidden;
left: 170px;
top: 183px;
}
#gomel a:hover {
background: url(cities.gif) -330px 0 no-repeat;
display: block;
}
#gomel a:hover span {
margin-top: 146px;
margin-left: -171px;
}
#grodno a {
position: absolute;
width: 119px;
height: 156px;
visibility: hidden;
left: 24px;
top: 82px;
}
#grodno a:hover {
background: url(cities.gif) 0 0 no-repeat;
display: block;
}
#grodno a:hover span {
margin-top: 247px;
margin-left: -25px;
}
#minsk a {
position: absolute;
width: 156px;
height: 185px;
visibility: hidden;
left: 116px;
top: 84px;
}
#minsk a:hover {
background: url(cities.gif) -987px 0 no-repeat;
display: block;
}
#minsk a:hover span {
margin-top: 245px;
margin-left: -117px;
}
#mogilev a {
position: absolute;
width: 204px;
height: 129px;
visibility: hidden;
left: 197px;
top: 110px;
}
#mogilev a:hover {
background: url(cities.gif) -762px 0 no-repeat;
display: block;
}
#mogilev a:hover span {
margin-top: 219px;
margin-left: -198px;
}
Напомню, что рабочий пример можно посмотреть здесь. Еще его можно скачать в архиве, чтобы самостоятельно во всем разобраться.
Если кто-то что-то не понял по реализации, прошу в комменты. Критики тоже туда :)
Плюсы и минусы
Чего тут больше на самом деле решать вам. Я перечислю некоторые спорные и достойные моменты на мой взгляд.
- при отключенных стилях пользователь увидит просто список со ссылками;
- при отключенной графике — те же ссылки, но придется постараться их поискать :) (на самом деле минус);
- плюс, что можно обойтись лишь CSS, без помощи JavaScript;
- минус: нельзя писать сложные вещи из-за того, что IE6 поддерживает :hover только для ссылок, реализация же этой поддержки с помощью JavaScript может ввергнуть разработчика в такую пучину ошибок и несоответствий в браузерах, что придется дополнительно писать кучу хаков.
Где применять
Такое решение отлично подойдет для реализации карты проезда, чтобы сделать ее более динамической и user frendly, со множеством подсказок и пояснений. Также для компаний, имеющих филиалы в разных странах (почему бы и не прикрутить карту мира) или регионах, и желающих сэкономить средства на создании флэш-роликов.
Для небольших сайтов подойдет для создания визуально интересных меню, со всплывающими фотками, подсказками или дополнительным описанием категорий. Правда тут уж придется каждый раз настраивать его ручками.
Как вариант можно использовать с юмором на коллективных фотках, чтобы показать высказывания или мысли отдельных людей, как в комиксах.
Примеры создания различных потрясающих карт изображений с помощью CSS можно посмотреть на cssplay.co.uk.
Креативьте!
* * *
Сканер блогов:
На chernev.ru наткнулся на интересный линк онлайн-генератора фоновых паттернов. dimox.name поделился новостями о полезной программе, которая одним кликом добавляет статьи в 20+ сервисов социальных закладок. Вещь однозначно полезная.
* * *
Понравилась статья?
Тогда помогите мне сделать её доступной для других, или будьте в курсе событий:
- подпишитесь на обновления по RSS
- получайте новые статьи на E-mail

- добавьте в Twitter: Карты изображений на CSS
- добавьте статью в закладки:
* * *

Однозначно в избранные «сочинения» :)
Сердце кольнуло — «Стью»... и точно он. Но какой отличный пример!
Всем бы верстальщикам твою аккуратность (это я про сайт в целом), стало бы не стыдно говорить «байнет».
Спасибо, я старался :)
А пример такой, потому что я из Гродно.
ыыы) недавно таким способом делал подсветку районов города в проекте vlg-nav.ru. Правда из-за использования png-24 убрал эффект в IE6. Был удивлен сегодня, увидев подробное описание этого способа :-)
Отличный способ, спасибо!
Увы, есть и еще один очевидный минус — области ссылок по прежнему прямоугольные в отличие от того же .
Спасибо большое. Как раз то что я искал.
Спасибо за статью. Достаточно интересное решение.
Очень интересное решение. Но вижу здесь один минус — много областей, он влечет за собой все остальные минусы:
1) надо в фотошопе долго все области разделять;
2) в цсс все отступы считать;
3) файл цсс раздуется сильно.
отличная статья. Очень интересные методы. Теперь совершенно по другому смотрю на css)
Подскажите, как сделать подсказку не внизу всей карты, а рядом с указанным мышкой объектом.
Спасибо
Подсказка выводится с помощью тега span с абсолютной позицией, который находится внутри ссылки. Например:
#grodno a:hover span { margin-top: 247px; margin-left: -25px; }чтобы выводить рядом с указанным объектом сначала обнулите оба margin, тогда span будет выровнен по левому верхнему углу нужного объекта, а затем задайте нужные значения для отступов.
Ширину и высоту для всех подсказок сразу, можно задать в блоке
a span {...}Rotor, спасибо за ответ:
[code] #brest a {
position: absolute;
width: 0;
height: 0;
show: hidden;
left: 7px;
top: 185px;
}
#brest a:hover {
background: url (cities.gif) -137px 0 no-repeat;
display: block;
}
#brest a:hover span {
margin-top: 144px;
margin-left: -8px;
}
[/code]
Посмотри, так я исправила или нет?
И еще я не понимаю, где задать координаты для объекта... Сорьки, если бестолково объеяснила, у меня на сайтике карта похожая... хочу сделать типа навигацию по ней с хорошими подсказками.
Спасибисссимо!
Совершенно не так.
Перечитайте внимательнее статью и мой комментарий выше. Нужно было обнулить отступы margin-top и margin-left, а не ширину и высоту ссылки.
Координаты объекта (нужной вам ссылки) задаются в блоке:
#brest a { position: absolute; width: 176px; height: 133px; show: hidden; left: 7px; top: 185px; }с помощью left и top. Для каждой ссылки придется настраивать отдельно.
Скачайте исходник и поэкспериментируйте с ним, тогда вам не составит труда сделать что-то подобное для себя.
Спасибо за быстрый ответ! )))
Буду пробовать.
Rotor, еще можно спросить?
Мой вариант наверное проще, т.к. у меня имеется только фоновая картинка с изображениями объектов и я буду к их координатам задавать подсказки... и поэтому не поняла, где прописать адрес картинки-карты? (((
Картинку можно вставить в div:
#map { border: 1px solid black; width: 401px; height: 328px; background: url(<strong>ваша_картинка.gif</strong>) left bottom no-repeat; position: relative; }Ахха, тогда для моего варианта (когда нет меняющихся по цвету объектов) в них прописывать не надо?
Вот тут:
#minsk a { position: absolute; width: 156px; height: 185px; show: hidden; left: 116px; top: 84px; } #minsk a:hover { background: url(cities.gif) -987px 0 no-repeat; display: block; } #minsk a:hover span { margin-top: 245px; margin-left: -117px; }Я правильно пишу для: url= или надо по-другому?
ой, или надо через a href="//////"?
Дело в том, что сами подсказки я вижу, а картинку карты — нет, и в подсказках только квадратики вместо слов... (((
Саня
Для начала почитайте какой-нибудь справочник по CSS (например тут).
А квадратики потому, что не объявлена кодировка в документе:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />И сам документ тоже должен быть сохранён в этой же кодировке (смотрите в опциях своего редактора).
Я понимаю, что моя задача гораздо проще, чем ваш пример, но для новичков и это сложно (сайт Мержевича я читала, но про всплывающие подсказки там почти нет, только alt и title). У меня к вам предложение: может попробовать выложить вариант не такой сложный, как в вашем примере (хотя бы чтоб могли сделать начинающие, особенно «чайницы»)))).
Например: есть фоновая картинка с изображениями зданий и объектов, надо подводя к ним мышкой вызвать подсказку в виде красного прямоугольника (или уже сложнее??? готовую картинку овальную с надписью).
Вот над этим я ломаю голову и ищу в инете образец, чтоб можно было оттолкнуться уже месяц.
Спасибо.
Стучитесь в аську, помогу в вашей проблеме.
Аххха... )))
соопчаю, что вариант с подсказкой в виде цветного прямоугольника и текста к объектам на моей карте удачно сверстался (самое сложное оказалось правильно прописать url картинки — надо в скобках и одинарных кавычах, этого же не указано)
Терь буду пробовать ставить подсказку в виде заготовленной картинки с надписью... а куда-чего вписать еще не догоняю.
*номер вашей аси можно мне на майл?
Номер icq есть в контактах.
Доброе время суток!
Я продолжаю модернизировать свой сайтик... с помощью вашей статьи у меня получилось создать всплывающие подсказки в нужном месте и в виде любой картинки... но! В FF (в IE этого нет) у меня все вплывающие картинки выходят в рамке, а она нигде не задана (особенно это не хорошо выглядит для gif стрелок).
Если у вас есть решение для этой проблемы, то буду очень вам благодарна!
Саня, давайте решать личные вопросы в ICQ или почте. Я об этом написал выше.
Хороший способ. Только, жаль что подсвечиваемые блоки могут быть только прямоугольными и при построении карты с непрямоугольными объектами отчетливо заметны «бока».
Проблема в том что из-за квадратных блоков, могут не работать маленькие участки на более детальных картах.
надо сделать также, но подсветы (появление картинок) сделать при наведения на точные области .
Жаль, что ссылки до сих пор квадратные :(
Даёшь не квадратные ссылки! =)
Думаю, мой коммент понятен веб-мастерам.
Имеется в виду: область ссылки — прямоугольный блок. Из-за этого карта получается немного некорректной.
Всех огорчу, но «неквадратных» ссылок на карте не будет. Пока что, в CSS нет средств для их реализации.
Евгений, вы могли бы предложить туториал по применению «всплывающих» изображений на HTML-странице?
Т.к. то, что я нашла не кроссбраузерно и не позиционирует в точности, как необходимо, а «раскидывает».
Желательно не оччч громоздкое решение. )))
Ваш вариант с картой очень помог мне на сайте и сейчас буду переделывать портал тоже используя этот способ. ;)
Сенькую!
Ну хоть маленький пример покажите. Как они должны «всплывать»?
Аххха, показываю страничку - www.sun-place.com/html-h14.htm
«Всплывает» хорошо и рядом только второе изображение, остальные убрала, т.е.:
— в остальных браузерах (например, в Опере — уносит все вверх странички, а рядом не показывает)
— нет одинакового позиционирования, т.е. все одинаково не отступают от превью на одинаково заданное количество px
Если предложишь работающий вариант, то буду безмерно благодарна...
Т.к. все, что было найдено, имело множество минусов
Без проблем, но лучше по скайпу/аське.
Хммм... а если написать об этом Туториал, я понимаю, что это не в рамках данной темы... ;)
*буду ждать
**в асе задам вопросы по ходу реализации...
Как-то косячно отправилось. Еще раз:
Здравствуйте, посмотрела карту изображений на СSS. Хорошая вещь. Но! У вас на DIVах верстка, а я на таблицах делаю, если содержимое между ul вставить например в строку таблицы, то не работает в IE6, там фон показывается вместе с фрагментами цветных рисунков. Можно как то это на таблицы перевести?
Теоретически, наверное, можно. Главное правильно выбрать контейнеры для абсолютного позиционирования.
Но я бы не стал смешивать список с таблицей. В вашем коде не будет логики.
А в IE может не работать, потому, что стили нужно применять к ячейкам таблицы
td, а не к строкамtr.Знаете, я попробовала сделать и почти получилось, вместо div — table, ul — tr, li — td и все бы хорошо, в IE во всех версиях работает, в Опере, Гугле, еще 2-3 браузерах, но! В Mozilla Firefox не работает. То есть, если просто написать таблицу как я предложила, то и в Мозиле работает, но у меня идет структура в несколько таблиц, вложенных друг в друга и вдобавок они все вложены в один единственный div, чтобы heght 100% работал. И по какой-то причине только в Мозиле идет сдвиг цветных картинок влево. У вас случайно нет идей что с Мозилой делать, у меня уже просто сил нет биться с этим кодом.
Короче говоря, весь код в div (вместе с тегом div) вставила в столбец таблицы, все работает. Коряво, конечно, так делать — вроде, дивы в таблицу не вставляют, но не все ли равно — главное, что работает. Спасибо вам за карту!