Содержание
Решил я однажды реализовать гибкий способ стилизации подчеркивания ссылок — чтобы просто делать полупрозрачные подчеркивания, регулировать паттерн в dashed/dotted-border, делать волнистые подчеркивания и вообще иметь настройки CSS3 text-decoration, которые еще ни один браузер не умеет.
В результате получился генератор PNG в data-URI на LESS.
Демо.
Варианты реализации
Полупрозрачное, пунктирное и точечное подчеркивания весьма просто делаются черезborder-bottom
☞.
Интересное начинается, когда хочется сместить линию ближе к тексту.
Можно соорудить конструкцию вида
<a class="link"><span>Some link text here</span></a>
и регулировать line-height
элемента span
(или a
), задав ему display:inline-block
, но тогда возникает проблема на многострочном тексте: inline-block
становится настоящим block’ом в плане отображения бордера (иллюстрация справа).
После размышлений и экспериментов, я пришел к выводу, что самым «чистым» и удобным решением было-бы класть паттерн подчеркивания в background
с высотой, равной line-height
. Осталось только понять, откуда брать этот паттерн.
- Генерировать картинку где-то на стороне и подключать её как файл — негибко и неудобно для разработки, каждое изменение будет убивать нервы.
- Использовать генератор PNG через canvas (такой, к примеру), но это также неудобно в разработке: каждый раз генерировать data-URI на стороне.
- Генерировать Repeating-gradient, но это весьма ненадежный способ, так как есть риск не попасть точно в пиксель линии подчеркивания, да и пунктирные подчеркивания не реализовать.
Самым логичным оставалось генерировать PNG динамически и вставлять в data-URI. Извопроса на stackoverflow выяснилось, что один человек уже сумел генерировать GIF-картинку в один пиксель (тут), но, надо сказать, весьма прямолинейно и негибко: изменение размеров этой картинки было-бы задачей, равносильной переписыванию всего кода.
Гряли выходные, и я решил наконец перестать фрустрироваться грязной реализацией подчеркивания ссылок и разобраться с генерацией PNG.
PNG.js
После нескольких часов изучения спецификаций PNG, ZLIB Data Format и DEFLATE Data Format, а также примера сериреализации png и небольшого реверс-инжиниринга (тут пример генерации сырого png), был создан js-класс для работы с PNG, пригодный для распила на куски в LESS.
Класс PNG умеет генерировать несжатый PNG с индексированным цветом (indexed-color) или битмапа (truecolor with alpha). Используется следующим образом:
Запуск JS в LESS
Как оказалось, LESS весьма гибок для запуска JS. К примеру, функции можно запускать следующим обазом:
@test: `function(a){ return a }`; test: `(@{test})(3)`; //test: 3
Переместив png.js в примесь и написав интерфейс к нему, в итоге получился следующий код:
Как использовать?
1. Подключить painter.less
и less.js
, как в демо
<link rel="stylesheet/less" type="text/css" href="painter.less" /> <script src="less.js" type="text/javascript"></script>
2. Использовать классы для span-элементов:
<span class="underline">Простое подчеркивание</span> <span class="underline thick">Толcтое подчеркивание</span> <span class="underline offset">Смещенное подчеркивание</span> <span class="underline transparent">Полупрозрачное подчеркивание</span> <span class="waved">Волнистое подчеркивание</span> <span class="waved alt">Волнистое подчеркивание 2</span> <span class="dotted">Точечное частое подчеркивание</span> <span class="dotted rare">Точечное редкое подчеркивание</span> <span class="dotted thick">Точечное толстое подчеркивание</span> <span class="dashed">Пунктирное подчеркивание</span> <span class="dashed thick">Пунктирное толстое подчеркивание</span> <span class="dot-dashed">Штрих-пунктирное подчеркивание</span>
И отрегулировать позицию background:
span { background-position: 0 -5px; }
3. Доступные миксины:
.underline(@height: 20, @color: @text, @thickness: 1)
.waved(@height: 20, @color: @red, @thickness: 2, @width: 4)
.dotted(@height: 20, @color: @text, @width: 3, @thickness: 1)
.dashed(@height: 20, @color: @text, @width: 8, @thickness: 1, @length: 4)
.dot-dashed(@height: 20, @color: @text, @width: 10, @thickness: 1)
Можно также использовать миксин .png(@stream: "0001", @w: 2, @h: 2, @color: black)
, отправляя напрямую поток битов индексированных цветов.
[emc2alert type=»info» style=»normal» position=»top» visible=»visible» closebtn=»0″ ]Итог: демо, репозиторий на github.[/emc2alert]