Иконки, смайлики и т.п. зло: методы борьбы

Преамбула


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

Плохие примеры


Первый плохой пример:
Первый плохой пример
Второй плохой пример:
Второй плохой пример
В качестве третьего примера см. 99% форумов

Делаем лучше


Собственно, идея состоит в использовании одного файла, где собраны все пиктограммы, против множества файлов. И это вовсе не сложно, нам достаточно вооружиться знанием CSS и фотошопом, чтобы склеить иконки в один файл.
Предположим, что наши иконки имеют соотношение сторон 16х16 пикселов.
html-код размещения пиктограммы будет выглядеть примерно так:
<div class="my_icon">
    <div id="icon_1" onclick="some_event()"></div>
</div>

или так:
<div class="my_icon">
    <a href="/dir/file.ext"><span id="icon_1"></span>link text</a>
</div>

Фантазия подскажет разработчику, какой вариант удобнее выбрать в том или ином примере.
CSS будет, соответственно, примерно таким:
.my_icon div {
    width: 16px; height: 16px;
    background: url('/cp/images/icons.png') no-repeat;
    cursor: pointer;
}
#icon_1 {background-position: 0px}
#icon_2 {background-position: -16px}
/* и так далее по количеству пиктограмм */

Если мы расположим пиктограммы не только по горизонтали, но и по вертикали, нам потребуется второе значения background-position, регулирующее высоту:
#icon_4 {background-position: -16px -16px}

использовать PNG-24 выгоднее чем GIF только в случае наличия более 256 цветов во всех «склееных» пиктограммах.

Реальные полезности


  1. Размер склееного графического файла стремится к половине суммы всех мелких файлов,
  2. Сокращается количество HTTP запросов к серверу с кол-во иконок на итерацию * кол-во итераций до одного из файла *.css ( характерно для форумов и блогов),
  3. Сокращается кол-во html-кода.

Сплошные плюсы :)

Авторитетные примеры на десерт


Первый авторитетный пример:
Первый авторитетный пример
Второй авторитетный пример:
Второй авторитетный пример

Надеюсь, Хабралюдям этот топик сослужит хорошую службу.
P.S. Хабру стоит взять вышеизложенное на вооружение. ИМХО.
P.P.S. На Хабре глючит сервис загрузки изображений :( пришлось наспех искать место для размещения иллюстраций
+41
29 августа 2007, 18:36
68
alkeeper 6,7

комментарии (58)

+4
beshenov #
<a href="/dir/file.ext"><span id="icon_1"></span>link text</a> — вполне.

А вот <div id="icon_1" onclick="some_event()"></div> — абсолютное отсутствие семантики.
0
alkeeper #
Я уже говорил выше:
Фантазия подскажет разработчику, какой вариант удобнее выбрать в том или ином примере

На Яндексе сделано примерно так:

<div id="icons"><a href="some_link"><i id="some_id"></i>link text</a>

italic вообще здесь ни в какую семантику не укладывается, но, в отличие от span, в нем на 6 байт меньше
+1
alkeeper #
Ой, div забыл закрыть
0
ha2bj #
гениально!
+4
fatal #
Как разработчик, уже давно этот метод использую, а как пользователь, к сожалению, продолжаю страдать от недогруженных иконок.
0
evgeny_tech #
Отличная идея и хорошая статья. Всем верстальщикам на заметку :) А также тимлидерам: следите за этим!:)
–2
Ivanhoe #
Противоречиво. С одной стороны - суперэлегантно и красиво. С другой - fatal уже сказал...
0
maq #
Что-то непонятно, чего такого fatal сказал «с другой стороны»
0
Ivanhoe #
Пардон, я неправильно понял уважаемого fatal. "а как пользователь, к сожалению, продолжаю страдать от недогруженных иконок" вероятнее всего относилось к стандартному способу.
+1
napster #
Еще один пример, один из наиболее «впечатляющих» по количеству иконок в одном файле — Yahoo, а здесь его иконки. Кстати таким способом (CSS-спрайты, об этом уже писал уважаемый посмотреть профиль sunnybear в своем топике «Оптимизируем загрузку веб-страницы») они оторбражают не только иконки, а и всяческие градиенты и другую графику.
НЛО прилетело и опубликовало эту надпись здесь
0
djko #
альт можно заменить текстом внутри спана, а стилями послать текст в космос
+1
Lipa #
Если без изображения нельзя обойтись - то оно уже выходит за рамки декоративной пиктограммы. Несет самостоятельный смысл и публикуется с помощью тега IMG.
+3
artemenko #
Это вовсе не ново. Он этом еще 2 июня 2005 года написал Владимир Токмаков в разделе "Техногрет" - Студии Артемия Лебедева.
Тут - http://www.artlebedev.ru/tools/technogrette/html/picture_fragmentation/
0
korovkin #
Полность согасен, но вот, 2 июня 2005 года, это уже было не ново.
0
Yakor #
–3
amordezomb #
только что хотел об этом написать.
+1
pho3nix #
> пришлось наспех искать место для размещения иллюстраций
Интересно, по какому поисковому запросу вы выбрали именно этот сервис для хранения картинок ;)
+1
alkeeper #
А какой в SSH-клиент был вбит, такой и выбрал :)
0
romantolkachyov #
В очередной раз удивляюсь докалупливости русского человека) Ну грузятся ведь картинки, ан нет, надо посмотреть куда :)
0
rold #
А проблем со скоростью рендеринга страницы не будет?
0
evgeny_tech #
нет. Время на обработку одной картинки во много раз меньше времени на несколько.
0
Archie #
Ребят, а не подскажете с какой прогой можно спрайты по быстрому клеить?
0
sotakone #
Adobe Photoshop
0
Archie #
Как функция называется?
+8
Apostol #
Приблизительно так: Ctrt+N, Ctrt+C, Ctrt+V, [Ctrt+C, Ctrt+V, ...] Alt+Shift+Ctrl+S
+1
Apostol #
Если уж совсем по-быстрому — http://csssprites.com/
0
Archie #
Хех, это разве быстро каждый файл по одиночке вбивать? Что-то поудобней, типа Drag&Drop надо. И не веб-приложение а простую утилиту. Заранее спасибо.
+6
mas #
ImageMagick:
montage -mode concatenate -tile 4x1 icon1.gif icon2.gif icon3.gif icon4.gif all_icons.png
0
Archie #
Спасибо друг.

