Bouton CSS, SVG ou Canvas, quel format choisir?

Exemples de base de la création de nouveaux objets de formulaire pour étendre HTML 5.

Pour créer de nouveaux objets de formulaires, trois voies se présentent, aussi afin d'avoir une idée de leurs avantages et inconvénients, comparons avec la création d'un simple bouton personnalisé dans chaque format.

Bouton CSS 3

Ces boutons sont basés sur des balises HTML standards, <button> pour les deux premiers, <input> pour le dernier, et personnalisés avec une feuille de style. On pourra combiner des balises HTML pour créer des objets plus complexes comme par exemple une liste aborescente.

Ces boutons CSS sont compatibles avec les navigateurs modernes.

<![if gte IE 9]> 
<link href="button.css" rel="stylesheet" type="text/css" />
<![endif]>

Les objets SVG ou Canvas n'offrent pas cette possibilité, il faudra recourir à des plugins ou des frameworks alternatifs pour les navigateurs anciens.

Bouton SVG

SVG button

Le bouton SVG permet des effets de style que l'on va définir visuellement à partir d'un logiciel comme Inkscape. Malheureusement le rendu peut différer selon les navigateurs (le bouton est laid sous Chrome).

Cette démonstration sert surtout à voir comment l'utilisateur peut interagir avec un objet SVG. Ce format permet d'étendre HTML 5 avec de nouveaux objets plus complexes, en permettant d'interagir avec des parties spécifiques de cet objet. Il suffit d'associer des gestionnaires d'évènements à une balise, comme on le fait dans cet exemple.

Bouton Canvas

Une troisième possibilité est l'utilisation de Canvas. Il est plus facile d'obtenir un rendu compatible qu'en SVG, mais créer des objets composites interactifs sera aussi compliqué que de créer un jeu. Ce format convient pour créer de nouveaux objets avec peu d'interaction utilisateur, comme par exemple une horloge.

Conclusion: Choisir le bon format pour chaque usage

Il est difficile en créant un objet SVG ou Canvas d'écrire un code qui soit compatible avec tous les navigateurs, chacun ayant sont interprétation quand à l'implémentation de ces formats. L'essentiel du travail consiste donc à résoudre les problèmes de compatibilité ce qui est une perte de temps à moins de trouver des widgets prêts à être utilisés.
On utilisera de préférence:

Codes sources

CSS

Code HTML des boutons CSS:

<div class="buttonbar">  		
<button class="button red">Red button</button></li>
<button class="button blue">Blue button</button>
<input type="button" value="Gray input" class="button gray">
</div>

Code CSS:

.button, .button:visited 
{
color: #fff;
text-decoration: none;
border-radius: 6px;
box-shadow: 1px 2px 4px 0 rgba(0,0,0,0.6);
text-shadow: 0 -1px 1px rgba(0,0,0,0.25);
border-bottom: 1px solid rgba(0,0,0,0.25);
border-right: 1px solid rgba(0,0,0,0.25);
position: relative;
cursor: pointer;
font-family:Calibri, Arial;
margin-left:4px;
font-size: 16px;
padding: 1px 8px 3px 8px;
} .button:active
{
top: 1px;
left:1px;
} .gray.button, .gray.button:visited
{
background-color:#CCCCCC;
box-shadow: inset 1px 1px 2px 0 rgba(255,255,255,0.6),
inset -1px -1px 1px 0 rgba(100,120,140,0.6),
1px 2px 4px 0 rgba(0,0,0,0.6);
color:#333;
border-left:1px solid #999;
border-top:1px solid #999;
text-shadow:none;
}
.gray.button:hover
{
background-color:#999;
color:#111;
}

Code CSS complet. Pour les boutons bleu et rouge, seule change les propriétés de couleur.

SVG

Code SVG:

