У верстальщика все углы должны быть, как солдаты, – подстрижены под одну гребёнку. Так что, откроем Gimp и терпеливо нарисуем идеальный уголок попиксельно - для каждого из 13-ти вариантов цветов и размеров?..

Скругление углов CSS, JavaScript

Кажется, на эту тему трудно написать что-то новое. Точнее, трудно изобрести новый метод скругления углов. А взглянуть на проблему под другим углом всегда можно. Мы попробуем доказать неизбежность и предопределённость единственно возможного способа скругления углов на HTML страницах.

Чем плохи картинки?

Сторонники скругления «CSS only» традиционно упоминают о «размере кода» и «скорости загрузки». В теории скругление с помощью картинок не уступает CSS-способу ни в том, ни в другом. На практике иногда CSS бывает оптимальнее. Но представьте себе 20 одинаковых кнопок: картинка для них будет загружена одна, а HTML кода понадобится ровно в 20 раз больше, и он наверняка превзойдёт по размеру правильно сделанную картинку.

Вот тут и появляются грабли. Как сделать «правильно сделанную картинку» для скругления угла? Ну, нарисуем идеальную кривую в векторе. Скажем... в Кореле. Потом проэкспортируем в gif. Вот как будут выглядеть правые верхние углы первых 4-х из двадцати наших кругленьких кнопок:

scrug1.gif

И какой из этих углов «правильный»? Какую кнопку будем брать за основу? Художник может, конечно, позволить себе такое разообразие. Этакий лёгкий произвол, навеянный вдохновением. Верстальщик – нет. У верстальщика все углы должны быть, как солдаты, – подстрижены под одну гребёнку.

Можно, конечно, открыть сразу Gimp и терпеливо нарисовать идеальный уголок попиксельно. Только вот мы не знаем заранее, какой нам понадобится в очередной кнопке радиус скругления. И придётся рисовать много-много уголков: разнообразие радиусов помноженное на разнообразие цветов и толщину линий.

Почему HTML-CSS не идеальной решение?

Векторная графика выводится на печать принципиально медленнее, чем растровая. Устройства вывода (и на принтер, и на экран...) не могут «печатать» формулы, – они могут отображать только точки, пикселы. То есть устройства вывода вообще не могут печатать векторную графику напрямую.

Браузер тоже выводит на экран точки; и картинку (уже состоящую из готового набора точек!) ему вывести проще. Графические элементы, созданные с помощью кода (HTML-CSS), браузер вообще не может вывести на экран непосредственно, – он всё равно сначала превращает все эти элементы (и даже шрифты!) в ту же самую пиксельную картинку, то есть обязательно растеризует все графические задачи, полученные в виде формул.