п.с. Погуглил и нашёл некую GraficsGale. Утилита гуевая и довольно таки простая. Попробуйте. ;)
0
beshenov #
ImageMagick лучше, особенно если процесс нужно автоматизировать.
+3
rossomachin #
Тепхника известная. Вот только не всегда возможно чётко задать фиксированные размеры того окна, через который будет проглядывать фон — банально будут торчать соседние картинки.
+2
pepelsbey #
Эти наивные ребята опять забыли, что пользователь может увеличивать размер шрифта и их спрайты начнут вылазить.
А ещё они забыли, что наиболее удобный способ выравнивания иконки в такой ситуации — это 0 50%, что с этим спрайтом сделать невозможно.

В общем — спрайты и текст несовместимы.
Сборка картинок в одну оправдана только в ситуации полной замены текста графикой.
0
rossomachin #
Совершенно с тобой согласен.
Кстати, вот ещё кое-что по наши души: http://mihazimin.habrahabr.ru/blog/24383…,
http://rossomachin.livejournal.com/87135…
0
altmind #
хм. применение слова спрайт тут уместно? не надо только тыкать меня носом в определение, поясните что это так, как вы это понимаете.
0
zencd #
примеры для меня не заработали ( «лебедевский» код хоть и слишком специфичен, зато работает сразу ) ; вот например так отличаются два пункта: один див, другой спан o_o

[ div id="icon_1" onclick="some_event()" ][ /div ]
vs
[ a href="/dir/file.ext" ][ span id="icon_1" ][ /span ]link text[ /a ]

вообще техника полезная, хотя лучше было бы это посредством HTML IMG организовать :)
+1
miha_ha #
Идея отличная. Раньше я использовал эту идею для пунктов меню, которые сделаны в виде меняющихся картинок при наведении.

Только, думаю, может возникнуть проблема с mate. Если иконки в сете будут размещены на разных беках, то придется с этим бороться и это вызовет некторые сложности, а png24 не всегда удобен (нужно еще ie учить их отображать)
+3
miha_ha #
Кстати, по поводу alt. Можно же положить вместо этой иконки в div однопиксельный gif и растянуть его по размеру иконки (саму иконку на background). Вот на этот gif и ставить alt
0
alkeeper #
В результате чего благополучно теряем прелести второго преимущества.
+4
vtx #
всего +1 запрос на t.gif, разве много прибавилось?
+1
oxff #
Почему же? Запросы делаются только для картинок, которых еще нет в кеше. Поэтому просто прибавьте к вашей формуле еще один запрос для однопиксельного гифа.
0
alkeeper #
Действительно, что-то протупил :)
НЛО прилетело и опубликовало эту надпись здесь
+2
romantolkachyov #
>Иконки замечательно оседают в кэше и в дальнейшем уже не запрашиваются (если все правильно настроено, конечно).
Могу заверить, что IFModified всё так же отправляется. (если это среднестатистический пользователь, "несреднестатистический" даже первый раз не загружает)
+2
trinko #
ужос...
http://www.simplebits.com/notebook/2003/…
техника 4 года назад описана, кстати.
http://www.artlebedev.ru/tools/technogre…
лебедевцы ее описывали 2 года назад.
И сегодня на индексе хабра =)

