Canvas vs CSS3: маленький пример
Сравнивать CSS3 и canvas — это все равно, что сравнивать декларативную и императивную парадигмы программирования (собственно, они тут и представлены). Но все же именно такое сравнение на простом примере помогает обратить внимание на некоторые архитектурные особенности.
Вот такие CSS3 примеры вы можете видеть на рисунке:
Цели и задачи
Цели исследования были следующими:
- Сравнить подходы к решению элементарных задач;
- Указать на недостатки — тут оговорюсь, что недостатками я называю то, что мешает решать данную конкретную задачу, не отрицая возможности эффективного использования той же особенности в других случаях (холивара не будет);
- Оценить поддержку разными браузерами — мой стенд: Opera 10.52 и Firefox 3.6.3 (устарел уже на момент окончания работы над статьей, но для примера сгодится).
Сравнивалась реализация следующих задач:
- Нестандартные шрифты (webfonts) — я использовал Lobster и Yanone Kaffeesatz из Google Font Directory;
- Тень под текстом;
- Тень под блоками;
- Закругленные углы рамок.
На рисунке выше обратите внимание на тень под восклицательным знаком а также на то, что позиционирование немного отличается — подозреваю, что последнее связано с использованием разных форматов шрифтов, когда каждый браузер по сути отображает отдельный шрифт.
Реализация
Сравнение возможностей Canvas и CSS3 <script type="text/javascript">// <![CDATA[ window.onload = function(e) { var canv = document.getElementById('cnv'); var ctx = canv.getContext('2d'); ctx.strokeStyle = '#69a'; ctx.fillStyle = '#def'; ctx.lineWidth = 8; ctx.shadowColor = '#aaa'; ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; ctx.shadowBlur = 6; //bg ctx.beginPath(); ctx.moveTo(30,12); ctx.lineTo(440,12); ctx.quadraticCurveTo(460,12,460,32); ctx.lineTo(460,270); ctx.quadraticCurveTo(460,290,440,290); ctx.lineTo(30,290); ctx.quadraticCurveTo(10,290,10,270); ctx.lineTo(10,32); ctx.quadraticCurveTo(10,12,30,12); //shadow trick ctx.stroke(); //now we have shadow ctx.shadowColor = 'transparent'; //turn shadow off ctx.fill(); //fill, no shadow ctx.stroke(); //stroke again, no shadow //text+shadow ctx.shadowBlur = 4; ctx.shadowColor = '#223338'; ctx.fillStyle = '#69a'; ctx.textBaseline = 'bottom'; ctx.font = 'normal 94px "Lobster", arial, serif'; ctx.fillText('I can do', 64, 140); ctx.font = 'normal 106px "Lobster", arial, serif'; ctx.fillText('canvas', 64, 238); ctx.font = 'normal 210px "Lobster", arial, serif'; ctx.fillText('!', 358, 260); //text+rotation ctx.font = 'normal 28px/28px "Yanone Kaffeesatz", arial, serif'; ctx.fillStyle = '#b88'; ctx.shadowColor = 'transparent'; ctx.rotate(-4*2*Math.PI/360); ctx.fillText('Kneel before HTML5', 230, 280); }; // ]]></script></pre> <div id="css-wrapper"> <div class="line1">I can do</div> <div class="line2">styles<span>!</span></div> <div class="line3">Kneel before CSS3</div> </div> <div id="canvas-wrapper"><canvas id="cnv" width="500" height="300"> Здесь была эротическая картинка, но ваш браузер не может canvas :( Установите хороший браузер и наслаждайтесь! </canvas></div> <pre>
Уже при беглом взгляде на исходный код видно, что оба решения примерно одинаковы по количеству строк, причем каждое из них страдает от своей неуклюжести. В стилях приходится дублировать свойства с префиксами для разных движков (причем меньше двух повторов никак не получается, при условии работы хотя бы в двух браузерах), а в коде для canvas приходится изобретать четырехколесный велосипед, чтобы просто закруглить углы:
ctx.beginPath();
ctx.moveTo(30,12);
ctx.lineTo(440,12);
ctx.quadraticCurveTo(460,12,460,32);
ctx.lineTo(460,270);
ctx.quadraticCurveTo(460,290,440,290);
ctx.lineTo(30,290);
ctx.quadraticCurveTo(10,290,10,270);
ctx.lineTo(10,32);
ctx.quadraticCurveTo(10,12,30,12);
…
Дальше — больше. Вот так из-за отсутствия функции strokeAndFill()
(или fillAndStroke()
?) рисуется тень:
ctx.shadowColor = '#aaa'; //цвет тени
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 6;
…
ctx.stroke(); //рисуем рамку с тенью
ctx.shadowColor = ‘transparent’; //выключаем тень
ctx.fill(); //закрашиваем тень внутри рамки
ctx.stroke(); //рисуем рамку снова, поверх заливки
Недостатки CSS3
Могу выделить следующие моменты:
- Многословность — количество свойств на один селектор даже для простых примеров довольно большое, поэтому лучше бы иметь более легковесный синтаксис для всего этого. Решение: Sass;
- Дублирование свойств с префиксами для разных движков. Решение: eCSStender;
- Невозможность узнать, поддерживается ли определенное свойство. Решение: Modernizr
Недостатки HTML5 canvas
Об этом можно поспорить всерьез и надолго, но рискну их назвать:
- Скудный набор инструментов для работы с тектом. По сути, самой интересной особенностью является рисование контуров глифов с помощью strokeText(). Не хватает подгона размера под заданную ширину и высоту;
- Скудный набор примитивов — вот это весьма спорный момент, минимализм не является недостатком (скорее наоборот), но в данном конкретном примере это создало излишние трудности;
- Нет функции strokeAndFill(), что затрудняет работу с тенями;
- Нет понятия графических объектов или групп операций, все возлагается на разработчика.
Все вышеназванные трудности решаются при помощи библиотек — конкретных наименований не знаю, но могу привести в пример processing.js.
Внешний вид в разных движках
Тут ситуация довольно плачевная. Помимо обрезаных теней есть общий недостаток Firefox и Opera: достаточно темная тень под закругленным углом имеет неприятный артефакт в виде окантовки закругленного угла полоской светлых пикселей — попробуйте поменять цвет тени под блоком на более темный, чтобы увидеть.
Интересно то, что и Opera, и Firefox портят тени по одинаковой схеме, рисуя их только в clipping region’е символов и игнорируя реальную форму глифов, но Opera делает это для CSS, а Firefox — для canvas. Это наглядный пример типичной ошибки разработчиков.
Ситуацию с разным позиционированием я пояснил выше, но это только мое предположение.
Выводы
Все плохо, ничего не работает :)
Если серьезно, то CSS3 примеры показывают, что на данный момент действительно не все гладко, причем замечание это касается не только неполной поддержки в браузерах, но и некоторыми архитектурными особенностями. Благо, решения многих проблем уже имеются.
Вопрос об IE умалчивается сознательно.
Ссылки
- Спецификация canvas и документация по canvas на MDC;
- Модули CSS3 и сайт CSS3.info с примерами.