<svg width="132" height="36"  id="svg1"
xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs
id="defs4">
<linearGradient id="gradient1">
<stop id="stop1" style="stop-color:#eee;stop-opacity:1;" offset="0" />
<stop id="stop2" style="stop-color:#aaa;stop-opacity:0;" offset="1" />
</linearGradient>
<linearGradient xlink:href="#gradient1" id="gradient2"
x1="0" y1="28" x2="0" y2="1"
gradientUnits="userSpaceOnUse" />
<filter id="drop-shadow" filterUnits="userSpaceOnUse" width="144" height="38">
<feGaussianBlur in="SourceAlpha" result="blur-out" stdDeviation="2" />
<feOffset in="blur-out" dx="2" dy="2"/>
<feBlend in="SourceGraphic" mode="normal"/>
</defs>
<g id="" class="buttonbar" onmousedown="svgDown()" onmouseover="svgOver()"
onmouseout="svgOut()" onmouseup="svgUp()">
<rect id="svgbutton" x="0" y="0" rx="8" ry="6" width="122" height="28"
stroke="#000066"
style="fill:url(#gradient2);fill-rule:evenodd;stroke:#000000; stroke-width:1px;stroke-linecap:butt; stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
filter="url(#drop-shadow)"
/>
<text x="28" y="18" fill="black"
font-family="Calibri, Arial" font-size="15" font-weight="500">
SVG button
</text>
<g>
</svg>

Code JavaScript associé au code SVG:

function svgOver()
{
document.getElementById("stop2").setAttribute('style', "stop-color:#000;stop-opacity:0;");
}
function svgOut()
{
document.getElementById("stop2").setAttribute('style', "stop-color:#666;stop-opacity:0;");
}
function svgDown()
{
var button= document.getElementById("svg1");
button.style.margin="1px 0 0 1px";
var x = document.getElementById("svgStorage");
x.innerHTML="Clicked on SVG button";
}
function svgUp()
{
var button= document.getElementById("svg1");
button.style.margin="0";
var x = document.getElementById("svgStorage");
x.innerHTML="";
}

On associe une fonction au fait que la souris passe sur le bouton ou le quitte, que le bouton est pressé (svgDown) ou relâché (svgUp).

Canvas

Code Canvas:

<canvas id="mycanvas" width="128" height="36"
onmousedown="canvasDown(this)" onmouseup="canvasUp(this)"
onmouseover="canvasOver()" onmouseout="canvasOut()">
</canvas>

<script>
canvasOut();
</script>

Code JavaScript pour dessiner le bouton dans Canvas:

function makeButton(x, y, w, h, radius, label, color)
{
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
// clear background
context.beginPath();
context.fillStyle="white";
context.fillRect(0,0, 126, 36);
// draw button
var r = x + w;
var b = y + h;
context.moveTo(x+radius, y);
context.lineTo(r-radius, y);
context.quadraticCurveTo(r, y, r, y+radius);
context.lineTo(r, y+h-radius);
context.quadraticCurveTo(r, b, r-radius, b);
context.lineTo(x+radius, b);
context.quadraticCurveTo(x, b, x, b-radius);
context.lineTo(x, y+radius);
context.quadraticCurveTo(x, y, x+radius, y);
// background gradient
var backgrad = context.createLinearGradient(1,1,0,30);
backgrad.addColorStop(0, '#5EF');
backgrad.addColorStop(0.5, color);
context.fillStyle = backgrad;
// drop shadow
context.shadowBlur = 3;
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowColor = "#669";
context.fill();
// the following lines before stroke are required for Chrome
context.shadowBlur = 0;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.stroke();
// label with shadowing
context.beginPath();
context.font = "12pt Calibri,Arial";
context.fillStyle = "#FFF";
context.shadowBlur = 0;
context.shadowOffsetX = -1;
context.shadowOffsetY = -1;
context.shadowColor = "#669";
context.fillText(label, x+w*0.1, y+h*0.66);
}

Code associé aux évènements:

function canvasUp(button)
{
button.style.margin="0";
document.getElementById("canvasStorage").innerHTML="";
}
function canvasDown(button)
{
button.style.margin="1px 0 0 1px";
document.getElementById("canvasStorage").innerHTML="Clicked on Canvas button";
}
function canvasOver()
{
makeButton(0,0,120,28,8, "Canvas button", '#19B');
}
function canvasOut()
{
makeButton(0,0,120,28,8, "Canvas button", '#2AC');
}

Ce sont les mêmes évènements que pour SVG, mais cette fois on doit redessiner le bouton entièrement pour changer les couleurs.

Code JavaScript complet.

Voir aussi