Далее по коду...
<div id="icon_1" onclick="some_event();"></div>

Во-первых, отключаем javascript и получаем бездействующий интерфейс.
Во-вторых, JS спецификация меняет пробел не на подчеркивание, а на заглавную последующую. Типа семантика и все такое %)) на самом деле JS просто так проще читается.
Примерно так бы сделал я...

<a id="icon_1" href="/some_event.html" onclick="someEvent();return false;"></a>

Хранить весь набор иконок в одном файле конечно круто, но если появляются они на страницы силами CSS, то уже пофиг, один там бэк или куча мелких, ибо все равно кешируется все. А значит смысла особого склеивать иконки - нет.
Склеенные иконки хуже поддаются редактированию. Если у тебя стартап, который ты обновляешь каждый день, через неделю тебе надоест постоянно открывать весь набор иконок, чтобы отредактировать одну.
Да и потом склеенные иконки все же сложнее позиционировать. Если к одной я могу задать
background-position:5px 50%;
чтобы иконка была смещена на 5 пикселей слева и центровалась по вертикали, то с кучей иконок в одном файле так легко уже не сделать.

Ну и на последок пример с тем же яндексом. Вот код яндекса:

<div id=services class=r>
  <div id=market>
    <h2>
      <a href="http://market.yandex.ru"onclick="p('next.market.title')">
        <i></i>
        Маркет
      </a>
    </h2>
  </div>
  <div id=moikrug>
    <h2>
      <a href="http://moikrug.ru/mates/school/russia/?from=yandex_main&geo=213"onclick="p('next.moikrug.title')">
        <i></i>
        Мой Круг
      </a>
    </h2>
  </div>

  ...

</div>


и вот возможная альтернатива:

<ul class="iconmenu" id="services">
  <li id="market">
    <a href="http://market.yandex.ru" onclick="p('next.market.title')">
      Маркет
    </a>
  </li>
  <li id="moikrug">
    <a href="http://moikrug.ru/mates/school/russia/?from=yandex_main&geo=213" onclick="p('next.moikrug.title')">
      Мой Круг
    </a>
  </li>

  ...

</ul>


Ну и в каком месте кода меньше? Помойму бездействующие ненужные и (бля буду!) не семантические %)))) <i></i> тут лишние.

Примерно так. Статья с тех. точки ужасно не точная =( Однако, надеюсь будет многим отправной точкой для изучения данной техники, раз так популярна. Лишь бы код у автора тупо не копировали...
0
gunkin #
Вещь хорошая, но... Мне вот как правило приходится вставлять иконки в PNG с прозрачностью и на не однотонный фон - самизнаетепроIE6.
0
alkeeper #
Разумеется, для IE приходится совершать исправляющие телодвижения типа таких:

<!--[if IE]><link href="http://www.habrahabr.ru/css/ie_only.css" rel="stylesheet" type="text/css"><![endif]-->
0
gunkin #
И что там будет прописано про background?
0
trinko #
background:0;
filter:....
не помню точно но это не проблема.
0
alkeeper #
0
gunkin #
Ммм, пардон, оказывается прошли времена PNG Behavior, и прозрачность фона не проблема: http://alistapart.com/stories/pngopacity…
0
Scream #
Большое спасибо за статью!
Как раз сейчас занимаюсь проектом, в котором будет много иконок :)
0
Sam_des #
Отлично!
+2
rybnadzorro #
Черезжопье дикое :). Начиная с того, что прийдётся запихивать кучу каритинок в общую палитру (вы ведь не забыли ;)), продолжая тем, что откажемся от анимации (или будем с ней долго или высокотехнологично страдать).

ГОСПОДА! ЦСС ЭТО ПРОСТО ЗАШИБИСЬ! но не нужно пихать его прогрессивные средства в любую первую попавшуюся опу. как и дваноль. как и градиенты. и скруглённости. и ажакс. и персонализацию. и юзергенерейтедконтент....
0
gunkin #
Да, это опять похоже на дикую оптимизацию не особо нужную в наше время.
0
alexbig #
статья, как воспоминание давно описанной техники - отличная, единственное, что я бы посоветовал поменьше использовать атибут id, пользуйтесь class или селекторами чтобы не "мешать" потом работать (тормозить) всяким getElementById()...

<style>
.icon { background-image: url(/img/icons.png); }
.home { background-position: xpos ypos; }
</style>

<body>
<div class="icon home"></div>
</body>
0
conturov #
Представим себе вариант что иконок у меня на весь сайт порядком 150 штук
Я их загоняю в один большой рисунок и делаю такой же большой css.

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

А если они разного размера? тоже проблема в нахождении координат каждой из картинок.

На гугле и яндексе - понятно, там немного иконок с этим проще.
0
umnik #
Хаа =)) Всегда так и делал.
Про это есть в Техногрете Лебедева, а первое использование было еще в fckeditor, помоему

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.