Поэтому мы должны чётко понимать, что «рисование» на HTML-CSS (да любое «рисование» вместо готового gif'а!) усложняет работу браузера, увеличивает количество вычислений. «Чистый» выигрыш в скорости тут можно получить лишь в случае большого объёма картинки (при замене его небольшим фрагментом HTML-кода) – за счёт времени загрузки.

И мы всё-таки отказываемся от картинок в пользу HTML-CSS, потому что так можно добиться большей «правильности» и однородности в скруглениях углов; потому что это технологичней – отображать всё разнообразие радиусов скругления и цветов фона с помощью формул (создаваемых по мере необходимости), а не хранить в виде кучи отдельных файлов.

Но как вы себе это представляете – выдавать браузеру коды нужных скруглений «по мере необходимости»? В момент осознания необходимости верстальщик должен будет плотно сесть за монитор, и скопировать и перелопатить код образца, заменив в нём цвета и добавив часть элементов «по аналогии» с существующими. То есть проделать кучу ручной работы. Верстальщик десять раз пожалеет, что не заготовил заранее набор картинок для уголков «на все случаи жизни»...

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

HTML-код скруглений надо «считать» с помощью JavaScript

На самом деле, конечно, добросовестный разработчик должен здесь разделить вопрос на две части: «считать» и «на JavaScript». Потому что считать шаблоны (избавить верстальщика от рутины) можно ещё и на сервере. Но тогда возрастёт трафик между сервером и браузером (да и вычислительной нагрузки серверу добавится).

Нет, HTML с сервера должен идти максимально «чистый», простой (и, по возможности, короткий!) а всякие рюшечки и свистелочки типа уголков разумно передавать одной командой: «этому элементу добавить скругления номер 5». А команду выполнит JavaScript уже на клиенте. Или не выполнит, если JS отключён. И пользователь не увидит рюшечек. Это выбор пользователя.

Алгоритм и сущности

Скругление – это удаление части пикселов. Их можно удалять побольше или поменьше. Вот как это приблизительно выглядит:

round_all.gif

Из рисунка видно, что для иллюзии округлости видимая часть каждого последующего вынимаемого слоя пикселов должна увеличиваться в длину на один пиксел. То есть размеры видимых частей в пикселах будут "1", "2", "3", "4"... Возьмём за основу алгоритма число – длину самой большой видимой части. Тогда общая глубина «выемки» будет равна сумме всех видимых частей (1 + 2 + 3 ...) плюс количество слоёв.

Для средней фигуры рисунка это будет 1 + 2 + (2) = 5; для правой (самой большой) фигуры: 1 + 2 + 3 + (3) = 9. Для следующей по сложности фигуры: 1 + 2 + 3 + 4 + (4) = 14. Закономерность достаточно простая. Полученное число будет равно общей (видимой и невидимой) длине каждого слоя и общему количеству слоёв (выемка – квадрат).

Сущности, с которым мы будем работать – это стопка слоёв толщиной в 1 px (пиксел) и шириной в максимальную ширину слоя. А может, и не так. Ведь ширину видимой части можно воплощать по-разному. Попробуем сделать её равно ширине самого слоя. Тогда стопка слоёв для средней фигуры будет выглядеть примерно так:

То есть материал потребовал сделать наоборот: опираться на ширину «невидимой» части слоёв. В кавычках – потому что по-настоящему невидимой она всё-таки быть не может, если мы сделаем её реально прозрачной, из-под неё будет виден фон основной фигуры (углы которой мы скругляем). То есть цвет «невидимой» части слоёв мы будем задавать явно, и он должен быть равен цвету фона, на котором лежит основная (скругляемая) фигура.

С учётом этих условий, функция генерации массива слоёв (точнее, классов CSS для этих слоёв) для верхнего левого угла может выглядеть так:

Для нижнего левого угла, очевидно, достаточно будет выполнить list.reverse(). Ну, а поменять левые углы на правые можно с помощью CSS.

Конечно, такое приближённое вычисление окружности работает только до входящего параметра d = 3. При значении 4 уже ясно видно, что скругление получается не в форме круга. Чтобы не возиться с формулами, можно использовать здесь готовые наборы параметров вида:

В принципе таких наборов не должно быть очень уж много. Создать их можно, «подсмотрев» пиксельную структуру закруглённых линий в каком-нибудь графическом редакторе.

Рисование

Функция addRound, добавляющая углы к заданному элементу, получилась у нас сейчас грубая и циничная, так как мы спешим. Она работает, да и ладно. Просто по очереди формируем из массива слоёв четыре угла и присоединяем, куда функция corners скажет (подробности в файле skrug.js).

Мы добавили там и вариант со сглаживанием. Он получился «неровный», но всё равно в общем-то работает.

Ближе к концу работы функция addRound формирует HTML-элемент, содержащий все 4 закругления (переменная container). Если кнопок (элементов, требующих скругления) много, нет необходимости запускать функцию addRound много раз, достаточно просто присоединить к каждой кнопке копию (cloneNode) элемента, на которй ссылается container. Нечто вроде небольшого кэширования.

Для полного счастья

В предлагаемом варианте осталось недоработанным вот что: для формирования контуров кнопок (а не просто скруглений фона) серверный скрипт должен знать некоторые условности. Они не то чтобы сложные (должно быть два элемента div, вложенных друг в друга, с classname "dark1" и "dark2"), но важен сам принцип – что в создании скруглений участвует сервер. А он не должен участвовать.

В идеале надо отправлять с сервера один признак (тот же classname), а уже JavaScript сам должен при необходимости оборачивать «кнопку» в два элемента "dark1" и "dark2".

Пример для работы

http://ir2.ru/static/scrug_css_js.htm (+skrug.js, skrug.css)

D.M., admin
Полиграфические услуги и создание пластиковых карт в Екатеринбурге.

Комментарии

Дилетант 16.10.2013 14:33:13

Иван,

не корите себя; а страницу (любую, особенно с javascript) лучше всегда скачивать полностью, со всеми файлами с помощью браузера.

Иван 12.10.2013 08:07:08

Скачал на комп 3 файла и открыл – не работает, открыл исходный код страницы, а там ещё один файл нужен. С ним работает. Мудак.