Balise SVG text: Des titres de pages enjolivés

Le graphisme d'un site peut être amélioré en toute compatibilité grâce à SVG et la balise text.

La plupart des navigateurs reconnaissent maintenant le code SVG, et quand ce n'est pas le cas, les balises sont ignorées et le navigateur ne voit que le code HTML ce qui fait que la page reste fonctionnelle et son contenu entièrement présenté à l'internaute... avec le rendu classique.

SVG dispose de quatre fonctions qui manquent à CSS pour le rendu des textes:

  1. La bordure.
  2. Les gradients.
  3. La texture.
  4. L'effet de lumière.

Il est possible de transformer un filtre SVG en attribut CSS, mais cela ne fonctionnera que sur Firefox.

Pour utiliser SVG avec une option de remplacement sur les anciens navigateurs on va insérer le code SVG dans une balise H1, comme ceci:

<h1>
  <svg><text>... Titre ...</text></svg>
</h1>

Sur les anciens navigateurs les balises <svg> et, <text> sont ignorées, ne reste que <h1>titre</titre>. Il en est de même pour les moteurs de recherche.

Texte avec une bordure

La balise SVG text permet d'écrire un texte et de lui appliquer des propriétés. Les propriétés fill et stroke permettent le remplissage et le tracé d'une bordure.

Démonstration
<svg width="100%" height="64px">
  <text font-size="64" fill="#bbccee" stroke="#003366" stroke-width="1px" 
           x="0" y="48" font-family="Arial">
    Démonstration
  </text>
</svg>

Utiliser des gradients

On fabrique un gradient et les attributs stop-color déterminent les limites des zones en couleurs dégradées. On pourrait en ajouter plus de deux.

Démonstration
<svg width="100%" height="64px">
  <linearGradient id="shaded" x1="0" x2="0" y1="0" y2="1">
    <stop offset="0%" stop-color="#bbccee" stop-opacity="0"/>
    <stop offset="80%" stop-color="#6699cc"/>
  </linearGradient>
  <text font-size="64" fill="url(#shaded)" stroke="#000" stroke-width="1px" x="0" y="48px"
     font-family="Arial">
    Démonstration
  </text>
</svg>  

Ajouter une ombre

On crée un filtre qui crée une ombre de l'image initiale et on l'assigne par la propriété filter. Je recommande une police de caractère ronde car SVG ne fournit pas de bon résultats pour ombrer les droites.

Démonstration
<svg  width="100%" height="64px">
  <defs>
    <filter id="drop-shadow" filterUnits="userSpaceOnUse" width="100%" height="92">
      <feGaussianBlur in="SourceAlpha" result="blur-out" stdDeviation="3" />
      <feOffset in="blur-out" result="shadowoffset" dx="2" dy="2"/>
      <feBlend in="SourceGraphic" in2="shadowoffset" mode="normal"/>
    </filter>
  </defs>
  <linearGradient id="shaded" x1="0" x2="0" y1="0" y2="1">
    <stop offset="0%" stop-color="#bbccee" stop-opacity="0"/>
    <stop offset="70%" stop-color="#6699cc"/>
  </linearGradient>
  <text font-size="64" fill="url(#shaded)" stroke="#336" stroke-width="1px" 
      filter="url(#drop-shadow)" x="0" y="48px"  font-family="Arial">
    Démonstration
  </text>
</svg>

Utiliser une texture

La balise image permet de charger une image utilisable comme texture. Celle-ci s'applique de la même façon qu'un gradient.

Démonstration
<svg height="64px" width="480px">
 <pattern id="pattern1" patternUnits="userSpaceOnUse" viewBox="0 0 184 162" width="184" height="162">
   <image xlink:href="texture.jpg" width="184" height="162"/>
  </pattern>
  <text x="0" y="48" font-size="64" fill="url(#pattern1)" stroke="#000" stroke-width="1px"
           font-family="Arial">
    Démonstration
  </text>
</svg>

Ajouter un effet de lumière à une texture

On définit un filtre qui crée une nouvelle image. L'attribut feComposite permet de fusionner l'image originale avec l'image à laquelle est appliqué le filtre.

Démonstration
<svg height="64px" width="480px">
  <defs>
  <filter id="lighting">
    <feGaussianBlur in="SourceAlpha" stdDeviation = "1" result = "blur1"/>
    <feSpecularLighting result="specOut" in="blur1" specularExponent="20" lighting-color="#fff">
      <fePointLight x="-200" y="30" z="150"/>
    </feSpecularLighting>
    <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"/>
  </filter>
 </defs>
 <pattern id="pattern1" patternUnits="userSpaceOnUse" viewBox="0 0 184 162" width="184" height="162">
  <image xlink:href="texture.jpg" width="184" height="162"/>
 </pattern>
 <text filter="url(#lighting)" x="0" y="48" fill="url(#pattern1)" stroke="#000" stroke-width="1px"
           font-size="64px" font-family="Arial">
    Démonstration
 </text>
</svg>

Ajouter une ombre et un effet de lumière avec une texture

Cette fois nous avons besoin de deux filtres mais le standard ne permet pas d'appliquer plusieurs filtres à un objet aussi on-t-on créé un filtre unique qui combine deux effets.
La balise feMerge contient deux noeuds correspondant à un effet d'ombrage et un effet de lumière. Le text est toujours rempli par une texture avec la balise fill et la balise filter lui applique le filtre composite.

Démonstration
<svg height="64px" width="480px">
 <defs>
   <filter id="shadelight">
      <feGaussianBlur in="SourceAlpha" stdDeviation = "1" result = "lightblur"/>
      <feSpecularLighting result="specOut" in="lightblur" specularExponent="20" lighting-color="#fff">
          <fePointLight x="-200" y="30" z="150"/>
      </feSpecularLighting>
      <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"
                             result="lighted" />
      <feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blurred" />
      <feOffset in="blurred" result="shadowoffset" dx="3" dy="3"/>
      <feMerge>
        <feMergeNode in="shadowoffset"/>
        <feMergeNode in="lighted"/>
       </feMerge>
    </filter>
  </defs>
  <pattern id="pattern1" patternUnits="userSpaceOnUse" viewBox="0 0 184 162" width="184" height="162">
    <image xlink:href="texture.jpg" width="184" height="162"/>
  </pattern>
  <text filter="url(#shadelight)" x="0" y="48" fill="url(#pattern1)" stroke="#221" stroke-width="1px"
           font-size="64" font-family="Arial">
    Démonstration
  </text>
</svg>