Pull to refresh

Fugue-Icons — динамический Sprite

Reading time3 min
Views2.8K
Для одного из проектов мне нужно было использовать набор простых иконок. Сначала я остановил свой выбор на популярный набор Silk Icons и его Sprite-плагин для Blueprint, но чем дальше я с ним работал, тем сильнее требовалось что-то большее. Иконок было маловато, ненужных гораздо больше, чем нужных, а подгружать приходилось все.

Далее мой выбор остановился на Fugue Icons. Я поискал в гугле что-либо для CSS и нашел два решения. Первое: каждая иконка отдельным файлом. Сразу нет, потому что при загрузке страницы это смотрится очень убого. Второе: несколько отдельных PNG со спрайтами и единый CSS. Все это дело весило 1.4 Мб, что никак не допустимо для среднестатистического сайта.

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

Итак, я написал простой скрипт на Python, который автоматизирует задачу. От нас требуется только закинуть в каталог со скриптом нужную иконку и запустить скрипт на выполнение.

Исходник (mkicons.py) с комментариями:

#!/usr/bin/env python

#Импортируем все нужное. Из нестандартного только PIL
import Image
import glob
import os

ICON_WIDTH, ICON_HEIGHT = 16, 16 #Ширина и высота иконки (На случай использования скрипта для другого набора).
OUTPUT_DIR_NAME = 'sprite' #Каталог, в который будем сохранять готовые файлы
OUTPUT_SPRITE_PNG = 'sprite.png' #Имя файла со спрайтом
OUTPUT_SPRITE_CSS = 'sprite.css' #Имя CSS-файла
OUTPUT_SPRITE_HTML = 'test.html' #Имя HTML-файла для тестирования иконок
CSS_SPRITE_TEMPLATE = '.fg_%s{background-position:0px %spx}' #Шаблон для одной иконки в CSS
#Шаблон для одной иконки в тестовом HTML
HTML_SPRITE_TEMPLATE = '''<span class="fg_sprite fg_%(spritename)s "></span>
<input type="text" value=\'<span class="fg_sprite fg_%(spritename)s">
</span>\'><br />
'''
#Исходное содержимое CSS-файла. Общий стиль для всех иконок
CSS_CONTENT='''
.fg_sprite{
    display:inline;
    overflow:hidden;
    background-repeat:no-repeat;
    background-image:url('../img/%s');
    height:16px; width:16px; overflow:hidden; margin:-2px 3px 3px 0; padding: 0px;
    display:-moz-inline-box;display:inline-block; vertical-align:middle;
}
''' % OUTPUT_SPRITE_PNG #Сразу подключаем png-шку со спрайтом

#Исходное содержимое HTML-файла. Между <body> и </body> будут вставляться иконки по одной
HTML_CONTENT = '''
<html><style>input{width:400px;}</style><head><link href="css/sprite.less" rel="stylesheet" type="text/css" />
</head><body>%s</body></html>
'''

pngs = glob.glob('*.png') + glob.glob('*.PNG') #Выбираем все иконки к текущем каталоге
sprite_height = len(pngs)*ICON_HEIGHT #Считаем общую высоту всего спрайта
sprite = Image.new('RGBA', (ICON_WIDTH, sprite_height),(0,0,0,0)) #Создаем спрайт с прозрачным фоном. Высота и ширина уже известны

html_include='' #Будущий HTML для инклюда

#Обрабатываем каждую иконку в отдельности.
for idx,png in enumerate(pngs): 
    icon = Image.open(png) #Открываем иконку
    offset = ICON_HEIGHT * idx #Будущее смещение по вертикали в спрайте
    sprite.paste(icon,(0, offset)) #Вставляем в спрайт по смещению
    
    spritename=png.replace('.png','').replace('.PNG','').replace('--','-') #Для CSS - убираем расширение и лишние тире
    CSS_CONTENT+=CSS_SPRITE_TEMPLATE % (spritename,-offset) #Вставляем в CSS стиль для этой иконки
    html_include+=HTML_SPRITE_TEMPLATE % {'spritename':spritename} #И в HTML

#Создаем каталоги для новых файлов, если их не существует
if not os.path.exists(OUTPUT_DIR_NAME):
    os.makedirs(OUTPUT_DIR_NAME)
if not os.path.exists(os.path.join(OUTPUT_DIR_NAME, 'img')):
    os.makedirs(os.path.join(OUTPUT_DIR_NAME, 'img'))
if not os.path.exists(os.path.join(OUTPUT_DIR_NAME, 'css')):
    os.makedirs(os.path.join(OUTPUT_DIR_NAME, 'css'))

#И сохраняем файлы
sprite.save(os.path.join(OUTPUT_DIR_NAME, 'img', OUTPUT_SPRITE_PNG),'PNG')

cssfile = open(os.path.join(OUTPUT_DIR_NAME, 'css', OUTPUT_SPRITE_CSS),'w')
cssfile.write(CSS_CONTENT)
cssfile.close()

htmlfile = open(os.path.join(OUTPUT_DIR_NAME, OUTPUT_SPRITE_HTML),'w')
htmlfile.write(HTML_CONTENT % html_include)
htmlfile.close()


Работает так:
  1. Создаем каталог для проекта
  2. Кидаем туда файл mkicons.py (Исходник выше)
  3. И нужные иконки из набора
  4. Запускаем «python mkicons.py»
  5. Идем в каталог «sprite» и забираем оттуда готовые файлы
  6. Для просмотра и получения кода иконок открываем test.html

test.html выглядит так:

image

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

И еще, если кто-то пользуется Less, то вместо:

OUTPUT_SPRITE_CSS = 'sprite.css'


пишем:

OUTPUT_SPRITE_CSS = 'sprite.less'


А затем инклюдим:

@import "/path/to/fg-icons/sprite/css/sprite.less";


Вот вроде и все. Спасибо за внимание, буду рад выслушать ваши комментарии.
Tags:
Hubs:
Total votes 40: ↑38 and ↓2+36
Comments16

Articles