<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:webfeeds="http://webfeeds.org/rss/1.0" version="2.0">
  <channel>
    <atom:link href="http://pubsubhubbub.appspot.com/" rel="hub"/>
    <atom:link href="https://f43.me/la-cascade.xml" rel="self" type="application/rss+xml"/>
    <title>La Cascade</title>
    <description/>
    <link>http://la-cascade.io</link>
    <webfeeds:icon>https://s2.googleusercontent.com/s2/favicons?alt=feed&amp;domain=la-cascade.io</webfeeds:icon>
    <generator>f43.me</generator>
    <lastBuildDate>Sun, 19 Apr 2026 17:07:52 +0200</lastBuildDate>
    <item>
      <title><![CDATA[OKLCH en CSS, des palettes de couleurs accessibles et cohérentes]]></title>
      <description><![CDATA[<p><em>Le nouveau modèle de couleur OKLCH offre une façon intuitive et cohérente de créer des couleurs pour le web.</em></p><div class="articleContent"><p>Les couleurs jouent un rôle important dans le design web, mais créer une palette de couleurs peut paraître une tâche intimidante pour les développeurs et designers. De nombreux facteurs entrent en compte lorsqu'on conçoit une palette de couleurs : la marque (branding), l'information que vous souhaitez faire passer, le maintien d'une luminosité cohérente à travers les différentes couleurs, le contraste entre les ombres, la façon dont les couleurs s'affichent en mode sombre ou lumineux, etc.</p><p>CSS propose plusieurs fonctions de couleurs, mais plusieurs sont difficiles à utiliser ou créent des résultats incohérents. Dans cet article, nous allons explorer un nouveau modèle de couleur, <code>oklch()</code>, conçu pour offrir une façon intuitive et cohérente de créer des couleurs pour le web.</p><p><strong>Table des matières</strong> :</p><ul><li><a href="https://la-cascade.io/articles/oklch-en-css/#display-p3">Le modèle de couleur Display P3</a></li>
<li><a href="https://la-cascade.io/articles/oklch-en-css/#syntaxe-oklch">Comprendre la syntaxe OKLCH</a></li>
<li>Comment OKLCH se compare aux autres fonctions de couleurs :
<ul><li><a href="https://la-cascade.io/articles/oklch-en-css/#oklch-vs-rbg">OKLCH vs RGB et HEX</a></li>
<li><a href="https://la-cascade.io/articles/oklch-en-css/#oklch-vs-hsl">OKLCH vs HSL</a></li>
<li><a href="https://la-cascade.io/articles/oklch-en-css/#oklch-vs-lch">OKLCH vs LCH</a></li>
</ul></li>
<li><a href="https://la-cascade.io/articles/oklch-en-css/#palettes-oklch">Créer des palettes de couleurs avec OKLCH</a></li>
</ul><h2 id="display-p3">Le modèle de couleurs Display P3</h2><p>Lorsque le <a href="https://www.w3.org/TR/css-color-4/">module de couleur CSS de niveau 4</a> est arrivé au stade recommandation en 2022, il a ajouté de nouveaux espaces de couleur. Les espaces de couleur sont, en gros, les représentations graphiques de groupes de couleurs disponibles sur un appareil qui accepte une gamme donnée de couleurs. Par exemple, l'espace de couleur sRGB est disponible sur la plupart des appareils depuis un certain temps. Les fonctions de couleur comme RGB et HSL créent des couleurs avec cet espace de couleurs.</p><p>Aujourd'hui, certains appareils acceptent l'espace de couleur <a href="https://developer.apple.com/documentation/appkit/nscolorspace/1644170-displayp3">Display P3</a>, conçu par Apple, qui offre à peu près 50% de couleurs de plus que sRGB :</p><figure id="attachment_175917" aria-describedby="caption-attachment-175917" class="wp-caption aligncenter c1"><img data-attachment-id="175917" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/srgb-display-p3-color-models/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png" data-orig-size="720,405" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sRBG Display P3 color models" data-image-description="" data-image-caption="&lt;p&gt;Color spectrum, showing the overlap of the sRGB and Display P3 color models. The Display P3 color space offers more colors than sRGB; image credit: &lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2023/10121/?&quot;&gt;What’s new in CSS &lt;/a&gt;– Apple Worldwide Developers Conference.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png?w=720" class="wp-image-175917 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png" alt="sRBG Display P3 Color Models" width="720" height="405" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png?resize=300,169 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175917" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/srgb-display-p3-color-models/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png" data-orig-size="720,405" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sRBG Display P3 color models" data-image-description="" data-image-caption="&lt;p&gt;Color spectrum, showing the overlap of the sRGB and Display P3 color models. The Display P3 color space offers more colors than sRGB; image credit: &lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2023/10121/?&quot;&gt;What’s new in CSS &lt;/a&gt;– Apple Worldwide Developers Conference.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png?w=720" class="wp-image-175917 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png" alt="sRBG Display P3 Color Models" width="720" height="405" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/srgb-display-p3-color-models.png?resize=300,169 300w" /></noscript>
<figcaption id="caption-attachment-175917" class="wp-caption-text">Le spectre de couleurs, montrant comment se recouvrent les modèles de couleur sRGB et Display P3. L'espace Display P3 offre plus de couleurs que sRGB ; crédit image : <a href="https://developer.apple.com/videos/play/wwdc2023/10121/">What’s new in CSS – Apple Worldwide Developers Conference</a>.</figcaption></figure><p>Le module CSS Couleur 4 propose de nouvelles fonctions de couleurs avec l'espace de couleurs Display P3 : LCH, OKLCH, LAB et OKLAB. Pour voir l'étendue de couleurs qu'offre Display P3 il vous faudra un appareil qui puisse afficher ces couleurs. Cela dit, vous pouvez toujours en profiter même si votre appareil utilise l'espace de couleur sRGB. S'il ne peut pas rendre une couleur en particulier, le navigateur choisira l'alternative la plus proche.</p><h2 id="syntaxe-oklch">Comprendre la syntaxe OKLCH</h2><p>La fonction de couleur <code>oklch()</code> prend trois paramètres obligatoires et un paramètre optionnel :</p><ul><li><code>L</code> : la Luminosité définit la proximité de la couleur avec le blanc ou le noir, où 0% est du noir pur et 100% du blanc pur.</li>
<li><code>C</code> : le Chroma représente la quantité de couleur appliquée. À la valeur minimum de 0, la couleur est proche du gris, tandis que les valeurs plus élevées sont associées à une couleur plus saturée. En théorie, la valeur du chroma est infinie, mais en pratique elle est rarement supérieure à 0.5</li>
<li><code>H</code> : la Teinte (<em>Hue</em>) définit la couleur elle-même, et sa valeur va de 0 à 360. Dans le concept, <code>H</code> est similaire à un disque chromatique. Dans le modèle de couleur sRGB, <code>0</code> représente le rouge, mais dans le model Display P3, <code>0</code> est un rose profond.</li>
<li><code>alpha</code> : cette valeur optionnelle représente l'opacité, elle va de <code>0</code> à <code>1</code>.</li>
</ul><p>Voici un exemple de couleur écrit avec la fonction <code>oklch()</code> :</p><pre class="language-css">  .color: {
    oklch(70% 0.3 150) /* Ça donnera un vert éclatant */
  }
  .color.alpha {
    color: oklch(70% 0.3 150 / 0.5) /* Ce vert aura de la transparence */
  }</pre><p>La fonction <code>oklch()</code> est assez intuitive. On n'a besoin que de la quantité de luminosité, de l'intensité de l'ombre et de la couleur elle-même.</p><h2>Comparaison de OKLCH avec d'autres fonctions de couleurs</h2><p>Le modèle de couleur <code>oklch</code> est plus intuitif et plus cohérent que d'autres fonctions comme <code>rgb()</code>, <code>hex</code>, <code>hsl()</code> et <code>lch()</code>. Voyons ça de plus près.</p><h2 id="oklch-vs-rbg">OKLCH vs RGB et HEX</h2><p>Les fonctions de couleur <code>rbg()</code> et <code>hex</code> utilisent la même approche, seule change la notation. Toutes deux créent une couleur de l'espace sRGB en modifiant trois valeurs : le rouge, le vert et le bleu. <code>rgb()</code> et <code>hex</code> sont probablement les deux fonctions les plus utilisées sur le web.</p><p>Voici un exemple de couleurs <code>rgb()</code> et <code>hex</code> :</p><pre class="language-css">.rgb-square{
  background-color: rgb(145, 230, 200);
}
.hex-square {
  background-color: #78f25b;
}</pre><p>Pouvez-vous déterminer de quelles couleurs il s'agit rien qu'en lisant le code ?</p><p>Dans cet exemple, la couleur <code>rgb()</code> est dominée par le vert, puis le bleu, et un peu de rouge. Comme les valeurs sont assez élevées, la couleur qui en résultera aura une assez grande luminosité. Mais comment cette information se traduit-elle en une couleur compréhensible ? La couleur <code>hex</code> quant ) elle est encore plus difficile à traduire car elle demande de savoir lire les valeurs hexadécimales.</p><p>Avec ces modèles, il est donc difficile de déterminer une couleur à partir de sa formule, et de savoir quelles valeurs modifier pour arriver à la couleur ou à la nuance recherchée est un vrai défi.</p><p>Voici les mystérieuses couleurs de nos exemples précédents :</p><figure id="attachment_175918" aria-describedby="caption-attachment-175918" class="wp-caption aligncenter c2"><img data-attachment-id="175918" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/colors-created-rgb-hex-color-functions/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png" data-orig-size="660,327" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Colors created RBG HEX color functions" data-image-description="" data-image-caption="&lt;p&gt;The left and right squares were created with the &lt;code&gt;rgb()&lt;/code&gt; and &lt;code&gt;hex&lt;/code&gt; color functions, respectively.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png?w=660" class="wp-image-175918 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png" alt="Colors Created RBG HEX Color Functions" width="660" height="327" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png 660w, https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png?resize=300,149 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175918" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/colors-created-rgb-hex-color-functions/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png" data-orig-size="660,327" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Colors created RBG HEX color functions" data-image-description="" data-image-caption="&lt;p&gt;The left and right squares were created with the &lt;code&gt;rgb()&lt;/code&gt; and &lt;code&gt;hex&lt;/code&gt; color functions, respectively.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png?w=660" class="wp-image-175918 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png" alt="Colors Created RBG HEX Color Functions" width="660" height="327" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png 660w, https://blog.logrocket.com/wp-content/uploads/2023/08/colors-created-rgb-hex-color-functions.png?resize=300,149 300w" /></noscript>
<figcaption id="caption-attachment-175918" class="wp-caption-text">Ces deux carrés ont été créés avec les fonctions de couleur <code class="prettyprinted">rgb()</code> et <code class="prettyprinted">hex</code> respectivement.</figcaption></figure><p>Regardons maintenant une couleur écrite avec la fonction <code>oklch()</code> :</p><pre class="language-css">.oklch-square {
  background-color: oklch(45% 0.2 200);
}</pre><p>Cette couleur a une luminosité de 45%, nous pouvons donc supposer qu'elle n'est pas très brillante. La valeur de chroma est <code>0.2</code>, elle est donc très saturée. Et la valeur <code>200</code> de la teinte correspond à la couleur turquoise, nous pouvons donc en déduire que la couleur est une variante légèrement sombre et atténuée de turquoise.</p><p>Voici la couleur :</p><figure id="attachment_175919" aria-describedby="caption-attachment-175919" class="wp-caption aligncenter c3"><img data-attachment-id="175919" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/color-created-oklch-color-function/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png" data-orig-size="311,308" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Color created OKLCH color function" data-image-description="" data-image-caption="&lt;p&gt;Square created with the &lt;code&gt;oklch()&lt;/code&gt; color function.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?w=311" class="wp-image-175919 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png" alt="Color Created OKLCH Color Function" width="311" height="308" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png 311w, https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?resize=150,150 150w, https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?resize=300,297 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175919" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/color-created-oklch-color-function/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png" data-orig-size="311,308" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Color created OKLCH color function" data-image-description="" data-image-caption="&lt;p&gt;Square created with the &lt;code&gt;oklch()&lt;/code&gt; color function.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?w=311" class="wp-image-175919 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png" alt="Color Created OKLCH Color Function" width="311" height="308" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png 311w, https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?resize=150,150 150w, https://blog.logrocket.com/wp-content/uploads/2023/08/color-created-oklch-color-function.png?resize=300,297 300w" /></noscript>
<figcaption id="caption-attachment-175919" class="wp-caption-text">Un carré créé avec la fonction de couleur <code class="prettyprinted">oklch()</code>.</figcaption></figure><p>Avec cette fonction de couleur il est bien plus facile de déduire la couleur et de comprendre quelles valeurs modifier pour créer des variantes plus claires, plus sombres ou plus brillantes. C'est ici que les avantages de <code>oklch()</code> commencent à apparaître.</p><p>Comparons maintenant <code>oklch()</code> avec un autre modèle de couleur qui fonctionne sur le même principe, mais qui n'a pas la même cohérence.</p><h2 id="oklch-vs-hsl">OKLCH vs HSL</h2><p>Avant le module de couleur 4, <code>hsl()</code> était la meilleure option pour créer intuitivement une palette de couleurs. Cette function a trois paramètres : la teinte (Hue), la saturation et la luminosité. On pourrait penser que saturation et chroma sont la même chose, mais en fait non ! La saturation renvoie à la force ou l'intensité d'une couleur, tandis que le chroma renvoie à la pureté de la couleur (combien de blanc, de noir ou de gris a été ajouté).</p><p>Comme le disent Andrey Sitnik et Travis Turner dans leur article <a href="https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl">OKLCH en CSS, pourquoi nous avons abandonné RGB et HSL</a>, HSL est un espace de couleur distribué dans un cylindre. Ça signifie que si nous plaçons cet espace dans un graphe à deux dimensions, nous observerons que chaque couleur a la même saturation, de 0% à 100%. Mais ce n'est pas comme cela que nos yeux perçoivent la saturation. En réalité, chaque teinte a des valeurs de saturation différentes.</p><p>Remarquez la différence quand nous comparonsles espaces de couleur HSL et OKLCH et que nous supprimons la teinte :</p><figure id="attachment_175920" aria-describedby="caption-attachment-175920" class="wp-caption aligncenter c1"><img data-attachment-id="175920" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/comparing-hsl-oklch-color-spaces/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png" data-orig-size="720,348" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Comparing HSL OKLCH color spaces" data-image-description="" data-image-caption="&lt;p&gt;Comparison of HSL and OKLCH color spaces with the same chroma or saturation values. The upper illustrations show how the hue is distributed in both color spaces; the lower illustrations show the same hue but in black and white; image credit: OKLCH in CSS: Why we moved from RGB and HSL.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png?w=720" class="wp-image-175920 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png" alt="Comparing HSL OKLCH Color Spaces" width="720" height="348" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png?resize=300,145 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175920" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/comparing-hsl-oklch-color-spaces/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png" data-orig-size="720,348" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Comparing HSL OKLCH color spaces" data-image-description="" data-image-caption="&lt;p&gt;Comparison of HSL and OKLCH color spaces with the same chroma or saturation values. The upper illustrations show how the hue is distributed in both color spaces; the lower illustrations show the same hue but in black and white; image credit: OKLCH in CSS: Why we moved from RGB and HSL.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png?w=720" class="wp-image-175920 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png" alt="Comparing HSL OKLCH Color Spaces" width="720" height="348" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/comparing-hsl-oklch-color-spaces.png?resize=300,145 300w" /></noscript>
<figcaption id="caption-attachment-175920" class="wp-caption-text">Comparaison des espaces de couleur HSL et OKLCH, avec les mêmes valeurs de chroma ou de saturation. Les illustrations du haut montrent commentla teinte est distribuée dans chaque espace ; les illustrations du bas montrent la même teinte mais en noir et blanc ; crédit image : OKLCH in CSS: Why we moved from RGB and HSL.</figcaption></figure><p>Vous remarquerez comment OKLCH présente une teinte plus uniforme que HSL. C'est ce qui affecte la cohérence de rendu de ce dernier lorsque nous commençons à manipuler les couleurs.</p><p>Pour mieux comprendre, prenons un exemple. nous allons créer deux boutons avec les modèles <code>hsl()</code> et <code>oklch()</code> en utilisant les valeurs suivantes :</p><ul><li>Teinte : 90 pour le premier bouton et 270 pour le second.</li>
<li>Saturation : 100% pour <code>hsl</code></li>
<li>Chroma : 0.5 pour <code>oklch</code></li>
<li>Luminosité : 50%</li>
<li>Couleur du texte : blanc</li>
</ul><p>Voici les boutons :</p><figure id="attachment_175921" aria-describedby="caption-attachment-175921" class="wp-caption aligncenter c1"><img data-attachment-id="175921" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/buttons-created-hsl-oklch-molor-models/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png" data-orig-size="720,163" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Buttons created HSL OKLCH color models" data-image-description="" data-image-caption="&lt;p&gt;The top buttons were created with the &lt;code&gt;hsl()&lt;/code&gt; color model; the bottom buttons were created with the &lt;code&gt;oklch()&lt;/code&gt; color model.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png?w=720" class="wp-image-175921 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png" alt="Buttons Created HSL OKLCH Color Models" width="720" height="163" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png?resize=300,68 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175921" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/buttons-created-hsl-oklch-molor-models/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png" data-orig-size="720,163" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Buttons created HSL OKLCH color models" data-image-description="" data-image-caption="&lt;p&gt;The top buttons were created with the &lt;code&gt;hsl()&lt;/code&gt; color model; the bottom buttons were created with the &lt;code&gt;oklch()&lt;/code&gt; color model.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png?w=720" class="wp-image-175921 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png" alt="Buttons Created HSL OKLCH Color Models" width="720" height="163" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/buttons-created-hsl-oklch-molor-models.png?resize=300,68 300w" /></noscript>
<figcaption id="caption-attachment-175921" class="wp-caption-text">Les boutons du haut ont été créés avec le modèle de couleur <code class="prettyprinted">hsl()</code> ; les boutons du bas ont été crées avec le modèle <code class="prettyprinted">oklch()</code>.</figcaption></figure><p>On constate d'abord que les couleurs ne sont pas les mêmes, car les cercles chromatiques de HSL et OKLCH diffèrent. On remarque que les boutons créés avec <code>hsl()</code> n'offrent pas le même niveau de contraste ; le bouton vert est presque illisible ! Les boutons créés avec la fonction de couleur <code>oklch()</code> ont un niveau de luminosité perçue assez similaires, et offrent une expérience comparable en termes de lisibilité.</p><p>Le modèle <code>hsl()</code> n'est pas fiable lorsqu'il s'agit de manipuler et créer des palettes de couleurs. <code>oklch()</code> offre la même expérience intuitive que <code>hsl()</code>, mais avec des rendus plus cohérents.</p><h2 id="oklch-vs-lch">OKLCH vs LCH</h2><p>Le modèle de couleur <code>lch()</code> est très similaire à <code>oklch()</code> et offre généralement des résultats très cohérents. Un point d'attention toutefois, comme Andrey Sitnik et Travis Turner l'ont fait remarquer dans leur article : <code>lch()</code> a un bug qui affecte les valeurs de chroma et luminosité du bleu (c'est à dire les teintes <code>lch()</code> entre 270 et 330).</p><p><code>oklch()</code> a été créé comme une version de <code>lch()</code> qui serait plus aisée à comprendre pour les devices et offirait des résultats plus cohérents. On y est parvenu en résolvant le bug en question, en améliorant la gamme de couleurs et en ajoutant quelques autres caractéristiques.</p><p>J'espère qu'il est clair que <code>oklch()</code> est intuitif, accessible et, d'une manière générale, qu'il représente la meilleure option pour créer des couleurs pour le web. Mettons cela en pratique.</p><h2 id="palettes-oklch">Créer des palettes de couleurs avec OKLCH</h2><p>Ah ! la partie amusante maintenant : nous allons utiliser <code>oklch()</code> pour créer quatre fenêtres d'alerte. Chacune aura une palette de couleurs différente pour communiquer un message spécifique. Voici une liste de palettes de couleurs et les messages associés :</p><ul><li>palette "couleurs de la marque" : message produit</li>
<li>palette verte : message de succès</li>
<li>palette jaune : message d'avertissement</li>
<li>palette rouge : message d'erreur</li>
</ul><p>Pouur chaque type de message (ou d'état), nous allons créer 9 nuances de la même couleur, depuis le très clair jusqu'au sombre. Nous associerons aussi une palette de couleur neutre pour le texte de la fenêtre et nous fournirons les modes lumineux et sombre.</p><p>Allons-y !</p><h3>Créer une palette de couleur neutre</h3><p>L'important quand on crée des couleurs neutres c'est d'avoir un chroma très faible. Le chroma définit la pureté de la couleur, donc une valeur proche de 0 résultera en une couleur proche du gris. Comme le noir pur (ou le blanc pur) peuvent fatiguer les yeux, nous ajoutons une teinte légère en utilisant une valeur de chroma de 0.01 .</p><p>Ensuite, nous définissons notre teinte de couleur de marque. Ça pourrait être n'importe quelle valeur, mais pour cet exemple j'ai choisi <code>280</code> parce que j'aime cette nuance particulière de bleu.</p><p>Maintenant nous allons commencer à modifier les valeurs de luminosité. L'important ici c'est de commencer avec une valeur assez élevée pour la première couleur et de la réduire petit à petit à une valeur relativement basse pour la dernière couleur.</p><p>J'ai commencé avec une valeur de luminosité de 97% et je termine avec 12%. Voici les propriétés custom auxquelles je suis arrivé :</p><pre class="language-css">:root {
  --clr-neutral-100: oklch(97% 0.01 280);
  --clr-neutral-200: oklch(89% 0.01 280);
  --clr-neutral-300: oklch(80% 0.01 280);
  --clr-neutral-400: oklch(71% 0.01 280);
  --clr-neutral-500: oklch(60% 0.01 280);
  --clr-neutral-600: oklch(49% 0.01 280);
  --clr-neutral-700: oklch(38% 0.01 280);
  --clr-neutral-800: oklch(25% 0.01 280);
  --clr-neutral-900: oklch(12% 0.01 280);
}</pre><p>Et voici la palette de couleur neutre qui en résulte :</p><figure id="attachment_175922" aria-describedby="caption-attachment-175922" class="wp-caption aligncenter c4"><img data-attachment-id="175922" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/neutral-color-palette-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png" data-orig-size="555,135" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Neutral color palette OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Neutral color palette, with colors arranged from lightest to darkest.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png?w=555" class="wp-image-175922 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png" alt="Neutral Color Palette OKLCH" width="555" height="135" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png 555w, https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png?resize=300,73 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175922" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/neutral-color-palette-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png" data-orig-size="555,135" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Neutral color palette OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Neutral color palette, with colors arranged from lightest to darkest.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png?w=555" class="wp-image-175922 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png" alt="Neutral Color Palette OKLCH" width="555" height="135" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png 555w, https://blog.logrocket.com/wp-content/uploads/2023/08/neutral-color-palette-oklch.png?resize=300,73 300w" /></noscript>
<figcaption id="caption-attachment-175922" class="wp-caption-text">Une palette de couleurs neutre, avec ses couleurs arrangées de la plus lumineuse à la plus sombre.</figcaption></figure><p>J'ai créé cette palette simplement en regardant les valeurs et le résultat est plutôt bon ! Il y a certainement des approches plus précises pour arriver à une transition plus douce entre les nuances, mais une des caractéristiques les plus remarquables de <code>oklch()</code> est qu'il permet de créer des palettes de couleurs de façon intuitive et avec des résultats assez cohérents.</p><p>Avant de créer les palettes de couleurs pour les différents états, jetons un œil au design de notre fenêtre, du point de vue de l'accessibilité.</p><h3>Prendre en compte les considérations d'accessibilité</h3><p>Pour ce qui est des couleurs, deux points d'accessibilité importants : assurer un contraste suffisant et fournir des façons alternatives (autres que la couleur) de faire passer une information.</p><h4>Améliorer le contraste</h4><p>Le <a href="https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html">critère de succès 1.4.3 - contraste minimum du WCAG 2.1</a> indique que le contraste minimal pour un texte normal ou grand est de 4.5:1 et 3:1 respectivement. Nous devrons choisir des combinaisons de couleurs permettant ces ratios de contraste. J'ai attendu, pour discuter de ce point, d'avoir déjà créé notre palette de couleur neutre, afin que nous puissions déjà l'utiliser pour faire un prototype.</p><table class="oklch"><thead><tr><th><strong>Item</strong></th>
<th><strong>Shade</strong></th>
</tr></thead><tbody><tr><td>Accent</td>
<td>700</td>
</tr><tr><td>Background</td>
<td>200</td>
</tr><tr><td>Text</td>
<td>800</td>
</tr></tbody></table><p>Voici notre fenêtre de message :</p><figure id="attachment_175923" aria-describedby="caption-attachment-175923" class="wp-caption aligncenter c5"><img data-attachment-id="175923" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/sample-message-window-neutral-color-palette/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png" data-orig-size="466,264" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Sample message window neutral color palette" data-image-description="" data-image-caption="&lt;p&gt;Sample message window created with the neutral color palette.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png?w=466" class="wp-image-175923 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png" alt="Sample Message Window Neutral Color Palette" width="466" height="264" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png 466w, https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png?resize=300,170 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175923" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/sample-message-window-neutral-color-palette/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png" data-orig-size="466,264" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Sample message window neutral color palette" data-image-description="" data-image-caption="&lt;p&gt;Sample message window created with the neutral color palette.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png?w=466" class="wp-image-175923 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png" alt="Sample Message Window Neutral Color Palette" width="466" height="264" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png 466w, https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-neutral-color-palette.png?resize=300,170 300w" /></noscript>
<figcaption id="caption-attachment-175923" class="wp-caption-text">Fenêtre de message créée avec la palette de couleurs neutres.</figcaption></figure><h4>Améliorer la communication</h4><p>Le <a href="https://www.w3.org/WAI/WCAG21/Understanding/use-of-color.html">critère de succès 1.4.1 - utilisation de la couleur du WCAG 2.1</a> spécifie que la couleur ne devrait pas "être utilisée comme moyen de communiquer une information, d'indiquer une action, de demander une réponse, ou de distinguer un élément visuel". En nous conformant aux techniques suggérées par le WCAG nous avons clarifié l'information du contenu textuel lui-même et nous avons ajouté une icône facilement reconnaissable pour donner une indication supplémentaire sur son contenu :</p><figure id="attachment_175924" aria-describedby="caption-attachment-175924" class="wp-caption aligncenter c6"><img data-attachment-id="175924" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/sample-message-window-improved-communication/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png" data-orig-size="487,266" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sSample message window improved communication" data-image-description="" data-image-caption="&lt;p&gt;Sample message window with an icon on the left side.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png?w=487" class="wp-image-175924 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png" alt="Sample Message Window Improved Communication" width="487" height="266" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png 487w, https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png?resize=300,164 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175924" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/sample-message-window-improved-communication/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png" data-orig-size="487,266" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sSample message window improved communication" data-image-description="" data-image-caption="&lt;p&gt;Sample message window with an icon on the left side.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png?w=487" class="wp-image-175924 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png" alt="Sample Message Window Improved Communication" width="487" height="266" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png 487w, https://blog.logrocket.com/wp-content/uploads/2023/08/sample-message-window-improved-communication.png?resize=300,164 300w" /></noscript>
<figcaption id="caption-attachment-175924" class="wp-caption-text">Fenêtre de message avec une icône à gauche.</figcaption></figure><p>Nous avons avancé sur l'accessibilité, créons maintenant une palette de couleurs pour nos différents états.</p><h4>Créer les palettes de couleurs d'états</h4><p>Maintenant que nous avons une échelle de luminosité, le temps est venu de l'utiliser pour créer nos couleurs de marque. Pour ce faire, nous allons modifier les valeurs de chroma — mais comment savoir lesquelles utiliser ? Là encore, le mieux est de faire confiance à ses propres yeux, mais il y a quand même une méthode qui donne de bons résultats la plupart du temps. Mon approche consiste à modifier les valeurs de façon telle que les nuances les plus extrêmes (les valeurs 100 et 900) aient des valeurs de chroma faibles et les nuances moyennes (vers 500) des valeurs de chroma élevées. Si je devais représenter cela sur un graphique, ça donnerait ceci :</p><figure id="attachment_175925" aria-describedby="caption-attachment-175925" class="wp-caption aligncenter c1"><img data-attachment-id="175925" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/chroma-values-color-shades/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png" data-orig-size="720,432" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Chroma values color shades" data-image-description="" data-image-caption="&lt;p&gt;Graph of chroma values for different color shades; medium shades have the highest chroma values.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png?w=720" class="wp-image-175925 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png" alt="Chroma Values Color Shades" width="720" height="432" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png?resize=300,180 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175925" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/chroma-values-color-shades/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png" data-orig-size="720,432" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Chroma values color shades" data-image-description="" data-image-caption="&lt;p&gt;Graph of chroma values for different color shades; medium shades have the highest chroma values.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png?w=720" class="wp-image-175925 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png" alt="Chroma Values Color Shades" width="720" height="432" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/chroma-values-color-shades.png?resize=300,180 300w" /></noscript>
<figcaption id="caption-attachment-175925" class="wp-caption-text">Graphe de valeurs de chroma pour différentes nuances de couleurs ; les nuances moyennes ont les valeurs de chroma les plus élevées.</figcaption></figure><p>Cela va créer un groupe de nuances allant du presque blanc au presque noir avec des couleurs plus vives au milieu. Nous devrons ajouter ces valeurs de chroma à nos propriétés custom.</p><p>Vous vous rappelez que nous avons sélectionné <code>280</code> comme la valeur de base de notre teinte (<em>Hue</em>) et nous l'utilisons pour notre palette de couleurs neutres. Maintenant nous allons copier les valeurs, les modifier, et les ajouter à de nouvelles propriétés custom :</p><pre class="language-css">:root {
  --clr-brand-100: oklch(97% 0.02 280);
  --clr-brand-200: oklch(89% 0.05 280);
  --clr-brand-300: oklch(80% 0.12 280);
  --clr-brand-400: oklch(71% 0.19 280);
  --clr-brand-500: oklch(60% 0.27 280);
  --clr-brand-600: oklch(49% 0.19 280);
  --clr-brand-700: oklch(38% 0.12 280);
  --clr-brand-800: oklch(25% 0.05 280);
  --clr-brand-900: oklch(12% 0.02 280);
}</pre><p>Voici notre palette de couleurs de marque :</p><figure id="attachment_175926" aria-describedby="caption-attachment-175926" class="wp-caption aligncenter c7"><img data-attachment-id="175926" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/brand-color-palette-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png" data-orig-size="553,135" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Brand color palette OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Brand color palette, with colors arranged from lightest to darkest.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png?w=553" class="wp-image-175926 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png" alt="Brand Color Palette OKLCH" width="553" height="135" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png 553w, https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png?resize=300,73 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175926" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/brand-color-palette-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png" data-orig-size="553,135" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Brand color palette OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Brand color palette, with colors arranged from lightest to darkest.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png?w=553" class="wp-image-175926 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png" alt="Brand Color Palette OKLCH" width="553" height="135" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png 553w, https://blog.logrocket.com/wp-content/uploads/2023/08/brand-color-palette-oklch.png?resize=300,73 300w" /></noscript>
<figcaption id="caption-attachment-175926" class="wp-caption-text">Palette de couleurs de marque, avec les couleurs allant du plus lumineux au plus sombre.</figcaption></figure><p>Et maintenant il est temps de créer les palettes de couleurs pour les messages de succès, avertissement et erreur. Tout ce que nous avons à faire, c'est de copier les valeurs de luminosité et de chroma utilisées pour nos couleurs de marque et de modifier les valeurs de teinte.</p><p>Le cercle chromatique d'OKLCH est un peu différent, donc je vais juste mettre les valeurs ici :</p><table class="oklch"><thead><tr><th><strong>État</strong></th>
<th><strong>Teinte</strong></th>
</tr></thead><tbody><tr><td>Succès</td>
<td>150</td>
</tr><tr><td>Avertissement</td>
<td>80</td>
</tr><tr><td>Erreur</td>
<td>20</td>
</tr></tbody></table><p>Et voici nos nouvelles propriétés custom :</p><pre class="language-css">:root {
  --clr-success-100: oklch(97% 0.02 150);
  --clr-success-200: oklch(89% 0.05 150);
  --clr-success-300: oklch(80% 0.12 150);
  --clr-success-400: oklch(71% 0.19 150);
  --clr-success-500: oklch(60% 0.27 150);
  --clr-success-600: oklch(49% 0.19 150);
  --clr-success-700: oklch(38% 0.12 150);
  --clr-success-800: oklch(25% 0.05 150);
  --clr-success-900: oklch(12% 0.02 150);
  --clr-warning-100: oklch(97% 0.02 80);
  --clr-warning-200: oklch(89% 0.05 80);
  --clr-warning-300: oklch(80% 0.12 80);
  --clr-warning-400: oklch(71% 0.19 80);
  --clr-warning-500: oklch(60% 0.27 80);
  --clr-warning-600: oklch(49% 0.19 80);
  --clr-warning-700: oklch(38% 0.12 80);
  --clr-warning-800: oklch(25% 0.05 80);
  --clr-warning-900: oklch(12% 0.02 80);
  --clr-error-100: oklch(97% 0.02 20);
  --clr-error-200: oklch(89% 0.05 20);
  --clr-error-300: oklch(80% 0.12 20);
  --clr-error-400: oklch(71% 0.19 20);
  --clr-error-500: oklch(60% 0.27 20);
  --clr-error-600: oklch(49% 0.19 20);
  --clr-error-700: oklch(38% 0.12 20);
  --clr-error-800: oklch(25% 0.05 20);
  --clr-error-900: oklch(12% 0.02 20);
}</pre><p>Et pour finir, voici nos palettes de couleurs pour les messages d'états :</p><figure id="attachment_175927" aria-describedby="caption-attachment-175927" class="wp-caption aligncenter c8"><img data-attachment-id="175927" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/success-warning-error-message-color-palettes-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png" data-orig-size="554,403" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Success warning error message color palettes OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Success (green), warning (yellow), and error (red) color palettes, with colors arranged from lightest to darkest; the colors share a similar luminosity.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png?w=554" class="wp-image-175927 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png" alt="Success Warning Error Message Color Palettes OKLCH" width="554" height="403" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png 554w, https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png?resize=300,218 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175927" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/success-warning-error-message-color-palettes-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png" data-orig-size="554,403" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Success warning error message color palettes OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Success (green), warning (yellow), and error (red) color palettes, with colors arranged from lightest to darkest; the colors share a similar luminosity.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png?w=554" class="wp-image-175927 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png" alt="Success Warning Error Message Color Palettes OKLCH" width="554" height="403" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png 554w, https://blog.logrocket.com/wp-content/uploads/2023/08/success-warning-error-message-color-palettes-oklch.png?resize=300,218 300w" /></noscript>
<figcaption id="caption-attachment-175927" class="wp-caption-text">Palettes de couleurs pour succès (vert), avertissement (jaune), et erreur (rouge), les couleurs sont organisées de la plus lumineuse à la plus sombre; les couleurs utilisent les mêmes valeurs de luminosité.</figcaption></figure><p>Et voilà ! avec OKLCH, vous pouvez créer rapidement les couleurs dont vous avez besoin, juste en modifiant quelques valeurs, de façon cohérente et intuitive.</p><p>Maintenant, nous allons appliquer ces couleurs à notre composant message d'état, et nous allons les rendre compatibles avec les modes light et dark. Pour cela, nous utiliserons ces propriétés custom pour définir des variantes.</p><h4>Gérer les différents états dans les fenêtres de messages</h4><p>Pour ce projet, nous allons créer trois nuances : <em>accent</em> (pour les bordures de cartes et pour les boutons), <em>background</em> et <em>texte</em>. Nous les utiliserons partout, sauf pour l'icône et le texte du bouton primaire qui seront réalisés avec la palette de couleurs neutres.</p><p>Nous devons modifier deux nuances : 200 (background) et 700 (accents), et créer quelques propriétés custom pour chaque état.</p><p>Nous allons aussi créer quelques "valeurs atomiques de design' (<em>design tokens</em>).</p><p class="is-style-explanation">Les <em>design tokens</em> sont des entités nommées qui représentent des valeurs de design atomiques. Ce sont des paires clé-valeur, dans lesquelles la clé est un nom qui représente <em>une valeur primitive</em> de couleur, d'espace, de taille de police, etc.</p><pre class="language-css">:root {
  /* Neutral color design tokens */
  --clr-text: var(--clr-neutral-800);
  --clr-text-invert: var(--clr-neutral-200);
  /* Non-neutral color design tokens */
  --clr-brand-accent: var(--clr-brand-700);
  --clr-brand-background: var(--clr-brand-200);
  --clr-success-accent: var(--clr-success-700);
  --clr-success-background: var(--clr-success-200);
  --clr-warning-accent: var(--clr-warning-700);
  --clr-warning-background: var(--clr-warning-200);
  --clr-error-accent: var(--clr-error-700);
  --clr-error-background: var(--clr-error-200);
}</pre><p>Ici, nous définissons des <em>design tokens</em> plutôt que d'utiliser les couleurs directement, ce qui nous facilitera la vie lorsque nous créerons des variantes pour le mode sombre tout à l'heure.</p><p>Pour la simplicité, je n'ajoute ici que le style en lien avec la couleur. J'ajoute également la structure HTML utilisée pour les fenêtres :</p><pre class="language-html">&lt;div class="card" data-type="brand"&gt; &lt;!-- This dataset will be used to define colors later --&gt;
  &lt;div class="card__icon-container"&gt;
    &lt;svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"&gt;
      &lt;!-- SVG path --&gt;
    &lt;/svg&gt;
  &lt;/div&gt;
  &lt;div class="card__text-container"&gt;
    &lt;h2&gt;Welcome to FakeApp™&lt;/h2&gt;
    &lt;p&gt;This is an app that doesn't exist at all!&lt;/p&gt;
    &lt;p&gt;We invite you to check what that app offers by using our tour functionality.&lt;/p&gt;
    &lt;div class="button__container"&gt;
      &lt;button class="button__primary"&gt;Start tour&lt;/button&gt;
      &lt;button class="button__secondary"&gt;Omit&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><pre class="language-css">.card {
  border: 5px solid var(--window-accent);
  background-color: var(--window-background);
}
.card__icon-container {
  background-color: var(--window-accent);
  color: var(--clr-text-invert);
}
.card__icon-container svg {
  stroke: currentColor;
}
.card h2 {
  color: var(--window-accent);
}
.button__primary {
  background-color: var(--window-accent);
  color: var(--clr-text-invert);
  border-color: transparent;
}
.button__secondary {
  background-color: transparent;
  color: var(--window-accent);
  border-color: currentColor;
}</pre><p>Comme vous le voyez, j'ai créé deux variables pour chaque fenêtre : <code>--window-accent</code> et <code>--window-background</code>. J'utiliserai un attribut <code>data-</code> pour définir les propriétés custom de la fenêtre, grâce à nos <em>design tokens</em> :</p><pre class="language-css">.card[data-type="brand"] {
  --card-accent: var(--clr-brand-accent);
  --card-background: var(--clr-brand-background);
}
.card[data-type="success"] {
  --card-accent: var(--clr-success-accent);
  --card-background: var(--clr-success-background);
}
.card[data-type="warning"] {
  --card-accent: var(--clr-warning-accent);
  --card-background: var(--clr-warning-background);
}
.card[data-type="error"] {
  --card-accent: var(--clr-error-accent);
  --card-background: var(--clr-error-background);
}</pre><p>Voici le résultat :</p><figure id="attachment_175928" aria-describedby="caption-attachment-175928" class="wp-caption aligncenter c1"><img data-attachment-id="175928" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/message-windows-custom-color-palettes-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png" data-orig-size="720,426" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Message windows custom color palettes OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Message windows using the blue (brand), green (success), yellow (warning), and error (red) color palettes.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png?w=720" class="wp-image-175928 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png" alt="Message Windows Custom Color Palettes OKLCH" width="720" height="426" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png?resize=300,178 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175928" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/message-windows-custom-color-palettes-oklch/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png" data-orig-size="720,426" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Message windows custom color palettes OKLCH" data-image-description="" data-image-caption="&lt;p&gt;Message windows using the blue (brand), green (success), yellow (warning), and error (red) color palettes.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png?w=720" class="wp-image-175928 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png" alt="Message Windows Custom Color Palettes OKLCH" width="720" height="426" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-custom-color-palettes-oklch.png?resize=300,178 300w" /></noscript>
<figcaption id="caption-attachment-175928" class="wp-caption-text">Fenêtres de message utilisant les palettes bleu (pour la marque), vert (succès), jaune (alerte) et rouge (erreur).</figcaption></figure><p>Nous avons vu à quel point il est facile de créer des variantes de couleurs à l'aide de <em>design tokens</em>, mais qu'en est-il du contraste ? Avec le modèle <code>oklch()</code>, si nous gardons les mêmes valeurs de luminosité sur l'ensemble des palettes, le contraste restera inchangé ou très proche. Pour le démontrer, voici une comparaison entre le contraste de la fenêtre de marque (couleurs neutres) et celle de la fenêtre d'erreur.</p><figure id="attachment_175929" aria-describedby="caption-attachment-175929" class="wp-caption aligncenter c1"><img data-attachment-id="175929" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/constrast-comparison-neutral-warning-message-windows/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png" data-orig-size="720,311" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Contrast comparison neutral warning message windows" data-image-description="" data-image-caption="&lt;p&gt;Comparison of a sample window with the neutral color palette and an error window with the red color palette. The contrast between the title (shade 700) and the background (shade 200) is 7.2 for the sample window and 7.5 for the error window.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png?w=720" class="wp-image-175929 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png" alt="Contrast Comparison Neutral Warning Message Windows" width="720" height="311" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png?resize=300,130 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175929" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/constrast-comparison-neutral-warning-message-windows/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png" data-orig-size="720,311" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Contrast comparison neutral warning message windows" data-image-description="" data-image-caption="&lt;p&gt;Comparison of a sample window with the neutral color palette and an error window with the red color palette. The contrast between the title (shade 700) and the background (shade 200) is 7.2 for the sample window and 7.5 for the error window.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png?w=720" class="wp-image-175929 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png" alt="Contrast Comparison Neutral Warning Message Windows" width="720" height="311" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/constrast-comparison-neutral-warning-message-windows.png?resize=300,130 300w" /></noscript>
<figcaption id="caption-attachment-175929" class="wp-caption-text">Comparaison des fenêtres "marque" (palette de couleurs neutres) et "erreur" (palette de couleurs rouges). Le contraste entre le titre (shade 700) et l'arrière-plan (shade 200) est de 7.2 pour la première et 7.5 pour la seconde.</figcaption></figure><p>Modifier les valeurs de chroma en revanche pourrait avoir un impact sur le constraste, mais à moins de créer une palette de couleurs vraiment saturées, on ne devrait pas avoir de problème. À présent, la seule chose qu'il nous reste à faire est de créer des versions pour le mode sombre.</p><h4>Créer des variantes pour le mode sombre</h4><p>Nous pouvons ajouter les variantes "dark-mode" à nos <em>design-tokens</em> dans la media query CSS <code>prefers-color-scheme</code> pour créer les variantes respectives lorsque l'utilisateur a activé le mode sombre dans son système ou son navigateur.</p><pre class="language-css">@media screen and (prefers-color-scheme: dark) {
  :root {
    --clr-background: var(--clr-neutral-900);
    --clr-text: var(--clr-neutral-200);
    --clr-text-invert: var(--clr-neutral-900);
    --clr-brand-accent: var(--clr-brand-300);
    --clr-brand-background: var(--clr-brand-800);
    --clr-success-accent: var(--clr-success-300);
    --clr-success-background: var(--clr-success-800);
    --clr-warning-accent: var(--clr-warning-300);
    --clr-warning-background: var(--clr-warning-800);
    --clr-error-accent: var(--clr-error-300);
    --clr-error-background: var(--clr-error-800);
  }
}</pre><p>Voici comment nos fenêtres s'afficheront en mode sombre :</p><figure id="attachment_175930" aria-describedby="caption-attachment-175930" class="wp-caption aligncenter c1"><img data-attachment-id="175930" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/message-windows-oklch-color-palettes-dark-mode/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png" data-orig-size="720,462" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Message windows OKLCH color palettes dark mode" data-image-description="" data-image-caption="&lt;p&gt;Brand, success, warning, and error message cards made with “inverted” color palettes for dark mode.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png?w=720" class="wp-image-175930 size-full jetpack-lazy-image jetpack-lazy-image--handled" src="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png" alt="Message Windows OKLCH Color Palettes Dark Mode" width="720" height="462" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png?resize=300,193 300w" data-lazy-loaded="1" /><noscript><img data-lazy-fallback="1" data-attachment-id="175930" data-permalink="https://blog.logrocket.com/oklch-css-consistent-accessible-color-palettes/attachment/message-windows-oklch-color-palettes-dark-mode/" data-orig-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png" data-orig-size="720,462" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Message windows OKLCH color palettes dark mode" data-image-description="" data-image-caption="&lt;p&gt;Brand, success, warning, and error message cards made with “inverted” color palettes for dark mode.&lt;/p&gt;" data-medium-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png?w=300" data-large-file="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png?w=720" class="wp-image-175930 size-full" src="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png" alt="Message Windows OKLCH Color Palettes Dark Mode" width="720" height="462" srcset="https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png 720w, https://blog.logrocket.com/wp-content/uploads/2023/08/message-windows-oklch-color-palettes-dark-mode.png?resize=300,193 300w" /></noscript>
<figcaption id="caption-attachment-175930" class="wp-caption-text">Messages de marque, succès, alerte, et erreur réalisées avec les palettes "inversées" du mode sombre.</figcaption></figure><p>Et voilà ! Vous pouvez utiliser la fonction de couleur <code>oklch()</code> pour créer une palette de couleurs qui produit des résultats cohérents.</p><h4>Compatibilité navigateurs</h4><p>Selon <a href="https://caniuse.com/mdn-css_types_color_oklch">CanIUse</a>, la fonction <code>oklch()</code> est compatible avec les principaux navigateurs. Cela dit, Firefox l'a mis en œuvre en juin 2023 et Samsung Internet n'est toujours pas compatible à la date de rédaction de cet article. On ne peut pas non plus supposer que tous les utilsateurs ont la dernière version de leur navigateur, par conséquent il est utile de créer une solution de repli si l'on souhaite utiliser ce modèle de couleur en production.</p><p>Un outil peut nous y aider : l'excellent site <a href="https://huetone.ardov.me/">Huetone</a> nous permet de créer facilement une palette de couleurs avec <code>oklch</code> et de l'exporter en format hexadécimal, prêt à l'usage en CSS. Nous pouvons même copier la palette sous forme de <em>design tokens</em> et l'utiliser dans Figma avec <a href="https://www.figma.com/community/plugin/888356646278934516/design-tokens">le plugin Design Tokens</a></p><p>Cet article n'est pas un tutoriel Huetone, d'autant que ce n'est pas nécessaire ! Le mode d'emploi est très clair. Voici les <em>design-tokens</em> que j'ai <a href="https://huetone.ardov.me/">créés sur Huetone</a>.</p><p>Prenez soin de bien nommer vos couleurs. Personnellement j'ai suivi cette convention de nommage pour mes propriétés custom : <code>--clr-[etat]-[nuance]</code>.</p><p><strong>N.B.</strong> : <em>si la couleur créée par <code>oklch</code> n'est pas supportée par l'espace sRGB, Huetone choisira l'option la plus proche. Ce ne sera pas une réplique exacte, en particulier pour les couleurs qui ont une valeur de chroma élevée, mais ce sera suffisant pour offrir une bonne expérience, et surtout, cela conservera le ratio de contraste et l'accessibilité ne sera pas affectée</em>.</p><h4>Créer une solution de repli</h4><p>Maintenant que nous avons nos couleurs alternatives, nous avons besoin de les ajouter comme solution de repli. C'est ici que la feature query <code>@supports</code> entre en jeu. Nous l'utilisons pour détecter si le navigateur supporte cette fonctionnalité, et sinon nous lui disons d'utiliser notre solution de repli.</p><p>La syntaxe de <code>@supports</code> est très simple, nous avons juste besoin d'ajouter entre parenthèses les propriétés que nous voulons détecter. Dans le cas présent, nous voulons détecter si <code>oklch()</code> n'est pas supporté, c'est pourquoi nous plaçons un préfixe <code>not</code> avant la prenthèse :</p><pre class="language-css">@supports not (background-color: oklch(0%, 0, 0)) {
  :root {
    --clr-neutral-100: #f3f4fc;
    --clr-neutral-200: #d9dae1;
    --clr-neutral-300: #bcbdc4;
    --clr-neutral-400: #a0a1a8;
    --clr-neutral-500: #7f8086;
    --clr-neutral-600: #5f6066;
    --clr-neutral-700: #414248;
    --clr-neutral-800: #212126;
    --clr-neutral-900: #050509;
    --clr-brand-100: #f3f4ff;
    --clr-brand-200: #d4d8fa;
    --clr-brand-300: #b0b7ff;
    --clr-brand-400: #9094ff;
    --clr-brand-500: #6d64ff;
    --clr-brand-600: #5147c9;
    --clr-brand-700: #383681;
    --clr-brand-800: #1d1e3a;
    --clr-brand-900: #05050e;
    --clr-success-100: #edf9ef;
    --clr-success-200: #c6e4cb;
    --clr-success-300: #83d494;
    --clr-success-400: #1dc15d;
    --clr-success-500: #009a46;
    --clr-success-600: #007433;
    --clr-success-700: #005121;
    --clr-success-800: #0b2813;
    --clr-success-900: #020703;
    --clr-warning-100: #fdf4e7;
    --clr-warning-200: #edd8b6;
    --clr-warning-300: #e5b562;
    --clr-warning-400: #d19500;
    --clr-warning-500: #a67600;
    --clr-warning-600: #7e5900;
    --clr-warning-700: #583d00;
    --clr-warning-800: #2e1e00;
    --clr-warning-900: #0a0500;
    --clr-error-100: #fff2f1;
    --clr-error-200: #fccecc;
    --clr-error-300: #ff9f9f;
    --clr-error-400: #ff6970;
    --clr-error-500: #ee003f;
    --clr-error-600: #b31030;
    --clr-error-700: #742028;
    --clr-error-800: #371617;
    --clr-error-900: #0c0303;
  }
}</pre><p>Vous pouvez jeter un coup d'œil au projet, avec sa solution de repli, dans ce codepen :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/ItsCrisDiaz/pen/mdQMGJy">Message windows with oklch()</a>de Cristian Diaz dans<a href="https://codepen.io">CodePen</a></div><h4>Conclusion</h4><p>CSS est en constante évolution. Le modèle de couleur <code>oklch()</code> nous permet d'utiliser la plus grande variété de couleurs disponible dans l'espace de couleur Display P3. Son utilisation est intuitive et, contrairement à la plupart des fonctions de couleurs précédentes, il offre des résultats cohérents.</p></div>]]></description>
      <link>https://la-cascade.io/articles/oklch-en-css</link>
      <guid>https://la-cascade.io/articles/oklch-en-css</guid>
      <pubDate>Mon, 18 Sep 2023 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[grid-column]]></title>
      <description><![CDATA[<p>La propriété CSS <code>grid-column</code> est une <em>abréviation</em> qui permet de spécifier en une seule déclaration les <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridline">lignes de grille</a> (<em>grid line</em>) de colonne déterminant le positionnement de départ et d'arrivée d'<a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#griditem">un élément de grille</a> (<em>grid item</em>) dans un layout de grille.</p><pre class="language-css">.grid-container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.grid-item:nth-child(2) {
  grid-column: 3 / 5; 
  /* Commence à la 3e ligne de colonne et s'arrête à la 5e ligne de colonne */
}</pre><p>En raison du comportement de <em>placement automatique par défaut</em> de la grille CSS, le deuxième élément enfant de la grille dans cet exemple devrait normalement être placé dans la deuxième colonne de la première ligne de la grille. Mais comme nous avons déclaré <code>grid-column</code> et l'avons paramétré pour aligner le point de départ de l'élément de la grille sur la troisième ligne de la grille et son point d'arrivée sur la cinquième ligne de la grille, l'élément s'étend sur les troisième et quatrième colonnes au lieu d'une seule colonne.</p><figure class="wp-block-image size-full" role="group"><img width="805" height="288" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662830734930_first-example.jpg?resize=805%2C288&amp;ssl=1" alt="" class="wp-image-374227" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662830734930_first-example.jpg?w=805&amp;ssl=1 805w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662830734930_first-example.jpg?resize=300%2C107&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662830734930_first-example.jpg?resize=768%2C275&amp;ssl=1 768w" /><figcaption>On définit l'emplacement et la taille du deuxième élément de la grille à l'aide de la propriété <code>grid-column</code> de CSS Grid.</figcaption></figure><h2>Syntaxe</h2><pre class="language-css">grid-column: &lt;grid-line&gt; [ / &lt;grid-line&gt; ]?</pre><h3>Définition complète</h3><pre class="language-css">&lt;grid-line&gt; =
  auto |
  &lt;custom-ident&gt; |
  [ [ &lt;integer [−∞,−1]&gt; | &lt;integer [1,∞]&gt; ] &amp;&amp; &lt;custom-ident&gt;? ] |
  [ span &amp;&amp; [ &lt;integer [1,∞]&gt; || &lt;custom-ident&gt; ] ]</pre><p>Cette propriété peut prendre deux valeurs séparées par une barre oblique (/). La valeur précédant la barre oblique définit la propriété <em>grid-column-start</em>, tandis que la valeur suivant la barre oblique définit la propriété <em>grid-column-end</em>. Vous pouvez aussi ne déclarer qu'une seule valeur, sans la barre oblique, qui s'appliquera à la propriété <em>grid-column-start</em>, et dans ce cas la propriété <em>grid-column-end</em> sera définie à <em>auto</em>.</p><h2>Valeurs</h2><pre class="language-css">/* Keyword value */
grid-column: auto;
/* &lt;custom-ident&gt; value */
grid-column: myLineName;
grid-column: myGridArea;
grid-column: sidebar-start / main-end;
/* &lt;integer&gt; + &lt;custom-ident&gt; values */
grid-column: 3;
grid-column: 2 / -3;
grid-column: main 2;
grid-column: 3 line / 5 line;
/* span + &lt;integer&gt; + &lt;custom-ident&gt; values */
grid-column: span 3;
grid-column: span 2 / 5;
grid-column: 1 / span myline;
grid-column: 2 / span gridline 3;
/* Global values */
grid-column: inherit;
grid-column: initial; /* same as `auto` */
grid-column: revert;
grid-column: revert-layer;
grid-column: unset;</pre><h3>auto</h3><p>Il s'agit de la valeur par défaut. Elle indique l'étendue (<em>span</em>) par défaut (1) et le comportement de placement automatique : l'élément de la grille sera automatiquement placé dans la prochaine cellule vide disponible.</p><p>Cette syntaxe vous permet d'utiliser soit un <em>nombre entier</em> pour faire référence à une ligne de grille numérotée, soit une <em>chaîne de caractères</em> pour faire référence à une ligne de grille nommée ou à une zone de grille nommée. En d'autres termes, vous pouvez spécifier une ligne de grille par son index numérique ou par son nom pour le bord de départ et le bord d'arrivée d'un élément de la grille.</p><h4>Positionnement des éléments par numéro de ligne</h4><p>Chaque <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/#gridtrack">piste de la grille</a> (<em>grid track</em>) est précédée et suivie d'une ligne de grille, et chacune a un indice numérique qui lui est attribué automatiquement, en commençant par le numéro un.</p><figure class="wp-block-image size-full" role="group"><img width="805" height="288" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662901953944_grid-lines-index.jpg?resize=805%2C288&amp;ssl=1" alt="A two row grid with four columns. The last two columns in the second row are empty." class="wp-image-374230" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662901953944_grid-lines-index.jpg?w=805&amp;ssl=1 805w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662901953944_grid-lines-index.jpg?resize=300%2C107&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662901953944_grid-lines-index.jpg?resize=768%2C275&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>On a indiqué seulement les index de colonnes</figcaption></figure><p>Dans le premier exemple de cet article, nous avons utilisé cette syntaxe pour désigner la troisième ligne de colonne de la grille par son indice (3), ce qui aligne le bord initial de l'élément de la grille sur le bord initial de la troisième colonne, tandis que son bord final est aligné sur la cinquième colonne à l'aide de la syntaxe :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: 3 / 5;
}</pre><p>Notez que vous pouvez également utiliser un nombre négatif pour faire référence à une ligne de la grille, mais il compte à partir du bord <em>final</em> de la grille. Le code suivant indique les mêmes lignes de la grille que dans l'exemple précédent, mais en comptant à l'envers :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: -3 / -1; 
  /* même chose que : grid-column: 3 / 5; */
}</pre><p>Remarquez comment les nombres entiers négatifs sont assignés à notre grille, de même que les nombres positifs :</p><figure class="wp-block-image size-full"><img width="805" height="288" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662902106902_first-example.jpg?resize=805%2C288&amp;ssl=1" alt="" class="wp-image-374235" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662902106902_first-example.jpg?w=805&amp;ssl=1 805w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662902106902_first-example.jpg?resize=300%2C107&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662902106902_first-example.jpg?resize=768%2C275&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>On place le 2e élément de grille dans les 3e et 4e colonnes avec la propriété CSS <code>grid-column</code></figcaption></figure><h4>Positionnement des éléments par nom de ligne</h4><p>Vous pouvez également attribuer <em>un nom personnalisé</em> à une ligne de la grille pour faire référence à cette ligne par son nom.</p><p>Reprenons notre exemple et nommons toutes ses lignes de suivi des colonnes comme suit :</p><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: [first] 1fr [second] 1fr [third] 1fr [fourth] 1fr [last];  
}</pre><p>Nous pouvons nous référer à la troisième et à la cinquième ligne par un identifiant personnalisé plutôt que par leur index :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: third / last; 
  /* même chose que les index 3 / 5 */
}</pre><p class="is-style-explanation">Il est à noter que l'identifiant personnalisé (<code>custom-ident</code>) ne peut pas prendre la valeur <em>span</em>. <code>span</code> est un mot-clé réservé aux propriétés de placement de la grille (par exemple, <code>grid-column : 1 / span 2</code>) comme nous le verrons plus loin.</p><h4>Positionnement des éléments avec grid-template-areas</h4><p>Lorsque vous définissez des zones de grille à l'aide de la propriété <code>grid-template-areas</code>, vous obtenez des noms de ligne implicites basés sur le nom des zones. Par exemple, une zone de grille portant le nom "content" (<em>contenu</em>) génère une ligne nommée "content-start" avant elle et une autre nommée "content-end" après elle. Vous pouvez vous référer à ces lignes pour définir la position d'un élément de la grille.</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: content-start / content-end;
}</pre><p>Vous pouvez également vous référer au nom de la zone pour positionner un élément à la ligne de début et de fin de la zone de contenu nommée :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: content;
}</pre><p>Voici un exemple complet :</p><pre class="language-html">&lt;body&gt;
  &lt;main&gt;&lt;/main&gt;
  &lt;aside&gt;&lt;/aside&gt;
&lt;/body&gt;</pre><pre class="language-css">body {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;   
  grid-template-areas: "content content sidebar";
}
main {
  grid-column: content;
}</pre><p>Ce CSS permet de positionner l'élément <code>&lt;main&gt;</code> dans la zone de contenu de notre grille.</p><figure class="wp-block-image size-full"><img width="804" height="374" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662904277267_area-name.jpg?resize=804%2C374&amp;ssl=1" alt="Single row grid with two columns." class="wp-image-374242" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662904277267_area-name.jpg?w=804&amp;ssl=1 804w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662904277267_area-name.jpg?resize=300%2C140&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662904277267_area-name.jpg?resize=768%2C357&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>On place l'élément <code>main</code> dans la zone de <code>content</code> en utilisant son nom et la propriété CSS <code>grid-column</code>.</figcaption></figure><h3>integer &amp; custom-ident ?</h3><p>Cette syntaxe vous permet de positionner les éléments de la grille par rapport aux lignes de la grille lorsque les noms sont répétés. Si plusieurs lignes de la grille portent le même nom, cette syntaxe permet de préciser à laquelle de ces lignes vous faites référence.</p><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: [bar] 1fr [foo] 1fr [bar] 300px [bar];
  /*
    La fonction repeat() permet de répéter des lignes de grille nommées, par exemple :
    grid-template-columns: repeat(3, [bar] 1fr);
  */
}</pre><p>Supposons que vous souhaitiez choisir la troisième ligne, mais que cette ligne porte le même nom que la première et la dernière ligne de la grille - elles s'appellent toutes <code>bar</code>. Puisque la deuxième ligne nommée <code>bar</code> est la troisième ligne de la grille, vous pouvez utiliser 2 pour la sélectionner comme point de départ :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: 2 bar; /* La 2e ligne `bar` est la 3e ligne */
  /* Ce qui est l'équivalent de : */
  grid-column-start: 2 bar;  
  grid-column-end: auto;  
}</pre><figure class="wp-block-image size-full"><img width="765" height="177" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1659028322971_repeated-linename.jpg?resize=765%2C177&amp;ssl=1" alt="Single row grid with three columns. The second column is empty." class="wp-image-374247" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1659028322971_repeated-linename.jpg?w=765&amp;ssl=1 765w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1659028322971_repeated-linename.jpg?resize=300%2C69&amp;ssl=1 300w" data-recalc-dims="1" /></figure><p>Notez que l'ordre n'a pas d'importance, de sorte que le code précédent peut également être écrit de cette manière :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: bar 2;
}</pre><p>Comme pour la syntaxe précédente, vous pouvez utiliser un nombre entier négatif pour compter les lignes de la grille à partir du bord final de la grille. Dans notre exemple, si nous voulons nous référer au premier <code>bar</code>, nous pouvons compter à partir du bord final de notre grille et l'écrire comme suit :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: -3 bar;
}</pre><p class="is-style-explanation">Attention : la valeur entière ne peut pas être zéro.</p><h3><code>span &amp;&amp; [ || ]</code></h3><p>Cette syntaxe permet à un élément de la grille de s'étendre sur les pistes de la grille. Elle peut être spécifiée de trois manières différentes.</p><p>Notez que si l'entier n'est spécifié nulle part dans cette syntaxe, la valeur par défaut est 1.</p><h3><code>span integer</code></h3><p>L'utilisation du mot-clé <code>span</code> suivi d'un nombre entier indique le nombre de pistes qu'un élément de grille couvre à partir d'une ligne de grille spécifique. Par exemple, si nous voulons qu'un élément de grille s'étende sur trois pistes de colonne vers son bord final, nous pouvons appliquer la valeur suivante :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-column: auto / span 3;
}</pre><figure class="wp-block-image size-full"><img width="751" height="390" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658590211906_span-integer.png?resize=751%2C390&amp;ssl=1" alt="A two row grid with 5 columns. The second grid item spands the middle three columns in the first row." class="wp-image-374252" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658590211906_span-integer.png?w=751&amp;ssl=1 751w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658590211906_span-integer.png?resize=300%2C156&amp;ssl=1 300w" data-recalc-dims="1" /><figcaption>L'élement de grille n°2 s'étend sur 3 colonnes avec la propriété <code>grid-column</code> et le mot-clé <code>span</code>.</figcaption></figure><h4><code>span custom-ident</code></h4><p>Il est également possible de combiner le mot-clé <code>span</code> avec le nom d'une ligne de la grille pour que l'élément de la grille s'étende jusqu'à ce qu'il atteigne la ligne spécifiée.</p><pre class="language-css">.grid-item:nth-child(3) {
  grid-column: 3 / span lastline;
}</pre><p>Puisque la ligne de départ de l'élément de grille est connue (3), nous pouvons étendre l'élément jusqu'à ce qu'il atteigne une ligne de la grille nommée <em>lastline</em>.</p><figure class="wp-block-image size-full"><img width="863" height="384" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662916517306_span-custom-ident.jpg?resize=863%2C384&amp;ssl=1" alt="Two row grid with five columns. The third grid item spans the last three columns in the first row." class="wp-image-374253" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662916517306_span-custom-ident.jpg?w=863&amp;ssl=1 863w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662916517306_span-custom-ident.jpg?resize=300%2C133&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662916517306_span-custom-ident.jpg?resize=768%2C342&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>L'élémrnt de grille s'étend dans la grille jusqu'à atteindre la ligne nommée <em>lastline</em> via la propriété <code>grid-column</code></figcaption></figure><h4><code>span custom-ident integer</code></h4><p>Si le nom de la ligne de grille spécifiée est attribué à plus d'une ligne de colonne de grille - en d'autres termes, si nous avons plusieurs lignes de colonne de grille nommées - nous devons indiquer celles que nous voulons cibler. Pour ce faire, nous pouvons ajouter un nombre entier à notre valeur en précisant la ligne de grille à laquelle nous nous référons.</p><p>Prenons l'exemple de la grille suivante :</p><pre class="language-css">.grid-container {
  display: grid;
  grid-template-columns: [y] 1fr [x] 1fr [x] 1fr [y] 1fr [x] 1fr [x];
}
.grid-item:nth-child(3) {
  grid-column: 2 /span x 2;
}</pre><p>Nous fixons la ligne de départ de l'élément de grille à la deuxième ligne. Ensuite, nous voulons qu'il s'étende vers la droite jusqu'à ce qu'il atteigne une ligne de la grille nommée x. Et comme nous voulons qu'il aille jusqu'à la deuxième ligne de colonne x (sans compter la ligne de départ), nous obtenons <code>span x 2</code>.</p><p>Notre élément de grille s'étend à partir de la deuxième ligne, comme illustré ci-dessous. La première ligne de colonne qu'il atteint est nommée x, elle est suivie d'une ligne nommée y, et enfin, il atteint la deuxième ligne x souhaitée.</p><figure class="wp-block-image size-full"><img width="737" height="546" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658672273188_span-integer-custom-indent.jpg?resize=737%2C546&amp;ssl=1" alt="Three row grid with five columns." class="wp-image-374258" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658672273188_span-integer-custom-indent.jpg?w=737&amp;ssl=1 737w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658672273188_span-integer-custom-indent.jpg?resize=300%2C222&amp;ssl=1 300w" data-recalc-dims="1" /><figcaption>Ici, on fixe la position d'un élément de grille à partir de la 2e ligne de colonne jusqu'à la 2e ligne nommée <code>x</code> avec <code>grid-column</code></figcaption></figure><p>Cette syntaxe est utile lorsque vous souhaitez étendre un élément de la grille vers une ligne de la grille en utilisant son nom. Mais comme il y a plus d'une ligne de grille portant ce nom, nous ajoutons un entier pour dire que nous voulons le n-ième rencontré.</p><p class="is-style-explanation">Voir <em>grid-column-start</em> et <em>grid-column-end</em> pour plus d'informations et des exemples de la syntaxe de ces propriétés individuelles.</p><h2>Exemples</h2><p>Examinons quelques scénarios différents dans lesquels la colonne de grille peut être utilisée.</p><h3>Mise en page avec un élément étendu</h3><p>Imaginons que nous voulions que notre texte soit réduit et centré, mais qu'un élément tel qu'une image ou une vidéo s'étende d'un bord à l'autre de la fenêtre de visualisation.</p><figure class="wp-block-image size-full"><img width="805" height="630" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990035830_example-1.jpg?resize=805%2C630&amp;ssl=1" alt="Demonstrating a full bleed layout that has the text centered but the image extends to the very edge." class="wp-image-374263" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990035830_example-1.jpg?w=805&amp;ssl=1 805w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990035830_example-1.jpg?resize=300%2C235&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990035830_example-1.jpg?resize=768%2C601&amp;ssl=1 768w" data-recalc-dims="1" /></figure><p>Prenons le HTML suivant :</p><pre class="language-html">&lt;article&gt;
  &lt;h1&gt;&lt;/h1&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;img src="bridge.webp" alt="A brightly-lot floating bridge against the night sky."&gt;
  &lt;p&gt;&lt;/p&gt;
&lt;/article&gt;</pre><p>Pour créer cette mise en page à l'aide de CSS Grid, nous avons mis en place une grille à trois colonnes :</p><pre class="language-css">article {
  display: grid;
  grid-template-columns: 1fr min(60ch, 100%) 1fr;
}</pre><p>Nous devons maintenant placer tous les enfants de l'<code>&lt;article&gt;</code> dans la deuxième colonne et aligner le bord initial de l'<code>&lt;img&gt;</code> sur la première ligne de la grille et son bord final sur la dernière ligne :</p><pre class="language-css">article &gt; * {
  grid-column: 2 / 3;
}
article &gt; img {
  grid-column: 1 / -1;
}</pre><p>Voici le résultat :</p><figure class="wp-block-image size-full"><img width="805" height="684" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990038305_example.jpg?resize=805%2C684&amp;ssl=1" alt="Show the grid lines of an article layout that contains an image that spans edge to edge." class="wp-image-374264" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990038305_example.jpg?w=805&amp;ssl=1 805w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990038305_example.jpg?resize=300%2C255&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_5E600D44A3602E06FB6B7B59AD446BE1961B4B0D409EEEA69A28E839C5C65BD4_1662990038305_example.jpg?resize=768%2C653&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>Avec <code>grid-column</code> on détermine que l'image s'étend sur toutes les colonnes et les autres éléments sont placés sur la 2e colonne.</figcaption></figure><p>Le CSS complet :</p><pre class="language-css">.content {
  display: grid;
  grid-template-columns: 1fr min(60ch, 100%) 1fr;
}
.content &gt; * {
  grid-column: 2 / 3;
}
.full-bleed {
  grid-column: 1 / -1;
}</pre><h3>Empiler des éléments de la grille</h3><p>Lorsque l'on positionne des éléments dans la grille, il est possible de les empiler ou de les faire se chevaucher. Cela nous permet parfois d'utiliser la grille CSS comme alternative au positionnement absolu. Par exemple, nous pouvons placer un calque de légende au-dessus d'une image sans utiliser la propriété de position, comme illustré ci-dessous :</p><pre class="language-html">&lt;figure&gt;
  &lt;img src="image.png" alt="Quoi ? le texte alternatif est vide ??"&gt;
  &lt;figcaption&gt;La légende de notre image&lt;/figcaption&gt;
&lt;/figure&gt;</pre><pre class="language-css">figure {
  display: grid;
}
img,
figcaption {
  grid-column: 1 / -1;
  grid-row: 1 / -1;
}</pre><p>On obtient ceci :</p><figure class="wp-block-image size-full"><img width="250" height="250" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/08/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658845486547_caption.png?resize=250%2C250&amp;ssl=1" alt="Cabin in the woods with a green to blue gradient overlay and the words the caption of our image on top." class="wp-image-372562" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/08/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658845486547_caption.png?w=250&amp;ssl=1 250w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/08/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658845486547_caption.png?resize=150%2C150&amp;ssl=1 150w" /></figure><p>Par défaut, les éléments de la grille s'empilent dans l'ordre de la source, mais vous pouvez contrôler leur niveau à l'aide de la propriété <a href="https://la-cascade.io/articles/comment-fonctionne-z-index">z-index</a>. Dans l'exemple suivant, certains éléments se chevauchent et nous utilisons la propriété <code>z-index</code> pour placer le deuxième élément au niveau le plus élevé dans le contexte d'empilement :</p><pre class="language-css">.item:nth-child(2) {
  grid-column: 2 / 4;
  grid-row: 2 / 4;
  z-index: 1;
}</pre><figure class="wp-block-image"><img src="https://paper-attachments.dropbox.com/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658926511371_stacking.jpg" alt="Four overlapping grid items in a five-by-five grid." /><figcaption>Le 2e élément de grille est affiché par-dessus les autres via <code>z-index</code></figcaption></figure><h3>Accessibilité</h3><p>Une chose à noter lors de l'utilisation des propriétés de placement de la grille est le problème causé par le réarrangement des éléments. Lorsque vous modifiez la position d'un élément, seul l'ordre visuel des éléments de la grille change, et cet ordre peut être différent de l'ordre original du document. Cela peut entraîner une très mauvaise expérience pour une personne qui parcourt le document à l'aide d'un clavier ou qui écoute un lecteur d'écran, qui lit le contenu dans le même ordre que le code HTML.</p><p>Il faut donc éviter de modifier l'ordre des éléments de la grille lorsque l'ordre HTML des éléments est important. Par exemple, cela peut être intéressant pour une galerie d'images aléatoires, mais peut-être pas autant pour les entrées de votre formulaire.</p><p>Toutefois, à l'heure où nous écrivons ces lignes, il existe une proposition visant à résoudre ce problème qui, nous l'espérons, sera résolu à l'avenir.</p><h3>Démo</h3><p>Vous pouvez modifier la valeur des propriétés de placement de la grille dans la démo pour voir ce qu'il advient du troisième élément de la grille :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/seyedi/pen/MWGXdmJ">Grid item placement with shorthands</a>de seyedi dans<a href="https://codepen.io">CodePen</a></div>]]></description>
      <link>https://la-cascade.io/articles/grid-column</link>
      <guid>https://la-cascade.io/articles/grid-column</guid>
      <pubDate>Thu, 10 Aug 2023 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[grid-row]]></title>
      <description><![CDATA[<p>La propriété CSS <code>grid-row</code> est un raccourci permettant de spécifier les lignes de la grille où un élément de la grille commence et se termine dans une mise en page de type grille, et ce en une seule déclaration.</p><pre class="language-css">.grid-container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.grid-item:nth-child(2) {
  grid-row: 2 / 4; /* Commence à la deuxième ligne de rangée et se termine à la quatrième ligne de rangée */
}</pre><p>En raison du comportement de placement automatique par défaut de la grille CSS, le deuxième élément enfant de la grille dans cet exemple devrait normalement être placé dans la première rangée de la deuxième colonne de la grille. Mais nous déclarons une rangée de grille (<em>grid-row</em>) et la définissons de manière à aligner le bord de départ de l'<a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#griditem">item de grille</a> sur la deuxième <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridline">ligne de grille</a> et son bord d'arrivée sur la quatrième ligne de la grille, ce qui déplace l'élément de la grille.</p><figure class="wp-block-image size-full"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?resize=803%2C395&amp;ssl=1" alt="" class="wp-image-374486" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?w=803&amp;ssl=1 803w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?resize=300%2C148&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?resize=768%2C378&amp;ssl=1 768w" /><figcaption>On a défini la position et la dimension du deuxième item de grille avec la propriété CSS <code>grid-row</code></figcaption></figure><h2>Propriétés constitutives</h2><p>La propriété <code>grid-row</code> est une abréviation qui combine deux propriétés : <code>grid-row-start</code> et <code>grid-row-end</code>.</p><h2>Syntaxe</h2><pre class="language-css">grid-row: &lt;grid-line&gt; [ / &lt;grid-line&gt; ]?;</pre><h3>Définition complète</h3><pre class="language-css">&lt;grid-line&gt; =
  auto |
  &lt;custom-ident&gt; |
  [ [ &lt;integer [−∞,−1]&gt; | &lt;integer [1,∞]&gt; ] &amp;&amp; &lt;custom-ident&gt;? ] |
  [ span &amp;&amp; [ &lt;integer [1,∞]&gt; || &lt;custom-ident&gt; ] ]</pre><ul><li>Valeur initiale : <code>auto</code></li>
<li>S'applique aux items de la grille et aux boîtes positionnées de manière absolue dont le bloc contenant est un conteneur de grille</li>
<li>Héritée : non</li>
<li>Valeur calculée : telle que spécifiée pour ses propriétés développées</li>
<li>Type d'animation : discrète</li>
</ul><p>Cette propriété peut prendre deux valeurs séparées par une barre oblique (/). La valeur précédant la barre oblique définit la propriété de début de ligne de la grille, tandis que la valeur suivant la barre oblique définit la propriété de fin de ligne de la grille. Il est possible de déclarer une seule valeur sans la barre oblique, qui s'applique à la propriété "<a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcs">grid-row-start</a>" et qui définit la propriété "grid-row-end" à "auto".</p><h2>Valeurs</h2><pre class="language-css">/* Keyword value */
grid-row: auto;
/* &lt;custom-ident&gt; value */
grid-row: myLineName;
grid-row: myGridArea;
grid-row: header-start / main-end;
/* &lt;integer&gt; + &lt;custom-ident&gt; values */
grid-row: 3;
grid-row: 2 / -3;
grid-row: main 2;
grid-row: 3 line / 5 line;
/* span + &lt;integer&gt; + &lt;custom-ident&gt; values */
grid-row: span 3;
grid-row: span 2 / 5;
grid-row: 1 / span myline;
grid-row: 2 / span gridline 3;
/* Global values */
grid-row: inherit;
grid-row: initial; /* same as `auto` */
grid-row: revert;
grid-row: revert-layer;
grid-row: unset;</pre><h3>auto</h3><p>Il s'agit de la valeur <strong>par défaut</strong>. Elle indique la portée (<em>span</em>) par défaut (1) et le comportement de placement automatique, ce qui signifie que l'élément de la grille est automatiquement placé dans la prochaine cellule vide disponible.</p><h3><code>&lt;custom-ident&gt;</code></h3><p>Cette syntaxe permet d'utiliser soit un nombre entier pour faire référence à une ligne de grille numérotée, soit une chaîne de caractères pour faire référence à une ligne de grille nommée ou à une zone de grille nommée. En d'autres termes, il est possible de spécifier une ligne de grille par son index numérique ou par son nom pour le bord de départ et le bord d'arrivée d'un élément de la grille.</p><h3>Positionnement des éléments par numéro de ligne</h3><p>Chaque piste de la grille est précédée et suivie de deux lignes de grille auxquelles un indice numérique est attribué automatiquement, en commençant par le numéro un.</p><figure class="wp-block-image size-full"><img width="803" height="395" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665133261994_grid-lines-index.jpg?resize=803%2C395&amp;ssl=1" alt="A three by three grid of numbered rectangles. The third cell in the third row is blank." class="wp-image-374490" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665133261994_grid-lines-index.jpg?w=803&amp;ssl=1 803w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665133261994_grid-lines-index.jpg?resize=300%2C148&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665133261994_grid-lines-index.jpg?resize=768%2C378&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>Image montrant l'indice attribué automatiquement.</figcaption></figure><p>Dans le premier exemple de cet article, nous avons utilisé cette syntaxe pour désigner la deuxième ligne de la grille par son indice (2), ce qui aligne le bord initial de l'élément de la grille sur le bord initial de la deuxième ligne, tandis que son bord final est aligné sur la quatrième ligne à l'aide de la syntaxe :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: 2 / 4;
}</pre><p>Notez que vous pouvez également utiliser un nombre négatif pour faire référence à une ligne de la grille, mais il compte à partir du bord final de la grille. Le code suivant indique les mêmes lignes de la grille que dans l'exemple précédent, mais en comptant à l'envers :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: -3 / -1;
  /* identique à : */
  grid-row: 2 / 4;
  grid-row: 2 / -1;
  grid-row: -3 / 4;
}</pre><p>Remarquez que les nombres entiers négatifs ont été assignés à notre grille, de même que les nombres positifs :</p><figure class="wp-block-image size-full"><img width="743" height="365" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?resize=803%2C395&amp;ssl=1" alt="" class="wp-image-374486" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?w=803&amp;ssl=1 803w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?resize=300%2C148&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665075356323_first-example.jpg?resize=768%2C378&amp;ssl=1 768w" /><figcaption>On place le deuxième élément de grille dans les deuxième et troisième rangées avec CSS <code>grid-row</code></figcaption></figure><h3>Positionnement des éléments par nom de ligne</h3><p>On peut attribuer un nom personnalisé à une ligne de la grille en utilisant les propriétés de la grille de placement basée sur les lignes <code>grid-template-columns</code> et <code>grid-template-rows</code> pour faire référence à cette ligne par son nom.</p><p>Reprenons notre exemple et nommons toutes ses lignes de suivi des rangées comme dans la déclaration suivante :</p><pre class="language-css">.grid {
  display: grid;
  grid-template-rows: [first] 100px [second] 100px [third] 100px [last];
  grid-template-columns: 1fr 1fr 1fr;
}</pre><p>On peut se référer à la deuxième et à la quatrième ligne par les noms personnalisés au lieu de leur index :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: second / last; /* same as index numbers 2 / 4 */
}</pre><p class="is-style-explanation">Notez que le "custom-ident" ne peut pas prendre la valeur "span". span est un mot-clé réservé aux propriétés de placement de la grille (par exemple, `grid-row : 1 / span 2`).</p><h3>Positionnement des éléments en fonction des zones de la grille</h3><p>Lorsqu'on définit des zones de grille à l'aide de la propriété <code>grid-template-areas</code>, on obtient gratuitement des noms de ligne implicites basés sur le nom des zones. Par exemple, une zone de grille portant le nom "content" génère une ligne nommée "content-start" avant elle et une autre nommée "content-end" après elle. On peut se référer à ces lignes pour définir la position d'un élément de la grille.</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: content-start / content-end;
}</pre><p>On peut également se référer au nom de la zone pour positionner un élément à la ligne de début et de fin de la zone de contenu nommée :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: content;
}</pre><p>Voici un exemple complet :</p><pre class="language-html">&lt;body&gt;
  &lt;header&gt;&lt;/header&gt;
  &lt;main&gt;&lt;/main&gt;
  &lt;footer&gt;&lt;/footer&gt;
&lt;/body&gt;</pre><pre class="language-css">body {
  display: grid;
  grid-template-rows: min-content 1fr min-content;
  grid-template-areas:
    'header'
    'content'
    'footer';
}
main {
  grid-row: content;
}</pre><p>Ceci définit la position de l'élément <code>&lt;main&gt;</code>, qui sera dans la zone <code>content</code> de notre grille.</p><h4><code>&lt;integer&gt;</code> &amp;&amp; <code>&lt;custom-ident&gt;</code> ?</h4><p>Cette syntaxe permet de positionner les éléments de la grille en fonction des lignes de la grille lorsque les noms sont répétés. Si plusieurs lignes de la grille portent le même nom, cette syntaxe permet de préciser à laquelle de ces lignes on fait référence.</p><pre class="language-css">.grid {
  display: grid;
  grid-template-rows: [bar] 100px [foo] 100px [bar] 150px [bar];
}</pre><p>Supposons qu'on veuille choisir la troisième ligne, mais que cette ligne porte le même nom que la première et la dernière ligne de la grille — elles s'appellent toutes <code>bar</code>. Puisque la deuxième ligne nommée bar <code>est</code> la troisième ligne de la grille, on peut utiliser 2 pour la sélectionner comme point de départ :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: 2 bar; /* The second `bar` named line which is the third line */
  /* This is equivalent to */
  grid-row-start: 2 bar;
  grid-row-end: auto;
}</pre><figure class="wp-block-image size-full"><img width="879" height="444" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233129141_repeated-linename.jpg?resize=879%2C444&amp;ssl=1" alt="A single column grid wuth three rows. The second row is green and has swapped places with the third row." class="wp-image-374499" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233129141_repeated-linename.jpg?w=879&amp;ssl=1 879w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233129141_repeated-linename.jpg?resize=300%2C152&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233129141_repeated-linename.jpg?resize=768%2C388&amp;ssl=1 768w" data-recalc-dims="1" /></figure><p>Remarquez que lm'ordre n'a aucune importance. Le code précédent peut aussi s'écrire :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: bar 2;
}</pre><p>Comme pour la syntaxe précédente, on peut utiliser un nombre entier négatif pour compter les lignes de la grille à partir du bord final de la grille. Dans notre exemple, si nous voulons nous référer à la première barre, nous pouvons compter à partir du bord final de notre grille et l'écrire comme suit :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: -3 bar;
}</pre><p class="is-style-explanation">Notez que la valeur entière ne peut pas être égale à zéro.</p><h4><code>span</code> &amp;&amp; <code>[ &lt;integer&gt; || &lt;custom-ident&gt; ]</code></h4><p>Cette syntaxe permet à un élément de la grille de s'étendre sur les pistes de la grille. Elle peut être spécifiée de trois manières différentes.</p><p>Notez que la valeur par défaut est 1 si l'entier n'est spécifié nulle part dans cette syntaxe.</p><h4>span <code>&lt;integer&gt;</code></h4><p>L'utilisation du mot-clé <code>span</code> suivi d'un nombre entier indique le nombre de pistes qu'un élément de grille couvre à partir d'une ligne de grille spécifique. Par exemple, si nous voulons qu'un élément de grille s'étende sur trois pistes de ligne vers son bord final, nous pouvons appliquer la valeur suivante :</p><pre class="language-css">.grid-item:nth-child(2) {
  grid-row: 1 / span 3;
}</pre><figure class="wp-block-image size-full"><img width="879" height="494" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233659152_span-integer.jpg?resize=879%2C494&amp;ssl=1" alt="A three by four grid of rectangles. The first three rows in the second column are selected." class="wp-image-374507" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233659152_span-integer.jpg?w=879&amp;ssl=1 879w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233659152_span-integer.jpg?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233659152_span-integer.jpg?resize=768%2C432&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>L'élément de grille s'étend sur 3 rangées avec CSS <code>grid-row</code>.</figcaption></figure><h4><code>span &lt;custom-ident&gt;</code></h4><p>Il est également possible de combiner le mot-clé <code>span</code> avec le nom d'une ligne de la grille pour que l'élément de la grille s'étende jusqu'à ce qu'il atteigne la ligne spécifiée.</p><pre class="language-css">.grid-item:nth-child(3) {
  grid-row: 3 / span lastline;
}</pre><p>Comme la ligne de départ de l'élément de la grille est connue (3), nous pouvons étendre (<em>span</em>) l'élément jusqu'à ce qu'il atteigne une ligne de la grille nommée lastline.</p><figure class="wp-block-image size-full"><img width="652" height="248" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233825573_span-custom-ident.jpg?resize=879%2C334&amp;ssl=1" alt="A three by five grid with the last three rows in the first column selected." class="wp-image-374511" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233825573_span-custom-ident.jpg?w=879&amp;ssl=1 879w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233825573_span-custom-ident.jpg?resize=300%2C114&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233825573_span-custom-ident.jpg?resize=768%2C292&amp;ssl=1 768w" /><figcaption>L'item grid s'étend à travers la grille jusqu'à rencontrer la grille de ligne nommée <code>lastline</code> via la propriété CSS <code>grid-row</code>.</figcaption></figure><h4>span <code>&lt;custom-ident&gt; &lt;integer&gt;</code></h4><p>Si le nom de la ligne de grille spécifié est attribué à plus d'une ligne de grille - en d'autres termes, si nous avons plusieurs lignes de grille nommées - nous devons indiquer celles que nous voulons cibler. Pour ce faire, nous pouvons ajouter un nombre entier à notre valeur en spécifiant la ligne de grille à laquelle nous faisons référence.</p><p>Prenons l'exemple de la grille suivante :</p><pre class="language-css">.grid-container {
  display: grid;
  grid-template-rows: [y] 50px [x] 50px [x] 50px [y] 50px [x] 50px [x];
  grid-template-columns: 1fr 1fr;
}
.grid-item:nth-child(2) {
  grid-row: 2 / span x 2; /* equivalent to grid-row-end: 5; */
}</pre><p>Nous fixons la ligne de départ de l'élément de grille à la deuxième ligne. Ensuite, nous voulons qu'il s'étende vers l'avant jusqu'à ce qu'il atteigne une ligne de la grille nommée "x". Et comme nous voulons qu'il s'agisse de la deuxième ligne de la grille x, nous obtenons span x 2.</p><p>Résultat, notre élément de grille s'étend à partir de la deuxième ligne, comme illustré ci-dessous. La première ligne qu'il atteint est la première, x, suivie de y, et enfin, il atteint la deuxième ligne souhaitée, nommée x.</p><figure class="wp-block-image size-full"><img width="652" height="266" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233795120_span-integer-custom-indent.jpg?resize=819%2C334&amp;ssl=1" alt="A two by five grid. The middle three rows in the first column are selected." class="wp-image-374515" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233795120_span-integer-custom-indent.jpg?w=819&amp;ssl=1 819w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233795120_span-integer-custom-indent.jpg?resize=300%2C122&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665233795120_span-integer-custom-indent.jpg?resize=768%2C313&amp;ssl=1 768w" /><figcaption>On fixe la position d'un item grid partant de la deuxième ligne jusqu'à la deuxième ligne nommée <code>x</code> named via la propriété CSS <code>grid-row</code>.</figcaption></figure><p>Cette syntaxe est utile lorsqu'on souhaite étendre un élément de la grille vers une ligne de la grille en utilisant son nom. Comme nous savons qu'il y a plus d'une ligne de grille portant ce même nom, nous ajoutons un entier pour dire que nous voulons le Nième de cette ligne de grille.</p><h3>Exemples</h3><h4>Des barres d'histogrammes flottantes</h4><p>Beaucoup considèrent CSS Grid comme un outil permettant de créer la structure principale et la mise en page d'une page web ou d'une application, mais Grid est capable de bien plus que cela.</p><p>Prenons l'exemple du graphique suivant. Si vous regardez de près, vous pouvez voir que chaque barre s'étend d'une certaine ligne à une autre pour montrer l'étendue qui est censée marquer le graphique.</p><figure class="wp-block-image size-full"><img width="652" height="503" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325456608_example.jpg?resize=773%2C596&amp;ssl=1" alt="A bar chart with bars that span single columns and various numbers of rows, like a calendar weekly view." class="wp-image-374521" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325456608_example.jpg?w=773&amp;ssl=1 773w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325456608_example.jpg?resize=300%2C231&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325456608_example.jpg?resize=768%2C592&amp;ssl=1 768w" /><figcaption>Un histogramme flottant avec des barres qui s'étendent d'une rangée à une autre.</figcaption></figure><p>Si l'on considère le graphique comme une grille, on voit à quel point il est facile de spécifier la taille et la position des barres à l'aide des propriétés de placement de la grille CSS :</p><figure class="wp-block-image size-full"><img width="652" height="503" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325476792_example-detail.jpg?resize=773%2C596&amp;ssl=1" alt="A bar chart with bars that span single columns and various numbers of rows, like a calendar weekly view. The grid lines are shown." class="wp-image-374525" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325476792_example-detail.jpg?w=773&amp;ssl=1 773w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325476792_example-detail.jpg?resize=300%2C231&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/10/s_4530D59E6D8D175D8E884F20E670093F1161A40D0DD939A565C36C81F0A4B651_1665325476792_example-detail.jpg?resize=768%2C592&amp;ssl=1 768w" /><figcaption>Une grille contenant les barres dans ses colonnes, leur position est fixée via la propriété CSS <code>grid-row</code>.</figcaption></figure><p>Pour créer une grille pour ce graphique, nous pouvons écrire le code suivant :</p><pre class="language-css">.chart {
  display: grid;
  grid-template-columns: repeat(10, 40px);
  grid-template-rows: repeat(9, 40px);
  gap: 0 8px;
}</pre><p>Nous devons maintenant placer toutes les barres dans les bonnes lignes et colonnes :</p><pre class="language-css">.bar:nth-child(1) {
  grid-column: 1;
  grid-row: 1 / 3;
}
.bar:nth-child(2) {
  grid-column: 2;
  grid-row: 5 / 10;
}
/* ... */
.bar:nth-child(10) {
  grid-column: 10;
  grid-row: 9 / 10;
}</pre><p>Jetez un coup d'œil à cette démo et voyez comment le reste s'articule :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/seyedi/pen/RwyeXJG">Floating Bar Chart with CSS Grid</a>de seyedi dans<a href="https://codepen.io">CodePen</a></div><h3>Empiler des items grid</h3><p>Lorsque nous positionnons des éléments dans la grille, nous pouvons les empiler ou les faire se chevaucher. Cela nous permet parfois d'utiliser la grille CSS comme alternative au positionnement absolu. Par exemple, nous pouvons placer un calque de légende au-dessus d'une image sans utiliser la propriété de position, comme illustré ci-dessous :</p><pre class="language-html">&lt;figure&gt;
  &lt;img src="image.png" alt="how dare you leave alt empty?"&gt;
  &lt;figcaption&gt;The caption of our image&lt;/figcaption&gt;
&lt;/figure&gt;</pre><pre class="language-css">figure {
  display: grid;
}
img,
figcaption {
  grid-column: 1 / -1;
  grid-row: 1 / -1;
}</pre><p>Et voilà le résultat :</p><figure class="wp-block-image size-full"><img width="250" height="250" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/08/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658845486547_caption.png?resize=250%2C250&amp;ssl=1" alt="Cabin in the woods with a green to blue gradient overlay and the words the caption of our image on top." class="wp-image-372562" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/08/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658845486547_caption.png?w=250&amp;ssl=1 250w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/08/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658845486547_caption.png?resize=150%2C150&amp;ssl=1 150w" /></figure><p>Par défaut, les éléments de la grille s'empilent dans l'ordre de la source, mais vous pouvez contrôler leur niveau à l'aide de la propriété z-index. Dans l'exemple suivant, certains éléments se chevauchent et nous utilisons la propriété z-index pour placer le deuxième élément au niveau le plus élevé dans le contexte d'empilement :</p><pre class="language-css">.item:nth-child(2) {
  grid-column: 2 / 4;
  grid-row: 2 / 4;
  z-index: 1;
}</pre><figure class="wp-block-image"><img src="https://paper-attachments.dropbox.com/s_66AE538FE3EF7732102B9AF7161E0839F67CE60C5D1206875C538C7FCE63BEF8_1658926511371_stacking.jpg" alt="Four overlapping grid items in a five-by-five grid." /><figcaption>Placer le deuxième item grid au sommet de la pile avec la propriété CSS <code>z-index</code>.</figcaption></figure><h2>Accessibilité</h2><p>Une chose à noter lors de l'utilisation des propriétés de placement de la grille est le problème causé par le réarrangement des éléments. Lorsque vous modifiez la position d'un élément, seul l'ordre visuel des éléments de la grille change, et cet ordre peut être différent de l'ordre original du document (HTML). Cela peut entraîner une très mauvaise expérience pour une personne parcourant le document à l'aide d'un clavier ou écoutant un lecteur d'écran qui lit le contenu dans le même ordre que le code HTML.</p><p>Il faut donc éviter de modifier l'ordre des éléments de la grille lorsque l'ordre HTML des éléments est important. Par exemple, cela peut être intéressant pour une galerie d'images aléatoires, mais sans doute pas pour les entrées de votre formulaire.</p><p>Toutefois, à l'heure où nous écrivons ces lignes, il existe <a href="https://github.com/w3c/csswg-drafts/issues/7387">une proposition visant à résoudre ce problème</a>] qui, nous l'espérons, sera résolu à l'avenir.</p><h3>Démo</h3><p>Vous pouvez modifier la valeur des propriétés de placement de la grille dans la démo pour voir ce qu'il advient du troisième élément de la grille :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/seyedi/pen/MWGXdmJ">Grid item placement with shorthands</a>de seyedi dans<a href="https://codepen.io">CodePen</a></div>]]></description>
      <link>https://la-cascade.io/articles/grid-row</link>
      <guid>https://la-cascade.io/articles/grid-row</guid>
      <pubDate>Mon, 10 Apr 2023 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[10 astuces pour améliorer vos transitions et animations]]></title>
      <description><![CDATA[<p><em>En matière d'animation, de petites différences peuvent avoir un grand impact. Josh Collinsworth livre 10 astuces pour améliorer nos transitions et animations.</em></p><div class="articleContent"><p>Il y a des choses qu'on <em>sait</em> quand on les vit, même si l'on ne sait pas d'où nous en vient l'intuition, et même si l'on n'arrive pas à mettre des mots sur ce que l'on reconnaît exactement.</p><p>Vous ne connaissez peut-être rien aux <em>intérieurs</em>, mais lorsque vous vous trouvez dans un espace bien conçu, vous le percevez.</p><p>Vous pouvez aussi probablement distinguer une bonne appli d'une mauvaise, même si parfois vous ne pouvez pas expliquer exactement ce qui fait que l'une est meilleure que l'autre.</p><p>De la même manière, nos utilisateurs ne se rendent peut-être pas compte de ce qui caractérise les transitions ou les animations de nos sites web et de nos applications, mais ils sont capables de faire la différence entre ce qui est bon et ce qui ne l'est pas. Ils savent intuitivement quand le mouvement d'une application est agréable, et quand l'impression est plutôt banale ou pas fignolée — même s'ils ne peuvent pas expliquer comment ni pourquoi.</p><p>Ainsi, pour mieux comprendre ce qui dégage ces vibrations et comment éviter les mauvaises <em>vibes</em> lors de la création de vos propres interfaces utilisateur, j'ai rassemblé ici ce que j'ai appris ces dernières dix années sur la création de transitions et d'animations pour le web.</p><p class="is-style-explanation">Même si "transition" et "animation" sont des concepts distincts en CSS, je continuerai à utiliser ces mots de manière interchangeable ici, pour signifier <em>tout type de mouvement ou de changement</em>.</p><h2>1. Faites en sorte qu'elle soit plus courte que vous ne le pensez</h2><p>Ok, ok, je comprends : vous venez de consacrer du temps et des efforts à la création d'une belle transition, vous voulez en profiter, et si vous êtes comme moi (et comme la plupart des développeurs), il se peut même que vous restiez assis à admirer votre jolie animation, en la regardant passer d'un côté à l'autre avec délectation... mais voilà :</p><p><strong>L'indicateur n°1 d'une animation mal conçue est qu'elle dure trop longtemps</strong>.</p><p>Vos utilisateurs ne sont pas aussi enthousiastes — et donc patients — que vous. Ils sont venus ici pour faire quelque chose, et ils n'ont pas envie d'attendre plus longtemps que nécessaire, même si c'est très cool.</p><p>Mon conseil : essayez de rendre vos transitions aussi rapides que possible — sans qu'elles soient trop courtes au risque de passer inaperçues. En règle générale, il me semble que la plupart des transitions simples donnent de meilleurs résultats entre 150 et 400 millisecondes (0,15 à 0,4 seconde). Si vous avez des transitions consécutives, par exemple lorsqu'un élément sort et qu'un autre entre après, vous pouvez doubler ce chiffre et ajouter un peu de temps entre les deux (pour éviter que <em>deux</em> animations distinctes se bousculent).</p><p><strong>Continuez à accélérer jusqu'à ce que vous ayez l'impression que c'est <em>trop</em> rapide, puis ralentissez un peu</strong>.</p><p>Cela dit, il y a toujours des exceptions, et plus le changement est important sur la page, plus la transition doit être perceptible. Il y a une grande différence entre, par exemple, une petite animation d'accentuation pour la mise à jour du nombre d'articles dans votre panier d'achat et la transition d'une page entière. Ne laissez pas les changements importants passer <em>trop</em> vite.</p><p>Un dernier point mérite d'être souligné : <strong>une animation ne <em>semble</em> pas toujours aussi longue qu'elle l'est en réalité</strong>. Une transition très lente peut donner l'impression de ne pas commencer tout de suite ; à l'inverse, une transition avec une longue traîne peut <em>sembler</em> terminée avant de l'être techniquement. Gardez cela à l'esprit. <em>La perception est la réalité</em>, la façon dont on ressent le changement est plus importante que la durée techniquement prévue dans le code.</p><h2>2. Adaptez la courbe à l'action</h2><p>Certes, c'est plus facile à dire qu'à faire. Vous vous dites peut-être "ok, super, mais comment puis-je <em>savoir</em> quel type de courbe de Bézier cubique utiliser dans une situation donnée ?"</p><p>La réponse, moyennement satisfaisante, est la suivante : essayer, se planter, recommencer (autrement dit l'<em>expérience</em>) sont les meilleurs maîtres en la matière.</p><p><strong>Le mouvement est aussi subjectif que la couleur, mais il est aussi important. C'est un élément-clé du ressenti et de l'image de marque de votre site web ou de votre application</strong>.</p><p>Lorsque vous expérimentez, pensez au mouvement dans le monde réel et comparez-le au mouvement avec lequel vous travaillez dans votre application. Cette transition est-elle une confirmation positive, qui apparaît et se met en place ? Ça pourrait nécessiter une intro rapide avec une sortie douce mais rapide, comme un assistant enthousiaste qui se précipite pour signaler qu'il a terminé sa tâche.</p><p>Quid d'un message d'échec apparaissant à l'écran ? Dans ce cas, la courbe d'atténuation (<em>easing</em>) doit être légèrement plus lente, comme pour indiquer une légère réticence.</p><p>S'il s'agit de quelque chose d'important qui doit être connu immédiatement, la rapidité et la transparence seront une priorité. S'il s'agit de quelque chose de <em>très</em> critique, un mouvement plus agressif (comme une secousse) peut être nécessaire pour faire comprendre la gravité de la situation et attirer l'attention là où c'est nécessaire.</p><p>Ma recommandation est donc la suivante : investissez du temps et demandez-vous si le mouvement transmet le <em>sentiment</em> approprié. Ce mouvement semble-t-il cohérent avec la marque du produit ou avec la page ?</p><p>Si Pixar animait un robot faisant la même chose que votre interface utilisateur, comment se déplacerait-il ?</p><h2>3. Accélérer et décélérer</h2><p>Dans le monde réel, nous ne voyons pratiquement jamais un mouvement passant immédiatement à la vitesse maximale ou s'arrêtant complètement et instantanément. Nos interfaces utilisateur sembleront donc un peu plus "réelles" et intuitives si nous évitons les courbes qui créent ce type de mouvement.</p><p><strong>Lorsque quelque chose semble anormal dans une animation, il y a de fortes chances que ce soit parce qu'elle commence ou se termine avec une soudaineté peu naturelle</strong>.</p><p>Même s'il s'agit d'un léger mouvement, je recommande d'ajouter un peu d'assouplissement (<em>easing</em>) à vos courbes <code>cubic-bezier</code>. Cette petite accélération et/ou décélération détectable peut faire la différence entre une transition fluide et une transition qui semble juste un peu mal fichue.</p><p>Jetez un coup d'œil à cette démo, où les quatre carrés tournent d'un tour complet, mais avec des <em>easing</em> différents :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/collinsworth/pen/poORdVo/6a29e9ec4ceb068892a7b77211864139">Sudden animations demo</a>de Josh Collinsworth dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez que les premier et deuxième carrés ci-dessus semblent commencer ou se terminer de manière beaucoup trop abrupte.</p><p>La troisième option "lisse" donne de bien meilleurs résultats, car sa courbe personnalisée permet d'obtenir des mouvements d'accélération et de décélération plus gracieux.</p><p>Si vous souhaitez aller encore plus loin dans l'animation et donner l'impression que la physique du monde réel est appliquée, la quatrième option "inertie" fonctionne également très bien ; elle "s'enroule" et s'emballe, comme si elle était actionnée par un ressort. (N'oubliez pas qu'un peu d'inertie suffit pour ce type d'animation).</p><p>Une remarque importante sur les démarrages et les arrêts soudains : il n'y a pas de problème si l'utilisateur ne peut pas les voir. Si l'objet en question s'efface, un démarrage soudain peut être acceptable (puisque le début de l'animation ne sera pas perceptible).</p><p>Il en va de même dans le sens inverse : si un élément s'estompe jusqu'à une opacité de 0, la façon dont la courbe de transition se termine n'a pas d'importance puisqu'elle ne sera de toute façon pas visible à la fin de l'animation.</p><h2>4. Moins, c'est mieux</h2><p>Beaucoup de ces conseils pourraient être résumés par la formule "moins, c'est mieux".</p><p>Il est facile de se laisser emporter et d'animer tout ce qui se trouve sur la page. Mais à moins qu'il ne s'agisse de votre site web personnel et que vous ayez envie de vous lâcher un peu, trop de mouvement peut facilement faire plus de mal que de bien. Lorsqu'il s'agit d'effectuer des transitions avec CSS, la sobriété est généralement préférable à l'exagération.</p><p>Plus un élément change au cours d'une animation, plus la transition risque de paraître exagérée.</p><p>Si vous animez l'opacité de 0 à 1 (ou l'inverse), essayez plutôt une plage plus petite, comme 0,4 à 1. Si votre élément s'adapte à la taille réelle, essayez de le rendre légèrement plus petit au départ, plutôt que si petit qu'il ne peut être vu.</p><p>Un élément se met-il en place par glissement ? Dans la plupart des cas, ce type de mouvement doit être compris entre 5 et 40 pixels. S'il est inférieur, le mouvement risque d'être trop subtil pour être remarqué ; s'il est supérieur, un glissement en douceur risque de se transformer en une chute maladroite.</p><p>Voici un exemple de transition qui anime l'opacité, translateY et l'échelle. Comparez la première animation prononcée et longue (orange) avec la même transition, mais atténuée et un peu plus rapide (bleu).</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/collinsworth/pen/abaqpRV">Big vs subtle animation</a>de Josh Collinsworth dans<a href="https://codepen.io">CodePen</a></div><p>En faire trop peut être pire que de ne rien faire du tout. Trouvez donc le point où la transition est juste suffisante pour être efficace, et si vous allez plus loin, faites-le avec prudence.</p><h2>5. Éviter les paramètres par défaut du navigateur</h2><p>Vous savez peut-être déjà que le navigateur dispose de courbes d'assouplissement intégrées : linear, ease, ease-in, ease-out et ease-in-out.</p><p>Toutefois, si ces cinq fonctions de synchronisation nommées sont pratiques et utiles dans certaines situations, elles sont également très génériques (de nombreuses animations intégrées dans des outils et des bibliothèques en ligne sont victimes de la même homogénéité, même si elles offrent un plus large éventail de choix).</p><p>Si vous voulez tirer le meilleur parti du mouvement, vous devez aller au-delà des options nommées les plus courantes.</p><p>Tout comme un site construit avec Bootstrap ou Tailwind risque de paraître générique, les courbes d'assouplissement prêtes à l'emploi peuvent souvent rendre les interfaces utilisateur fades et homogènes.</p><p>Comme alternative, VS Code a une autocomplétion étonnante pour les courbes de cubic-bezier avec un large éventail d'options ; commencez à taper cubic-bezier dans un contexte CSS, et vous devriez voir la liste déroulante suivante apparaître :</p><figure><img src="https://la-cascade.io/images/vs-code.png" alt="" /></figure><p>Toutes ces options sont couvertes par <a href="https://joshcollinsworth.com/demos/easing">mon terrain de jeu sur l'easing</a>, si vous souhaitez y jeter un coup d'œil et jouer avec les préréglages.</p><p>Une autre excellente option : ouvrez les outils de développement de votre navigateur et jouez avec les courbes d'easing qui s'y trouvent.</p><p>Tous les principaux navigateurs disposent d'un panneau d'easing qui sert de bac à sable pour essayer différentes options et procéder à des ajustements. Pour y accéder, ouvrez les outils de développement et cliquez sur l'icône de courbe située à côté d'une valeur de bézier cubique dans le panneau des styles CSS. (L'icône varie, mais le processus est fondamentalement identique dans tous les navigateurs).</p><figure><img src="https://la-cascade.io/images/firefox.png" alt="" /></figure><p>Quelle que soit la manière dont vous choisirez de définir vos courbes d'easing, je vous recommande de prendre le temps de procéder à des ajustements subtils. Utilisez cubic-bezier et n'ayez pas peur de bricoler.</p><p>Vous pouvez certainement vous débrouiller avec les préréglages dans le navigateur ou dans VS Code. Et si vous utilisez le cubic-bezier sur les valeurs des mots-clés, vous avez déjà une longueur d'avance.</p><p>Cela dit, vous ne limiteriez probablement pas votre palette de couleurs à des couleurs CSS nommées prédéfinies. Vous ne voudrez peut-être pas non plus limiter vos transitions à une petite poignée de courbes prédéfinies.</p><h2>6. Propriétés multiples, assouplissements multiples</h2><p>Bien que ce ne soit pas toujours utile, il vous arrivera d'animer plus d'une propriété à la fois sur un même élément, comme lorsque vous mettez à l'échelle un élément avec transformation et que son opacité change également.</p><p>Vous pouvez appliquer la même courbe cubic-bezier aux deux propriétés, comme illustré ici :</p><pre class="language-css">/* ⛔ Ok, mais on peut faire mieux: */
.my-element {
  transition: all cubic-bezier(0.5, 0, 0.5, 1) 0.5s;
}
/* ⛔ Peut-être pas idéal non plus: */
@keyframes scale_and_appear {
  from {
    opacity: 0;
    transform: scale(0);
  }
}
.my-element {
  animation: scale_and_appear 0.5s cubic-bezier(0.5, 0, 0.5, 1) forwards;
}</pre><p>Selon les cas, ça peut sembler parfait. Toutefois, dans certaines situations, la même courbe ne convient pas vraiment à toutes les propriétés faisant l'objet d'une transition.</p><p>La courbe d'assouplissement qui fonctionne bien pour la transformation peut ne pas convenir pour le fondu. C'est à ce moment-là qu'il est pratique de définir une courbe d'assouplissement unique pour chaque propriété CSS.</p><p>Dans ce cas, vous pouvez diviser les animations <code>@keyframes</code> par propriété ou spécifier plusieurs transitions. Vous pouvez ensuite spécifier une courbe différente pour chaque propriété, puisque la transition et l'animation peuvent accepter plusieurs valeurs :</p><pre class="language-css">/* ? C'est mieux; chaque propriété a sa propre courbe */
.my-element {
  transition: opacity linear 0.5s, transform cubic-bezier(
        0.5,
        0,
        0.5,
        1
      ) 0.5s;
}
/* ? Utilisez deux animations */
@keyframes scale {
  from {
    transform: scale(0);
  }
}
@keyframes appear {
  from {
    opacity: 0;
  }
}
.my-element {
  animation: scale 0.5s cubic-bezier(0.5, 0, 0.5, 1) forwards, appear
      0.5s linear forwards;
}</pre><p>Voici une démo ; lorsque les cases entrent et sortent en alternance, remarquez que l'opacité et l'échelle suivent la même accélération pour le carré de gauche. À droite, en revanche, l'opacité suit sa propre courbe linéaire.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/collinsworth/pen/NWLdLGW">Varying easings per property</a>de Josh Collinsworth dans<a href="https://codepen.io">CodePen</a></div><p>Lequel est le meilleur ? Tout dépend de l'effet recherché.</p><p>Encore une fois, cet effet ne se produit pas très souvent, mais il est très pratique lorsqu'il se produit, et facile à oublier, ce qui lui vaut une place sur la liste.</p><p>Vous pouvez même aller jusqu'à modifier la durée de chaque propriété, mais faites attention à ce que les choses ne se désynchronisent pas si vous décidez d'aller aussi loin.</p><h2>7. Utiliser des délais échelonnés</h2><p>Lors de la transition de plusieurs éléments (ou d'un élément composé de plusieurs parties), ne sous-estimez pas l'effet que peuvent avoir les délais d'animation ou de transition, en particulier lorsqu'ils sont décalés.</p><p>Jetez un coup d'œil à cet exemple CodePen ; chaque ligne utilise un nouveau type de délai d'animation pour créer un effet différent :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/collinsworth/pen/yLxVZMx">Play more with delay</a>de Josh Collinsworth dans<a href="https://codepen.io">CodePen</a></div><p>Dans le codepen ci-dessus, la première ligne transitionne d'un seul coup. C'est bien, mais ce n'est pas particulièrement net.</p><p>Dans chaque ligne suivante, différents degrés de retard sont appliqués à chaque lettre, pour créer un effet ludique de "rebond". Il y en a même un qui va à l'envers et un autre qui fait apparaître la ligne du milieu vers l'extérieur.</p><p>Cependant, n'oubliez pas que le moins est le mieux. Il est très facile d'exagérer les animations de ce type, surtout lorsqu'il y a beaucoup d'éléments en transition. J'ai rendu cet exemple beaucoup plus exagéré que ce que je recommanderais généralement, juste à des fins de démonstration. Il est probablement un peu trop chargé pour la plupart des travaux d'interface utilisateur.</p><p>Cela dit, il est possible d'appliquer cet effet à une échelle plus subtile. Des points dans un écran de chargement, peut-être ? Lorsqu'un tiroir ou un menu hamburger est ouvert, chaque élément peut apparaître avec un léger retard.</p><p>Là encore, l'effet doit être court et subtil. Mais lorsqu'ils sont bien appliqués, les délais échelonnés peuvent contribuer à porter les transitions web au top.</p><h2>8. Les entrées sortent, les sorties entrent</h2><p>Si vous avez examiné divers types de courbes d'easing, vous avez peut-être remarqué qu'elles se présentent généralement sous trois formes : un <em>ease-in</em> (qui commence plus lentement), un <em>ease-out</em> (qui se termine plus lentement) et <em>in-out</em> (qui est essentiellement les deux : plus rapide au milieu et plus lent au début et à la fin).</p><p>Le problème avec les transitions, c'est qu'on veut souvent que la transition <em>in</em> soit une transition <em>ease-out</em> et que la transition <em>out</em> soit une transition <em>ease-in</em>.</p><p>...Ok, c'était probablement aussi déroutant pour vous de le lire que pour moi de l'écrire... Revenons en arrière.</p><p>Supposons que vous ayez une animation dans laquelle un élément quitte la page tandis qu'un autre apparaît pour prendre sa place, comme une transition de page ou un glissement entre deux images dans une boîte.</p><p>L'utilisateur perçoit cela comme une transition d'interface utilisateur. Mais en coulisses, il s'agit en fait de <em>deux</em> transitions : le départ de l'ancien élément, suivi de l'entrée du nouvel élément.</p><p>Cela signifie que si vous faites sortir un élément (<em>out</em>) et que vous voulez qu'il démarre lentement, vous avez besoin d'un <em>ease-in</em>.</p><p>Inversement, lorsqu'un élément entre (<em>in</em>), il doit normalement s'arrêter progressivement. Dans ce cas, il faut un <em>ease-out</em>.</p><p>Ces deux éléments s'associent pour créer l'effet d'un mouvement homogène.</p><h2>9. S'appuyer sur l'accélération matérielle</h2><p>Toutes les propriétés CSS ne peuvent pas être animées ou faire l'objet d'une transition fluide sur tous les appareils et navigateurs. En fait, seules quelques-unes sont capables d'exploiter l'accélération matérielle d'un appareil pour obtenir les transitions les plus fluides et les plus rapides possibles.</p><p class="is-style-explanation">Il n'est pas nécessaire de comprendre ce qu'est l'accélération matérielle pour en tirer parti. Mais si vous êtes curieux, sachez que cela signifie que le navigateur peut faire appel à l'unité de traitement graphique (GPU) de l'appareil pour accélérer considérablement le rendu et le rendre plus fluide, mais uniquement sous certaines conditions.</p><p>Propriétés qui peuvent toujours être accélérées par le matériel :</p><ul><li><code>transform</code> (y compris toutes les formes de <code>translate</code>, <code>scale</code> et <code>rotate</code>, ainsi que tous leurs équivalents <code>3d</code>)</li>
<li><code>opacity</code></li>
</ul><p>Propriétés qui peuvent parfois être accélérées par le matériel :</p><ul><li>Certaines propriétés SVG</li>
<li><code>filter</code>, en fonction du navigateur et du filtre</li>
</ul><p>D'autres éléments non-CSS, comme le canvas et le WebGL, peuvent également bénéficier de l'accélération matérielle. Je n'en parlerai pas ici.</p><p>Le tl;dr de tout ce qui précède est : Si vous souhaitez déplacer, mettre à l'échelle ou faire pivoter un élément, utilisez toujours la propriété CSS <code>transform</code>.</p><p>L'application d'une transformation n'affecte pas la mise en page, ce qui minimise les recalculs et permet au navigateur de fonctionner en douceur. La plupart des animations et des transitions les plus courantes que vous pouvez utiliser sur le web peuvent être réalisées en combinant <code>transform</code> et <code>opacity</code>.</p><p>Mais quoi que vous fassiez, <em>évitez de modifier directement la taille ou l'emplacement d'un élément</em>. Si vous modifiez une propriété susceptible d'affecter la disposition des éléments sur la page - hauteur, largeur, bordure, marge, padding, etc. - vous risquez de ralentir sensiblement la page en raison des calculs nécessaires pour effectuer cette modification.</p><p>Si vous devez animer de telles propriétés, veillez à les tester sur tous les appareils et navigateurs possibles. D'après mon expérience, Safari en particulier ne traite pas les animations de manière performante par défaut, surtout sur iOS. Firefox n'est pas loin derrière, mais vous ne vous en rendrez peut-être pas compte si vous ne testez que sur des appareils puissants. Une grande partie du monde vit sur des Androïdes bon marché ; n'oubliez pas de les inclure dans vos tests.</p><p class="is-style-explanation">Ce n'est pas parce que quelque chose peut être accéléré au niveau matériel qu'il le sera. C'est le navigateur qui prend la décision finale.Une raison potentielle pour laquelle il peut se retirer : le GPU est plus rapide, mais il consomme aussi plus d'énergie. Par conséquent, si l'appareil est peu gourmand en énergie ou en mode d'économie de la batterie, le navigateur peut préférer la batterie aux performances graphiques.</p><h2>10. Utilisez will-change si nécessaire</h2><p>Si vous rencontrez des problèmes avec des animations qui devraient être fluides et performantes en théorie, mais qui semblent hachées ou guindées en pratique (encore une fois : c'est généralement dans Safari pour moi, mais votre kilométrage peut varier), <a href="https://developer.mozilla.org/fr/docs/Web/CSS/will-change">utilisez la propriété will-change</a>.</p><p>Je n'entrerai pas trop dans les détails techniques, mais la propriété <code>will-change</code> vous permet essentiellement d'indiquer au navigateur ce qui va changer (assez facile à retenir), afin qu'il puisse ignorer d'autres calculs. C'est un peu comme si vous indiquiez à l'avance au restaurant que tout votre groupe ne commandera qu'un menu limité ; cela permet de gagner du temps en indiquant à la cuisine/au navigateur ce sur quoi il doit se concentrer et ce dont il n'a pas besoin de se préoccuper.</p><p>Exemple : si vous êtes certain que la seule chose qui va changer avec un élément est sa propriété <code>transform</code>, et que vous pouvez en toute confiance le faire savoir au navigateur à l'avance via <code>will-change : transform</code>, il peut en toute sécurité ignorer toutes les autres étapes qu'il aurait dû suivre pour rendre à nouveau cet élément lorsque quelque chose change sur la page.</p><p>Dans le meilleur des cas, lorsqu'il est utilisé avec des propriétés qui n'affectent pas la mise en page, il permet au navigateur de décharger entièrement le calcul sur le GPU afin d'obtenir un taux de rafraîchissement plus élevé et des performances plus fluides.</p><p>Cependant, <code>will-change</code> n'est pas une solution miracle. En fait, s'il est utilisé à outrance, il peut nuire aux performances.</p><p>En effet, le navigateur crée une nouvelle couche (un peu comme un nouveau niveau d'indice z) pour chaque élément auquel est appliqué un <code>will-change</code>, ce qui rend les choses un peu plus complexes à composer. Utilisé judicieusement, cet échange vaut son prix. Utilisé sans précaution, cependant, il pourrait créer encore plus de travail pour le navigateur. Comme le dit MDN :</p><figure class="quote"><blockquote cite=""><div>Avertissement : will-change est destiné à être utilisé en dernier recours, afin d'essayer de résoudre des problèmes de performance existants. Il ne doit pas être utilisé pour anticiper les problèmes de performance.</div></blockquote>
</figure><p>Certaines sources vont même jusqu'à recommander d'appliquer <code>will-change</code> avant une animation ou une transition, puis de le retirer après.</p><p>Là encore, le meilleur conseil est de faire des tests approfondis.</p><h3>Bonus : respecter les préférences de l'utilisateur</h3><p>Les utilisateurs peuvent indiquer, via les paramètres de leur appareil, s'ils préfèrent les mouvements réduits.</p><p>Les raisons pour lesquelles un utilisateur peut le faire sont nombreuses et variées. Il y a tout d'abord des raisons médicales : un utilisateur peut avoir des vertiges, des nausées ou même des crises d'épilepsie lorsqu'il est exposé à des mouvements excessifs. Ou encore, un utilisateur peut simplement trouver que trop de mouvements le distraient ou l'ennuient.</p><p>La raison n'a pas vraiment d'importance ; c'est à nous, développeurs, qu'il incombe de tenir compte des préférences de l'utilisateur, quelles qu'elles soient.</p><p>Nous pouvons le faire en CSS, à l'aide d'une requête média (comme celle-ci, tirée de MDN) :</p><pre class="language-css">@media (prefers-reduced-motion) {
  /* styles to apply if the user's settings
     are set to reduced motion */
}</pre><p>Nous pouvons également utiliser JavaScript. Dans cet exemple, nous allons vérifier s'il existe une préférence pour les mouvements réduits et ajouter une classe à la balise si c'est le cas :</p><pre class="language-js">const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
).matches
if (prefersReducedMotion) {
  document.documentElement.classList.add('reduce-motion')
}</pre><p>En suivant cet exemple JavaScript, nous pourrions ensuite ajouter des feuilles de style CSS à des éléments ciblés de la page pour définir des dérogations :</p><pre class="language-css">.reduce-motion {
  /* Select stuff here and reduce motion */
}</pre><p>Notez simplement que si vous utilisez JavaScript, vous voudrez que la page soit progressivement améliorée, afin de vous assurer qu'il n'y a pas d'éclair de mouvement avant l'exécution du script, et que les utilisateurs qui ont désactivé JavaScript ne sont pas exclus de la page. L'idéal est donc de combiner <em>les deux</em> techniques.</p><p>Pour ce qui est de ce que nous devons faire exactement avec notre CSS dans ces cas, n'oubliez pas que la réduction du mouvement <em>ne signifie pas qu'il n'y a pas de mouvement</em>, ni même qu'il n'y a pas d'animation du tout.</p><p>Une technique que j'utilise souvent consiste à modifier les animations des images clés pour n'utiliser l'opacité que lorsqu'une préférence de mouvement réduit est détectée :</p><pre class="language-css">@keyframes slide_in {
  from {
    opacity: 0;
    transform: translateY(2rem);
  }
}
@keyframes slide_in_reduced {
  from {
    opacity: 0;
  }
}
.animated-thing {
  animation-name: slide_in;
}
@media (prefers-reduced-motion) {
  .animated-thing {
    animation-name: slide_in_reduced;
  }
}</pre><p><strong>Ce n'est pas parce qu'un utilisateur préfère un mouvement minimal qu'il n'apprécie pas les transitions</strong>.</p><p>De plus, dans certaines situations, il est préférable de ne pas modifier les mouvements. Par exemple, si vous affichez une barre de progression pendant le chargement d'un élément en arrière-plan, ou un indicateur de lecture sur un fichier audio ou vidéo, il s'agit d'un élément d'information clé de l'interface utilisateur. Plutôt que d'éliminer complètement cet indicateur, envisagez de trouver un moyen de rendre le mouvement subtil et discret. Il est possible de permettre à l'utilisateur de masquer le mouvement. Il est également possible de représenter l'information différemment (un compteur de pourcentage numérique au lieu d'une barre animée, par exemple).</p><p>Au minimum, les utilisateurs devraient pouvoir interrompre toutes les animations continues, y compris les vidéos et les gifs. Toutefois, dans l'idéal, nous devrions anticiper leurs besoins en fonction des préférences de leur appareil, au lieu de les forcer à gérer quelque chose qu'ils ont déjà indiqué qu'ils préféraient ne pas voir.</p><p>Je vous renvoie à <a href="https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/">cet article de Val Head</a> pour Smashing Magazine, qui approfondit la question du design avec des mouvements réduits. Il s'agit d'un vaste sujet en soi, mais j'espère que ce conseil vous fournira des indications générales.</p><h2>Mettre tout cela en place</h2><p>Cette démo CodePen permet d'illustrer comment la combinaison des astuces de cet article peut complètement changer la sensation d'une transition d'interface utilisateur. Cliquez sur le bouton "Exécuter l'animation" d'un côté ou de l'autre pour voir la transition des éléments de cette colonne.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/collinsworth/pen/jOvaYxK">Animation tips visualized</a>de Josh Collinsworth dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez que les deux côtés ont essentiellement la même animation ; les boîtes changent d'échelle, se déplacent et s'estompent dans les deux cas. Mais les détails de cette transition transforment complètement l'effet (sans jeu de mots).</p><p>Dans la colonne de gauche (rouge-orange), les éléments ne sont pas décalés dans le temps ; ils apparaissent tous en même temps, avec une grande variation d'opacité, de position et d'échelle. La transition dure également assez longtemps et utilise la courbe <em>ease-out</em> par défaut du navigateur, ce qui n'est pas mauvais dans ce cas, mais pas optimal non plus.</p><p>Dans la colonne de droite (bleue), en revanche, l'animation est décalée, de sorte que les éléments entrent l'un après l'autre. Le délai et la durée totale de la transition sont tous deux assez minimes, et les effets sont toujours présents, mais beaucoup plus subtils. Enfin, l'assouplissement est une courbe de bezier personnalisée.</p><p>J'espère que cette démo vous permettra de vous rendre compte de l'énorme différence que peuvent faire de petites modifications.</p><h3>Récapitulatif</h3><p>Bonne chance pour créer vos propres animations sur le web ! J'espère que cet article a été engageant et utile, et que vous vous sentez mieux équipé pour créer des expériences interactives encore plus fortes.</p><p>Comme toujours, n'hésitez pas à nous faire part de vos commentaires ou de vos questions (<a href="https://joshcollinsworth.com/blog/great-transitions">dans l'article original</a>), et merci de votre lecture !</p></div>]]></description>
      <link>https://la-cascade.io/articles/10-astuces-pour-ameliorer-vos-transitions-et-animations</link>
      <guid>https://la-cascade.io/articles/10-astuces-pour-ameliorer-vos-transitions-et-animations</guid>
      <pubDate>Sun, 19 Mar 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Que peut-on mettre dans une variable CSS?]]></title>
      <description><![CDATA[<p><em>Will Boyd fait un point complet sur les variables CSS et tout ce qu'on peut faire avec. Bluffant, comme d'habitude.</em></p><div class="articleContent"><p>Les variables CSS (également appelées <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Using_CSS_custom_properties">propriétés personnalisées</a> CSS, <em>custom properties</em> en anglais) peuvent contenir toutes sortes de choses. Certaines n'étaient pas évidentes pour moi, c'est pourquoi j'ai décidé d'écrire cet article.</p><p>Pour être clair, cet article se concentre sur ce que vous pouvez mettre dans une variable CSS — avec une démonstration d'animation vers la fin parce que je ne pouvais pas m'en empêcher. Si vous recherchez des conseils plus généraux sur l'utilisation des variables CSS, il existe <a href="https://increment.com/frontend/a-users-guide-to-css-variables/">d'autres excellents articles</a> pour cela.</p><figure><img src="https://la-cascade.io/images/colorful-bowls.jpg" alt="des cercles de couleur concentriques" /></figure><h2>Valeurs unitaires et un peu de maths</h2><p>Commençons par le plus simple. Il est courant de mettre des valeurs numériques avec des unités dans une variable CSS. Celles-ci sont formellement connues sous le nom de dimensions.</p><pre class="language-css">:root {
  --nice-padding: 20px;
  --decent-font-size: 1.25rem;
}
article {
  padding: var(--nice-padding);
  font-size: var(--decent-font-size);
}</pre><p>Les variables peuvent contenir les résultats de calculs impliquant d'autres variables via calc().</p><pre class="language-css">:root {
  --image-width: 800px;
  /* calculate height to preserve a 4:3 aspect ratio */
  --image-height: calc(var(--image-width) / (4 / 3));
}
img {
  width: var(--image-width);
  height: var(--image-height);
}</pre><p>De même, les variables peuvent être utilisées avec les fonctions CSS intégrées.</p><pre class="language-css">:root {
  --min: 1rem;
  --max: 4rem;
  --clamped-font-size: clamp(var(--min), 2.5vw, var(--max));
}
p {
  font-size: var(--clamped-font-size);
}</pre><h2>Valeurs numériques sans unité</h2><p>Les variables peuvent également contenir des valeurs numériques sans unité. Certaines propriétés CSS utilisent directement ces valeurs.</p><pre class="language-css">:root {
  --obnoxiously-big-number: 9001;
}
.important-modal {
  z-index: var(--obnoxiously-big-number);
}</pre><p>Mais d'autres fois, vous pouvez vouloir appliquer des unités à ces valeurs. Ça peut se faire très simplement avec une multiplication dans une expression calc().</p><pre class="language-css">:root {
  --magic-number: 41;
}
.crazy-box {
  width: calc(var(--magic-number) * 1%);
  padding: calc(var(--magic-number) * 1px);
  transform: rotate(calc(var(--magic-number) * 1deg));
}</pre><h2>Des trucs non numériques</h2><p>Les variables CSS ne sont pas uniquement destinées aux chiffres. Elles peuvent contenir des mots-clés prédéfinis que les propriétés reconnaissent.</p><pre class="language-css">:root {
  --bullets: circle;
  --casing: uppercase;
}
ul {
  list-style-type: var(--bullets);
  text-transform: var(--casing);
}</pre><p>Il existe également des <a href="https://developer.mozilla.org/fr/docs/Web/CSS/custom-ident">identifiants personnalisés</a> qui pointent vers des éléments que vous avez définis et nommés, comme un nom d'animation ou une zone de grille, comme indiqué ci-dessous.</p><pre class="language-css">:root {
  --layout-position: center-stage;
}
body {
  grid-template-areas: 'left center-stage right';
}
main {
  grid-area: var(--layout-position);
}</pre><h2>Chaînes de contenu</h2><p>Les pseudo-éléments <code>::before</code> et <code>::after</code> utilisent la propriété <code>content</code> pour afficher, eh bien... du contenu. Ce contenu peut être un certain nombre de choses différentes, mais il s'agira souvent de chaînes de caractères (<em>string</em>).</p><p>Le CSS suivant montre que le contenu est alimenté par des variables de type <em>string</em>. Vous pouvez également voir comment concaténer des variables de type <em>string</em> avec d'autres chaînes de caractères et comment extraire une valeur de type <em>string</em> d'un attribut avec <code>attr()</code>.</p><pre class="language-css">:root {
  --open: '(';
  --close: ')';
  --heading-hint: ' ' var(--open) 'this is a heading' var(--close);
  --link-hint: ' ' var(--open) attr(href) var(--close);
}
h1::after {
  content: var(--heading-hint);
}
a::after {
  content: var(--link-hint);
}</pre><p>Voici une démo pour vous montrer le résultat.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/GRjZwEM">CSS Variables with Content Strings</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><h2>Images</h2><p>Les variables CSS peuvent également contenir des <a href="https://developer.mozilla.org/fr/docs/Web/CSS/image">images</a>. Les images peuvent également être affichées dans le contenu, mais on les voit sans doute plus couramment dans <code>background-image</code>.</p><pre class="language-css">:root {
  /* image from an external URL (PNG in this case) */
  --image-from-somewhere: url(https://codersblock.com/assets/images/logo.png);
  /* image from embedded data (SVG in this case) */
  --image-embedded: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M8 256c0 136.966 111.033 248 248 248s248-111.034 248-248S392.966 8 256 8 8 119.033 8 256zm248 184V72c101.705 0 184 82.311 184 184 0 101.705-82.311 184-184 184z'%3E%3C/path%3E%3C/svg%3E");
}
.a {
  background-image: var(--image-from-somewhere);
}
.b::after {
  content: var(--image-embedded);
}</pre><p>Cela vous permet de vous débarrasser des URL d'images longues et difficiles à manier et d'utiliser des noms de variables plus courts lorsque c'est nécessaire.</p><h2>Abréviations</h2><p>Une variable CSS peut être utilisée comme une valeur unique dans un raccourci, ou comme le racourci entier lui-même. Les deux éléments conteneurs ci-dessous auront le même padding.</p><pre class="language-css">:root {
  --top-padding: 60px;
  --all-padding: 60px 20px 40px 10px;
}
.container {
  padding: var(--top-padding) 20px 40px 10px;
}
.another-container {
  padding: var(--all-padding);
}</pre><p>J'ai trouvé intéressant que les variables CSS puissent également contenir un segment partiel d'un raccourci formé de plusieurs valeurs.</p><h2>Listes</h2><p>Certaines propriétés, comme <code>background</code> et <code>box-shadow</code>, peuvent prendre une liste d'éléments. Vous pouvez utiliser une variable CSS comme un seul élément de la liste, une sous-liste de la liste ou la liste entière.</p><p>Voici quelques exemples de mélanges de listes <code>box-shadow</code> et de variables CSS. J'ai également glissé un exemple de mise en place d'une liste de couleurs dans une variable CSS pour l'utiliser dans un dégradé linéaire, car vous pouvez tout à fait le faire !</p><pre class="language-css">/*
  quick reminder of the anatomy of a box-shadow!
  box-shadow: &lt;x-offset&gt; &lt;y-offset&gt; &lt;blur&gt; &lt;spread&gt; &lt;color&gt;;
*/
:root {
  --single-shadow: 0 0 0 40px #355c7d;
  --multi-shadow: 0 0 0 60px #f67280, 0 0 0 80px #6c5b7b;
  --gradient-colors: #f1bbba, #ece5ce, #c5e0dc;
}
.a {
  box-shadow: 0 0 0 20px #60b99a, var(--single-shadow);
}
.b {
  box-shadow: var(--multi-shadow);
}
.c {
  box-shadow: 0 0 0 20px #60b99a, var(--single-shadow), var(
      --multi-shadow
    );
}
body {
  background-image: linear-gradient(45deg, var(--gradient-colors));
}</pre><p>Et voici une démo pour voir ce que ça peut donner :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/gOwrQRX">CSS Variables with Shadow Lists</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><h2>Couleurs</h2><p>Ah ! on ne peut pas oublier les couleurs ! Les variables CSS fonctionnent très bien pour les couleurs et il est très courant de les voir utilisées pour définir un thème de couleurs facile à consommer dans tout un site.</p><pre class="language-css">@media (prefers-color-scheme: light) {
  :root {
    --color-text: #233742;
    --color-links: #d80b77;
    --color-bg: white;
  }
}
@media (prefers-color-scheme: dark) {
  :root {
    --color-text: white;
    --color-links: #b4cddd;
    --color-bg: #233742;
  }
}
body {
  color: var(--color-text);
  background-color: var(--color-bg);
}
a {
  color: var(--color-links);
}</pre><p>Vous pouvez également placer des valeurs de paramètres de couleur distinctes dans des variables CSS, puis les combiner en une couleur à l'aide de <code>rgb()</code>/<code>rgba()</code> et <code>hsl()</code>/<code>hsla()</code>. Voici un exemple utilisant <code>rgb()</code>.</p><pre class="language-css">:root {
  --red: 216;
  --green: 11;
  --blue: 119;
}
a {
  color: rgb(var(--red), var(--green), var(--blue));
}</pre><h2>Réunir le tout avec l'animation</h2><p>Peut-on mettre une valeur animée dans une variable CSS ? La réponse est : c'est compliqué !</p><p>Par défaut, la plupart du temps non. Certains navigateurs afficheront un seul saut discret de la valeur de départ à la valeur d'arrivée. D'autres navigateurs ne feront rien. Dans tous les cas, vous n'obtiendrez pas d'animation lisse et interpolée.</p><p>Le problème est que votre navigateur ne sait pas comment animer vos variables inventées. Mais bonne nouvelle ! Vous pouvez résoudre ce problème grâce à l'<a href="https://drafts.css-houdini.org/css-properties-values-api/">API Propriétés et Valeurs</a>. Elle fait partie de <a href="https://ishoudinireadyyet.com/">Houdini</a> et fonctionne actuellement dans Chrome, Edge et Opera, et d'autres navigateurs devraient suivre.</p><p>Voici comment cela fonctionne. Tout d'abord, déclarez vos propriétés personnalisées.</p><pre class="language-css">@property --red {
  syntax: '&lt;integer&gt;';
  inherits: true;
  initial-value: 0;
}
@property --green {
  syntax: '&lt;integer&gt;';
  inherits: true;
  initial-value: 0;
}
@property --blue {
  syntax: '&lt;integer&gt;';
  inherits: true;
  initial-value: 0;
}</pre><p>Il s'agit de dire à votre navigateur "hé, voici quelques variables, ce sont des entiers qui ont la valeur 0 par défaut". Ensuite, votre navigateur peut dire "oh les entiers, super, <a href="https://developer.mozilla.org/fr/docs/Web/CSS/integer#interpolation">je sais comment les animer</a>". Et maintenant, nous sommes prêts pour l'animation.</p><pre class="language-css">@keyframes red-fade {
  50% {
    --red: 255;
  }
}
@keyframes green-fade {
  50% {
    --green: 255;
  }
}
@keyframes blue-fade {
  50% {
    --blue: 255;
  }
}
:root {
  animation: red-fade 16s, green-fade 14s, blue-fade 12s;
  animation-iteration-count: infinite;
}</pre><p>Dans le CSS ci-dessus, il y a une animation keyframe pour chaque variable allant de 0 (la valeur initiale <code>initial-value</code> que nous avons déclarée) à 255 et inversement. Ces valeurs sont animées sur l'élément <code>:root</code> et tous les éléments enfants peuvent les utiliser car nous avons déclaré les variables avec <code>inherits : true</code>.</p><pre class="language-css">.swatch {
  background-color: rgb(var(--red), var(--green), var(--blue));
}</pre><p>Et avec ça, nous avons 3 variables CSS animées indépendamment qui sont combinées ensemble via <code>rgb()</code> pour créer une <code>background-color</code> en constante évolution. Pas de JavaScript. Super !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/PoGNxjE">CSS Variables Color Animation</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Il se passe en fait beaucoup de choses dans cette démo. De multiples animations sont alimentées par ce trio de variables CSS animées (<code>--red</code>, <code>--green</code>, <code>--blue</code>). Décomposons le tout.</p><p>Tout d'abord, la grande palette de couleurs RGB. Nous en avons déjà parlé.</p><p>Ensuite, les indicateurs qui montent et descendent au-dessus des barres de couleur. Ils sont positionnés en convertissant les variables CSS en valeurs <code>px</code> négatives. Par exemple, voici le rouge.</p><pre class="language-css">.red .indicator {
  transform: translateY(calc(var(--red) * -1px));
}</pre><p>Troisièmement, les chiffres affichés sous les barres de couleur. Celui-ci est intéressant. Comme mentionné précédemment, vous pouvez utiliser <code>content</code> pour afficher des <a href="denied:javascript:void(0)">chaînes de caractères</a>, mais cela ne fonctionnera pas avec nos variables <a href="denied:javascript:void(0)">entières</a>. Cependant, les compteurs CSS fonctionnent avec des valeurs entières et peuvent être affichés tout comme une chaîne de caractères avec du contenu.</p><pre class="language-css">.red .value::before {
  /* in goes an integer variable */
  counter-reset: color-value var(--red);
  /* out comes a string-like counter value */
  content: counter(color-value);
}</pre><p>En gros, nous abusons des compteurs CSS pour convertir un nombre entier en chaîne de caractères. Que du plaisir.</p><h2>Valeurs à l'échelle du CSS</h2><p>Les propriétés personnalisées suivent les mêmes règles que les propriétés intégrées en ce qui concerne la cascade et l'héritage. Vous pouvez utiliser les mêmes valeurs spéciales CSS que sont <code>initial</code>, <code>inherit</code>, <code>unset</code> et <code>revert</code> sur les variables CSS pour contrôler ce qui y est finalement placé.</p><h2>Au revoir</h2><p>Du point de vue de la syntaxe, les variables CSS sont "extrêmement permissives". Il y a certainement d'autres types de choses que vous pouvez y mettre que je n'ai pas spécifiquement couvertes, mais j'espère en avoir montré suffisamment pour vous donner une idée des possibilités. De plus, nous avons eu l'occasion de jouer avec des couleurs animées, donc c'était amusant.</p></div>]]></description>
      <link>https://la-cascade.io/articles/que-peut-on-mettre-dans-une-variable-css</link>
      <guid>https://la-cascade.io/articles/que-peut-on-mettre-dans-une-variable-css</guid>
      <pubDate>Sun, 26 Feb 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Plongée en profondeur dans les pseudo-éléments :before et :after]]></title>
      <description><![CDATA[<p><em>NdT : Pour une intro générale, vous pouvez consulter <a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after">Les pseudo-éléments CSS3 :before et :after</a></em></p><p>Les pseudo-éléments <code>::before</code> et <code>::after</code> sont des outils incroyablement polyvalents dans la boîte à outils CSS. Leur compréhension peut vous aider à élaborer des CSS pratiques pour résoudre toutes sortes de situations. Vous pouvez également aller plus loin et les utiliser pour créer d'impressionnantes prouesses en matière d'astuces CSS.</p><p>Cet article commence par le rez-de-chaussée, en expliquant ces <a href="https://la-cascade.io/tags/pseudo-elments">pseudo-éléments</a> et comment les utiliser. Nous nous plongerons dans des sujets plus excitants au fil de l'article. Nous parlerons également beaucoup de la propriété CSS <a href="https://developer.mozilla.org/fr/docs/Web/CSS/content">content</a>, car elle est très liée.</p><figure><img src="https://la-cascade.io/images/two-birds.jpg" alt="deux moineaux" /></figure><h2>Une présentation rapide de ::before et ::after</h2><p>En CSS, <code>::before</code> et <code>::after</code> sont des mots-clés que vous pouvez ajouter à un sélecteur pour créer des pseudo-éléments. Les pseudo-éléments sont insérés dans le ou les éléments correspondant au sélecteur, avant ou après tout contenu.</p><p>Le plus simple est probablement de montrer un exemple. Prenez le HTML et le CSS suivants.</p><pre class="language-html">&lt;p class="my-paragraph"&gt;I'm a paragraph!&lt;/p&gt;</pre><pre class="language-css">.my-paragraph {
  padding: 20px;
  border: 4px dashed lightgray;
}
.my-paragraph::before {
  content: 'This is before!';
  color: hotpink;
}
.my-paragraph::after {
  content: 'This is after!';
  color: steelblue;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/vYyeomY">::before and ::after Pseudo-Elements</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Si vous jetez un coup d'œil aux outils de développement, vous verrez <code>::before</code> et <code>::after</code> à l'intérieur de l'élément <code>&lt;p&gt;</code>. Vous pouvez cliquer dessus pour afficher ou modifier leurs styles, comme tout autre élément.</p><figure><img src="https://la-cascade.io/images/dev-tools-pseudo-elements.png" alt="" /></figure><p>Nous venons d'utiliser CSS pour créer des éléments et du contenu qui n'existaient pas dans le HTML. Trop fort !</p><h2>Lignes d'en-tête décoratives</h2><p><code>::before</code> et <code>::after</code> sont parfaits pour ajouter une décoration. Regardez ce titre avec des lignes décoratives.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/OJbxKmX">Decorative Lines Heading</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Le HTML consiste juste en une seule balise <code>&lt;h1&gt;</code>.</p><pre class="language-html">&lt;h1&gt;Elegant Heading&lt;/h1&gt;</pre><p>Tout se passe dans le CSS :</p><pre class="language-css">h1 {
  display: grid;
  grid-template-columns: minmax(50px, 1fr) auto minmax(50px, 1fr);
  align-items: center;
  text-align: center;
  gap: 40px;
}
h1::before,
h1::after {
  content: '';
  border-top: 6px double;
}</pre><p>Avec ces quelques ligne de CSS, on insère des pseudo-éléments avant et après le texte du titre. Leur <code>content</code> a pour valeur <code>''</code>, car nous ne voulons pas réellement de contenu, nous voulons simplement des éléments à cet endroit afin de pouvoir leur appliquer des doubles bordures pour créer les lignes.</p><p>C'est le bon moment pour mentionner que la propriété <code>content</code> est <em>requise</em> pour qu'un pseudo-élément soit créé, mais comme vous le voyez ici, on peut très bien la régler sur <code>''</code> (chaîne vide).</p><p>La mise en page est réalisée en transformant l'élément <code>&lt;h1&gt;</code> en 3 colonnes <a href="https://la-cascade.io/tags/cssgrid">Grid</a>. Les colonnes de gauche et de droite sont des lignes doubles, toutes deux avec une largeur de <code>minmax(50px, 1fr)</code>, ce qui signifie qu'elles auront toujours des largeurs correspondantes non inférieures à <code>50px</code>. Le texte du titre est proprement centré dans la colonne centrale.</p><h2>Ruban d'en-tête décoratif</h2><p>Bon, poussons ce concept plus loin. Voici un titre en forme de ruban.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/MWbENmV">Decorative Ribbon Heading</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Là encore, tout ce dont nous avons besoin est une seule balise dans le HTML.</p><pre class="language-html">&lt;h1&gt;Ribbon Heading&lt;/h1&gt;</pre><pre class="language-css">h1 {
  position: relative;
  margin: 0 auto 20px;
  padding: 10px 40px;
  text-align: center;
  background-color: #875e46;
}
h1::before,
h1::after {
  content: '';
  width: 80px;
  height: 100%;
  background-color: #724b34;
  /* positionner les bouts du ruban en arrière et légèrement plus bas */
  position: absolute;
  z-index: -1;
  top: 20px;
  /* clip ribbon end shape */
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 25% 50%);
  /* draw and position the folded ribbon bit */
  background-image: linear-gradient(
    45deg,
    transparent 50%,
    #5d3922 50%
  );
  background-size: 20px 20px;
  background-repeat: no-repeat;
  background-position: bottom right;
}
h1::before {
  left: -60px;
}
h1::after {
  right: -60px;
  transform: scaleX(-1); /* flip horizontally */
}</pre><p>Cette fois, nous utilisons le positionnement absolu pour placer les pseudo-éléments. L'extrémité gauche du ruban est créée avec <code>::before</code> et la droite avec <code>::after</code>. Le CSS les dessine ensemble avec des styles partagés, dans la même direction, puis retourne <code>h1::after</code> avec <code>transform : scaleX(-1)</code>.</p><p>La forme des extrémités du ruban est obtenue avec <code>clip-path</code>. Les bouts de ruban pliés sont de petits triangles d'image de fond dessinés avec <code>linear-gradient()</code> et soigneusement positionnés dans les coins intérieurs inférieurs.</p><h2>Travailler avec des guillemets</h2><p>Revenons au réglage du contenu de <code>::before</code> et de <code>::after</code> sur autre chose qu'une chaîne vide, car il y a des trucs intéressants à faire.</p><p>Le contenu peut être défini sur les valeurs spéciales <code>open-quote</code> et <code>close-quote</code>. Ça permet d'insérer des guillemets ouverts/fermés appropriés à la langue actuelle. Le style appliqué à un <code>&lt;blockquote&gt;</code> est un bon cas d'utilisation pour ça.</p><pre class="language-html">&lt;blockquote lang="en"&gt;
  Hello! I am a block quote in English. Check out how the quotation
  marks are automatically added around me!
&lt;/blockquote&gt;
&lt;blockquote lang="fr"&gt;
  Salut ! Je suis une citation en français. Je ne connais pas le
  français, alors j’ai demandé à quelqu’un sur Twitter de le traduire
  !
&lt;/blockquote&gt;</pre><pre class="language-css">blockquote::before {
  content: open-quote;
}
blockquote::after {
  content: close-quote;
}
blockquote::before,
blockquote::after {
  opacity: 0.25;
  padding: 0 10px;
  font-size: 3em;
}
blockquote {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 20px;
  padding: 20px 10px;
  border-radius: 10px;
  background-color: #e5ddcb;
}</pre><p>Nous avons maintenant des guillemets stylisés automatiquement pour <code>&lt;blockquote&gt;</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/zYoEgwm">Stylish Blockquotes</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Contrairement à <code>&lt;blockquote&gt;</code>, la balise <code>&lt;q&gt;</code> (citation en ligne) affiche des guillemets par défaut. Ce n'est pas de la magie — c'est la feuille de style de l'agent utilisateur par défaut de votre navigateur qui fait la même chose que nous venons de faire !</p><pre class="language-css">q::before {
  content: open-quote;
}
q::after {
  content: close-quote;
}</pre><p>Une autre caractéristique intéressante des balises <code>open-quote</code> et <code>close-quote</code> est qu'elles tiennent compte de l'imbrication. Par exemple, en anglais, si vous avez des balises <code>&lt;q&gt;</code> imbriquées, la balise extérieure utilisera les guillemets doubles <code>“</code> et <code>”</code> tandis que la balise intérieure utilisera des guillemets simples <code>‘</code> et <code>’</code>.</p><p>La propriété CSS <code>quotes</code> vous donne un contrôle direct sur ce qui est utilisé pour <code>open-quote</code> et <code>close-quote</code>.</p><pre class="language-css">q {
  quotes: '&lt;' '&gt;'; /* wrap all quotes with &lt; and &gt; */
}
q {
  quotes: '&lt;' '&gt;' /* wrap outermost quotes with &lt; and &gt; */ '&lt;&lt;' '&gt;&gt;'
    /* then quotes nested one level deep with &lt;&lt; and &gt;&gt; */ '&lt;&lt;&lt;' '&gt;&gt;&gt;'; /* then quotes nested deeper with &lt;&lt;&lt; and &gt;&gt;&gt; */
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/VwmMoWZ">Open/Close Quotation Marks</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Chaque citation a le même balisage...</p><pre class="language-html">&lt;q&gt;If you're fine with &lt;q&gt;unexplained phenomena&lt;/q&gt; then go ahead.&lt;/q&gt;</pre><p>...mais des valeurs différentes de `quote'.</p><pre class="language-css">.customized {
  quotes: '→' '←';
}
.customized-nested {
  quotes: '⟪' '⟫' '⟨' '⟩';
}
.emoji {
  quotes: '??"' '"';
}
q::before,
q::after {
  color: #ff003c;
}</pre><p>NdT : <em>pour en savoir plus sur le sujet des citations en HTML, vous pouvez consulter <a href="https://la-cascade.io/articles/citer-en-html">Citer en HTML</a> ici-même</em>.</p><h2>Afficher des attributs d'éléments</h2><p>Les attributs des éléments peuvent être affichés dans les pseudo-éléments <code>::before</code> et <code>::after</code> en utilisant <code>attr()</code>. Par exemple, <code>href</code> est un attribut de l'élément <code>&lt;a&gt;</code> ci-dessous...</p><pre class="language-html">&lt;a href="https://tacobell.com"&gt;Taco Bell&lt;/a&gt;</pre><p>...et nous pouvons afficher la valeur de <code>href</code> dans le lien avec ceci.</p><pre class="language-css">a::after {
  content: ' → ' attr(href); /* show an arrow before the href */
}</pre><p>Voici ce que ça peut donner :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/dyOVxzx">Displaying Link URLs</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>J'ai glissé quelque chose de plus dans le CSS ci-dessus. Vous pouvez mettre plusieurs choses dans le <code>content</code> (généralement séparées par un espace blanc) pour les concaténer. Dans ce cas, <code>' → '</code> est concaténé avec <code>attr(href)</code> pour obtenir ce que vous voyez dans la démo.</p><h2>Afficher le compte avec Counters</h2><p><a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Counter_Styles/Using_CSS_counters">CSS counters</a> vous permet de, eh bien, compter des choses. Les valeurs de comptage peuvent être affichées à l'aide de <code>::before</code> et <code>::after</code>. Regardez cette démo qui affiche le nombre de cases à cocher cochées. Il n'y a pas de JavaScript impliqué.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/gOLGVXM">Checked Checkboxes Counter</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Voici le CSS correspondant.</p><pre class="language-css">input:checked {
  counter-increment: total;
}
output::before {
  content: counter(total);
}</pre><p>Chaque case cochée incrémente le compteur total, qui est ensuite affiché dans le pseudo-élément <code>::before</code> de l'élément <code>&lt;output&gt;</code>.</p><p>Si vous souhaitez en savoir plus sur les compteurs CSS, consultez <a href="https://codersblock.com/blog/fun-times-with-css-counters/">cet article</a>.</p><h2>Jouer avec les images</h2><p>Vous pouvez placer une image dans <code>::before</code> ou <code>::after</code> en définissant à <code>content</code> une url.</p><pre class="language-css">div::before {
  content: url(image.png);
}</pre><p>Vous vous rappelez la concaténation de <code>content</code> de tout à l'heure ? Elle fonctionne également avec les images ! Voici un exemple qui concatène une image, une chaîne de caractères et un attribut.</p><pre class="language-html">&lt;div data-lives="3"&gt;&lt;/div&gt;</pre><pre class="language-css">div::before {
  content: url(mario.gif) ' × ' attr(data-lives);
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/MWbENOG">Mario Lives Screen</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Vous n'êtes pas obligé d'utiliser <code>content</code> pour afficher une image. Une autre option consiste à utiliser <code>background-image</code> avec un pseudo-élément de taille appropriée.</p><pre class="language-css">div::before {
  content: '';
  background-image: url(image.png);
  display: block;
  width: 100px;
  height: 100px;
}</pre><p>Il vaut la peine de noter que <code>::before</code> et <code>::after</code> ont par défaut la valeur <code>display : inline</code>. Vous devrez modifier cela si vous souhaitez définir la largeur/hauteur, comme vous pouvez le voir dans le CSS ci-dessus.</p><h2>Remplacement du contenu</h2><p>Comme vous l'avez déjà remarqué, <code>::before</code> et <code>::after</code> dépendent de <code>content</code>. Ils ne s'afficheront pas si <code>content</code> n'est pas défini. Mais la dépendance n'est pas réciproque — il existe des situations où <code>content</code> peut être utilisé sans <code>::before</code> ou <code>::after</code>.</p><p>Si <code>content</code> a pour valeur une seule image, vous pouvez l'utiliser directement sur un élément pour remplacer le contenu HTML de cet élément.</p><pre class="language-css">.replace {
  content: url(replace.png);
}</pre><p>Essayons-le sur le HTML suivant.</p><pre class="language-html">&lt;span class="replace"&gt;This is text!&lt;/span&gt;
&lt;span class="replace"
  &gt;&lt;img src="chicken-nugget.png" alt="chicken nugget"
/&gt;&lt;/span&gt;
&lt;img class="replace" src="chicken-nugget.png" alt="chicken nugget" /&gt;</pre><p>Le HTML teste 3 cas.</p><ol><li>Un élément avec un texte simple. Il sera remplacé.</li>
<li>Un élément avec <code>&lt;img&gt;</code> à l'intérieur. Il sera également remplacé.</li>
<li>Un élément <code>&lt;img&gt;</code> directement. Firefox ne le remplacera pas, mais d'autres navigateurs le feront.</li>
</ol><p>Voyez par vous-même !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/rNWGXYZ">Content Replacement</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Pour clarifier, tout ce qui se trouve à l'intérieur de l'élément est remplacé. Vous pourriez donc remplacer une page entière par un nugget de poulet en faisant quelque chose comme ceci :</p><pre class="language-css">body {
  content: url(chicken-nugget.png);
}</pre><p><small>(Veuillez utiliser ce pouvoir de manière responsable)</small>.</p><h2>content et ::marker</h2><p><code>::marker</code> est un autre pseudo-élément qui peut utiliser du contenu, comme <code>::before</code> et <code>::after</code>. Il est utilisé pour styliser les marqueurs des éléments de liste. NdT : <em>voir de bons exemples dans <a href="https://la-cascade.io/articles/des-styles-de-listes-creatifs">Des styles de listes créatifs</a></em>.</p><pre class="language-html">&lt;ul&gt;
  &lt;li&gt;Cupcakes are essentially cakes, but cuppier.&lt;/li&gt;
  &lt;li&gt;
    The first cupcake was invented by Harley McCupcakken in 1796.
  &lt;/li&gt;
  &lt;li&gt;
    Alright fine, I don't actually know anything about cupcakes.
  &lt;/li&gt;
&lt;/ul&gt;</pre><pre class="language-css">li::marker {
  content: '?';
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/JjbrgOV">Cupcake Markers with ::marker</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Malheureusement, Safari ne vous permet pas de définir le contenu du <code>::marker</code> (NdT : <em>ce n'est plus tout à fait le cas, voir <a href="https://caniuse.com/?search=%3A%3Amarker">CanIUse</a>)</em>, et les navigateurs qui l'autorisent ont encore d'<a href="https://developer.mozilla.org/fr/docs/Web/CSS/::marker">autres restrictions</a>.</p><p>Une autre option consiste à masquer entièrement le marqueur avec <code>list-style-type : none</code>, puis à utiliser <code>::before</code> pour faire votre propre truc. Pour illustrer, j'ai <a href="https://codepen.io/lonekorean/pen/zYoEgRy">recréé la démo précédente</a> en utilisant <code>::before</code> au lieu de <code>::marker</code>.</p><h2>Shenanigans !</h2><p>Parfois, les gens veulent simplement être créatifs avec CSS. C'est amusant ! Un jeu particulièrement populaire consiste à voir tout ce que l'on peut faire avec un seul élément. <code>::before</code> et <code>::after</code> entrent très souvent en jeu ici, car le fait d'avoir ces pseudo-éléments supplémentaires à disposition ouvre de nombreuses possibilités.</p><ul><li>La galerie <a href="https://a.singlediv.com/">A Single Div</a> de Lynn Fisher contient quelques exemples impressionnants. Vérifiez le CSS et vous verrez beaucoup de pseudo-éléments <code>::before</code> et <code>::after</code>.</li>
<li><a href="https://codepen.io/dhanishgajjar/full/xLmyjJ/">Pure CSS Flags, Single Divs</a> de Dhanish Gajjar est une collection de 113 drapeaux du monde, dont beaucoup sont dessinés avec des pseudo-éléments <code>::before</code> et <code>::after</code>.</li>
<li>Et puis il y a les <a href="https://css.gg/">700+ icônes CSS</a> d'Astrit Malsija. Regardez de plus près <a href="https://css.gg/attachment">une icône</a> et, eh bien, vous comprenez l'idée.</li>
</ul><p>Ces choses ne sont pas toujours pratiques, mais ce n'est pas le sujet. Il s'agit de s'amuser un peu et d'apprendre de nouvelles astuces en cours de route.</p><h2>Contrôler la mise en page</h2><p>Pour en revenir à des questions pratiques, <code>::after</code> peut être utilisé avec des classes utilitaires pour contrôler la mise en page. Un exemple célèbre est le "clearfix", qui garantit qu'un élément enveloppe tous les éléments flottants qu'il contient. Voici un exemple d'implémentation, bien qu'il existe de nombreuses variantes.</p><pre class="language-css">.clearfix::after {
  content: '';
  display: block;
  clear: both;
}</pre><p>Ce bout de CSS a été indispensable pendant de nombreuses années, mais il existe désormais <a href="https://caniuse.com/flow-root">une solution plus moderne</a>.</p><pre class="language-css">.clearfix {
  display: flow-root;
}</pre><p>Voici une démo illustrant le problème et les corrections. Remarquez comment le premier nugget de poulet s'étend en dehors de son élément parent, mais pas le deuxième ni le troisième.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/ExNwqQr">Clearing Chicken Nuggets</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Le pseudo-élément <code>::after</code> peut également aider à la mise en page en insérant des sauts de ligne. Pour cela, je vous renvoie à l'<a href="https://piccalil.li/quick-tip/inline-line-break/">astuce rapide</a> d'Andy Bell.</p><h2>Est-ce qu'on peut l'animer ?</h2><p>Pouvez-vous appliquer des animations CSS à <code>::before</code> et <code>::after</code> ? Oui ! Elles fonctionnent exactement comme sur les éléments normaux.</p><p>Cela dit, l'animation de la propriété <code>content</code> est un peu plus intéressante. Dans les navigateurs autres que Safari, elle peut être animée <strong>de manière discrète</strong>, ce qui signifie que le contenu basculera entre les valeurs sans aucune sorte de transition graduelle.</p><pre class="language-css">div::before {
  content: '';
  animation: flip 6s linear infinite;
}
@keyframes flip {
  from {
    content: 'Hello!';
  }
  to {
    content: 'Goodbye!';
  }
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/qBqPexz">Discretely Animated Text</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Si vous souhaitez animer des nombres comptés dans du contenu, il existe une astuce, mais elle ne fonctionne que dans Chrome, Edge et Opera (ce sont les navigateurs qui prennent actuellement en charge l'<a href="https://drafts.css-houdini.org/css-properties-values-api/">API Propriétés et valeurs</a>, sur laquelle repose cette astuce).</p><p>Voici comment cela fonctionne.</p><ol><li>Déclarez une propriété personnalisée qui est un nombre entier.</li>
<li>Configurez un compteur pour prendre la valeur de ce nombre entier via <code>counter-reset</code>.</li>
<li>Affichez ce compteur dans le contenu d'un pseudo-élément.</li>
<li>Animez la valeur de l'entier.</li>
</ol><pre class="language-css">@property --num {
  syntax: '&lt;integer&gt;';
  inherits: true;
  initial-value: 0;
}
div::before {
  counter-reset: my-counter var(--num);
  content: counter(my-counter);
  animation: count 10s ease-in-out infinite alternate;
}
@keyframes count {
  to {
    --num: 100;
  }
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/dyOVxmy">Number Counter Animation</a>de lonekorean dans<a href="https://codepen.io">CodePen</a></div><p>Si vous souhaitez approfondir cette technique, consultez <a href="https://codersblock.com/blog/what-can-you-put-in-a-css-variable/#bringing-it-all-together-with-animation">ce tutoriel</a> qui va un peu plus loin.</p><h2>Pseudo-éléments vs. pseudo-classes</h2><p>Outre <code>::before</code> et <code>::after</code>, il existe d'autres pseudo-éléments qui sont utilisés pour styliser des parties d'éléments existants. Nous avons parlé de <code>::marker</code> plus tôt, pour styliser les marqueurs d'éléments de liste. Un autre exemple est <code>::selection</code>, qui est utilisé pour styliser le texte sélectionné.</p><p>Il existe également des <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Pseudo-classes">pseudo-classes</a>, qui sont différentes des pseudo-éléments. Les <a href="https://la-cascade.io/tags/pseudo-classes">pseudo-classes</a> appliquent des styles basés sur l'état. Par exemple, nous avons utilisé <code>:checked</code> dans une démo précédente pour appliquer un style uniquement lorsqu'une case à cocher était cochée.</p><p>Les pseudo-éléments sont préfixés par deux points (: :) alors que les pseudo-classes sont préfixées par un seul point ( :). Les anciennes versions de la spécification du W3C utilisaient des deux-points simples pour les pseudo-éléments, de sorte que vous pouvez voir occasionnellement :before et :after. Ils fonctionnent toujours, mais il est recommandé d'utiliser <code>: :</code> à la place.</p><h2>Accessibilité</h2><p>Il est intéressant de parler de la manière dont le contenu est transmis par les lecteurs d'écran. Selon la spécification du W3C, le contenu est destiné à être prononcé.</p><figure class="quote"><blockquote cite="https://www.w3.org/TR/css-content-3/#accessibility"><div>La propriété "content" s'applique à la parole et le contenu généré doit être rendu pour la sortie vocale.</div></blockquote>
<figcaption><cite><a href="https://www.w3.org/TR/css-content-3/#accessibility">CSS Generated Content Module Level 3</a></cite></figcaption></figure><p>D'accord, ça a l'air bien. Mais regardons de plus près ce qui se passe dans différents cas.</p><p>Si vous utilisez <code>::before</code> ou <code>::after</code> à des fins décoratives et que <code>content</code> est défini comme '' (chaîne vide), les lecteurs d'écran ne les annonceront pas. Cela ne pose aucun problème !</p><pre class="language-css">div::after {
  /* le lecteur d'écran reste muet */
  content: '';
}</pre><p>Les lecteurs d'écran lisent le texte placé dans <code>content</code>. Ça n'a pas toujours été le cas, mais ça l'est maintenant... à moins que vous ne supportiez encore IE11 (désolé). D'autres personnes ont partagé leurs résultats en testant diverses combinaisons navigateur + lecteur d'écran <a href="https://tink.uk/accessibility-support-for-css-generated-content/">ici</a>, <a href="https://jhalabi.com/blog/before-after-accessibility">ici</a> et <a href="https://www.powermapper.com/tests/screen-readers/content/css-generated-content/">ici</a>. Ce dernier semble mauvais au premier abord, jusqu'à ce que vous réalisiez que tous les échecs proviennent d'IE11 et de Firefox 29 (sorti en 2014).</p><pre class="language-css">div::after {
  /* le lecteur d'écran dit "hello" */
  content: 'hello';
}</pre><p>N'oubliez pas que les emojis et les symboles comptent comme du texte. Les lecteurs d'écran les annonceront, ce qui peut être bien, mais peut aussi être gênant si vous les utilisez comme décoration.</p><pre class="language-css">div::after {
  /* le lecteur d'écran dit "yellow five pointed star" */
  content: '⭐';
}
div::after {
  /* le lecteur d'écran dit "clockwise open circle arrow" */
  content: '↻';
}</pre><p>Les lecteurs d'écran peuvent reconnaître les images dans le contenu. Dans mes tests, VoiceOver annonçait "image" dans Firefox et Safari, et "image non étiquetée" dans Chrome.</p><pre class="language-css">div::after {
  /* le lecteur d'écran dit un truc comme "image" ou "unlabelled image" */
  content: url(image.png);
}</pre><p>Si l'image n'est pas décorative, alors nous sommes dans une mauvaise passe. Nous avons une image significative qui n'est transmise que comme "image".</p><p>Si l'image est décorative, la personne qui utilise un lecteur d'écran ne manque peut-être rien d'important, mais elle ne le sait pas ! Elle entendra "image" et se demandera ce qu'elle rate.</p><p>La bonne nouvelle est que vous pouvez spécifier un texte alternatif pour le contenu. Cela nous donne un moyen d'indiquer aux lecteurs d'écran ce qu'il faut annoncer, de manière similaire à la définition de l'attribut <code>alt</code> sur <code>&lt;img&gt;</code>.</p><pre class="language-css">div::after {
  /* le lecteur d'écran dit "chicken nugget" */
  content: url(chicken-nugget.png) / 'chicken nugget';
}
div::after {
  /* le lecteur d'écran reste muet */
  content: url(decorative-image.png) / '';
}</pre><p>Il fonctionne également avec du texte, de sorte que nous pouvons indiquer aux lecteurs d'écran comment annoncer les émojis et les symboles décoratifs.</p><pre class="language-css">div::after {
  /* le lecteur d'écran reste muet */
  content: '⭐' / '';
}
div::after {
  /* le lecteur d'écran dit "refresh" */
  content: '↻' / 'refresh';
}</pre><p>La mauvaise nouvelle est que Firefox et Safari ne prennent pas en charge le texte alternatif pour le contenu. En fait, le / invalidera entièrement le contenu dans ces navigateurs. Vous pouvez contourner ce problème en déclarant le contenu deux fois. L'ordre est important !</p><pre class="language-css">div::after {
  content: '⭐'; /* Firefox and Safari will use this */
  content: '⭐' / ''; /* other browsers will use this */
}</pre><p>Vous devez également savoir que le texte dans <code>content</code> est non sélectionnable et non cherchable, et que les images dans <code>content</code> ne peuvent pas faire l'objet d'un clic droit pour obtenir le menu contextuel de l'image. Ce n'est pas un gros problème pour des choses triviales ou décoratives, mais je réfléchirais avant de mettre du texte long ou des images importantes dans <code>content</code>.</p><h3>Au revoir !</h3><p>Il y a tellement de choses que vous pouvez faire avec les pseudo-éléments <code>::before</code> et <code>::after</code> et la propriété <code>content</code>. Je pense que c'est vraiment génial que vous puissiez avoir un balisage minimal — souvent une simple balise HTML — et que CSS puisse s'en servir et faire toutes ces choses étonnantes.</p><p>J'espère que nous avons couvert suffisamment de terrain dans cet article pour vous donner une idée des possibilités (et des limites !) et susciter un intérêt créatif.</p><p>Merci de votre lecture !</p>]]></description>
      <link>https://la-cascade.io/articles/plongee-en-profondeur-dans-les-pseudo-elements-before-et-after</link>
      <guid>https://la-cascade.io/articles/plongee-en-profondeur-dans-les-pseudo-elements-before-et-after</guid>
      <pubDate>Mon, 13 Feb 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Un guide visuel des références en JavaScript]]></title>
      <description><![CDATA[<p><em>a.k.a. "pointeurs pour les développeurs JavaScript"</em>.</p><p>Au premier jour de votre apprentissage du code, quelqu'un vous dit "Une variable c'est comme une boîte. Quand tu écris <code>bidule = 5</code>, tu mets 5 dans la boîte <code>bidule</code>". Bon, ce n'est pas vraiment comme ça que les variables fonctionnent, mais ça permet avancer. C'est comme en cours de maths, quand on vous ment sur l'image complète, parce que l'image complète vous ferait exploser le cerveau à ce moment précoce de votre apprentissage.</p><p>Mais quelque temps plus tard, vous commencez à voir surgir des problèmes bizarres. Des variables qui changent, alors que vous ne les avez pas modifiées. Des fantômes dans la machine.</p><p>"Je pensais avoir fait une copie de ce truc ! Pourquoi ça a changé ?"  ? ça, c'est <strong>un bug de référence</strong> !</p><p>À la fin de ce billet, vous comprendrez pourquoi ça se produit et comment le corriger.</p><h2>Qu'est-ce qu'une référence ?</h2><p>Les références sont partout dans JS, mais elles sont invisibles. Elles ressemblent simplement à des variables. Certains langages, comme le C, les appellent explicitement des <strong>pointeurs</strong>, qui ont leur propre syntaxe. Mais JS n'a pas de pointeurs, du moins pas sous ce nom. Et JS n'a pas non plus de syntaxe spéciale pour eux.</p><p>Prenez cette ligne de JavaScript par exemple : elle crée une variable appelée word qui stocke la chaîne "hello".</p><pre class="language-js">let word = "hello"</pre><div class="img-with-margins"><img src="https://daveceddia.com/images/Word_Variable.png" srcset="https://daveceddia.com/images/Word_Variable@2x.png 2x" alt="the word variable pointing at a box containing the string hello" /></div><p>Remarquez comment <code>word</code> <em>pointe</em> vers la boîte avec le <code>"hello"</code>. Il y a une possibilité de confusion ici, donc soyons clair : <strong>La variable n'est pas la boîte. La variable pointe vers la boîte</strong>. Laissez-vous imprégner par cette idée pendant que vous continuez à lire.</p><p>Donnons maintenant une nouvelle valeur à cette variable en utilisant l'opérateur d'assignation <code>=</code> :</p><pre class="language-js">word = "world"</pre><p>Ce qui se passe en fait ici n'est pas que le "hello" est remplacé par "world" — c'est plutôt qu'une boîte entièrement nouvelle est créée, et la variable <code>word</code> est réassignée pour pointer vers la nouvelle boîte (et une conséquence liée est qu'à un moment donné, la boîte "hello" est nettoyée par le <a href="https://fr.wikipedia.org/wiki/Ramasse-miettes_(informatique)">"ramasse-miettes"</a>, puisque rien ne l'utilise).</p><p></p><p>Si vous avez déjà essayé d'attribuer une valeur à un paramètre de fonction, vous avez probablement réalisé que cela ne change rien en dehors de la fonction.</p><p>La raison en est que la réassignation d'un paramètre de fonction n'affecte que la variable locale, et non la variable originale qui a été transmise. Voici un exemple :</p><pre class="language-js">function reassignFail(word) {
  // this assignment does not leak out
  word = "world"
}
let test = "hello"
reassignFail(test)
console.log(test) // prints "hello"</pre><p>Au départ, seul <code>test</code> pointe sur la valeur "hello".</p><p>Cependant, une fois que nous sommes à l'intérieur de la fonction, test et word pointent tous deux sur la même case.</p><div class="img-with-margins"><img src="https://daveceddia.com/images/Two_Variables_Same_Value.png" srcset="https://daveceddia.com/images/Two_Variables_Same_Value@2x.png 2x" alt="Two variables with the same value" /></div><p>Après l'assignation (word = "world"), la variable <code>word</code> pointe sur sa nouvelle valeur "world". Mais nous n'avons pas modifié <code>test</code>. La variable test indique toujours son ancienne valeur.</p><div class="img-with-margins"><img src="https://daveceddia.com/images/After_Reassignment.png" srcset="https://daveceddia.com/images/After_Reassignment@2x.png 2x" alt="After reassigning word" /></div><p>C'est ainsi que l'assignation fonctionne en JavaScript. La réassignation d'une variable ne modifie que cette variable. Elle ne modifie pas les autres variables qui pointent également sur cette valeur. Ça reste vrai, que la valeur soit une chaîne de caractères, un booléen, un nombre, un objet, un tableau, une fonction... tous les types de données fonctionnent de cette manière.</p><h2>Deux types de types</h2><p><strong>JavaScript a deux grandes catégories de types</strong>, et ils ont des règles différentes autour de l'assignation et de l'égalité référentielle. Regardons cela.</p><h3>Types primitives en JavaScript</h3><p>Il y a les <a href="https://developer.mozilla.org/fr/docs/Glossary/Primitive">types primitives</a> comme les chaînes de caractères, les nombres, les booléens (et aussi les <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Symbol"><code>Symbol</code></a>s, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined"><code>undefined</code></a> et <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null"><code>null</code></a>). Ces types sont <a href="https://developer.mozilla.org/fr/docs/Glossary/Immutable">immuables</a>, c'est-à-dire en lecture seule, ils ne peuvent pas être modifiés.</p><p>Lorsqu'une variable contient l'un de ces types primitives, vous ne pouvez pas modifier la valeur elle-même. Vous pouvez seulement réassigner à cette variable une nouvelle valeur.</p><p></p><p>La différence est subtile, mais importante !</p><p>En d'autres termes, lorsque la valeur contenue dans une boîte est une chaîne de caractères/un nombre/un booléen/un symbole/undefined/null, vous ne pouvez pas modifier cette valeur. Vous pouvez seulement créer de nouvelles cases.</p><p>Cela ne fonctionne <strong>pas</strong> comme ça...</p><p></p><p>C'est pourquoi, par exemple, toutes les méthodes sur les chaînes de caractères renvoient <em>une nouvelle chaîne</em>. Elles ne modifient pas la chaîne originale, et donc si vous voulez utiliser cette nouvelle valeur, vous devez la stocker quelque part.</p><pre class="language-js">let name = "Dave"
name.toLowerCase();
console.log(name) // toujours Dave avec une majuscule "Dave"
name = name.toLowerCase()
console.log(name) // maintenant c'est "dave"</pre><h3>Tous les autres types : objets, tableaux, etc.</h3><p>L'autre catégorie est le type <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Object"><strong>objet</strong></a>. Elle englobe les objets, les tableaux (<a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array"><strong>Array</strong></a>), les <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Functions">fonctions</a> et d'autres structures de données comme <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Map">Map</a> et <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set">Set</a>. Ce sont tous des objets.</p><p>La grande différence avec les types primitives est que les objets sont <strong>muables</strong> ! Vous pouvez modifier la valeur d'un objet.</p><div class="img-with-margins"><img src="https://daveceddia.com/images/Mutable_And_Immutable_JavaScript_Types.png" srcset="https://daveceddia.com/images/Mutable_And_Immutable_JavaScript_Types@2x.png 2x" alt="Mutable and immutable JavaScript types" /></div><h2>Immuable =&gt; prévisible</h2><p>Si vous passez une valeur primitive dans une fonction, la variable originale que vous avez passée est garantie non modifiable. La fonction ne peut pas modifier ce qui s'y trouve. Vous pouvez être assuré que la variable sera toujours la même après avoir appelé une fonction — n'importe quelle fonction.</p><p>Mais avec les <strong>objets</strong> et les <strong>tableaux</strong> (et les autres types d'objets), vous n'avez pas cette garantie. Si vous passez un objet dans une fonction, <em>cette fonction peut modifier votre objet</em>. Si vous passez un tableau, la fonction peut y ajouter de nouveaux éléments ou le vider entièrement.</p><p>C'est l'une des raisons pour lesquelles de nombreuses personnes de la communauté JS essaient d'écrire du code de manière immuable : il est plus facile de comprendre ce que fait le code lorsque vous êtes sûr que vos variables ne changeront pas de manière inattendue. Si chaque fonction est écrite pour être immuable par convention, vous n'avez jamais besoin de vous demander ce qui va se passer.</p><p>Une fonction qui ne modifie pas ses arguments, ou quoi que ce soit en dehors d'elle-même, est appelée une <em>fonction pure</em>. Si elle doit modifier quelque chose dans l'un de ses arguments, elle le fera en renvoyant une nouvelle valeur à la place. C'est plus flexible, car cela signifie que le code appelant peut décider de ce qu'il faut faire avec cette nouvelle valeur.</p><h3>Récapitulation : Les variables pointent vers des boîtes, et les primitives sont immuables.</h3><p>Nous avons vu comment l'assignation ou la réassignation d'une variable "pointe" effectivement vers une boîte qui contient une valeur. Et comment l'assignation d'une valeur littérale (par opposition à une variable) crée une nouvelle boîte et y dirige la variable.</p><pre class="language-js">let num = 42
let name = "Dave"
let yes = true
let no = false
let person = {
  firstName: "Dave",
  lastName: "Ceddia"
}
let numbers = [4, 8, 12, 37]</pre><div class="img-with-margins"><img src="https://daveceddia.com/images/Mutable_And_Immutable_JavaScript_Types.png" srcset="https://daveceddia.com/images/Mutable_And_Immutable_JavaScript_Types@2x.png 2x" alt="Mutable and immutable JavaScript types" /></div><p>C'est vrai pour les types primitives et les types objets, et c'est vrai qu'il s'agisse de la première assignation ou d'une réassignation.</p><p>Nous avons parlé de l'immuabilité des types primitives. Vous ne pouvez pas les modifier, vous pouvez seulement réassigner la variable à autre chose.</p><p></p><p>Voyons maintenant ce qui se passe lorsque vous modifiez une propriété d'un objet.</p><h2>Modifier le contenu de la boîte</h2><p>Nous allons commencer par un objet <code>book</code> représentant un livre d'une bibliothèque qui peut être emprunté. Il possède un titre, un auteur et un indicateur <code>isCheckedOut</code>.</p><pre class="language-js">let book = {
  title: "Tiny Habits",
  author: "BJ Fogg",
  isCheckedOut: false
}</pre><p>Voici notre objet et ses valeurs sous forme de boîtes :</p><div class="img-with-margins"><img src="https://daveceddia.com/images/Book_Object_With_3_Properties.png" srcset="https://daveceddia.com/images/Book_Object_With_3_Properties@2x.png 2x" alt="a Book object with 3 properties" /></div><p>Et puis imaginons que nous exécutions ce code :</p><pre class="language-js">book.isCheckedOut = true</pre><p>Voici ce que ce qui se passe au niveau de l'objet :</p><p></p><p>Remarquez comment la variable <code>book</code> ne change jamais. Elle continue de pointer vers la même boîte, contenant le même objet. C'est seulement une des <em>propriétés</em> de cet objet qui a changé.</p><p>Remarquez que cela suit également les mêmes règles que précédemment. La seule différence est que les variables se trouvent maintenant dans un objet. Au lieu d'une variable <code>isCheckedOut</code> de niveau supérieur, nous y accédons par <code>book.isCheckedOut</code>, mais sa réassignation fonctionne exactement de la même manière.</p><p>La chose cruciale à comprendre est que <strong>l'objet n'a pas changé</strong>. En fait, même si nous faisions une "copie" du livre en l'enregistrant dans une autre variable avant de le modifier, nous ne créerions toujours pas un nouvel objet.</p><pre class="language-js">let book = {
  title: "Tiny Habits",
  author: "BJ Fogg",
  isCheckedOut: false
}
let backup = book
book.isCheckedOut = true
console.log(backup === book)  // true!
console.log(backup.isCheckedOut)  // également true!!</pre><p>La ligne <code>let backup = book</code> fera pointer la variable <code>backup</code> sur l'objet <code>book</code> existant. (il ne s'agit donc pas réellement d'une copie !)</p><p>Voici comment cela se passerait :</p><p></p><p>Le <code>console.log</code> à la fin prouve encore plus le point : <code>book</code> est toujours égal à <code>backup</code>, parce qu'ils pointent vers le même objet, et parce que la modification d'une propriété sur <code>book</code> n'a pas changé la <em>coquille</em> de l'objet, elle a seulement changé les données internes.</p><p>Les variables pointent toujours vers des boîtes, jamais vers d'autres variables. Lorsque nous assignons <code>backup = book</code>, JS fait immédiatement le travail de recherche de ce vers quoi <code>book</code> pointe, et pointe <code>backup</code> vers la même chose. Il ne fait pas pointer <code>backup</code> vers <code>book</code>.</p><p>C'est une bonne chose : cela signifie que chaque variable est indépendante et que nous n'avons pas besoin de conserver dans notre tête une carte tentaculaire indiquant quelles variables pointent vers quelles autres. Il serait très difficile d'en garder la trace !</p><h2>Mutation d'un objet dans une fonction</h2><p>Dans l'introduction, j'ai fait allusion à la modification d'une variable à l'intérieur d'une fonction, et à la manière dont cette modification "reste parfois à l'intérieur de la fonction", tandis que d'autres fois, elle se propage dans le code appelant et au-delà.</p><p>Nous avons déjà expliqué que la réassignation d'une variable à l'intérieur d'une fonction n'entraîne pas de fuite, tant qu'il s'agit d'une variable de niveau supérieur comme <code>book</code> ou <code>house</code> et non d'une sous-propriété comme <code>book.isCheckedOut</code> ou <code>house.address.city</code>.</p><pre class="language-js">function doesNotLeak(word) {
  // this assignment does not leak out
  word = "world"
}
let test = "hello"
doesNotLeak(test)
console.log(test) // prints "hello"</pre><div class="img-with-margins"><img src="https://daveceddia.com/images/After_Reassignment.png" srcset="https://daveceddia.com/images/After_Reassignment@2x.png 2x" alt="After reassigning word" /></div><p>Et de toute façon, cet exemple utilisait une chaîne de caractères, donc nous ne pourrions pas la modifier même si nous essayions (car les chaînes de caractères sont immuables, rappelez-vous).</p><p>Mais que se passerait-il si nous avions une fonction qui recevait un objet comme argument ? Et modifiait ensuite une propriété de celui-ci ?</p><pre class="language-js">function checkoutBook(book) {
  // this change will leak out!
  book.isCheckedOut = true
}
let book = {
  title: "Tiny Habits",
  author: "BJ Fogg",
  isCheckedOut: false
}
checkoutBook(book);</pre><p>Voici ce qui se passe :</p><p></p><p>Ça vous semble familier ? Il s'agit de la même animation que précédemment, car le résultat final est exactement le même ! Peu importe que <code>book.isCheckedOut = true</code> se produise à l'intérieur ou à l'extérieur d'une fonction, car cette assignation modifiera les éléments internes de l'objet <code>book</code> dans les deux cas.</p><p>Si vous voulez éviter que cela ne se produise, vous devez faire une copie, puis modifier la copie.</p><pre class="language-js">function pureCheckoutBook(book) {
  let copy = { ...book }
  // this change will only affect the copy
  copy.isCheckedOut = true
  // gotta return it, otherwise the change will be lost
  return copy
}
let book = {
  title: "Tiny Habits",
  author: "BJ Fogg",
  isCheckedOut: false
}
// This function returns a new book,
// instead of modifying the existing one,
// so replace `book` with the new checked-out one
book = pureCheckoutBook(book);</pre><p>Si vous voulez en savoir plus sur l'écriture de fonctions immuables comme celle-ci, lisez mon <a href="https://daveceddia.com/react-redux-immutability-guide/">guide sur l'immuabilité</a>. Il est écrit en tenant compte de React et Redux, mais la plupart des exemples sont en JavaScript.</p><h2>Les références dans le monde réel</h2><p>Avec vos nouvelles connaissances sur les références, examinons quelques exemples qui pourraient poser problème. Voyez si vous pouvez repérer le problème avant de lire la solution.</p><h2>Écouteurs d'événements DOM</h2><p>Un bref aperçu du fonctionnement des fonctions d'écoute d'événements (<em>event listener</em>) : pour ajouter une écoute d'événements, appelez <a href="https://daveceddia.com/react-redux-immutability-guide/">addEventListener</a> avec le nom de l'événement et une fonction. Pour supprimer un écouteur d'événements, appelez <a href="https://developer.mozilla.org/fr/docs/Web/API/EventTarget/removeEventListener">removeEventListener</a> avec le même nom d'événement et la même fonction, comme dans la même référence de fonction. (sinon, le navigateur ne peut pas savoir quelle fonction supprimer, puisqu'un événement peut avoir plusieurs fonctions qui lui sont attachées).</p><p>Jetez un coup d'œil à ce code. Utilise-t-il correctement les fonctions d'ajout/suppression ?</p><pre class="language-js">document.addEventListener('click', () =&gt; console.log('clicked'));
document.removeEventListener('click', () =&gt; console.log('clicked'));</pre><p>...</p><p>...</p><p>...</p><p>...</p><p>Vous avez trouvé ?</p><p>Ce code ne supprimera jamais l'écouteur d'événements, car ces deux fonctions fléchées ne sont pas <em>référentiellement égales</em>. Ce sont deux fonctions distinctes, même si elles sont identiques du point de vue de la syntaxe.</p><p>Chaque fois que vous écrivez une fonction flèche () =&gt; { ... } ou une fonction ordinaire <code>function whatever() { ... }</code>, vous créez <em>un nouvel objet</em> (les fonctions sont des <strong>objets</strong>, n'oubliez pas).</p><p>Facile à prouver avec la console :</p><pre class="language-js">let a = () =&gt; {}
let b = () =&gt; {}
console.log(a === b)</pre><p>Ça imprimera <code>false</code> ! Chaque nouvel objet (tableau, fonction, Set, Map, etc.) vit dans une toute nouvelle boîte, distincte des autres boîtes.</p><p>Pour que l'exemple de l'écouteur d'événements fonctionne correctement, stockez d'abord la fonction dans une variable, et passez cette même variable à la fois à add et à remove.</p><pre class="language-js">const onClick = () =&gt; console.log('clicked');
document.addEventListener('click', onClick);
document.removeEventListener('click', onClick);</pre><h2>Mutation involontaire</h2><p>Examinons-en une autre. Voici une fonction qui trouve le plus petit élément d'un tableau en le triant d'abord, puis en prenant le premier élément.</p><pre class="language-js">function minimum(array) {
  array.sort();
  return array[0]
}
const items = [7, 1, 9, 4];
const min = minimum(items);
console.log(min)
console.log(items)</pre><p>Qu'est-ce que cela imprime ?</p><p>...</p><p>...</p><p>...</p><p>...</p><p>Si vous avez dit 1 et [7, 1, 9, 4], vous n'avez qu'à moitié raison ;)</p><p>La méthode .sort() sur les tableaux trie le tableau <em>en place</em>, ce qui signifie qu'<em>elle change l'ordre sur le tableau d'origine sans le copier</em>.</p><p>Cet exemple imprime 1 et [1, 4, 7, 9].</p><p>Maintenant, c'est peut-être ce que vous vouliez. Mais probablement pas, n'est-ce pas ? Lorsque vous appelez une fonction <em>minimum</em>, vous ne vous attendez pas à ce qu'elle réorganise les éléments de votre tableau.</p><p>Ce type de comportement peut être particulièrement déroutant lorsque la fonction se trouve dans un autre fichier, ou dans une bibliothèque, où le code n'est pas sous vos yeux.</p><p>Pour résoudre ce problème, <em>faites une copie du tableau</em> avant de le trier, comme dans le code ci-dessous. Ici, nous utilisons l'opérateur d'étalement, ou syntaxe de décomposition (<a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Operators/Spread_syntax"><strong>spread</strong></a>) pour faire une copie du tableau (la partie <code>[...array]</code>). Il s'agit en fait de créer un tout nouveau tableau, puis de copier chaque élément de l'ancien tableau.</p><pre class="language-js">function minimum(array) {
  const newArray = [...array].sort();
  return newArray[0]
}</pre><h2>On avance et on référence</h2><p>Ce genre de choses arrive tout le temps, mais c'est aussi l'une de ces choses que l'on peut ignorer sans trop savoir comment elles fonctionnent.</p><p>Il faut parfois un certain temps pour comprendre le concept des "pointeurs", des variables qui pointent vers des valeurs et des références. Si vous avez l'impression que votre cerveau est dans le brouillard en ce moment, mettez cet article en signet et revenez dans une semaine.</p><p>Une fois que vous l'aurez compris, vous l'aurez compris, et ça rendra tout votre développement JS plus facile.</p><p>Cet article est le premier d'une série sur les structures de données et les algorithmes en JS. Le prochain article portera sur les listes liées en JavaScript ! Maintenant que vous savez comment fonctionnent les références, les listes liées seront beaucoup plus faciles à comprendre.</p>]]></description>
      <link>https://la-cascade.io/articles/un-guide-visuel-des-references-en-javascript</link>
      <guid>https://la-cascade.io/articles/un-guide-visuel-des-references-en-javascript</guid>
      <pubDate>Sun, 12 Feb 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Le progrès plutôt que la perfection, une meilleure approche de l'accessibilité]]></title>
      <description><![CDATA[<h2>Table des matières</h2><ul><li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#progression">L'approche progrès vs perfection</a></li>
<li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#progres-vs-perfection">Le progrès par rapport à la perfection pour les partisans de l'accessibilité</a>
<ul><li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#repercussions">Nos mauvaises journées se répercutent sur nos interactions</a></li>
<li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#signaler-vs-laisser-passer">Signaler les problèmes d'accessibilité ou les laisser aller</a></li>
</ul></li>
<li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#erreurs">Quand les défenseurs de l'accessibilité et des personnes handicapées font des erreurs</a></li>
<li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#education">Le progrès plutôt que la perfection est axé sur l'éducation</a>
<ul><li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#cauchemar">Un vrai cauchemar</a></li>
<li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#eduquer">Éduquer ... ne pas réprimander</a></li>
<li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#commencer">Commencer par l'accessibilité</a></li>
</ul></li>
<li><a href="https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite#sensibilisation">Formation de sensibilisation à l'accessibilité et au handicap</a></li>
</ul><figure><img src="https://la-cascade.io/images/progress.png" alt="image" /></figure><h2>Résumé</h2><p>Que signifie "progrès plutôt que perfection" en matière d'accessibilité ? Cela signifie qu'il faut <strong>commencer</strong>. N'attendez pas que tout soit fait et parfait. Les petits pas font une grande différence. Cela signifie également <strong>éduquer</strong> les personnes qui ne connaissent pas l'accessibilité. Éduquez, ne réprimandez pas. Si le monde a besoin de plus de quelque chose, c'est de gentillesse.</p><p><strong>Quelle est l'approche "progrès plutôt que perfection" en matière d'accessibilité ?</strong></p><p>Tout d'abord, mettons les choses au clair. Souvent, les gens pensent que l'accessibilité est le travail de l'équipe de développement Web ou de l'équipe informatique. C'est loin d'être le cas.</p><p>L'accessibilité concerne tout le monde. C'est la responsabilité de tous, chaque département, depuis les Ressources Humaines jusqu'au Marketing en passant par les Finances et les Achats, a un rôle à jouer.</p><p>Les RH doivent créer un processus d'embauche accessible et inclusif. Le marketing doit s'assurer que <a href="https://meryl.net/digital-content-accessibility/">le contenu de son site Web et de ses médias sociaux destinés au public est accessible</a>. Les ventes produisent des présentations et de la documentation qui doivent être accessibles. Les graphistes doivent tenir compte d'éléments tels que le contraste des couleurs pour produire des designs accessibles.</p><p>Le service des achats peut exiger des fournisseurs qu'ils fournissent un rapport de conformité sur l'accessibilité en utilisant le modèle volontaire d'accessibilité des produits (<a href="https://www.section508.gov/sell/vpat/">VPAT®</a>) pour sélectionner les produits les plus accessibles. Les employés peuvent demander à leur équipe comment ils préfèrent communiquer et collaborer. Ils peuvent également vérifier que leurs réunions en présentiel <a href="https://meryl.net/accessible-online-video-meetings/">et en distanciel sont accessibles</a>.</p><p>L'assistance clients doit offrir plusieurs options de saisie et de communication pour s'assurer que les communications sont accessibles. Les clients peuvent demander aux entreprises de rendre leur contenu, leurs produits, leurs services et leurs expériences accessibles.</p><p>Lorsque les entreprises s'informent sur l'accessibilité, il ne faut pas longtemps avant qu'elles ne ressemblent à un lapin pris dans les phares. L'accessibilité, c'est grand. C'est intimidant. Elles se sentent dépassées. Elles ne peuvent pas se lancer. Mais c'est plus facile lorsque vous adoptez l'approche "progression plutôt que perfection" en matière d'accessibilité.</p><h2 id="progression">L'approche progression vs perfection</h2><p>En matière d'accessibilité, j'encourage à se concentrer sur le progrès plutôt que sur la perfection. Faites ce premier pas. Aussi petit soit-il, c'est un pas en avant. N'attendez pas que le site Web, le produit ou autre, soit parfait. N'attendez pas de lancer quelque chose.</p><p>Ce dessin animé est un parfait exemple de progrès vs perfection. Il comporte deux planches. Celle du haut montre deux personnes dont l'une a deux grandes piles de livres à côté d'elle. L'autre personne dit : "Sommes-nous prêts à inclure les élèves ayant des handicaps plus sévères dans la classe ordinaire ?"</p><p>La deuxième personne répond : "Dès que j'aurai fini de lire ces livres sur l'inclusion et que j'aurai rédigé notre plan à long terme... Nous devrions être prêts dans 7 ou 8 ans."</p><p>La planche du bas présente deux personnes qui se font face. L'une dit : "Je suis bien content que nous ayons commencé à inclure et à soutenir tous nos élèves dans les classes ordinaires." L'autre personne répond : "Moi aussi ! Je sais que nous apprendrons des choses en cours de route grâce à nos réussites et à nos erreurs." Le slogan sous la bande dessinée est le suivant : "L'histoire de deux écoles".</p><figure class="reduce-img"><img src="https://la-cascade.io/images/deux-ecoles.jpeg" alt="image" /><figcaption>Source: <a href="https://cdi.uvm.edu/islandora/object/uvmcdi-uvmcdi104998">The University of Vermont Center on Disability and Inclusion</a> par Michael Giangreco et illustré par Kevin Ruelle</figcaption></figure><p>Au lieu d'attendre d'étudier le design inclusif et l'accessibilité et de faire de grands plans, lancez-vous et tirez les leçons de vos succès et de vos erreurs. Parfois, vous reculerez. Ce n'est pas grave. Cela ne signifie pas que le progrès s'est arrêté. Le progrès n'est pas toujours une ligne droite.</p><p>Ce qui compte c'est de commencer le voyage et de garder le cap. Même si vous prévoyez de lancer plus tard un site Web remanié et conçu dans un souci d'accessibilité, vous pouvez toujours rendre votre nouveau contenu accessible. Lorsque vous publierez le prochain article de votre blog, assurez-vous qu'il comporte des titres appropriés et du texte alternatif pour toutes les images.</p><p>En outre, vous finirez par vous heurter, comme le dit <a href="https://www.linkedin.com/in/patnoe/">Christopher Patnoe</a>, au paradoxe de l'accessibilité ou, comme j'aime l'appeler, au chat de Schrödinger a11y (A11y est l'abréviation de accessibility. Il y a 11 lettres entre A et Y.) Alors, qu'est-ce que le chat de Schrödinger a11y ? Cela signifie que quelque chose que vous faites pour l'accessibilité pourrait être un problème d'accessibilité pour quelqu'un d'autre.</p><p>Vous pourriez lancer un site Web avec des couleurs sombres, car beaucoup de personnes ont du mal à supporter la luminosité du blanc. Pourtant, certains préféreront des couleurs plus claires. De nombreux produits offrent le choix entre le mode sombre et le mode clair. Mais tout le monde ne peut pas le faire.</p><p>Un autre exemple est celui des sous-titres. Je connais une personne malentendante qui préfère les transcriptions aux sous-titres. Ils ont besoin de voir plus de lignes. Beaucoup d'entre nous préfèrent les sous-titres traditionnels parce que les transcriptions nous donnent une surcharge cognitive.</p><p>De plus, il est facile de proposer des transcriptions lorsque vous avez des sous-titres. Ce n'est pas une situation de l'un <em>ou</em> l'autre. Proposez les deux. Les lecteurs d'écran et les afficheurs braille rafraîchissables fonctionnent bien avec les transcriptions lorsqu'ils sont compatibles. Par exemple, les transcriptions de YouTube fonctionnent avec les lecteurs d'écran et les afficheurs braille rafraîchissables, mais pas la transcription de Zoom. (Au moment de la rédaction de cet article du moins).</p><p>Considérez l'accessibilité comme un voyage continu sans ligne d'arrivée. Cette perspective rend les choses plus faciles car vous savez qu'elle fera partie de vos activités quotidiennes.</p><h2 id="progres-vs-perfection">Le progrès plutôt que la perfection pour les partisans de l'accessibilité</h2><p>Sur les sujets liés aux handicaps et à l'accessibilité, certaines personnes handicapées ou certains partisans de l'accessibilité expriment parfois de la colère. Cela peut se produire pour différentes raisons.</p><h3 id="repercussions">Nos mauvais jours se répercutent sur nos interactions</h3><p>Si vous avez fait l'objet de cette colère, vous êtes peut-être la quatrième personne à qui ils ont parlé dans votre entreprise. Tous les autres les ont ignorés. Ou peut-être ont-ils passé des heures au téléphone ou en chat avec le service clientèle, sans résultat. Ou encore, ils en ont trop bavé avec leurs expériences vécues de manière intersectionnelle.</p><p>Pensez-y. Si votre trajet de cinq minutes se transforme en un trajet inattendu de 65 minutes, comment pensez-vous que vous vous sentirez ? Ou un appel téléphonique de 20 minutes se transforme en une conversation de 2 heures. (C'est ce qui est arrivé à mon époux lorsque le système téléphonique de l'entreprise a mal fonctionné.) Au moment où la personne vous rejoint, elle est peut-être au bout du rouleau.</p><p>Il se peut qu'il ne s'agisse d'aucun de ces cas. Certaines personnes semblent s'énerver dans la plupart des interactions. J'ai été le sujet de leur colère, c'est pourquoi j'ai fait un cauchemar qui m'a réveillé. Nous en reparlerons plus tard.</p><p>Je gère de nombreux comptes de médias sociaux pour mes clients et moi-même. J'ajoute toujours du texte alternatif pour les images. Eh bien, une image est passée sans encombre ... ou plutôt sans texte alternatif. Et quelqu'un m'a sauté dessus. Je me suis excusée et j'ai corrigé le problème. Heureusement, je me soucie de l'accessibilité et je corrige les choses quelle que soit l'attitude des gens.</p><p>Mais ils n'auront peut-être pas cette chance avec les 10 prochaines personnes qui n'ajoutent pas du tout de texte alternatif. Leur attitude pourrait avoir l'effet inverse. Lorsque quelqu'un se fait rappeler à l'ordre, il peut décider... "Eh bien, si c'est ainsi que les gens réagissent, je ne vais pas me soucier de l'accessibilité. À quoi bon ?</p><h3 id="signaler-vs-laisser-passer">Signaler les problèmes d'accessibilité ou les laisser passer</h3><p>Je connais un responsable de l'accessibilité qui ajoute du texte alternatif à ses publications sur les médias sociaux. Un jour, j'ai été choqué de voir que de nouvelles photos n'avaient aucun texte alternatif. Qu'ai-je fait à ce sujet ? Rien. Je ne sais pas ce qui se passe dans la vie de cette personne. Mauvaise journée ? Multitâche et oubli ? Mauvais mal de tête ? Peut-être ... peut-être ... peut-être.</p><p>Pourtant, j'ai envoyé un message privé à un autre ami pour l'informer sur l'ajout de texte alternatif. Bien qu'ils se soucient de l'accessibilité, ils sont novices en matière de texte alternatif. Ils m'ont remercié et ont fait un effort.</p><p>Chacun a son propre point de vue sur l'accessibilité, y compris les personnes handicapées. Comme une personne sourde qui sous-titre tout mais ne fait pas de texte alternatif. Une autre personne sourde utilise l'un des pires styles de légende sur les médias sociaux avec des légendes en majuscules qui bougent et changent de taille. Je ne leur dis rien.</p><p>Non. Je célèbre le fait qu'ils ajoutent intentionnellement des légendes alors que tant de personnes ne le font pas. Ils ne laissent pas les légendes automatiques faire tout le travail. Lorsque j'ai donné mon avis, par exemple sur <a href="https://meryl.net/stranger-things-captions/">les légendes de "Stranger Things"</a>, je l'ai abordé en disant qu'il y avait de bonnes légendes. Voici ce qu'ils font bien. Voici quelques points à améliorer et à faire passer au niveau supérieur. Heureusement, cela a été bien accueilli. En fait, certaines personnes m'ont remercié d'avoir dit quelque chose sur le fait qu'il y avait trop de sous-titres. Ouf.</p><p>C'est pourquoi je prêche le progrès plutôt que la perfection. C'est plus <em>gentil</em>. Les gens réagissent mieux. Ils sont plus susceptibles de continuer à essayer. Parfois, c'est deux pas en avant, un pas en arrière. Parfois, c'est deux pas en arrière et aucun pas en avant.</p><h2 id="erreurs">Quand les défenseurs des personnes handicapées et de l'accessibilité font des erreurs</h2>Il existe de nombreux sujets liés à l'accessibilité. Personne ne peut tout savoir. Pourtant, la communauté de l'accessibilité dénoncera quelqu'un pour une erreur d'accessibilité.<p>Par exemple, quelqu'un a partagé cette image d'une publicité étonnante à la fenêtre d'un arrêt de bus. Elle dit :</p><p>"Chère industrie du divertissement, Il n'y a pas de diversité, d'équité et d'inclusion sans handicap. Le handicap est la diversité .com. Conçu par une équipe créative entièrement handicapée et alimenté par Inevitable Foundation."</p><figure class="reduce-img"><img src="https://la-cascade.io/images/abri-bus.jpeg" alt="image" /></figure><p>La personne qui a partagé la photo n'a pas ajouté de texte <code>alt</code> <em>aka texte alternatif aka description de l'image</em>. Heureusement, dans ce cas, les commentaires sur le texte alternatif manquant étaient sympas ou parlaient de l'ironie de la situation. La personne qui a partagé l'image est un grand partisan de la participation des personnes handicapées à la diversité, l'équité et l'inclusion (DEI). La personne a remercié tout le monde pour son aide et a ajouté le texte alternatif. C'est un progrès !</p><p>Voici un autre exemple. Une de mes collègue est conférencière et éducatrice sur l'inclusion des personnes handicapées. Elle ajoutait des sous-titres à ses vidéos. Mais ses images n'avaient pas de texte alternatif. Dès que quelqu'un l'a éduquée, elle a commencé à ajouter du texte alternatif. C'est un progrès !</p><p>Un autre exemple encore. Cette personne donne souvent des conférences sur l'accessibilité numérique dans un secteur spécifique. Ses images avaient un texte alternatif, mais leur rapport de contraste n'était pas assez fort. Je l'ai éduquée et lui ai parlé d'un outil de contraste des couleurs. À partir de ce moment-là, ses images ont commencé à obtenir de bonnes notes de contraste des couleurs. C'est ça le progrès !</p><h2 id="education">Le progrès plutôt que la perfection est axé sur l'éducation</h2><p>Pendant mon sommeil, j'ai un jour fait un cauchemar qui semblait réel. J'ai posté une photo ressemblant à un mème sur les médias sociaux. Peu de temps après, j'ai été horrifiée de constater que j'avais oublié la description de l'image, également connue sous le nom de texte alternatif. Heureusement, je m'en suis aperçue et je l'ai supprimée. Puis, j'ai posté une autre image.</p><h3 id="cauchemar">Un vrai cauchemar</h3><p>J'ai poursuivi mon week-end. Étant l'accro aux médias sociaux, je n'ai pas pu m'empêcher d'y retourner un peu plus tard. Imaginez mon visage horrifié ! Je l'ai encore fait ! J'ai oublié la description de l'image ! Et bien sûr, le post est devenu viral. Croyez-moi, je me suis réprimandée pour mon erreur. Comme prévu, j'ai reçu quelques réponses me reprochant de ne pas avoir de texte alternatif.</p><p>Je suis déjà en colère contre moi-même et ces réponses ne font qu'aggraver mon cas. Je deviens une boule d'émotions car je suis déjà énervée contre moi-même et ces réponses grossières me mettent encore plus en colère. Pendant que j'écris ceci, des brûlures d'estomac apparaissent. Cette expérience semble réelle car elle m'est arrivée.</p><p>D'abord, je devais réparer mon erreur. J'ai repartagé le post viral en y ajoutant des excuses et une description de l'image. J'ai également répondu au post au cas où des personnes suivraient le fil de discussion.</p><p>N'oubliez pas que c'est un cauchemar qui m'a réveillée de mon sommeil. La critique est restée en moi. Heureusement, je me soucie de l'accessibilité et ne me laisse pas décourager. Cependant, je me sens mal pendant quelques jours.</p><p>J'ai cette réaction à cause de mes expériences avec des partisans trop zélés de l'accessibilité dont les commentaires sont blessants. Engueuler les gens ne servira pas à grand-chose si on les éduque. J'ai entendu les nombreuses raisons pour lesquelles la communauté de l'accessibilité fait ça. Oui, de temps en temps, c'est nécessaire, surtout lorsqu'une entreprise ne les écoute pas après qu'ils aient essayé une approche plus sympa. Ne me lancez pas sur la façon dont l'industrie aérienne traite les fauteuils roulants...</p><p>Mais une personne qui n'est pas passionnée par l'accessibilité risque d'abandonner purement et simplement.</p><h3 id="eduquer">Éduquer ... ne pas réprimander</h3><p>Éduquez... ne réprimandez pas. N'oubliez pas que nous sommes humains. Nous faisons des erreurs. Je suis une travailleuse indépendante qui porte plusieurs chapeaux et qui est au service de ses merveilleux clients. Tout travail que je fais pour mon entreprise ici à meryl.net est la dernière chose que je fais. Bien que j'aie pris l'habitude d'ajouter du texte alternatif, il m'arrive d'être distraite ou d'être fatiguée et de sauter une étape.</p><p><em>Éduquer ... ne pas réprimander</em>.</p><p>Je ne me sentirais pas aussi mal si les personnes qui ont repéré mon erreur disaient quelque chose comme : "Hé, Meryl ! Tu as oublié le texte alternatif". Ou, s'ils ne me connaissent pas et ne connaissent pas mes antécédents en matière d'accessibilité, "Hé, Meryl. Au cas où tu ne le saurais pas, ajouter du texte alternatif aide ceux qui utilisent des lecteurs d'écran. Ce serait génial si tu pouvais l'ajouter".</p><p>Même si j'en ai pris l'habitude, il arrive qu'une de mes images passe sans texte alternatif. Je suis un être humain. Peut-être que je suis multitâche. Peut-être suis-je fatiguée. Qui sait ? Croyez-moi, quand je m'en rendrai compte, je me réveillerai à 3 h 30 du matin sans pouvoir me rendormir avant d'avoir corrigé le problème. Pour de vrai.</p><p><em>Éduquer ... ne pas réprimander</em>.</p><h3 id="commencer">Commencer par l'accessibilité</h3><p>La clé est de continuer à aller de l'avant. Désigner un cadre passionné pour en être le champion à l'intérieur de l'entreprise est une première étape importante. Vous avez besoin de ce champion pour faire bouger les choses.</p><p>L'étape suivante consiste à organiser une formation sur l'accessibilité et la sensibilisation aux handicaps dans toute l'entreprise. Je ne dis pas ça parce que je propose cette formation. Je préfère que vous engagiez quelqu'un d'autre plutôt que de ne pas la faire du tout.</p><p>Si votre organisation n'a pas encore de champion, vous pouvez faire quelque chose en tant que leader. La création de processus et de listes de contrôle contribuera grandement à éviter de sauter ou d'oublier une étape.</p><p>Voici quelques façons simples d'agir pour faire des progrès en matière d'accessibilité et d'inclusion.</p><ul><li>Vérifiez dans vos formulaires que vous offrez aux gens plusieurs options de contact ou que vous leur demandez leur méthode de contact préférée.</li>
<li>Mettez la première lettre de chaque mot en majuscule dans un hashtag. Cela améliore la lisibilité et aide les lecteurs d'écran à dire les choses correctement. Vérifiez tout de même votre hashtag en minuscules pour vous assurer qu'il ne crée pas une phrase malheureuse. Voici un exemple : #GodIsNowHere vs. #godisnowhere</li>
<li>Prenez l'habitude de toujours avoir un deuxième moyen de communication au cas où le moyen par défaut ne fonctionnerait pas. Si quelqu'un ne vous comprend pas, soyez aimable et proposez une autre façon de communiquer. (Indice : <a href="https://www.youtube.com/watch?v=Wx8gGP79QTY">regardez la conférence TEDx</a>).</li>
<li>Prenez l'engagement #CaptionPledge d'ajouter des sous-titres à toutes les vidéos à l'avenir. John Espirian explique : https://bit.ly/3yOtuce</li>
<li>Créez une transcription pour votre podcast ou clip audio le plus important.</li>
<li>Dites "C'est [votre nom]" chaque fois que vous parlez lors d'un appel.</li>
<li>Ajoutez une description à votre image sur un blog ou un post de média social.</li>
<li>Mettez toutes les questions posées dans le chatbox lors d'un appel vidéo. (Ou lisez à voix haute si elles sont saisies dans la boîte de dialogue).</li>
<li>Utilisez "Vérifier l'accessibilité" sur Microsoft Word et PowerPoint dans le menu Révision. C'est très facile !</li>
<li><a href="https://www.linkedin.com/posts/meryl_zoom-communication-accessibility-activity-6867522025343266816-veOC/">Vérifiez que les sous-titres sont activés sur votre compte Zoom</a> AVANT la réunion.</li>
<li>Activez les sous-titres sur Zoom à chaque fois.</li>
<li>Demandez à vos collègues et clients leurs préférences en matière de communication en direct (synchrone) et hors direct (asynchrone).</li>
<li>Ayez une conversation par messagerie texte avec une personne présente dans la pièce avec vous. Idéal pour les environnements bruyants !</li>
<li>Obtenez un swag <a href="https://scottvinkle.me/collections/progress?dt_id=68081">"Progress Over Perfection"</a> ou "Progress Not Perfection" !</li>
<li>Engagez-moi pour faire une conférence ou former vos employés.</li>
</ul><p>Éduquer les gens va loin et conduit au changement. Voilà ce qu'est le progrès plutôt que la perfection. Un pas après l'autre. Parfois, il s'agira de petits pas. D'autres fois, ce seront de grands pas. <a href="https://meryl.net/accessibility-progress-not-perfection/">Privilégiez le progrès à la perfection</a>.</p><h3 id="sensibilisation">Formation de sensibilisation à l'accessibilité et au handicap</h3><p>Je peux vous aider. Je peux faire une série de présentations et de séances de formation. Ou si vous voulez commencer petit, je peux former l'équipe de marketing et de communication sur la façon de créer du contenu accessible. <a href="https://meryl.net/contact/">Contactez-moi</a> ou apprenez à <a href="https://meryl.net/about/">me connaître</a>.</p><p><strong>Description de l'image en vedette</strong> : "C'est le progrès" six cercles remplis d'eau, le premier étant petit jusqu'à être plein. "Ceci est aussi un progrès" montre un progrès très lent. "And so this" montre peu, puis beaucoup, puis redescend et remonte. Crédit image : <a href="https://www.instagram.com/mounika.studio/">mounika.studio</a>.</p>]]></description>
      <link>https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite</link>
      <guid>https://la-cascade.io/articles/progres-plutot-que-perfection-pour-laccessibilite</guid>
      <pubDate>Sun, 12 Feb 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[grid-template-areas]]></title>
      <description><![CDATA[<p><em>Une explication très claire et détaillée de la propriété grid-template-area de CSS Grid par Mojtaba Sereyi.</em></p><div class="articleContent"><p>La propriété CSS <code>grid-template-areas</code> permet de définir et de nommer les <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridcell">cellules</a> (ou les <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridarea">zones de grille</a>) d'un conteneur de grille CSS.</p><pre class="language-css">.grid-container {
  display: grid;
  grid-template-areas: 'header header' 'sidebar main';
}</pre><p>Que fait le code ci-dessus ? Eh bien nous obtenons une grille de deux par deux dont la rangée supérieure réserve deux colonnes à une zone appelée "header". La rangée inférieure dispose également de deux colonnes, mais les réserve à des zones de la grille appelées respectivement sidebar et main.</p><figure class="wp-block-image size-full is-resized"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652729495228_grid-areas.jpg?resize=436%2C427&amp;ssl=1" alt="Two by two grid of squares." class="wp-image-365853" width="436" height="426" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652729495228_grid-areas.jpg?w=872&amp;ssl=1 872w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652729495228_grid-areas.jpg?resize=300%2C293&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652729495228_grid-areas.jpg?resize=768%2C751&amp;ssl=1 768w" /></figure><p>Notre grille est créée et nous avons défini des zones de grille, mais il n'y a rien d'assigné encore à ces zones. Si nous voulons placer un élément dans une zone de la grille, nous devons le déclarer explicitement avec la propriété <code>grid-area</code> <em>sur cet élément</em> :</p><pre class="language-css">.grid-container {
  display: grid;
  grid-template-areas: 'header header' 'sidebar main';
}
.grid-header {
  grid-area: header;
}
.grid-sidebar {
  grid-area: sidebar;
}
.grid-content {
  grid-area: main;
}</pre><p>Il faut garder à l'esprit qu'une zone de grille doit être soit une cellule unique dans le conteneur de la grille, soit un groupe de cellules adjacentes <em>de forme rectangulaire</em>. Tous les exemples suivants sont valables :</p><figure class="wp-block-image size-full"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360289791_valid-areas.png?resize=1360%2C808&amp;ssl=1" alt="Two valid and valid examples of grid areas." class="wp-image-365854" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360289791_valid-areas.png?w=1360&amp;ssl=1 1360w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360289791_valid-areas.png?resize=300%2C178&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360289791_valid-areas.png?resize=1024%2C608&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360289791_valid-areas.png?resize=768%2C456&amp;ssl=1 768w" data-recalc-dims="1" /><figcaption>Ces rectangles verts sont des exemples de grid template areas valides.</figcaption></figure><p>Mais nous ne pouvons pas former des zones de grille non rectangulaires. Donc, pas de chance si la zone que vous voulez définir a plutôt la forme d'un "T" ou d'un "L".</p><figure class="wp-block-image size-full"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652731081877_grid-template-areas-nope.jpg?resize=1353%2C387&amp;ssl=1" alt="Two invalid examples of grid-template-areas." class="wp-image-365855" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652731081877_grid-template-areas-nope.jpg?w=1353&amp;ssl=1 1353w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652731081877_grid-template-areas-nope.jpg?resize=300%2C86&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652731081877_grid-template-areas-nope.jpg?resize=1024%2C293&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_447572E1EBD548569C470162BD6B789F3DA660DCD973CC1C9548F73A0070C9FB_1652731081877_grid-template-areas-nope.jpg?resize=768%2C220&amp;ssl=1 768w" data-recalc-dims="1" /></figure><h2>Syntaxe</h2><pre class="language-css">grid-template-areas: none | string
Initial value: none
Applies to: grid containers
Inherited: no
Computed value: as specified, the keyword none or a list of string values
Animation type: discrete</pre><h2>Valeurs</h2><pre class="language-css">/* Keyword value */
grid-template-areas: none;
/* &lt;string&gt; values */
grid-template-areas: 'col-1 col-2 col-3';
grid-template-areas: 'header header header' 'sidebar main main';
grid-template-areas:
  'header header header'
  'sidebar main main'
  '. footer footer';
/* Global values */
grid-template-areas: inherit;
grid-template-areas: initial;
grid-template-areas: revert;
grid-template-areas: unset;</pre><h3>none</h3><p>C'est la valeur <strong>par défaut</strong>. Comme vous l'avez sans doute deviné, <code>none</code> signifie qu'aucune zone de grille nommée ni aucune <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridtrack">piste de grille</a> explicite n'est définie dans le conteneur de grille. Ça signifie également que les pistes de la grille sont générées implicitement et que leurs tailles sont définies par les propriétés <code>grid-auto-columns</code> et <code>grid-auto-rows</code>.</p><p>Il existe en fait une autre façon de créer des pistes de grille explicites qu'en utilisant <code>grid-template-areas</code>, et c'est d'utiliser les propriétés <code>grid-template-columns</code> et <code>grid-template-rows</code> à la place. Nous y reviendrons plus en détail dans la suite de cet article.</p><h3>string</h3><p>Une chaîne de caractères (<em>string</em>) peut être n'importe quel nom que l'on souhaite donner à une zone spécifique du modèle de grille. Ainsi, si vous avez une rangée supérieure dans votre conteneur de grille et que vous voulez que l'en-tête de votre mise en page s'y trouve, vous pouvez nommer la zone "en-tête" ou "page-top" ou littéralement ce que vous voulez. En fait, s'il y a plusieurs colonnes dans cette rangée, nous pouvons donner à chacune d'elles un nom différent.</p><pre class="language-css">.grid {
  grid-template-areas: 'logo menu utility-nav';
}</pre><p>On remarque que la totalité de la rangée de trois colonnes de cet exemple est entre guillemets. C'est essentiel, car les <code>grid-template-area</code> entre guillemets indiquent une nouvelle rangée. Ainsi, si nous avons deux rangées, nous verrons deux groupes entre guillemets :</p><pre class="language-css">.grid {
  grid-template-areas: 'logo menu utility-nav' 'sidebar-1 content sidebar-2';
}</pre><p>Mieux encore, nous pouvons améliorer la lisibilité en écrivant chaque rangée sur sa propre ligne :</p><pre class="language-css">.grid {
  grid-template-areas:
    'logo menu utility-nav'
    'sidebar-1 content sidebar-2';
}</pre><p>La syntaxe des chaînes de caractères permet de couvrir ou de sauter des cellules dans le conteneur de la grille. Nous y reviendrons dans un instant.</p><h2>Utilisation de base</h2><p>Tout d'abord, définissons les zones de grille en utilisant la propriété <code>grid-template-areas</code> dans le conteneur de grille parent :</p><pre class="language-css">.grid {
  display: grid;
  grid-template-areas:
    'header header header'
    'sidebar main main'
    'footer footer footer';
}</pre><p>Dans l'état actuel des choses, le conteneur de grille comporte des zones nommées, mais rien à l'intérieur. Pour y placer des éléments, nous devons assigner la zone de grille nommée à un élément en utilisant la propriété <code>grid-area</code> sur l'élément que nous plaçons :</p><pre class="language-css">header {
  grid-area: header;
}
aside {
  grid-area: sidebar;
}
main {
  grid-area: main;
}
footer {
  grid-area: footer;
}</pre><p>Voici le résultat basé sur les zones du modèle de grille que nous avons définies sur le conteneur de grille parent :</p><figure class="wp-block-image size-full"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360923904_grid-template-areas.png?resize=2048%2C1200&amp;ssl=1" alt="A webpage layout created using the CSS `grid-template-areas` property" class="wp-image-365857" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360923904_grid-template-areas.png?w=2048&amp;ssl=1 2048w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360923904_grid-template-areas.png?resize=300%2C176&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360923904_grid-template-areas.png?resize=1024%2C600&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360923904_grid-template-areas.png?resize=768%2C450&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642360923904_grid-template-areas.png?resize=1536%2C900&amp;ssl=1 1536w" data-recalc-dims="1" /></figure><h2>Dimensionnement des zones nommées d'une grille</h2><p>La taille des zones de la grille peut être définie à l'aide des propriétés <code>grid-template-columns</code> et <code>grid-template-rows</code> dans le conteneur de la grille parente.</p><p>Supposons que notre grille ait besoin de deux colonnes et que la deuxième colonne prenne deux fois plus d'espace que la première. Nous pouvons utiliser l'<a href="https://css-tricks.com/introduction-fr-css-unit/">unité fraction (fr)</a> pour cela :</p><pre class="language-css">.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr 2fr;
  grid-template-areas: 'sidebar main';
}</pre><p>Il en va de même pour les rangées. Supposons maintenant que nous ayons besoin de la présentation suivante dans une grille de trois par trois :</p><figure class="wp-block-image size-full"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642100877006_grid-template-areas.png?resize=2048%2C1200&amp;ssl=1" alt="A webpage layout created using the CSS grid-template-areas property" class="wp-image-365858" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642100877006_grid-template-areas.png?w=2048&amp;ssl=1 2048w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642100877006_grid-template-areas.png?resize=300%2C176&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642100877006_grid-template-areas.png?resize=1024%2C600&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642100877006_grid-template-areas.png?resize=768%2C450&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642100877006_grid-template-areas.png?resize=1536%2C900&amp;ssl=1 1536w" data-recalc-dims="1" /></figure><p>Cette fois-ci, les première et troisième rangées ont la même hauteur fixe de 250 pixels, mais la rangée du milieu est dimensionnée de manière à occuper autant d'espace que le contenu en a besoin :</p><pre class="language-css">.grid {
  display: grid;
  gap: 1rem;
  grid-template-rows: 250px auto 250px;
  grid-template-areas:
    'header header header'
    'sidebar main main'
    'footer footer footer';
}</pre><p>Si vous vous demandez ce qu'il se passe avec toutes ces zones de gabarit de grille nommées à plusieurs reprises, il s'agit de...</p><h3>...cellules et rangées qui s'étendent</h3><p>La répétition d'une zone nommée relie les cellules. Ainsi, si l'objectif est de créer une zone nommée "feature" et qu'elle occupe deux colonnes dans la rangée supérieure, nous pouvons faire quelque chose comme ceci :</p><pre class="language-css">/* Valid declaration */
grid-template-areas: 'feature feature widget';</pre><p>Cool, et nous pouvons faire la même chose dans le sens vertical si la même zone nommée commence chaque ligne :</p><pre class="language-css">/* Valid declaration */
grid-template-areas:
  'feature aside widget-1'
  'feature aside widget-2';</pre><p>Bien entendu, nous pouvons combiner les deux pour obtenir une zone de gabarit qui s'étend dans les deux directions :</p><pre class="language-css">/* Valid declaration */
grid-template-areas:
  'feature feature widget-1'
  'feature feature widget-2';</pre><p>Comme indiqué précédemment, les zones de grille doivent être <em>rectangulaires</em>. Ça signifie que la variante suivante du dernier exemple n'est <em>pas valable</em> :</p><pre class="language-css">/* Invalid declaration */
grid-template-areas:
  'feature feature widget-1'
  'feature aside widget-2';</pre><h2>Nous pouvons créer des espaces (ou des "arrêts") entre les cellules</h2><p>C'est possible en utilisant la notation <em>point</em> (<code>.</code>) :</p><pre class="language-css">grid-template-areas:
  "header header header"
  "sidebar main main"
  ". footer footer"; /* la 1ère cellule est vide */
}</pre><p>Le nombre de points n'a pas d'importance. Nous aurions pu faire ceci à la place :</p><pre class="language-css">grid-template-areas:
  "header  header header"
  "sidebar main   main"
  "....... footer footer"; /* la 1ère cellule est vide */
}</pre><p>Les deux déclarations créent la même grille :</p><figure class="wp-block-image size-full"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642429460064_localhost_8080_NestHub.png?resize=2048%2C1200&amp;ssl=1" alt="" class="wp-image-365860" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642429460064_localhost_8080_NestHub.png?w=2048&amp;ssl=1 2048w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642429460064_localhost_8080_NestHub.png?resize=300%2C176&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642429460064_localhost_8080_NestHub.png?resize=1024%2C600&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642429460064_localhost_8080_NestHub.png?resize=768%2C450&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642429460064_localhost_8080_NestHub.png?resize=1536%2C900&amp;ssl=1 1536w" data-recalc-dims="1" /><figcaption>La cellule de la première colonne, troisième rangée, est vide, effet de la notation point.</figcaption></figure><h3>Les espaces blancs sont un bon moyen de visualiser la grille</h3><p>Les déclarations suivantes sont équivalentes, mais la seconde permet de mieux visualiser la structure de la grille, car nous utilisons des espaces vides pour <em>aligner les noms</em> :</p><pre class="language-css">grid-template-areas:
  'header header header'
  'sidebar main main'
  '. footer footer';
grid-template-areas:
  'header  header header'
  'sidebar main   main'
  '.       footer footer';</pre><p>Si vous cherchez une autre façon de visualiser un conteneur de grille, <a href="https://css-tricks.com/little-tip-draw-your-grid-in-ascii-in-your-css-comments-for-quick-reference/">Chris a une idée astucieuse</a> pour le "dessiner" dans une sorte de format ASCII.</p><h3>Les rangées doivent avoir le même nombre de colonnes</h3><p>Toutes les listes doivent avoir le même nombre de valeurs, sinon la déclaration n'est pas valide.</p><pre class="language-css">/* ? */
grid-template-areas:
  'name name-2 name-3'
  'name name-2 name-3'
  'name name-2 name-3';
/* ? */
grid-template-areas:
  'header header'
  '. main'
  'footer footer';
/* ? */
grid-template-areas:
  'name name-2 name-3'
  'name name-2 name-3'
  'name name-3';</pre><h3>Utilisation de caractères Unicode pour les zones de grille nommées</h3><p>Selon les spécifications, tout nom qui ne correspond pas à la <a href="https://drafts.csswg.org/css-values-4/#typedef-ident">syntaxe ident</a> doit être échappé lorsqu'il est fait référence à cette zone par son nom dans d'autres propriétés. Par exemple, dans la déclaration suivante, le nom de la première zone commence par un chiffre et ne correspond donc pas à la syntaxe <code>&lt;ident&gt;</code> :</p><pre class="language-css">.grid {
  grid-template-areas: '1st b c';
}</pre><p>La solution consiste à déclarer le <a href="https://infra.spec.whatwg.org/#code-point">code hexadécimal</a> non échappé pour le chiffre 1. Dans ce cas, c'est <code>U+0031</code>, que nous échappons dans le CSS sous la forme <code>\31st</code>. C'est donc ce que nous utilisons pour affecter un élément à la zone de grille nommée :</p><pre class="language-css">.grid-item {
  grid-area: \31st;
}</pre><h2>Noms de rangées attribués implicitement</h2><p>La définition des pistes avec la propriété <code>grid-template-areas</code> nous donne gratuitement des noms de lignes basés sur les noms attribués. C'est différent des propriétés <code>grid-template-rows</code> et <code>grid-template-columns</code> où nous devons fournir des noms de lignes lors de la définition des colonnes et des rangées. Ce n'est pas le cas de la propriété <code>grid-template-areas</code>, car elle prend les noms que nous lui fournissons et produit des noms de pistes pour nous.</p><p>Quatre lignes de grille sont créées pour chaque nom de zone de grille. Si nous avons une zone de grille nommée <code>sidebar</code>, nous obtenons deux paires de lignes de piste nommées <code>sidebar-start</code> et <code>sidebar-end</code> - une paire pour la direction de la colonne et une paire pour la direction de la rangée :</p><figure class="wp-block-image size-full"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642170540124_Untitled.png?resize=2048%2C1200&amp;ssl=1" alt="Showing track lines in a CSS grid layout created with grid-template-areas." class="wp-image-365861" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642170540124_Untitled.png?w=2048&amp;ssl=1 2048w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642170540124_Untitled.png?resize=300%2C176&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642170540124_Untitled.png?resize=1024%2C600&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642170540124_Untitled.png?resize=768%2C450&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2022/05/s_A8CA686DA97A9B54A10BB8506B0F905A3FEF553C480B7AEBFFA08B417AE4ABF7_1642170540124_Untitled.png?resize=1536%2C900&amp;ssl=1 1536w" data-recalc-dims="1" /></figure><p>On peut se demander ce qui se passe si l'on définit explicitement les noms des pistes et que l'on utilise le même nom que celui que l'on obtiendrait s'ils étaient définis implicitement — par exemple, si l'on définit explicitement une ligne de grille nommée <code>sidebar-start</code> pour une sidebar nommée <code>area</code>. Eh bien en fait les deux lignes peuvent coexister et être affectées à des éléments différents. En d'autres termes, la valeur explicite reste valable et les deux lignes peuvent être utilisées.</p><h2>Zones nommées implicitement</h2><p>Une autre façon de nommer les zones de grille dans un conteneur de grille est de laisser CSS Grid les nommer implicitement pour nous lors de la configuration des noms de pistes dans les propriétés <code>grid-template-columns</code> et <code>grid-template-rows</code>.</p><p>Tout ce que nous avons à faire est de choisir un nom pour la zone de grille et d'y ajouter à la fin <code>-start</code> et <code>-end</code> pour les noms de pistes. Ici, par exemple, nous obtenons une zone de grille appelée <code>sidebar</code> sans même déclarer la propriété grid-template-areas :</p><pre class="language-css">.grid-container {
  display: grid;
  grid-template-columns: [sidebar-start] 250px [sidebar-end] 1fr;
}
aside {
  grid-area: sidebar;
}</pre><p>Comme le montre l'exemple ci-dessus, bien qu'il n'y ait pas de propriété <code>grid-template-areas</code> pour définir explicitement une zone nommée "sidebar", cette zone peut toujours être référencée par les propriétés grid-placement telles que <code>grid-area</code>, <code>grid-row</code>, <code>grid-column</code> ou leurs équivalents en écriture développée.</p><h2>Exemple : Disposition réactive du Saint Graal</h2><p>Dans la démo suivante, nous utilisons la propriété <code>grid-template-areas</code> pour créer <a href="https://css-tricks.com/the-holy-grail-layout-with-css-grid/">la fameuse mise en page Holy Grail</a> avec CSS Grid :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/seyedi/pen/bGoZjzX">Holy grail layout with CSS Grid</a>de Mojtaba Seyedi dans<a href="https://codepen.io">CodePen</a></div><p>Cette mise en page doit son nom au fait qu'elle était extrêmement difficile à réaliser <a href="https://css-tricks.com/in-defense-of-tables-and-floats-in-modern-day-development/">à l'époque où l'on utilisait des <code>float</code></a> pour les mises en page. Heureusement, nous disposons de CSS Grid pour rendre cette tâche presque triviale.</p><p>Tout d'abord, notre HTML :</p><pre class="language-html">&lt;div class="grid"&gt;
  &lt;header&gt;Header&lt;/header&gt;
  &lt;main&gt;Main Content&lt;/main&gt;
  &lt;aside class="left-sidebar"&gt;Left Sidebar&lt;/aside&gt;
  &lt;aside class="right-sidebar"&gt;Right Sidebar&lt;/aside&gt;
  &lt;footer&gt;Footer&lt;/footer&gt;
&lt;/div&gt;</pre><p>C'est assez simple jusqu'à présent, pas vrai ? Nous voulons que l'en-tête soit en haut, que le pied de page soit en bas et que le contenu principal soit dans l'une des trois colonnes de la rangée du milieu.</p><p>Nous pouvons configurer les <em>grid template areas</em> nommées en CSS, et étendre les rangées si nécessaire :</p><pre class="language-css">.container {
  grid-template-columns: 12rem auto 12rem;
  grid-template-areas:
    'header header header'
    'left-sidebar main right-sidebar'
    'footer footer footer';
}</pre><p>Nous devons maintenant assigner chaque élément à une zone de grille nommée :</p><pre class="language-css">header {
  grid-area: header;
}
main {
  grid-area: main;
}
footer {
  grid-area: footer;
}
.left-sidebar {
  grid-area: left-sidebar;
}
.right-sidebar {
  grid-area: right-sidebar;
}</pre><p>Et voilà, techniquement c'est terminé ! C'est vraiment tout ce qu'il y a à faire. Nous pouvons aller plus loin en empilant les zones de la grille verticalement par défaut, puis construire le Saint Graal sur des écrans plus grands où l'aspect est bien meilleur :</p><pre class="language-css">.container {
  display: grid;
  grid-template-areas:
    /* Chaque zone est une rangée */
    'header'
    'nav'
    'article'
    'sidebar'
    'footer';
}
@media (min-width: 600px) {
  .container {
    grid-template-columns: 12rem auto 12rem;
    grid-template-areas:
      /* Build the Holy Grail layout */
      'header header header'
      'nav article article'
      'sidebar article article'
      'footer footer footer';
  }
}</pre><p>Voir aussi :</p><ul><li><a href="https://la-cascade.io/articles/comprendre-cssgrid-grid-template-areas">Comprendre CSS Grid : Grid template areas</a>, de Rachel Andrew</li>
<li><a href="https://la-cascade.io/articles/css-grid-difference-entre-grilles-explicite-et-implicite">CSS Grid : la différence entre grilles explicite et implicite</a>, de Manuel Matuzovic</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/grid-template-areas</link>
      <guid>https://la-cascade.io/articles/grid-template-areas</guid>
      <pubDate>Thu, 09 Feb 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Citer en HTML, un guide complet]]></title>
      <description><![CDATA[<p><em>John Rhea fait le point sur les blocs de citation et tout ce qu'il faut savoir sur les citations, pour respecter la sémantique HTML.</em></p><div class="articleContent"><p>Il n'est que trop fréquent de voir un HTML incorrect utilisé pour les citations dans le balisage. Dans cet article, nous allons creuser tout cela, en examinant différentes cas et différentes balises HTML pour gérer ces situations.</p><p>Il y a trois éléments HTML majeurs impliqués dans les citations :</p><ul><li><code>&lt;blockquote&gt;</code></li>
<li><code>&lt;q&gt;</code></li>
<li><code>&lt;cite&gt;</code></li>
</ul><p>Regardons ça de plus près.</p><h2>Les blocs de citation</h2><p>Les balises <a href="https://developer.mozilla.org/fr/docs/Web/HTML/Element/blockquote">Blockquote</a> sont utilisées pour distinguer le texte cité du reste du contenu. Mon professeur d'anglais de classe de seconde m'a fait entrer dans la tête que c'est ainsi qu'on devait distinguer toute citation de quatre lignes ou plus. <a href="https://html.spec.whatwg.org/multipage/grouping-content.html#the-blockquote-element">La spécification HTML n'impose pas une telle exigence</a>, mais tant que le texte est une citation et que vous souhaitez qu'il soit séparé du texte et des balises qui l'entourent, un bloc de citation est le choix sémantique à faire.</p><p>Par défaut, les navigateurs mettent en retrait les guillemets en ajoutant une marge de chaque côté.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/undeadinstitute/pen/MWWXzXP">The Blockquote Tag</a>de Undead Institute dans<a href="https://codepen.io">CodePen</a></div><p>En tant qu'élément de flux (càd un élément de "niveau bloc"), <code>blockquote</code> peut contenir d'autres éléments. Par exemple, nous pouvons y déposer des paragraphes sans problème :</p><pre class="language-html">&lt;blockquote&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;&lt;/p&gt;
&lt;/blockquote&gt;</pre><p>Mais on pourrait aussi y mettre d'autres éléments, comme un titre ou une liste non ordonnée :</p><pre class="language-html">&lt;blockquote&gt;
  &lt;h2&gt;&lt;/h2&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;/li&gt;
    &lt;li&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;</pre><p>Il est important de noter que les blocs de citation ne doivent être utilisés que pour les citations et non comme un élément décoratif dans un design. Cela facilite également l'accessibilité, car les utilisateurs de lecteurs d'écran peuvent sauter entre les blocs de citation. Un bloc de citation utilisé uniquement à des fins esthétiques pourrait vraiment dérouter ces utilisateurs. Si vous avez simplement besoin d'un élément décoratif qui ne correspond pas sémantiquement à cette notion, une <code>div</code> avec une classe est sans doute la meilleure solution.</p><pre class="language-css">blockquote,
.callout-block {
  /* Ils pourraient partager le style */
}</pre><h2>Citation avec Q</h2><p>Les balises Q (<code>&lt;q&gt;</code>) sont destinées aux citations <em>en ligne</em>, ou ce que mon prof de seconde appellerait les citations de moins de quatre lignes. De nombreux navigateurs modernes ajouteront automatiquement des guillemets à la citation en tant que pseudo-éléments, mais vous aurez peut-être besoin d'une solution de secours pour les navigateurs plus anciens.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/rNNEzOg">The Q Tag</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div><p>Les bon vieux guillemets sont tout aussi valables pour les citations en ligne que l'élément <code>&lt;q&gt;</code>. Cependant, l'élément <code>&lt;q&gt;</code> a quelques avantages : il comprend un attribut <code>cite</code>, la gestion automatique des guillemets et la gestion automatique des niveaux de citation. Les éléments <code>&lt;q&gt;</code> ne doivent pas être utilisés pour le sarcasme (par exemple, "vous utiliseriez une balise <code>&lt;q&gt;</code> pour le sarcasme ?"), ou pour signifier un mot avec des guillemets expressifs (par exemple, "génial" est une description "exacte" de l'auteur). Mais si vous arrivez à trouver une balise pour les guillemets expressifs, faites-le moi savoir. Parce que ce serait "génial".</p><h2>L'attribut de citation</h2><p>Aussi bien les <code>&lt;q&gt;</code> que les <code>blockquotes</code> peuvent utiliser un <a href="https://developer.mozilla.org/fr/docs/Web/HTML/Element/cite">attribut de citation</a> (<code>cite</code>). Cet attribut contient une URL qui fournit un contexte et/ou une référence à l'objet cité. La spécification met un point d'honneur à dire que l'URL peut être entourée d'espaces. (Je ne suis pas sûr de la raison pour laquelle c'est souligné, les dieux du code sémantique ont leurs raisons).</p><pre class="language-html">&lt;p&gt;
  The officer left a note saying
  &lt;q cite="https://johnrhea.com/summons"
    &gt;You have been summoned to appear on the 4th day of January on
    charges of attempted reader bribery.&lt;/q
  &gt;
&lt;/p&gt;
.</pre><p>Cet attribut <code>cite</code> n'est pas visible par l'utilisateur par défaut. Vous pourriez l'ajouter avec un soupçon de magie CSS comme la démo suivante. Vous pourriez même le bidouiller davantage pour que la citation apparaisse au survol.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/WNNVQyO">Attributable citations</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div><p>Aucune de ces options n'est particulièrement géniale. Si vous devez citer une source de manière à ce que les utilisateurs puissent la voir et y accéder, vous devez le faire en HTML et probablement avec l'élément <code>&lt;cite&gt;</code>, que nous aborderons ensuite.</p><h2>L'élément de citation</h2><p>La balise <code>&lt;cite&gt;</code> doit être utilisée pour référencer un <strong>travail créatif</strong> plutôt que l'auteur de la citation. En d'autres termes, ce n'est pas pour les citations. Voici les exemples tirés de la spécification :</p><pre class="language-html">&lt;p&gt;
  Mon livre préféré est &lt;cite&gt;The Reality Dysfunction&lt;/cite&gt; de Peter
  F. Hamilton. Ma bande dessinée préférée est
  &lt;cite&gt;Pearls Before Swine&lt;/cite&gt; de Stephan Pastis. Mon morceau
  préféré est &lt;cite&gt;Jive Samba&lt;/cite&gt; par le Cannonball Adderley
  Sextet.
&lt;/p&gt;</pre><p>Voici un autre exemple :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/RwwzZQj">Cite This!</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div><p>Si l'auteur de cet article vous disait qu'il vous donnerait un cupcake, et que vous le <code>&lt;cite&gt;</code>z <em>par son nom</em>, ce serait sémantiquement incorrect. Ainsi, aucun cupcake ne changerait de main. Si vous citiez <em>l'article</em> dans lequel il vous a offert un cupcake, ce serait sémantiquement correct, mais comme l'auteur ne le ferait pas, vous n'auriez toujours pas de cupcake. Désolé.</p><p>Par défaut, les navigateurs mettent le contenu des balises de citation en italiques et il n'est pas nécessaire qu'un <code>&lt;q&gt;</code> ou <code>&lt;blockquote&gt;</code> soit présent pour utiliser l'élément de citation. Si vous voulez citer un livre ou un autre travail créatif, placez-le dans l'élément <code>cite</code>. Les divinités sémantiques vous feront un grand sourire pour ne pas avoir utilisé les éléments <code>&lt;i&gt;</code> ou <code>&lt;em&gt;</code>.</p><p>Mais où placer l'élément <code>cite</code> ? À l'intérieur ? À l'extérieur ? A l'envers ? Si on le met <em>à l'intérieur</em> du <code>&lt;blockquote&gt;</code> ou du <code>&lt;q&gt;</code>, on l'intègre à la citation. C'est <a href="https://www.w3.org/TR/html5-author/the-blockquote-element.html#the-blockquote-element">interdit par la spécification</a> pour cette raison précise.</p><pre class="language-html">&lt;!-- C'est apparemment faux --&gt;
&lt;blockquote&gt;
  Citation sur la distribution de cupcakes à partir d'un article
  &lt;cite&gt;L'article&lt;/cite&gt;
&lt;/blockquote&gt;</pre><p>Le mettre à l'extérieur semble juste mauvais et nécessite également que vous ayez un élément englobant comme une <code>&lt;div&gt;</code> si vous vouliez les styliser ensemble.</p><pre>&lt;div class="need-to-style-together"&gt;
  &lt;blockquote&gt;
    Citation d'un article sur la distribution de cupcakes
  &lt;/blockquote&gt;
  &lt;cite&gt;L'article&lt;/cite&gt;
&lt;/div&gt;</pre><p>N.B. Si vous cherchez cette question sur Google, vous tomberez peut-être sur <a href="http://html5doctor.com/cite-and-blockquote-reloaded/">un article de HTML5 Doctor</a> datant de 2013 qui contredit une grande partie de ce qui est exposé ici. Cela dit, chaque fois qu'il établit un lien vers les docs, ceux-ci sont en accord avec l'article que vous êtes en train de lire plutôt qu'avec l'article de HTML5 Doctor. Il est donc fort probable que la documentation ait changé depuis la rédaction de cet article.</p><h3>Et l'élément figure ?</h3><p>Une façon de baliser une citation — et d'une manière qui plaît aux divinités du code sémantique — est de placer la citation en bloc dans un élément <code>figure</code>. Ensuite, mettez l'élément <code>cite</code> et toute autre information sur l'auteur ou la citation dans une <code>figcaption</code>.</p><pre class="language-html">&lt;figure class="quote"&gt;
  &lt;blockquote&gt;
    Mais les navigateurs Web ne sont pas comme les serveurs Web. Si
    votre code back-end devient si gros qu'il commence à s'exécuter
    notablement lentement, vous pouvez y injecter plus de puissance de
    calcul en mettant à l'échelle votre serveur. Ce n'est pas une
    option sur le front-end où vous n'avez pas vraiment un seul
    environnement d'exécution - vos utilisateurs finaux ont leur
    propre environnement d'exécution avec ses propres contraintes
    autour de la puissance de calcul et de la connectivité réseau.
  &lt;/blockquote&gt;
  &lt;figcaption&gt;
    &amp;mdash ; Jeremy Keith, &lt;cite&gt;Modèles mentaux&lt;/cite&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;</pre><p>Cela double le nombre d'éléments nécessaires, mais il y a plusieurs avantages :</p><ul><li>C'est sémantiquement correct pour les quatre éléments.</li>
<li>Il vous permet à la fois d'inclure et d'encapsuler des informations sur l'auteur au-delà de la citation du nom de l'œuvre.</li>
<li>Il vous offre un moyen facile de styliser la citation sans avoir recours aux divs, aux espaces ou à des expédients misérables.</li>
</ul><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/oNNreVe">It Figures You'd Say That</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div><h3>Rien de tout cela n'est pour le dialogue</h3><p>Pas de <a href="https://developer.mozilla.org/fr/docs/Web/HTML/Element/dialog"><code>&lt;dialog&gt;</code></a> ! Ça c'est pour les modales qui veulent attirer l'attention.</p><p>Ni <code>&lt;blockquote&gt;</code>, ni <code>&lt;q&gt;</code>, ni <code>&lt;cite&gt;</code> ne doivent être utilisés pour le dialogue et les échanges similaires entre locuteurs. Si vous marquez un dialogue, vous pouvez utiliser ce qui vous semble le plus logique. Il n'y a pas de manière sémantique de le faire. Cela dit, la spécification suggère les balises <code>&lt;p&gt;</code> et la ponctuation avec les balises <code>&lt;span&gt;</code> ou <code>&lt;b&gt;</code> pour désigner le locuteur et les balises <code>&lt;i&gt;</code> pour marquer les indications scéniques.</p><h2>Accessibilité des citations</h2><p>D'après mes recherches, les lecteurs d'écran ne devraient pas avoir de problème pour comprendre les balises <code>&lt;q&gt;</code>, <code>&lt;blockquote&gt;</code> ou <code>&lt;cite&gt;</code> approuvées par la sémantique.</p><h2>D'autres "façons" de "citer"</h2><p>Vous pouvez ajouter des guillemets à un <code>&lt;blockquote&gt;</code> en utilisant des <a href="https://la-cascade.io/tags/pseudo-elements">pseudo-éléments</a> CSS. L'élément <code>&lt;q&gt;</code> est livré avec des guillemets intégrés, il n'est donc pas nécessaire de les ajouter, mais les ajouter en tant que pseudo-éléments peut être une solution de contournement pour les anciens navigateurs qui ne les ajoutent pas automatiquement. Vu c'est ainsi que les navigateurs modernes ajoutent les guillemets, on ne risque pas d'ajouter des guillemets en double. Les nouveaux navigateurs écraseront les pseudo-éléments par défaut, et les anciens navigateurs qui prennent en charge les pseudo-éléments ajouteront les guillemets.</p><figure><img src="https://la-cascade.io/images/quotes-q.webp" alt="image" /></figure><p>Mais vous ne pouvez pas, comme je l'ai fait, supposer que ce qui précède vous donnera toujours des guillemets ouvrants et fermants intelligents. Même si la police prend en charge les guillemets intelligents, il arrive que des guillemets droits soient affichés. Pour être sûr, il est préférable d'utiliser la propriété CSS <code>quotes</code> pour améliorer l'intelligence de ces guillemets.</p><pre class="language-css">blockquote {
  quotes: '“' '”' '‘' '’';
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/OJJexXq">"Quot-a-tizing" the blockquote</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div><h2>Citation à plusieurs niveaux</h2><p>Examinons maintenant les niveaux de citation. La balise <code>&lt;q&gt;</code> ajustera automatiquement les niveaux de citation.</p><p>Disons que vous êtes dans une région qui utilise la convention britannique d'utiliser des guillemets simples. Vous pourriez utiliser la règle des guillemets CSS pour placer les guillemets simples d'ouverture et de fermeture en premier dans la liste. Voici un exemple des deux méthodes :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/vYYqpGg">Quote Within a Quote</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div><p>Il n'y a pas de limite à l'imbrication. Ces éléments <code>&lt;q&gt;</code> imbriqués pourraient même se trouver dans un bloc de citation qui se trouve à l'intérieur d'un autre bloc de citation.</p><p>Si vous ajoutez des guillemets à un bloc de citation, sachez que le blockquote ne modifie pas le niveau de citation comme le fait une balise <code>&lt;q&gt;</code>. Si vous vous attendez à avoir des guillemets à l'intérieur d'un blockquote, vous pouvez ajouter une règle de sélection descendante pour faire commencer les éléments <code>&lt;q&gt;</code> à l'intérieur d'un blockquote au niveau des guillemets simples (ou doubles si vous suivez les conventions britanniques).</p><pre class="language-css">blockquote q {
  quotes: '‘' '’' '“' '”';
}</pre><p>Le dernier niveau de guillemets que vous avez mis se poursuivra à travers les niveaux de guillemets suivants. Pour utiliser la convention double, simple, double, simple..., ajoutez d'autres niveaux à la propriété de guillemets CSS.</p><pre class="language-css">q {
  quotes: '“' '”' '‘' '’' '“' '”' '‘' '’' '“' '”';
}</pre><h2>Ponctuation suspendue</h2><p>De nombreux experts en typographie vous diront que le fait de suspendre les guillemets sur les blockquotes est plus esthétique (et ils ont raison). Dans le cas qui nous intéresse, la ponctuation suspendue ce sont des guillemets repoussés du texte de sorte que les caractères du texte s'alignent verticalement.</p><figure><img src="https://la-cascade.io/images/hanging-quote.webp" alt="" /></figure><p>Avec CSS, une possibilité serait d'utiliser une valeur légèrement négative sur la propriété d'indentation du texte <code>text-indent</code>. L'indentation négative exacte varie selon la police, alors assurez-vous de vérifier l'espacement avec la police que vous utilisez.</p><pre class="language-css">blockquote {
  text-indent: -0.45em;
}</pre><p>Il existe un moyen plus agréable de gérer cette situation en utilisant la propriété CSS <a href="https://developer.mozilla.org/fr/docs/Web/CSS/hanging-punctuation"><code>hanging-punctuation</code></a>. Elle n'est prise en charge que par Safari au moment de la rédaction de ce document, nous devrons donc l'améliorer progressivement :</p><pre class="language-css">/* Fallback */
blockquote {
  text-indent: -0.45em;
}
/* S'il y a un support, effacez le retrait et utilisez la propriété à la place */
@supports (hanging-punctuation: first) {
  blockquote {
    text-indent: 0;
    hanging-punctuation: first;
  }
}</pre><p>L'utilisation de la ponctuation suspendue est préférable car elle est moins compliquée. Cela fonctionnera simplement quand cela sera possible.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/NWWZXdB">Hanging Your Punctuation</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div><h2>Peut-on animer les guillemets ?</h2><p>Mais bien sûr !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/abbgEyv">Dancing Quotes</a>de CSSTricks dans<a href="https://codepen.io">CodePen</a></div></div>]]></description>
      <link>https://la-cascade.io/articles/citer-en-html</link>
      <guid>https://la-cascade.io/articles/citer-en-html</guid>
      <pubDate>Wed, 08 Feb 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Ce qu'une année à apprendre et enseigner l'accessibilité m'a appris]]></title>
      <description><![CDATA[<p><em>Le cheminement personnel de Sara Soueidan vers un web plus accessible, dont nous pouvons tous apprendre.</em></p><div class="articleContent"><h2>Table des matières</h2><ul><li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#fondement">Le HTML sémantique est la base d'un Web véritablement accessible</a>.</li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#polyfill">ARIA est un polyfill pour la sémantique HTML</a></li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#javascript">JavaScript est impératif pour créer des composants interactifs personnalisés véritablement accessibles</a></li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#progressive-enhancement">L'amélioration progressive est une stratégie inclusive de construction pour le Web</a></li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#design">Le design ne dicte pas toujours l'implémentation</a></li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#techniquement-accessible">Ce n'est pas parce que c'est techniquement accessible que c'est inclusif</a></li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#en-fin-de-compte">En fin de compte, il s'agit toujours de l'utilisateur</a></li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#doute">En cas de doute, demandez de l'aide</a></li>
<li><a href="https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite#derniers-mots">Derniers mots</a></li>
</ul><p><small><em>(Cet article a été initialement publié sur <a href="https://www.24a11y.com/">24 accessibilité</a>)</em></small>.</p><p>Il y a quelques années, je ne savais pas ce que signifiait le terme "accessibilité". J'ai construit des sites Web qui étaient partiellement inaccessibles <strong>parce que je ne savais pas mieux</strong>. Aujourd'hui, j'en sais assez pour écrire, parler et animer des ateliers sur l'accessibilité, afin d'aider les autres à créer un Web plus accessible et inclusif. Comme tout le monde dans notre domaine, j'apprends encore. Mais depuis que j'ai commencé, j'ai appris beaucoup de leçons précieuses et de valeurs fondamentales qui guident mon travail aujourd'hui. En voici quelques-unes.</p><h2 id="fondement">Le HTML sémantique est le fondement d'un Web véritablement accessible</h2>Le HTML sémantique est le langage universel que tous les appareils accédant à l'Internet comprennent. C'est le langage que vous utilisez pour communiquer votre contenu à ces différents appareils, y compris, mais sans s'y limiter, les navigateurs, les applications de lecture, les lecteurs d'écran, les montres intelligentes, etc.<p>Le HTML est sémantique, ou en d'autres termes, il est descriptif et donne du sens — chaque élément HTML décrit le type de contenu qu'il présente. Ainsi, si vous avez un titre, vous utilisez un élément de titre. Si vous avez un paragraphe, vous utilisez une balise <code>&lt;p&gt;</code>. En d'autres termes, il s'agit d'utiliser les bons éléments HTML pour leur objectif correct.</p><p>En utilisant les éléments corrects, le contenu de votre document aura une <strong>structure</strong> et un <strong>sens</strong> transmissibles.</p><p>La structure est importante car elle favorise l'interopérabilité. L'interopérabilité est la capacité de différents systèmes, dispositifs, applications ou produits à se connecter et à communiquer de manière coordonnée, sans effort de la part de l'utilisateur final. En d'autres termes, elle permet à davantage de dispositifs d'interpréter et d'accéder à votre contenu, y compris aux dispositifs qui apparaîtront dans le futur.</p><p>La structure aide les applications telles que les applications de lecture et les modes de lecture (comme le mode de lecture de Safari) ainsi que les environnements tels que le mode de contraste élevé de Windows à comprendre votre contenu et à le styliser de manière à améliorer l'expérience utilisateur. Cela n'est possible que lorsque les éléments sémantiques HTML appropriés sont utilisés, tels que <code>&lt;article&gt;</code>, <code>&lt;h1&gt;</code>, <code>&lt;ul&gt;</code>, <code>&lt;aside&gt;</code>, <code>&lt;nav&gt;</code>, parmi de <a href="https://developer.mozilla.org/fr/docs/Web/HTML/Element">nombreux autres disponibles dans HTML5</a>. Ces éléments décrivent le type de contenu qu'ils contiennent. Sans eux, ces applications ne seraient pas en mesure de dire ce qu'est ce contenu, et ne pourront donc pas le styliser correctement. Cela augmente le risque de rendre le contenu moins accessible, voire complètement inaccessible.</p><figure role="group"><img src="https://la-cascade.io/images/semantics-and-reader-modes.png" alt="Photos d'une page web mobile dans l'application Instapaper app." /><figcaption>Une page Web de Mandy Michael montrant comment un article est stylisé dans l'application Instapaper lorsque cet article est marqué à l'aide de divs sans sémantique (à gauche) et d'éléments HTML sémantiques (à droite) (<a href="https://medium.com/@mandy.michael/building-websites-for-safari-reader-mode-and-other-reading-apps-1562913c86c9">Source</a>).</figcaption></figure><p>La structure est également importante du fait qu'elle permet à vos utilisateurs de naviguer plus efficacement dans votre contenu. Les utilisateurs de lecteurs d'écran s'appuient sur une structure de document appropriée pour accéder plus rapidement aux zones de la page dont ils ont besoin. Pour ce faire, ils utilisent diverses touches de raccourci — des commandes puissantes mais destinées aux utilisateurs de lecteurs d'écran. Si vous n'utilisez pas de points de repère appropriés (exposés aux lecteurs d'écran via des éléments HTML sémantiques tels que <code>&lt;nav&gt;</code> et <code>&lt;main&gt;</code> et <code>&lt;header&gt;</code>), les utilisateurs de lecteurs d'écran risquent de ne pas pouvoir naviguer efficacement dans la page et devront rechercher leurs centres d'intérêt de manière plus fastidieuse.</p><figure role="group"><img src="https://la-cascade.io/images/rotor-landmarks.png" alt="Capture d'écran du rotor VoiceOver de macOS ouvert sur sarasoueidan.com" /><figcaption>Le menu rotatif de VoiceOver expose tous les points de repère (Landmarks) disponibles sur une page Web, permettant à l'utilisateur de sauter facilement à la partie de la page dont il a besoin.</figcaption></figure><p>La sémantique véhicule également un objectif. Les éléments HTML, comme le dit Jeremy Keith dans son livre Web "<a href="https://resilientwebdesign.com/">Resilient Web Design</a>", sont un <em>vocabulaire de signification</em>. Lorsque vous utilisez partout les bons éléments HTML, cela permet à différentes applications et appareils de transmettre la signification de votre contenu à l'utilisateur afin qu'il sache ce qu'il doit en attendre et comment interagir avec lui.</p><p>Par exemple, lorsque vous utilisez <code>&lt;button&gt;</code> pour créer un bouton, un lecteur d'écran expose ce bouton comme ce qu'il est, et l'utilisateur sait qu'il peut effectuer une action spécifique à l'aide de ce bouton (généralement spécifié à l'aide du nom accessible du bouton) en appuyant sur la touche ESPACE ou sur la touche ENTRÉE. L'élément natif <code>&lt;button&gt;</code> est livré avec toutes les fonctionnalités et l'accessibilité intégrées par défaut.</p><p>Mais si vous n'utilisez <em>pas</em> un <code>&lt;button&gt;</code> pour créer un bouton, et que vous choisissez d'utiliser une <code>&lt;div&gt;</code>, par exemple, à la place, vous perdez toute la sémantique intégrée et l'interactivité du clavier, ce qui rend le bouton complètement inaccessible aux lecteurs d'écran.</p><p>"Mais vous pouvez utiliser les attributs ARIA pour transformer un div en bouton ! N'est-ce pas ?"</p><p>Eh bien, oui et non...</p><h2 id="polyfill">ARIA est un polyfill pour la sémantique HTML</h2>Les attributs ARIA sont probablement l'outil le plus puissant de notre arsenal d'accessibilité. De nombreux attributs ARIA reflètent la sémantique native du HTML, tandis que d'autres fournissent une sémantique qui n'existe pas nativement dans le HTML. Ils ne modifient pas le comportement et n'ajoutent pas de fonctionnalité. Ils ne rendent pas un élément focalisable ou n'ajoutent pas de comportement au clavier, par exemple. Donc, si vous décidez de créer un bouton à partir d'und div, vous devrez ajouter cette fonctionnalité vous-même en utilisant JavaScript. Mais pourquoi créer une implémentation fragile de quelque chose qui vous est déjà fourni par défaut ?<p>La première règle de l'ARIA est la suivante :</p><figure class="quote"><blockquote cite="https://www.w3.org/TR/using-aria/#rule1">
<p>Si vous pouvez utiliser un élément ou un attribut HTML natif avec la sémantique et le comportement dont vous avez besoin <strong>déjà intégrés</strong>, au lieu de réaffecter un élément et d'ajouter un rôle, un état ou une propriété ARIA pour le rendre accessible, <strong>alors faites-le</strong>.</p>
</blockquote>
<figcaption><cite><a href="https://www.w3.org/TR/using-aria/#rule1">2.1 First Rule of ARIA Use</a></cite></figcaption></figure><p>Cependant, même si nous devons privilégier l'utilisation d'éléments HTML natifs chaque fois que possible, il existe certains widgets que nous ne pouvons construire qu'avec l'aide d'ARIA. Par exemple, il n'existe pas d'équivalent HTML natif pour les widgets d'onglet (par exemple, le balisage composé de <code>role=tab</code>, <code>tablist</code> et <code>tabpanel</code>) — avec toute l'interactivité intégrée par défaut, nous pouvons donc créer des onglets en réaffectant d'autres éléments avec ARIA et en les exposant combinés sous forme d'interface utilisateur à onglets aux utilisateurs de lecteurs d'écran (par exemple, <code>role="tab"</code>, <code>role="tablist"</code>, etc.)</p><p>Du fait que l'ARIA modifie fondamentalement la sémantique exposée et les mappages d'accessibilité des éléments, s'il est mal utilisé, il peut avoir des répercussions négatives sur la façon dont le contenu est exposé aux personnes utilisant des technologies d'assistance. <a href="https://www.scottohara.me/">Scott O'Hara</a>, se référant aux <a href="https://www.w3.org/WAI/ARIA/apg/">ARIA Practices Guidelines</a> note :</p><figure class="quote"><blockquote cite="https://www.scottohara.me/">
<p>Le premier principe des pratiques ARIA stipule : "Un rôle est une promesse".</p>
<p>Lorsque vous utilisez ARIA, ou même HTML d'ailleurs, pensez à ce que vous promettez aux personnes qui utilisent votre interface ou consomment vos documents.</p>
<p>Tenez-vous les promesses que vous faites ?</p>
</blockquote>
<figcaption><cite><a href="https://www.scottohara.me/">Scott O'Hara</a></cite></figcaption></figure><p>Avant d'utiliser les attributs ARIA, réfléchissez à ce que vous promettez à vos utilisateurs. Les attributs ARIA affectent directement la manière dont les éléments sont exposés dans l'<a href="https://developer.mozilla.org/fr/docs/Glossary/Accessibility_tree">arbre d'accessibilité</a>, et donc la manière dont ils sont communiqués à vos utilisateurs. Utilisez-les avec sagesse et parcimonie, et assurez-vous que ce que vous avez construit répond aux attentes que vous avez créées pour vos utilisateurs. Si vous avez besoin d'indications sur la façon de les utiliser et de ne <em>pas</em> les utiliser, le document <a href="https://www.w3.org/TR/using-aria/">Using ARIA</a> est un excellent point de départ.</p><figure class="quote"><blockquote cite="https://twitter.com/edinbeth/status/1176161245352927237">
<p>Conseil de @LeonieWatson pour l'accessibilité — il existe environ 147 éléments HTML et seuls deux d'entre eux n'ont pas de fonctions d'accessibilité intégrées — div et span. Utilisez les bons éléments sémantiques autant que possible !</p>
</blockquote>
<figcaption><cite><a href="https://twitter.com/edinbeth">Beth Fraser</a></cite></figcaption></figure><figure class="quote"><blockquote cite="https://twitter.com/codeability/status/1162861059822112770">
<p>Le conseil #a11y le plus simple que j'aie jamais reçu : la div est votre dernier recours. Est-ce votre contenu principal ? Il y a une balise pour ça. Est-ce votre en-tête ? Il y a aussi une balise pour ça. La div n'est pas mauvaise, c'est juste qu'elle ne signifie rien. Ce qui veut dire que vous n'en avez certainement pas besoin pour quelque chose de cliquable !</p>
<p>Partez du principe que votre contenu a une signification spécifique et essayez de trouver la balise correspondant à cette signification. Si ce n'est pas le cas, alors la div (ou le span) est ce qu'il vous faut ! La div a sa place. Cette place n'est pas celle que de nombreux tutoriels voudraient vous faire croire.</p>
</blockquote>
<figcaption><cite><a href="https://twitter.com/codeability">E.J. Mason</a></cite></figcaption></figure><h2 id="javascript">JavaScript est impératif pour créer des composants interactifs personnalisés réellement accessibles</h2><p>Même s'il est possible de créer des composants interactifs "fonctionnels" tels qu'une ouverture de modale en CSS uniquement, ou un <a href="denied:javascript:void(0)">widget de divulgation</a> (<em>disclosure widget</em>) à l'aide du fameux hack de la case à cocher, il est <em>presque</em> toujours garanti que ces composants en CSS uniquement ne sont pas réellement accessibles.</p><p>Lorsque vous créez un widget interactif, il est fort probable que ce widget ait un état (<em>state</em>). Un widget de divulgation est soit "ouvert", soit "fermé" (ou "déployé/rétracté"). Cet état est exposé aux utilisateurs de lecteurs d'écran à l'aide d'attributs ARIA (par exemple, <code>aria-expanded="true/false</code>), et lorsqu'un utilisateur interagit avec le widget, l'état change, et ce changement doit être transmis à l'utilisateur. JavaScript est <em>nécessaire</em> pour ce faire. J'ai fait la paix avec ce fait il y a deux ans lorsque j'ai dû <a href="https://www.sarasoueidan.com/blog/accessible-tooltips/">créer une infobulle accessible</a> pour l'un de mes clients.</p><p>JavaScript est également nécessaire pour ajouter des fonctionnalités de clavier à des composants personnalisés (par exemple, les onglets d'une interface à onglets doivent être nagivables par les touches fléchées, et un widget de divulgation doit pouvoir être utilisé à l'aide des touches ESPACE et ENTRÉE).</p><p>Remarque : même si JavaScript est obligatoire pour créer des composants interactifs personnalisés, afin de vous assurer que votre contenu est accessible à tous les utilisateurs quel que soit leur contexte, vous pouvez, et devriez probablement, dans la mesure du possible, vous assurer qu'ils peuvent consommer ce contenu lorsque JavaScript n'est pas disponible. En fait, vous ne devriez jamais supposer que vos utilisateurs disposeront de JavaScript, car ils pouraient avoir <a href="https://www.kryogenix.org/code/browser/everyonehasjs.html">bien des raisons</a> de ne pas en disposer. C'est pourquoi l'amélioration progressive est la stratégie la plus accessible pour construire pour le Web. J'irais même jusqu'à dire que c'est une exigence, dans certains cas, pour créer des documents et des composants inclusifs.</p><h2 id="progressive-enhancement">L'enrichissement progressif est une stratégie inclusive pour la construction du Web</h2><p>De nombreux développeurs semblent croire, à tort, que si JavaScript est nécessaire pour rendre un composant interactif accessible, alors il est impossible de le construire en utilisant l'amélioration progressive comme approche. Ces développeurs pensent que l'amélioration progressive est anti-JavaScript. C'est une erreur.</p><p>L'amélioration progressive consiste à superposer des couches, en commençant par la base la plus résistante — le HTML sémantique ! — puis en y superposant les styles (CSS) et les fonctionnalités (JavaScript !) selon les besoins.</p><p>L'amélioration progressive permet d'avoir une couche résiliente de contenu qui sera toujours accessible, même si le CSS et/ou le JavaScript sont absents.</p><p>Du jour où j'ai découvert l'amélioration progressive, c'est devenu ma stratégie de prédilection pour la création d'interfaces Web. Je ne peux pas imaginer créer pour le Web d'une autre manière. Et quand j'ai commencé à construire en tenant compte de l'accessibilité, j'ai été convaincue qu'il s'agissait de l'approche la plus sensée pour développer pour le Web.</p><p>Prenons à nouveau l'exemple d'un composant à onglets. Dans un tel composant, vous avez une série d'onglets qui contrôlent leurs panneaux de contenu respectifs. L'utilisateur peut naviguer entre ces panneaux en cliquant sur l'onglet qu'il souhaite. Les onglets nécessitent JavaScript pour être opérationnels et accessibles. Mais que se passe-t-il si JavaScript ne fonctionne pas ? Si les onglets n'ont pas été "améliorés progressivement" — s'ils ont été construits en partant du principe que JavaScript serait toujours présent, alors le composant ne fonctionnera pas et le contenu de tous les panneaux cachés sera totalement inaccessible.</p><p>Mais si vous envisagez ces onglets du point de vue de l'amélioration progressive, vous devrez considérer à quoi ressemblerait leur contenu s'ils avaient été créés uniquement à l'aide de HTML — sans le CSS qui permet de comprendre et d'utiliser l'interface à onglets, et sans le JavaScript qui les fait se comporter comme des onglets typiques.</p><p>Vous pouvez alors considérer les onglets et les panneaux comme une série de sections, chacune ayant un titre et un contenu. Ces sections peuvent avoir ou non une table des matières en haut. Il s'agit de la "vue" par défaut, et c'est ce que l'utilisateur obtient par défaut lorsque le JavaScript ne fonctionne pas.</p><figure role="group"><img src="https://la-cascade.io/images/tabs-1.png" alt="Illustration d'une série de sections enrichie d'une interface à onglets" /><figcaption>Un composant d'onglets peut être enrichi d'une série de sections, chacune ayant un titre et un contenu connexe</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/tabs-2.png" alt="Illustration d'une série de sections précédées d'une table des matières enrichie d'une interface à onglets" /><figcaption>Un composant d'onglets peut également être enrichi d'une série de sections, chacune comportant un titre et un certain contenu connexe, une table des matières précédant ces sections</figcaption></figure><p>Ensuite, lorsque le JavaScript s'exécute, vous pouvez améliorer ces sections en modifiant leur disposition et leur affichage, et en ajoutant l'interactivité requise. La façon dont je procéderais est que j'ajouterais probablement un hook de style que je souhaite dans le balisage, puis je l'utiliserais pour modifier la disposition de mes sections en sachant que le JavaScript a été exécuté et que les onglets seront exploitables et interactifs.</p><p>Lorsque vous <a href="https://www.deque.com/shift-left/">déplacez l'accessibilité à gauche</a> de votre processus, l'utilisation de l'amélioration progressive comme stratégie de développement prend encore plus de sens. Pratiquement tous les composants interactifs non natifs que j'ai construits au cours de l'année écoulée ont été améliorés à partir d'un composant non interactif de base. Commencez par HTMl. Utilisez tout ce qu'il a à offrir pour fournir une expérience de base accessible. Améliorez ensuite avec CSS et JavaScript lorsqu'ils sont disponibles.</p><figure class="quote"><blockquote cite="https://www.kryogenix.org/">
<p>Amélioration progressive. Parce que parfois, votre JavaScript ne fonctionne tout simplement pas.</p>
<p>Soyez prêt.</p>
</blockquote>
<figcaption><cite><a href="https://www.kryogenix.org/">@sil</a></cite></figcaption></figure><p>L'une des façons les plus courantes de démolir la sémantique est de la dériver du design visuel. Car le design visuel ne décrit pas toujours le <em>type</em> de contenu qu'elle représente.</p><p>Les titres en sont un parfait exemple. Lors d'une <a href="https://www.youtube.com/watch?v=are7ZZgA86I&amp;list=PLe9psSNJBf74yYiVXDXz8UnRnWf3NHzS-&amp;index=6">récente conférence</a>, j'ai montré un exemple tiré de l'un de mes derniers projets client, où la page était conçue de telle manière qu'un titre principal pour la page était apparemment inexistant, alors qu'en fait il ne l'était pas. Il n'était simplement pas stylisé comme le serait normalement un grand titre de niveau 1.</p><figure role="group"><img src="https://la-cascade.io/images/codrops-heading.png" alt="Capture d'écran de la page montrant comment le titre principal de la page n'est pas visuellement stylé comme un titre principal." /><figcaption>Le titre principal de la page qui décrit le contenu de la section principale de la page est positionné et stylisé d'une manière qui dissimule (involontairement) le fait qu'il s'agit d'un titre principal. Même s'il est stylisé comme un titre de niveau 6, il est implémenté comme un titre de niveau 1 dans le balisage pour représenter ce qu'il est réellement.</figcaption></figure><p>En réfléchissant à la structure du document et aux attentes des utilisateurs de lecteurs d'écran, je savais que la page devait avoir un titre principal. J'avais dû fournir un titre pour les utilisateurs de lecteurs d'écran pour certaines autres pages où un titre était visuellement absent mais, dans ce cas particulier, le titre était déjà là, il était juste stylisé pour avoir une apparence différente. Il <em>semblait</em> donc que la page n'avait pas de titre principal, mais en réalité elle en avait un.</p><p>En regardant la page du point de vue de l'accessibilité et en gardant à l'esprit la couche HTML — sémantique et structure, j'ai changé ma façon de voir la page, et j'ai fondamentalement changé la façon dont j'ai fini par la coder.</p><p>L'apparence d'un composant ou d'un élément ne dit pas ce qu'il l'est. Et ce n'est pas parce qu'il n'a pas une certaine apparence qu'il n'est pas ce qu'il est.</p><p>Il en va de même pour les modèles d'interface utilisateur interactive. Le même modèle peut créer une expérience différente selon le contexte dans lequel il se trouve. Souvent, le contexte définit le comportement d'un modèle, l'expérience de l'utilisateur, ce qui, à son tour, détermine la sémantique sous-jacente et l'implémentation.</p><p>Dans ce même projet que je viens de mentionner, il y avait un modèle d'interface utilisateur apparemment simple qui s'est avéré être un défi intéressant pour l'UX et l'accessibilité. L'image suivante est une capture d'écran de ce composant :</p><figure role="group"><img src="https://la-cascade.io/images/codrops-video-player.png" alt="Capture d'écran du composant Lecteur vidéo" /><figcaption>Le composant "Vidéos mises en avant" de mon récent projet client présente une vidéo sur la gauche avec une liste de lecture de vidéos sur la droite. En cliquant sur l'un des titres de la vidéo de droite, la vidéo de gauche est chargée, mais pas en lecture automatique. (Notez que le contenu de cette capture d'écran est factice).</figcaption></figure><p>Pour implémenter ce lecteur vidéo, j'avais besoin de savoir comment il fonctionnait, afin de pouvoir le baliser de manière à transmettre correctement sa sémantique et sa fonctionnalité aux lecteurs d'écran.</p><p>Même si la liste de titres de vidéos sur la droite ressemble à une liste de liens, ce n'est pas vraiment une <em>liste</em>, ni même des <em>liens</em>, car un lien est censé vous mener quelque part, mais ces "liens" ne le font pas. En fait, en cliquant sur un titre de vidéo, celle-ci est chargée dans le lecteur de gauche. Il s'agit donc d'un élément interactif qui effectue une action et qui n'est pas un lien. Par conséquent, et même si leur apparence ne le montre pas, ces titres sont en fait des <em>boutons</em>.</p><p>Ensuite, il y avait la question de savoir ce qui se passe lorsqu'on clique sur un titre. La vidéo se met-elle en lecture automatique ? Si c'est le cas, alors le bouton devrait probablement aussi mettre la vidéo en pause, ce qui en fait une sorte de bouton à bascule (<em>toggle</em>). Mais si vous lancez ou mettez en pause une vidéo à partir du bouton de titre, vous devriez associer ce bouton aux boutons de lecture/pause dans la vidéo elle-même, ce qui peut être un défi, car la vidéo pourrait être une vidéo Youtube, ou Vimeo, ou auto-hébergée. Et si vous ne faites pas de lecture automatique de la vidéo, devez-vous déplacer le focus vers l'iframe après avoir cliqué sur le bouton ?</p><p>Après avoir examiné l'interface utilisateur prévue et testé avec des lecteurs d'écran, j'ai fini par l'implémenter en tant que composant à onglets, tous les onglets contrôlant le seul panneau contenant la vidéo.</p><p>Je n'avais jamais pensé à une interface à onglets avec plusieurs onglets contrôlant le même panneau auparavant. Mais le contexte de ce composant et l'UX de celui-ci ont déclenché un train de pensées et de considérations UX qui ont conduit à l'implémentation finale.</p><p>L'une des choses que j'ai apprises de ce composant est donc que l'expérience utilisateur (UX) détermine la mise en œuvre. ARIA est livré avec de nombreux attributs qui nous permettent de créer différents modèles d'interface utilisateur dans différents contextes, et parfois, il suffit de modifier un peu le modèle pour qu'il fonctionne dans le contexte dans lequel il se trouve.</p><figure class="quote"><blockquote cite="https://twitter.com/rikschennink/status/1166771758684356608">
<p>Il est étrange que nous dérivions encore la sémantique d'un design visuel au lieu de l'inverse.</p>
<p>Le design visuel est différent selon le contexte, alors que la sémantique de base ne l'est pas.</p>
</blockquote>
<figcaption><cite><a href="https://twitter.com/rikschennink">Rik Schennink</a></cite></figcaption></figure><h2 id="techniquement-accessible">Ce n'est pas parce que c'est techniquement accessible que c'est inclusif</h2><p>Vous pouvez construire quelque chose de techniquement accessible mais qui n'en est pas pour autant inclusif. Cet élément ou ce composant peut avoir tous les boutons que vous voulez et vous pouvez peut-être y naviguer à l'aide d'un clavier et l'utiliser avec un lecteur d'écran, mais <em>avez-vous vraiment pris en compte les besoins et les attentes de votre utilisateur</em> lorsque vous avez décidé comment et avec quoi cet élément devait être exposé et interagir ?</p><p>Dans sa présentation "<a href="https://feather.ca/inclusion/aea2019/">Inclusive by Design</a>", Derek Featherstone, défenseur de l'accessibilité et designer, raconte comment lui et son équipe ont construit un lecteur vidéo accessible pour une organisation qui leur avait passé un contrat. Le lecteur vidéo comportait de nombreux boutons et son accessibilité technique a été testée au cours de nombreuses phases.</p><p>Mais lorsque le moment est venu de faire tester le composant par des utilisateurs souffrant de différents handicaps, ils ont réalisé que, même s'ils avaient construit le lecteur vidéo accessible parfait, ce lecteur vidéo n'était pas vraiment inclusif — il lui manquait certaines fonctionnalités qui facilitaient l'utilisation du lecteur pour un groupe d'utilisateurs, comme un bouton de retour en arrière ou d'avance rapide. Derek et son équipe avaient également fait des hypothèses sur la façon dont tous les utilisateurs utiliseraient le lecteur vidéo, et avaient oublié les utilisateurs qui connaissaient une ancienne version d'un lecteur d'écran et qui manquaient donc des annonces importantes, censées les aider à utiliser le lecteur vidéo. Ainsi, après plusieurs itérations et tests avec divers utilisateurs, ils ont fini par ajouter des fonctionnalités au lecteur vidéo qui prenaient en compte beaucoup plus de handicaps, et les attentes que ces utilisateurs auraient du lecteur, ce qui l'a rendu beaucoup plus inclusif et a énormément amélioré son expérience utilisateur.</p><p>L'exposé de Derek est rempli de bons exemples qui soulignent l'importance d'<strong>inclure vos utilisateurs dès le début du processus de conception</strong> et de veiller à ce que vous adoptiez la diversité par défaut. L'idée est que si vous concevez quelque chose pour moi, je devrais avoir un moyen raisonnablement significatif de participer à cette chose. Je devrais y être représenté d'une manière ou d'une autre.</p><figure class="quote"><blockquote cite="">
<p>Rien sur nous, sans nous.</p>
</blockquote>
<figcaption><cite><a href="">Michael Masutha</a></cite></figcaption></figure><h3 id="en-fin-de-compte">En fin de compte, il s'agit <em>toujours</em> de l'utilisateur</h3><p>À mesure que vous développez en tenant compte des expériences réelles des utilisateurs et de l'inclusivité, vous vous rendrez vite compte qu'un pattern de design peut être construit de plus d'une façon. Et il y a pas mal d'éléments dans la conception accessible qui sont le résultat d'une opinion.</p><p>Les fenêtres modales en sont un excellent exemple. Passons sur le fait qu'il s'agit d'un pattern d'interface utilisateur ennuyeux, la façon dont ils doivent être mis en œuvre et le comportement qu'ils doivent adopter une fois ouverts font l'objet de nombreuses discussions : Faut-il mettre le focus sur le premier élément focalisable à l'intérieur de la modale ? Que se passe-t-il s'il n'y a pas d'élément focalisable ? Que se passe-t-il si le premier élément focalisable est le bouton de fermeture ? Voudriez-vous que l'ouverture de la modale invite à une action de fermeture dès qu'elle est ouverte ? (bien sûr que non). Que se passe-t-il si le premier élément focalisable est un champ de saisie demandant à l'utilisateur son adresse électronique ? Est-il approprié d'inviter l'utilisateur à fournir ses informations personnelles sans contexte préalable ? (Là encore, bien entendu, non.)</p><p>En fin de compte, quelle que soit la décision que vous prenez, elle doit toujours concerner l'utilisateur. Il est donc essentiel d'impliquer l'utilisateur et/ou une équipe plus diversifiée dans le processus de design et de développement pour créer des interfaces Web véritablement inclusives.</p><p>Mais que faire si vous ne pouvez pas ? Et si vous n'avez pas accès à un tel environnement ou à une telle équipe ? Et si, comme moi, vous êtes un développeur solitaire qui rejoint souvent des équipes dans lesquelles ne participent généralement pas d'utilisateurs ou de personnes handicapées ?</p><h2 id="doute">En cas de doute, demandez de l'aide</h2><p>Si vous ne pouvez pas le faire vous-même, vous pouvez demander l'expérience et les conseils d'autres personnes qui le peuvent. Et il est très important que vous soyez ouvert aux commentaires constructifs.</p><p>Il existe dans notre domaine un grand nombre de merveilleux (et parfois grincheux, à juste titre) experts en accessibilité qui veulent que le Web soit et devienne plus accessible. La plupart d'entre eux font un travail gratuit comme donner des conseils gratuits et partager leurs précieuses connaissances sous diverses formes écrire des articles et des livres, réaliser des cours vidéo, donner des conférences et des ateliers, etc. Et nous pouvons apprendre beaucoup d'eux. Et la plupart d'entre eux accueillent volontiers les questions et les demandes (payantes ou non).</p><p>Certains de mes experts préférés sont (sans ordre particulier) :</p><ul><li><a href="https://tink.uk/">Leonie Watson</a></li>
<li><a href="https://feather.ca/">Derek Featherstone</a></li>
<li><a href="https://www.scottohara.me/">Scott O'Hara</a></li>
<li><a href="https://marcysutton.com/">Marcy Sutton</a></li>
<li><a href="https://www.youtube.com/channel/UCJAtIv92EJqzG2EOzo92sdQ">Rob Dodson</a></li>
<li><a href="https://twitter.com/sundress">Alice Boxhall</a></li>
<li><a href="https://ericwbailey.design/">Eric Bailey</a></li>
<li><a href="https://twitter.com/stevefaulkner">Steve Faulkner</a></li>
<li><a href="https://www.tpgi.com/">Le groupe Paciello</a></li>
</ul><p>Il serait bon de passer un peu de temps à lire les spécifications et les lignes directrices ARIA, et d'essayer de vous familiariser avec autant de choses que possible sur l'accessibilité, avant de demander de l'aide. Après tout, ces personnes bienveillantes sont peut-être en mesure de nous aider, mais elles ne devraient pas avoir à faire notre travail à notre place — du moins pas gratuitement.</p><h2 id="derniers-mots">Derniers mots</h2><p>L'accessibilité n'est pas facile. Et souvent, elle est carrément difficile. Mais cela vient avec le territoire. Concevoir pour les humains est difficile. Et l'accessibilité est, en fin de compte, tout sur et tout <em>pour</em> les humains.</p><p>Il se peut que nous n'y arrivions pas complètement et qu'il y ait toujours moyen de s'améliorer, surtout si davantage d'utilisateurs se servent de nos produits et consomment notre contenu, mais je sais une chose : cela ne doit jamais nous décourager. Presque tout peut être amélioré d'une manière ou d'une autre. Le plus important est d'être ouvert aux commentaires et d'être suffisamment empathique pour se soucier de nos utilisateurs et faire de notre mieux pour leur faciliter la vie avec les outils (puissants) que nous avons à notre disposition.</p><p>Utilisez le HTML. Améliorez avec CSS. Exploitez la puissance de JavaScript. Et incluez vos utilisateurs dans votre processus de conception le plus tôt possible. Et regardez toujours votre travail à travers le prisme de l'inclusion. Cela vous mènera loin devant. Alors apprenez davantage, itérez et améliorez. Et n'oubliez pas que <a href="https://uxmag.com/articles/were-just-temporarily-abled">nous sommes tous temporairement valides</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite</link>
      <guid>https://la-cascade.io/articles/une-annee-a-apprendre-et-enseigner-laccessibilite</guid>
      <pubDate>Mon, 30 Jan 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Un monde de possibilités nouvelles avec CSS :has()]]></title>
      <description><![CDATA[<p><em>Le sélecteur relationnel CSS nous offre ce qui était auparavant impossible sans JavaScript. Nous examinerons comment combiner :has() avec d'autres sélecteurs CSS et les pouvoirs magiques qu'il apporte.</em></p><div class="articleContent"><p>L'utilisation de <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:has">la pseudo-classe :has()</a> nous permet de "regarder en avant" avec CSS et de styliser un élément parent ou ancêtre. Nous pouvons ensuite élargir le sélecteur pour cibler un ou plusieurs éléments frères ou enfants. En utilisant l'état ou la position des éléments, nous pouvons styliser pratiquement n'importe quelle combinaison d'éléments comme des éléments uniques ou des plages.</p><p class="is-style-explanation"><a href="https://caniuse.com/css-has" class="noteLink">La compatibilité de :has()</a> s'améliore rapidement, :has() est disponible depuis Safari 15.4 et Chrome/Edge 105. Elle se cache également derrière un drapeau dans Firefox à partir de la <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1771896" class="noteLink">version 103</a>. Jusqu'à ce que la prise en charge complète soit disponible, consultez <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1771896" class="noteLink">ce conseil de Bramus Van Damme</a> sur la prise en charge de :has() aujourd'hui.</p><h2>Comment :has() fonctionne avec les combinateurs et les pseudo-classes</h2><p>Pour mieux comprendre le fonctionnement des sélecteurs avancés que nous allons créer, nous allons passer rapidement en revue les combinateurs et les pseudo-classes les plus pertinents.</p><p>Un "combinateur" est un caractère spécial qui désigne le type de relation entre les parties du sélecteur. Voici les principaux <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css">combinateurs</a> à connaître :</p><ul><li>caractère espace : le <strong>combinateur descendant</strong> correspond à un enfant direct ou imbriqué ;</li>
<li><code>&gt;</code> : le <strong>combinateur d'enfant direct</strong> correspond uniquement aux enfants de niveau supérieur, non imbriqués ;</li>
<li><code>+</code> : le <strong>combinateur de frère ou sœur adjacent(e)</strong> ne correspond qu'au frère ou sœur le plus proche ;</li>
<li><code>~</code> : le <strong>combinateur sibling général</strong> correspond à un ou plusieurs frères et sœurs suivant le sélecteur de base.</li>
</ul><p>La première étape de la création de sélecteurs complexes consiste à ajouter une <a href="https://la-cascade.io/tags/pseudo-classes">pseudo-classe</a> en une ou plusieurs parties. Une "pseudo-classe" définit un état spécial d'un élément, comme <code>:hover</code>, et a le format d'un simple deux-points suivi du nom. La pseudo-classe <code>:has()</code> est appelée <em>fonctionnelle</em> car elle accepte un argument. Plus précisément, elle accepte comme argument une liste de sélecteurs, qu'ils soient simples comme <code>img</code> ou complexes avec des combinateurs comme <code>img + p</code>.</p><p><code>:has()</code> est l'une des quatre pseudo-classes fonctionnelles, les autres étant <code>:is()</code>, <code>:where()</code> et <code>:not()</code>. Chacune prend une liste de sélecteurs ainsi que quelques autres caractéristiques uniques.</p><p>Si vous avez déjà utilisé <code>:is()</code> et <code>:where()</code>, c'était probablement pour gérer la spécificité. L'utilisation de <code>:is()</code> signifie que le sélecteur de la liste ayant la spécificité la plus élevée donne son poids à l'ensemble du sélecteur. L'utilisation de <code>:where()</code> quant à elle confère à l'ensemble de la liste de sélecteurs une spécificité nulle, ce qui permet aux règles ultérieures de la cascade de l'ignorer.</p><p>Par ailleurs, <code>:is()</code> et <code>:where()</code> ont la capacité spéciale d'être des sélecteurs <em>indulgents</em>, ce qui signifie que vous pouvez inclure (volontairement ou non) des sélecteurs que le navigateur ne comprend pas, et il traitera quand même les parties qu'il comprend. Sans ce comportement indulgent, le navigateur rejetterait la règle entière.</p><p>L'autre avantage de <code>:is()</code> et de <code>:where()</code> est de créer des sélecteurs succincts et complexes. C'est particulièrement pratique lorsque vous utilisez des combinateurs et que vous affectez plusieurs frères et sœurs ou descendants, par exemple, <code>article :is(h1, h2, h3)</code>.</p><p>Notre dernière pseudo-classe, <a href="https://la-cascade.io/articles/sur-not-et-la-specifite">:not()</a>, est disponible depuis plus longtemps. Toutefois, parallèlement aux sélecteurs de niveau 4, lorsque <code>:is()</code> et <code>:where()</code> ont été publiés, <code>:not()</code> <a href="https://www.w3.org/TR/selectors-4/#negation">a été améliorée</a>. Elle a été autorisée à accepter une <em>liste de sélecteurs</em> au lieu d'un seul sélecteur. Elle a également le même comportement de spécificité que <code>:is()</code>.</p><p>Enfin, nous devons connaître une fonctionnalité sous-utilisée et incroyablement puissante de <code>:is()</code>, <code>:where()</code> et <code>:not()</code>, que nous utiliserons pour créer nos sélecteurs <code>:has()</code> avancés. L'utilisation du caractère <code>*</code> dans ces sélecteurs — qui, normalement, en CSS, est le "sélecteur universel" — <strong>fait référence à la cible du sélecteur</strong>. Cela permet de vérifier les frères et sœurs ou les ancêtres précédents de la cible du sélecteur. Par exemple, dans <code>img:not(h1 + *)</code>, nous sélectionnons les images qui ne suivent pas directement un <code>h1</code>. Et dans <code>p:is(h2 + *)</code>, nous sélectionnons les paragraphes uniquement s'ils suivent directement un <code>h2</code>. Nous allons utiliser ce comportement pour notre première démo à venir.</p><h2>Polyfill pour le sélecteur <code>:only-of-type</code></h2><p><a href="https://developer.mozilla.org/fr/docs/Web/CSS/:only-of-type"><code>:only-of-type</code></a> est une pseudo-classe valide, (NdT : elle est décrite ainsi dans MDN : <em>La pseudo-classe <code>:only-of-type</code> permet de cibler un élément qui ne possède aucun nœud frère du même type au sein d'un même élément parent</em>). À partir du HTML ci-dessous...</p><pre class="language-html">&lt;p&gt;Not highlighted&lt;/p&gt;
&lt;p class="highlight"&gt;.highlight&lt;/p&gt;
&lt;p&gt;Not highlighted&lt;/p&gt;</pre><p>...avec le CSS <code>.highlight:only-of-type</code>, aucune correspondance ne serait faite parce que la classe n'a aucun effet sur la <em>réduction de la portée (scope)</em>.</p><p>Si le paragraphe porteur de la classe <code>highlight</code> était le seul paragraphe à l'intérieur de son parent, on pourrait croire que ça fonctionne. Mais ce serait une illusion car, dans ce cas, ce serait uniquement parce que le type d'élément racine auquel la classe est attachée est un paragraphe, donc il correspond comme vrai puisqu'il n'y a pas de paragraphes frères.</p><p><code>:has</code> nous permet de résoudre ce problème. En combinant <code>:has()</code> et <code>:not()</code>, nous pouvons effectivement créer un sélecteur <code>:only-of-selector</code> qui fera correspondre un singleton dans une plage de frères et sœurs basée sur une classe ou un autre sélecteur valide.</p><p>En fin de compte, nous voulons que notre sélecteur trouve une correspondance lorsqu'il n'existe aucun frère ou sœur correspondant avant ou après la cible.</p><p>Une force de <code>:has()</code> est de <em>tester ce qui suit un élément</em>. Ici, nous voulons tester un nombre quelconque de frères et sœurs qui suivent, nous utiliserons donc le combinateur général de frères et sœurs <code>~</code> pour créer la première condition.</p><pre class="language-css">.highlight:not(:has(~ .highlight)</pre><p>Jusqu'à présent, cela nous donne la correspondance de "classe highlight qui n'a pas de classe highlight sœur qui la suit".</p><p>Maintenant, nous devons vérifier les frères et sœurs précédents, et nous allons utiliser la capacité de <code>:not()</code> pour ajouter cette condition.</p><pre class="language-css">.highlight:not(:has(~ .highlight)):not(.highlight ~ *)</pre><p>La deuxième condition <code>:not()</code> ajoute une clause ET à notre sélecteur qui dit "ET pas lui-même un frère ou une sœur d'une highlight précédente".</p><p>Avec cela, nous avons polyfillé la pseudo-classe inexistante <code>:only-of-selector</code> !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/qByprrp">:only-of-selector using :has()</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><h2>Sélecteur de frères et sœurs précédents</h2><p>Nous avons parlé de la vérification des frères et sœurs <em>précédents</em> avec <code>:not()</code>, <code>:is()</code> et <code>:where()</code>. Avec <code>:has()</code>, nous pouvons en fait sélectionner et styliser les frères et sœurs <em>précédents</em> en fonction des conditions de ce qui vient <em>après eux</em> !</p><p>Pour démontrer cela, nous allons créer une liste d'éléments. Le comportement que nous souhaitons est le suivant : lorsqu'un élément de la liste est survolé, il s'agrandit et les éléments qui le précèdent et le suivent s'agrandissent également légèrement. Les autres éléments de liste non survolés doivent être réduits. L'opacité de tous les éléments de la liste, à l'exception de l'élément survolé, doit également être réduite. La vidéo suivante présente un aperçu de l'effet.</p><iframe src="https://player.vimeo.com/video/791142059?h=188ae0782a" width="800" height="472" frameborder="0" allowfullscreen="allowfullscreen"> </iframe><p><em><a href="https://vimeo.com/791142059">Previous/next list preview</a> from <a href="https://vimeo.com/smashingmagazine">Smashing Magazine</a> on <a href="https://vimeo.com">Vimeo</a></em>.</p><p>Le premier sélecteur doit correspondre à l'élément de la liste qui précède celui qui est survolé, ce que <code>:has()</code> rend possible. Le CSS qui suit se lit : "sélectionner l'élément liste dont le frère adjacent est survolé".</p><pre class="language-css">li: has(+ li: hover);</pre><p>Nous allons coupler cela avec un sélecteur de base de frère ou sœur adjacent pour obtenir également l'élément liste suivant celui qui est survolé, puis appliquer nos styles :</p><pre class="language-css">/* Sélectionne l'élément liste avant celui qui est survolé */
li:has(+ li:hover),
/* Sélectionner l'élément liste après l'élément survolé */
li:hover + li {
  /* ...modifier l'échelle et l'opacité */
}</pre><p>Le troisième sélecteur complexe que nous allons créer utilise notre combinaison de <code>:has()</code> et <code>:not()</code> mais d'une nouvelle manière. Nous qualifions d'abord le sélecteur pour qu'il ne s'applique que lorsqu'un enfant direct de l'<code>ul</code> (qui sera un élément liste) est survolé. Et si c'est le cas, nous sélectionnons les éléments de la liste en excluant celui qui est survolé et les éléments avant et après celui qui est survolé.</p><pre class="language-css">/* Lorsqu'un élément de liste est survolé,
sélectionner les éléments de la liste non survolés, ou avant/après le survol */
ul:has(&gt; :hover) li:not(:hover, :has(+ :hover), li:hover + *) {
  /* ...modifier l'échelle et l'opacité */
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/rNrpymj">Previous/Next Sibling Animation with :has()</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><p>Ceci nous montre non seulement la sélection d'un frère ou d'une sœur précédent(e) avec <code>:has()</code> mais aussi son utilisation pour sélectionner en fonction de l'état (state). La démo finale créera un exemple plus complexe en utilisant les états avec <code>:has()</code>.</p><p>D'autres personnes ont exploré des exemples similaires de sélection et d'application de frères et sœurs précédents, notamment <a href="https://codepen.io/chriscoyier/pen/qBoogaX">Chris Coyier</a>, <a href="https://codepen.io/pouriversal/pen/yLvdwQW">pourya</a> et <a href="https://blog.jim-nielsen.com/2022/previous-sibling-selector/">Jim Nielsen</a>.</p><h2>Sélection à l'intérieur d'une plage</h2><p>Considérons maintenant une plage d'éléments frères et sœurs, comme entre <code>h2</code> ou entre <code>hr</code>.</p><pre class="language-html">&lt;article&gt;
  &lt;h2&gt;Lorem, ipsum.&lt;/h2&gt;
  &lt;!-- h2 range starts --&gt;
  &lt;p&gt;Lorem ipsum, dolor sit amet consectetur adipisicing elit.&lt;/p&gt;
  &lt;p&gt;
    Nobis iusto voluptates reiciendis molestias, illo inventore ipsum?
  &lt;/p&gt;
  &lt;!-- h2 range ends --&gt;
  &lt;h2&gt;Lorem, ipsum dolor.&lt;/h2&gt;
  &lt;p&gt;Lorem ipsum dolor sit amet.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;!-- hr range starts --&gt;
  &lt;p&gt;Lorem ipsum dolor sit.&lt;/p&gt;
  &lt;p&gt;Dolor animi nisi ut?&lt;/p&gt;
  &lt;p&gt;Sunt consectetur esse quia.&lt;/p&gt;
  &lt;!-- hr range ends --&gt;
  &lt;hr /&gt;
  &lt;p&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit.&lt;/p&gt;
&lt;/article&gt;</pre><p>En utilisant :has() nous pouvons styliser :</p><ul><li>Le premier élément de la plage,</li>
<li>Le dernier élément de la plage,</li>
<li>tous les éléments frères et sœurs de la plage.</li>
</ul><p>Ces sélecteurs s'appuient fortement sur le combinateur général <code>~</code>, qui nous permet à la fois de "regarder vers l'avant" et de styliser plusieurs frères et sœurs à la fois.</p><h3>Sélectionner le premier élément de la plage</h3><p>Le CSS qui suit se lit ainsi : "sélectionner le frère ou la sœur adjacent(e) du <code>h2</code> tant qu'il existe un autre <code>h2</code> comme frère ou sœur ultérieur(e)", ce qui correspond au paragraphe suivant directement le premier <code>h2</code> dans notre exemple HTML.</p><pre class="language-css">article h2 + :has(~ h2)</pre><h3>Sélectionner le dernier élément de la plage</h3><p>Le CSS qui suit se lit ainsi : " sélectionner un élément qui suit un <code>h2</code> tant que son frère ou sa sœur suivant(e) est un <code>h2</code>", ce qui correspond au paragraphe qui précède directement le deuxième <code>h2</code> dans notre exemple HTML.</p><pre class="language-css">article h2 ~ :has(+ h2)</pre><h3>Sélectionner tous les frères et sœurs dans une plage</h3><p>Le sélecteur suivant est limité en ce sens qu'il ne fonctionne que pour <em>une seule</em> plage au sein d'un parent. En effet, lorsqu'on utilise le combinateur général de frères et sœurs sans indiquer de limite, ces frères et sœurs peuvent se trouver n'importe où après l'élément. On peut donc "sauter" d'autres éléments qui pourraient se trouver entre eux, ce qui a pour effet une plage étendue pour ce sélecteur.</p><p>Cela peut être utile si l'on est certain de n'avoir qu'un seul éventail de possibilités au sein d'un parent donné. Ce sélecteur se lit comme suit : "sélectionner tous les éléments frères et sœurs qui suivent un <code>hr</code> et qui ont eux-mêmes un frère et une sœur ultérieurs d'un <code>hr</code>", ce qui correspond aux trois paragraphes entre les éléments <code>hr</code> dans notre exemple HTML.</p><pre class="language-css">article hr ~ :has(~ hr)</pre><p>Nous verrons bientôt comment fixer une limite à notre plage et comment autoriser les groupes à plages multiples dans un seul parent.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/KKBZWqd">Select within an element range with :has() (limited)</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><h2>Sélection d'une seule plage complète</h2><p>Dans la série de sélecteurs suivante, nous supposerons que nous avons un élément d'identification supplémentaire à utiliser pour établir le début et la fin de notre plage. Pour les besoins de la démonstration, nous avons une liste où deux éléments de liste ont l'attribut <code>data-range</code>. Cette technique fonctionnerait pour visualiser la fonctionnalité de sélection multiple pour un contrôle personnalisé afin d'afficher la plage des éléments dans la sélection.</p><pre class="language-html">&lt;ul&gt;
  &lt;li&gt;Lorem&lt;/li&gt;
  &lt;li data-range&gt;Veritatis&lt;/li&gt;
  &lt;li&gt;Eos&lt;/li&gt;
  &lt;li&gt;Debitis&lt;/li&gt;
  &lt;li&gt;Autem&lt;/li&gt;
  &lt;li data-range&gt;Atque&lt;/li&gt;
  &lt;li&gt;Eius&lt;/li&gt;
  &lt;li&gt;Lorem&lt;/li&gt;
  &lt;li&gt;Nostrum&lt;/li&gt;
&lt;/ul&gt;</pre><p>Nous avons utilisé un attribut <code>data</code> pour signifier le début et la fin, cependant nous supposons qu'aucune valeur d'attribut n'a été fournie. Gardons cela à l'esprit lorsque nous examinerons la construction des sélecteurs d'éléments de début et de fin.</p><p>Pour sélectionner à la fois le début et la fin de la plage, nous pouvons simplement utiliser le sélecteur d'attribut <code>[data-range]</code>.</p><p>Ensuite, nous pouvons réutiliser le sélecteur que nous venons de créer dans la section précédente pour sélectionner tous les frères et sœurs dans la plage.</p><pre class="language-css">[data-range]~: has(~[data-range]);</pre><p>Pour styliser l'élément de plage de départ, le CSS qui suit se lit : "sélectionnez l'élément <code>[data-range]</code> qui a un frère ou une soeur <code>[data-range]</code> quelque part après lui" :</p><pre class="language-css">[data-range]: has(~[data-range]);</pre><p>Et enfin, pour sélectionner l'élément final de la plage, le CSS qui suit se lit : "sélectionnez un élément de <code>[data-range]</code> qui suit quelque part un élément de <code>[data-range]</code>".</p><pre class="language-css">[data-range] ~ [data-range]</pre><p>Dans cette démo CodePen, nous avons également réutilisé nos sélecteurs précédemment créés pour identifier le premier et le dernier élément de la plage.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/RwBxpgq">Single range element selectors with :has()</a><a href="https://codepen.io">CodePen</a></div><h2>Sélection de groupes de plages multiples</h2><p>Maintenant, nous allons poursuivre notre démo et résoudre le problème de la sélection de plages multiples.</p><p>Auparavant, notre problème était qu'un <code>h2</code> ou un <code>hr</code> dans une série de plus de deux ne nous donnait aucun moyen de déterminer les limites de chacune des plages.</p><p class="is-style-explanation">La clé pour rendre possible les groupes à plages multiples au sein d'un seul parent est la disponibilité d'indicateurs de début et de fin distincts.</p><p>Nous utiliserons à nouveau des attributs de données sur nos éléments de liste, mais cette fois, nous leur donnerons les valeurs réelles de "start" et "end".</p><pre class="language-html">&lt;ul&gt;
  &lt;li&gt;Lorem&lt;/li&gt;
  &lt;li data-range="start"&gt;Veritatis&lt;/li&gt;
  &lt;li&gt;Eos&lt;/li&gt;
  &lt;li&gt;Debitis&lt;/li&gt;
  &lt;li&gt;Autem&lt;/li&gt;
  &lt;li data-range="end"&gt;Atque&lt;/li&gt;
  &lt;li&gt;Eius&lt;/li&gt;
  &lt;li&gt;Lorem&lt;/li&gt;
  &lt;li&gt;Nostrum&lt;/li&gt;
&lt;/ul&gt;</pre><p>Maintenant que nous avons fourni des valeurs d'attributs explicites, nos sélecteurs de début et de fin sont assez basiques :</p><pre class="language-html">/* Éléments de début et de fin de plage */ [data-range] /* Élément de
départ d'une plage */ [data-range="start"] /* Élément de fin d'une
plage */ [data-range="end"]</pre><p>Allons-y et marquons le premier et le dernier élément de la plage. La première modif par rapport aux versions précédentes consiste à inclure les valeurs des attributs de données de début et de fin. Deuxièmement, nous avons ajouté la condition que le style ne soit pas appliqué à nos indicateurs de début/fin avec la condition d'exclusion <code>:not([data-range]</code>).</p><pre class="language-html">/* Premier élément à l'intérieur de la plage */ [data-range="start"] +
:has(~ [data-range="end"]):not([data-range]) /* Dernier élément à
l'intérieur de la plage */ [data-range="start"] ~ :has(+
[data-range="end"]):not([data-range])</pre><p>Enfin, notre sélecteur doit faire correspondre les éléments à l'intérieur de notre plage. Au départ, il est similaire à ce que nous avons créé précédemment pour les sélecteurs "à l'intérieur de la plage". Une fois encore, nous ajoutons la condition selon laquelle il ne doit pas correspondre à un élément qui est lui-même une <code>[data-range]</code>.</p><pre class="language-css">[data-range="start"] ~ :has(~ [data-range="end"]):not([data-range])</pre><p>Mais si vous vous souvenez, j'ai mentionné que le sélecteur général de frères et sœurs a la capacité de "sauter", donc pour l'instant, ce sélecteur va styliser les éléments en dehors de la limite de notre plage prévue. L'image montre comment la règle fonctionne sans autres restrictions.</p><figure><img src="https://la-cascade.io/images/out-of-range-styles.webp" alt="La liste des éléments a une plage et quelques éléments au milieu, et le début d'une autre plage. Le sélecteur précédent tente d'appliquer une couleur d'arrière-plan aux éléments d'une plage, mais comme le montrent les étiquettes au-dessus de l'image, la couleur d'arrière-plan s'applique à l'intérieur de la plage mais elle est également ajoutée aux éléments situés entre les plages." /></figure><p>Pour résoudre ce problème, nous devons ajouter une condition ET complexe à l'aide de <code>:not()</code> afin d'exclure les éléments qui ne se trouvent pas entre <code>[data-range="end"]</code> et <code>[data-range="start"]</code>, dans cet ordre.</p><p>Seule, cette partie du sélecteur se lit comme suit : "<em>ne pas sélectionner</em> les éléments qui suivent <code>[data-range="end"]</code> et qui ont également un frère ou une soeur plus tardif(ve) de <code>[data-range="start"]</code>".</p><pre class="language-css">/* Note : ceci doit être ajouté au sélecteur précédent, et non utilisé seul */
:not([data-range="end"] ~ :has(~ [data-range="start"]))</pre><p>Au total, cela donne un sélecteur certes long, mais très puissant, qui n'était pas possible avant <code>:has()</code> sans utiliser JavaScript, en raison de l'absence des capacités de "regarder devant" et "regarder derrière" dans CSS.</p><pre class="language-css">/* Sélectionner tout ce qui est compris dans une plage */
[data-range="start"] ~ :has(~ [data-range="end"]):not([data-range]):not([data-range="end"] ~ :has(~ [data-range="start"]))</pre><p class="is-style-explanation">N'oubliez pas que, tout comme les autres sélecteurs, vous pouvez utiliser :has() lorsque vous construisez un sélecteur dans JavaScript. La possibilité de sélectionner des frères et sœurs précédents, des ancêtres et les autres fonctionnalités que nous avons apprises rendront également vos sélecteurs JS plus performants !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/VwBypzB">Multi-range element selectors with :has()</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><h2>Sélection linéaire d'une plage basée sur l'état</h2><p>Rassemblons certaines des qualités des sélecteurs et combinateurs <code>:has()</code> que nous avons appris pour créer un composant de classement par étoiles.</p><p>L'"étoile" sous-jacente sera une entrée radio, qui nous donnera accès à un état <code>:checked</code> pour nous aider à développer les sélecteurs.</p><pre class="language-html">&lt;div class="star-rating"&gt;
  &lt;fieldset&gt;
    &lt;legend&gt;Notez cette démo&lt;/legend&gt;
    &lt;div class="stars"&gt;
      &lt;label class="star"&gt;
        &lt;input type="radio" name="rating" value="1" /&gt;
        &lt;span&gt;1&lt;/span&gt;
      &lt;/label&gt;
      &lt;!-- ...4 étoiles de plus --&gt;
    &lt;/div&gt;
  &lt;/fieldset&gt;
&lt;/div&gt;</pre><p>Comme le montre l'aperçu vidéo qui suit, lorsqu'un utilisateur survole les étoiles soulignées, la plage allant du début (le plus à gauche) à l'étoile survolée doit se remplir de couleur. Lors de la sélection, lorsque le outon radio des étoiles est coché, la taille de l'étoile et du numéro augmente et la couleur de remplissage est conservée. Si l'utilisateur survole des étoiles après l'étoile cochée, la plage doit remplir les étoiles jusqu'au survol. Si l'utilisateur survole les étoiles avant l'étoile cochée, la plage ne doit remplir que jusqu'à l'étoile survolée, et les étoiles situées entre le survol et l'étoile précédemment cochée doivent avoir leur couleur de remplissage éclaircie.</p><iframe src="https://player.vimeo.com/video/791142751?h=161e941af1" width="800" height="472" frameborder="0" allowfullscreen="allowfullscreen">[embedded content]</iframe><p><em><a href="https://vimeo.com/791142751">Star-rating preview</a> from <a href="https://vimeo.com/smashingmagazine">Smashing Magazine</a> on <a href="https://vimeo.com">Vimeo</a></em>.</p><p>Cela fait beaucoup de plages à gérer, mais avec <code>:has()</code>, nous pouvons les décomposer en sélecteurs segmentés très rapidement !</p><p>La série de sélecteurs suivante s'applique à tous les états où nous voulons qu'une étoile ou une plage d'étoiles ait un background bleu jusqu'à l'étoile <code>:checked</code>. La règle met à jour un ensemble de propriétés qui affecteront la forme de l'étoile, créée par une combinaison des pseudo-éléments <code>::before</code> et <code>::after</code> sur le label <code>.star</code>.</p><p>Au total, cette règle sélectionne la plage d'étoiles entre la première étoile et l'étoile survolée, ou la première étoile et l'étoile avec un bouton radio coché.</p><pre class="language-css">.star:hover,
/* Frères et sœurs précédents de l'étoile survolée */
.star:has(~ .star:hover),
/* L'étoile a une radio cochée */
.star:has(:checked),
/* Frères et soeurs précédents d'une étoile cochée */
.star:has(~ .star :checked) {
  --star-rating-bg: dodgerblue;
}</pre><p>Ensuite, nous voulons éclaircir la couleur de remplissage des étoiles situées entre l'étoile survolée et une étoile cochée ultérieure, et des étoiles cochées qui suivent l'étoile survolée.</p><pre class="language-css">/* Frères et sœurs entre une étoile survolée et une étoile cochée */
.star:hover ~ .star:has(~ .star :checked),
/* Étoile cochée suivant une étoile survolée */
.star:hover ~ .star:has(:checked) {
  --star-rating-bg: lightblue;
}</pre><p>Concernant les sélecteurs d'état pour notre composant de classement par étoiles, c'est tout ce qu'il y a à faire !</p><p>La démo CodePen qui suit présente quelques astuces supplémentaires sur la façon dont le composant est créé à l'aide de la grille CSS, des propriétés personnalisées et du <code>clip-path</code>. Pour l'accessibilité, elle garantit également que la couleur n'est pas le seul indicateur en mettant à l'échelle l'étoile cochée. Et il gère les <a href="https://blogs.windows.com/msedgedev/2020/09/17/styling-for-windows-high-contrast-with-new-standards-for-forced-colors/">thèmes à fort contraste</a> (alias "couleurs forcées") en fournissant des valeurs de la palette de couleurs du système pour garantir la visibilité du remplissage de l'étoile :checked. En outre, les transitions sont raccourcies lorsqu'un utilisateur préfère un mouvement réduit.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/ExpoWwv">Star Rating Component with :has()</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><h2>Groupes de sélection multi-plages avec état</h2><p>Alors que le composant de notation par étoiles présentait un changement de style dynamique basé sur l'état, la disponibilité d'éléments avec état facilite également l'utilisation de <code>:has()</code> pour créer des limites visuelles.</p><p>Nos précédents sélecteurs multi-plages s'appuyaient sur l'ajout manuel de "crochets" dans le balisage pour styliser correctement les gammes sans s'infiltrer dans les zones intermédiaires. Mais si nous avons un ensemble de champs contenant des cases à cocher, nous pouvons à nouveau utiliser l'état <code>:checked</code> pour identifier clairement les limites autour des éléments cochés et non cochés.</p><p>Dans cette vidéo d'aperçu, lorsque les cases à cocher sont sélectionnées, elles reçoivent une bordure et un fond vert pour créer la frontière visuelle. Grâce à <code>:has()</code>, cette limite s'agrandit pour paraître envelopper les groupes d'éléments cochés, de sorte que le cadre visuel semble entourer l'ensemble du groupe. Le premier élément (ou un singleton) reçoit des coins supérieurs arrondis, et le dernier élément (ou un singleton) reçoit des coins inférieurs arrondis ainsi qu'une ombre légère.</p><iframe title="vimeo-player" src="https://player.vimeo.com/video/791143211?h=a0a031f369" width="800" height="472" frameborder="0" allowfullscreen="allowfullscreen">[embedded content]</iframe><p>Nous devons créer des règles pour gérer l'apparence du haut, du milieu et du bas en fonction de l'emplacement de l'élément dans le jeu. Les éléments uniques doivent recevoir les trois styles.</p><p>Notre HTML est configuré pour envelopper chaque entrée de case à cocher avec son étiquette, donc tous nos sélecteurs commenceront par correspondre à <code>label:has(:checked)</code> pour voir si l'étiquette contient une entrée cochée.</p><p>Pour déterminer le premier ou l'unique élément de l'ensemble, nous devons ajouter la condition qu'il ne suive pas un élément précédent avec une entrée cochée. Cette règle donnera un style à l'apparence supérieure.</p><pre class="language-css">/* Premier élément coché dans une plage
 OU haut d'un élément unique coché */
label:has(:checked):not(label:has(:checked) + label)</pre><p>Pour déterminer le dernier ou l'unique élément de l'ensemble, nous retournons la condition précédente pour vérifier qu'elle n'est pas suivie d'une entrée cochée. Cette règle donnera un style à l'apparence du bas.</p><pre class="language-css">/* Dernier élément coché dans une plage
 OU le bas d'un seul élément coché */
label:has(:checked):not(label:has(+ label :checked))</pre><p>Pour l'apparence du milieu, nous allons créer une règle qui capture réellement le groupe du début à la fin puisque tous les éléments de la règle doivent recevoir une couleur de fond et des bordures latérales.</p><p>Nous pourrions simplement utiliser <code>label:has(:checked)</code> pour ce sélecteur étant donné le contexte. Cependant, nous apprenons à sélectionner et à styliser des plages, donc pour compléter notre exercice, nous allons écrire les sélecteurs étendus.</p><p>La logique représentée dans le premier sélecteur est la suivante : "sélectionner les étiquettes avec des entrées cochées qui sont suivies par des étiquettes sœurs contenant des entrées cochées", ce qui capture tous les éléments de la plage sauf le dernier. Pour cela, nous répétons le sélecteur que nous venons de créer pour styliser le dernier élément coché de la plage.</p><pre class="language-css">/* Plage d'éléments cochés */
label:has(:checked):has(~ label :checked),
label:has(:checked):not(label:has(+ label :checked))</pre><p>Cette démo CodePen présente également <code>accent-color</code> pour modifier la couleur de l'entrée cochée et utilise des propriétés personnalisées pour gérer le rayon de la bordure. Elle utilise également des propriétés logiques.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/RwBxpjE">Stateful multi-range selection groups with :has()</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><h2>Quelques ressources complémentaires pour écrire des sélecteurs :has()</h2><p>Vous pouvez explorer <a href="https://codepen.io/collection/wapNEJ">toutes les démos</a> dans ma collection CodePen.</p><p>D'autres personnes on expérimenté ce qu'on peut faire avec :has(), n'hésitez pas à consulter ces ressources pour vous inspirer. Comme pour toutes les nouvelles fonctionnalités, les possibilités sont nombreuses, et nous en bénéficions tous lorsque nous partageons ce ue nous avons découvert ou appris !</p><ul><li>Bramus Van Damme explore quelques sélecteurs complexes avec :has():
<ul><li><a href="https://www.bram.us/2022/12/13/quantity-queries-for-islands-of-elements-with-the-same-class-thanks-to-css-has/">Quantity Queries for “islands of elements” with the same class, thanks to CSS :has()</a></li>
<li><a href="https://www.bram.us/2022/12/14/a-nth-childanb-of-s-polyfill-thanks-to-css-has/">A :nth-child(An+B [of S]?) polyfill thanks to CSS :has() and :not()</a></li>
<li><a href="https://www.bram.us/2022/11/17/style-a-parent-element-based-on-its-number-of-children-using-css-has/">Style a parent element based on its number of children using CSS :has()</a></li>
</ul></li>
<li>Jhey Tompkins passe en revue des cas pratiques et/ou amusants dans <a href="https://developer.chrome.com/blog/has-m105/">“:has(): The Family Selector”</a></li>
<li>Jen Simmons explore les relations de :has() avec les combinateurs et propose quelques démos dans <a href="https://la-cascade.io/articles/utiliser-css-has">“Utiliser :has() comme sélecteur de parent et bien plus”</a></li>
<li>Adrian Bece envisage encore d'autres possibilités dans <a href="https://www.smashingmagazine.com/2021/06/has-native-css-parent-selector/">“Meet :has, A Native CSS Parent Selector (And More)”</a></li>
<li>Estelle Weyl démystifie plus encore le comportement du sélecteur <a href="https://12daysofweb.dev/2022/css-has-selector/">“CSS :has()”</a></li>
<li>Manuel Matuzović clarifie la différence importante entre <a href="https://www.matuzo.at/blog/2022/100daysof-day50/">“:has(:not()) vs. :not(:has())”</a></li>
</ul><p>❦</p><p>NdT : <em>un exemple intéressant d'utilisation de <code>:has()</code> cité dans la formidable newsletter <a href="https://bytes.dev/">Bytes</a></em> :</p><p>Si nous voulions mettre en place un effet de style ESPN où l'on assombrit tous les éléments de liste qui ne sont pas survolés, comment pourrions-nous le faire uniquement à l'aide de CSS ?</p><pre class="language-html">&lt;ul&gt;
  &lt;li&gt;NBA&lt;/li&gt;
  &lt;li&gt;NFL&lt;/li&gt;
  &lt;li&gt;NCAAF&lt;/li&gt;
  &lt;li&gt;MLB&lt;/li&gt;
  &lt;li&gt;NCAAM&lt;/li&gt;
  &lt;li&gt;NHL&lt;/li&gt;
&lt;/ul&gt;</pre><p>Grâce au nouveau sélecteur <code>:has</code> en CSS, nous pouvons utiliser le sélecteur général sibling (<code>~</code>) et un pseudo-sélecteur <code>:hover</code> pour cibler les éléments avant et après en seulement 3 lignes de css.</p><pre class="language-css">ul {
  display: flex;
  gap: 8px;
}
li {
  display: block;
  cursor: pointer;
  transition: opacity 0.3s ease-in-out;
}
li:has(~ li:hover),
li:hover ~ li {
  opacity: 0.5;
}</pre><p>Vous pouvez <a href="https://codesandbox.io/s/bytes-has-selector-lg94f7?file=/src/styles.css">le voir en action ici</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/un-monde-de-possibilites-nouvelles-avec-css-has</link>
      <guid>https://la-cascade.io/articles/un-monde-de-possibilites-nouvelles-avec-css-has</guid>
      <pubDate>Sat, 28 Jan 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[La propriété CSS Transform]]></title>
      <description><![CDATA[<p><em>La propriété CSS transform permet de manipuler visuellement un élément. Un article clair et détaillé de Sara Cope.</em></p><div class="articleContent"><p>La propriété <code>transform</code> nous permet de manipuler visuellement un élément en l'inclinant, le faisant pivoter, le translatant ou le mettant à l'échelle :</p><pre class="language-css">.element {
  width: 20px;
  height: 20px;
  transform: scale(20);
}</pre><p>Même avec une hauteur et une largeur déclarées, cet élément sera maintenant mis à l'échelle à vingt fois sa taille d'origine :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/gpQYwO/d5d50055d95ceecbf94068e75a502c97">Transform explanation</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><p>En donnant deux valeurs à cette fonction, nous l'étirons horizontalement de la première valeur (2) et verticalement de la seconde (0.5). Dans l'exemple suivant, l'élément sera désormais deux fois plus large et deux fois moins haut que l'élément d'origine :</p><pre class="language-css">.element {
  transform: scale(2, 0.5);
}</pre><p>Nous pouvons être plus précis, en n'utilisant pas la fonction de raccourci :</p><pre class="language-css">transform: scaleX(2);
transform: scaleY(0.5);</pre><p>Mais <code>scale()</code> n'est qu'une des nombreuses fonctions de transformation disponibles.</p><h2>Valeurs</h2><p><code>scale()</code> : Affecte la taille de l'élément. Cela s'applique également à la taille de la police, au padding, à la hauteur et à la largeur d'un élément. Il s'agit également d'une fonction raccourcie pour les fonctions scaleX et scaleY.</p><p><code>skewX()</code> et <code>skewY()</code> : Incline un élément vers la gauche ou la droite, comme pour transformer un rectangle en parallélogramme. skew() est un raccourci qui combine skewX() et skewY en acceptant les deux valeurs.</p><p><code>translate()</code> : Déplace un élément latéralement ou de haut en bas.</p><p><code>rotate()</code> : Fait pivoter l'élément dans le sens des aiguilles d'une montre à partir de sa position actuelle.</p><p><code>matrix()</code> : Une fonction qui n'est probablement pas destinée à être écrite à la main, mais qui combine toutes les transformations en une seule.</p><p><code>perspective()</code> : N'affecte pas l'élément lui-même, mais affecte les transformées des éléments descendants en 3D, leur permettant d'avoir tous une perspective de profondeur cohérente.</p><ul><li><a href="https://la-cascade.io/articles/la-propriete-css-transform#skew">Skew</a></li>
<li><a href="https://la-cascade.io/articles/la-propriete-css-transform#rotate">Rotate</a></li>
<li><a href="https://la-cascade.io/articles/la-propriete-css-transform#translate">Translate</a></li>
<li><a href="https://la-cascade.io/articles/la-propriete-css-transform#valeursmultiples">Valeurs multiples</a></li>
<li><a href="https://la-cascade.io/articles/la-propriete-css-transform#matrix">Matrix</a></li>
<li><a href="https://la-cascade.io/articles/la-propriete-css-transform#3dtransform">3D transform</a></li>
</ul><h2 id="skew">Skew</h2><pre class="language-css">/* Skew points along the x-axis */
.element {
  transform: skewX(25deg);
}
/* Skew point along the y-axis */
.element {
  transform: skewY(25deg);
}
/* Skew points along the x- and y-axis */
.element {
  transform: skew(25deg, 25deg);
}</pre><p>Les fonctions de transformation <code>skewX</code> et <code>skewY</code> inclinent un élément dans un sens ou dans l'autre. N'oubliez pas : il n'existe pas de propriété raccourcie pour incliner un élément, vous devrez donc utiliser les deux fonctions. Dans l'exemple ci-dessous, nous pouvons incliner un carré de 100px x 100px vers la gauche et la droite avec <code>skewX</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/BNGMRy/cb9ab0a908241806e3eff88b57f15693">Transform explanation</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><p>Dans cet exemple, nous inclinons un élément verticalement avec avec <code>skewY</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/jPQpzp/d7be823bca05649502f63fc8490c6d93">Transform explanation</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><p>Utilisons maintenant skew() pour combiner les deux :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/https://codepen.io/team/css-tricks/pen/povNBmQ">Transform explanation</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><h2 id="rotate">Rotate</h2><pre class="language-css">.element {
  transform: rotate(25deg);
}</pre><p>Ce CSS fait tourner un élément dans le sens des aiguilles d'une montre par rapport à sa position d'origine, tandis qu'une valeur négative le ferait tourner dans le sens inverse. Voici un exemple animé simple où un carré tourne en continu de 360 degrés toutes les trois secondes :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/VLVBdK/d31be2118a19782d2c4fcfb048351ccf">Transform explanation</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><p>Nous pouvons utiliser les fonctions <code>rotateX</code>, <code>rotateY</code> et <code>rotateZ</code>, comme suit :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/MwzBzR/ebb6b5a5cec86aa04168f03e26c7501c">Transform explanation</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><h2 id="translate">Translate</h2><pre class="language-css">.element {
  transform: translate(20px, 10px);
}</pre><p>Cette fonction de transformation déplace un élément latéralement, ou de haut en bas. Pourquoi ne pas utiliser simplement haut/gauche/bas/droite ? C'est parfois un peu confus. Personnellement, je considère ces fonctions comme des fonctions de mise en page/positionnement (elles sont mieux supportées par les navigateurs de toute façon) et cette fonction comme un moyen de déplacer ces éléments dans le cadre d'une transition ou d'une animation.</p><p>Ces valeurs pourraient être n'importe quelle valeur de longueur, comme <code>10px</code> ou <code>2.4em</code>. Une valeur déplacera l'élément vers la droite (les valeurs négatives vers la gauche). Si une deuxième valeur est fournie, cette deuxième valeur le déplacera vers le bas (valeurs négatives vers le haut). Vous pouvez aussi être plus spécifique :</p><pre class="language-css">transform: translateX(value);
transform: translateY(value);</pre><p>Il est important de noter qu'un élément utilisant la fonction <code>transform</code> ne fera pas circuler les autres éléments autour de lui. En utilisant la fonction de transformation ci-dessous et en faisant sortir le carré vert de sa position initiale, nous remarquons que le texte qui l'entoure reste fixe en place, comme si le carré était un élément block :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/eNQdgJ/b9df78cff3ab6b64b5925b10c1e52d9e">Transform explanation</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><p>Il convient également de noter que <code>translate</code> sera <a href="https://www.alsacreations.com/astuce/lire/1565-acceleration-materielle-au-service-de-vos-animations-css.html">accéléré par le matériel</a> si vous souhaitez animer cette propriété, contrairement à <code>position: absolute</code>.</p><h2 id="valeursmultiples">Valeurs multiples</h2>Avec une liste séparée par un espace, nous pouvons ajouter plusieurs valeurs à la propriété `transform` :<pre class="language-css">.element {
  width: 20px;
  height: 20px;
  transform: scale(20) skew(-20deg);
}</pre><p>Il est bon de noter qu'il y a un ordre dans lequel ces transformations seront effectuées, dans l'exemple ci-dessus <code>skew</code> sera effectué en premier et <em>ensuite</em> l'élément sera mis à l'échelle.</p><h2 id="matrix">Matrix</h2><p>La fonction de transformation matricielle peut être utilisée pour combiner toutes les transformations en une seule. C'est un peu comme un raccourci de transformation, sauf que je ne crois pas qu'il soit vraiment destiné à être écrit à la main. Il existe des outils comme <a href="https://meyerweb.com/eric/tools/matrix/">the Matrix Resolutions</a>, qui peuvent convertir un groupe de transformations en une seule déclaration matricielle. Peut-être que dans certaines situations, cela peut réduire la taille du fichier, bien que des micro-optimisations <em>peu amicales pour les auteurs</em> comme celle-ci ne valent probablement pas d'y passer trop de temps.</p><p>Pour les curieux, ceci :</p><pre class="language-css">rotate(45deg) translate(24px, 25px)</pre><p>...peut aussi être représenté comme :</p><pre class="language-css">matrix(0.7071067811865475, 0.7071067811865476, -0.7071067811865476, 0.7071067811865475, -0.7071067811865497, 34.648232278140824)</pre><h2 id="3dtransform">3D Transform</h2><p>La plupart des propriétés que nous avons passées en revue ont des versions 3D.</p><pre class="language-css">translate3d(x, y, z)
translateZ(z)</pre><p>La troisième valeur de <code>translate3d</code> ou la valeur de <code>translateZ</code> rapprochent l'élément de l'observateur, les valeurs négatives l'en éloignent.</p><pre class="language-css">scale3d(sx, sy, sz)
scaleZ(sz)</pre><p>La troisième valeur dans <code>scale3d</code> ou la valeur dans <code>scaleZ</code> affectent la mise à l'échelle le long de l'axe z (par exemple, la ligne imaginaire sortant directement de l'écran).</p><pre>rotateX(value)
rotateY(value)
rotate3d(x, y, z)</pre><p><code>rotateX</code> et <code>rotateY</code> feront tourner un élément dans l'espace 3D autour de ces axes. <code>rotate3d</code> nous permet de spécifier un point dans l'espace 3D autour duquel faire tourner l'élément.</p><pre class="language-css">matrix3d(…)</pre><p>Un moyen programmatique de décrire une transformation 3D dans une grille 4×4. Personne n'en écrira jamais une à la main, <em>jamais</em>.</p><pre class="language-css">perspective(value)</pre><p>Cette valeur n'affecte pas l'élément lui-même, mais elle affecte les transformées 3D des éléments descendants, leur permettant d'avoir tous une perspective de profondeur cohérente.</p><h3>Plus d'information</h3><ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Transforms">La doc MDN</a> sur transform et <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Transforms/Using_CSS_transforms">son utilisation</a>.</li>
<li><a href="https://3dtransforms.desandro.com/">La documentation de David DeSandro</a> sur 3D transforms</li>
<li>Surfin’ Safari: <a href="https://www.webkit.org/blog/386/3d-transforms/">3D transforms</a></li>
<li><a href="https://drafts.csswg.org/css-transforms-1/">La spec W3C</a> sur CSS3 transforms</li>
<li><a href="https://24ways.org/2010/intro-to-css-3d-transforms/">Intro à CSS 3D transforms</a> par David DeSandro</li>
<li><a href="https://www.digitalocean.com/community/tutorials/css-translatez-and-perspective">Astuces pour utiliser CSS translateZ() et perspective()</a> (DigitalOcean)</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/la-propriete-css-transform</link>
      <guid>https://la-cascade.io/articles/la-propriete-css-transform</guid>
      <pubDate>Fri, 27 Jan 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Data attributes, guide complet]]></title>
      <description><![CDATA[<p><em>Les attributs HTML data-* nous permettent de stocker des informations supplémentaires sur les éléments sémantiques standard, par Chris Coyier.</em></p><div class="articleContent"><h2>Introduction</h2><p>Les éléments HTML peuvent être dotés d'attributs qui servent à tout, depuis l'ajout d'informations sur l'accessibilité jusqu'au contrôle stylistique.</p><pre class="language-html">&lt;!-- Nous pouvons utiliser la "class" pour le style en CSS, et nous avons également fait de cet élément une région de repère --&gt;
&lt;div class="names" role="region" aria-label="Names"&gt;&lt;/div&gt;</pre><p>Ce qui est <em>déconseillé</em>, c'est d'<em>inventer</em> vos propres attributs, ou de réaffecter des attributs existants pour une fonctionnalité sans rapport.</p><pre class="language-html">&lt;!-- `highlight` n'est pas un attribut HTML --&gt;
&lt;div highlight="true"&gt;&lt;/div&gt;
&lt;!-- `large` n'est pas une valeur valide de `width` --&gt;
&lt;div width="large"&gt;&lt;/div&gt;</pre><p>C'est pas bien, et pour des tas de raisons. Votre HTML devient invalide, ce qui peut ne pas avoir de conséquences négatives réelles, mais vous prive de ce sentiment rassurant et flou d'avoir un HTML valide. La raison la plus convaincante est que le <strong>HTML est un langage vivant</strong> et ce n'est pas parce que des attributs et des valeurs ne font rien aujourd'hui qu'ils ne feront rien demain.</p><p>Bonne nouvelle cependant : vous pouvez créer vos propres attributs. Il vous suffit de les préfixer avec <code>data-*</code> et ensuite vous êtes libre de faire ce qui vous plaît !</p><h2>Syntaxe</h2><p>Il est très pratique de pouvoir créer nos propres attributs HTML et d'y placer nos propres informations. Et c'est possible ! c'est même exactement ce que sont les <strong>data attributes</strong> (<a href="https://developer.mozilla.org/fr/docs/Learn/HTML/Howto/Use_data_attributes">attributs de données</a>). Ils sont comme ceci :</p><pre class="language-html">&lt;!-- Ils n'ont pas besoin de valeur --&gt;
&lt;div data-foo&gt;&lt;/div&gt;
&lt;!-- ...mais ils peuvent avoir une valeur --&gt;
&lt;div data-size="large"&gt;&lt;/div&gt;
&lt;!-- Vous êtes en HTML ici, donc attention à l'échappement du code si vous devez faire quelque chose comme mettre plus de HTML à l'intérieur --&gt;
&lt;li data-prefix="Attention au HTML ici."&gt;&lt;/li&gt;
&lt;li&gt;
  &lt;!-- Vous pouvez continuer à mettre des tirets si vous voulez --&gt;
  &lt;aside data-some-long-attribute-name&gt;&lt;aside&gt;&lt;/aside&gt;&lt;/aside&gt;
&lt;/li&gt;</pre><p>Les data attributes sont souvent appelés attributs <code>data-*</code>, car ils sont toujours formatés de cette façon. Le mot <code>data</code>, puis un tiret <code>-</code>, puis un autre texte que vous pouvez inventer.</p><h3>Pouvez-vous utiliser l'attribut data seul ?</h3><pre class="language-html">&lt;div data=""&gt;&lt;/div&gt;</pre><p>Cela ne va probablement pas faire de mal, mais vous n'obtiendrez pas l'API JavaScript que nous verrons plus tard dans ce guide. Vous vous créez essentiellement un attribut pour vous-même, ce qui, comme je l'ai mentionné dans l'introduction, est <em>déconseillé</em>.</p><h4>Ce qu'il ne faut pas faire avec les data attributes</h4><p>Stockez du contenu qui doit être accessible. Si le contenu doit être vu ou lu sur une page, ne le mettez pas seulement dans des data attributes, mais assurez-vous que ce contenu se trouve quelque part dans le contenu HTML.</p><pre class="language-html">&lt;!-- Ce n'est pas du contenu accessible --&gt;
&lt;div data-name="Chris Coyier"&gt;&lt;/div&gt;
&lt;!-- Si vous avez besoin d'un accès programmatique à ce contenu mais qu'il ne doit pas être vu, il existe d'autres moyens... --&gt;
&lt;div&gt;
  &lt;span class="visually-hidden"&gt;Chris Coyier&lt;/span&gt;
&lt;/div&gt;</pre><p>Voici plus d'informations sur le <a href="https://la-cascade.io/articles/cacher-des-elements-avec-css">masquage des choses</a>.</p><h2>Stylisation avec des data attributes</h2><p>CSS peut <a href="https://css-tricks.com/almanac/selectors/a/attribute/">sélectionner des éléments HTML sur la base d'attributs</a> et de leurs valeurs.</p><pre class="language-css">/* Sélectionner tout élément ayant cet attribut de données et cette valeur */
[data-size='large'] {
  padding: 2rem;
  font-size: 125%;
}
/* Vous pouvez l'étendre à un élément, une classe ou n'importe quoi d'autre */
button[data-type='download'] {
}
.card[data-pad='extra'] {
}</pre><p>Cela peut être convaincant. Les principaux <em>hooks</em> de style en HTML/CSS, ce sont les <strong>classes</strong>, et bien que les classes soient excellentes (elles ont une spécificité moyenne et de belles méthodes JavaScript via <code>classList</code>), un élément en est doté ou non, c'est l'un ou l'autre, (essentiellement <em>activé</em> ou <em>désactivé</em>). Avec les attributs <code>data-*</code>, vous obtenez cette capacité d'activation/désactivation, <strong><em>et</em></strong> la possibilité de sélectionner en fonction de la valeur qu'il possède au même niveau de spécificité.</p><pre class="language-css">/* Sélectionne si l'attribut est présent du tout */
[data-size] {
}
/* Sélectionne si l'attribut a une valeur particulière */
[data-state='open'],
[aria-expanded='true'] {
}
/* Sélecteur "Commence par", ce qui signifie que cela correspond à "3" ou à tout ce qui commence par 3, comme "3.14" */
[data-version^='3'] {
}
/* "Contient" signifie que la valeur contient la chaîne de caractères n'importe où à l'intérieur */
[data-company*='google'] {
}</pre><h3>La spécificité des sélecteurs d'attributs</h3><p>C'est exactement la même chose qu'une classe. Nous pensons souvent à la spécificité comme à une valeur en quatre parties :</p><p>style en ligne, IDs, classes/attributs, balises.</p><p>Ainsi, un sélecteur d'attribut seul est <strong>0, 0, 1, 0</strong>. Un sélecteur comme celui-ci :</p><pre class="language-css">div.card[data-foo='bar'] {
}</pre><p>... serait <strong>0, 0, 2, 1</strong> — le 2 est dû au fait qu'il y a une classe (<code>.card</code>) et un attribut (<code>[data-foo="bar"]</code>), et le 1 est dû au fait qu'il y a une balise (<code>div</code>).</p><figure role="group"><img src="https://la-cascade.io/images/specificity-selector.webp" alt="schéma montrant la spécificité : une div (spécificité = 1) avec une classe (specificité = 1) et un attribut de données avec une valeur (spécificité = 1)" /><figcaption>Illustration d'un sélecteur CSS incluant un attribut data.</figcaption></figure><p>Les sélecteurs d'attributs ont moins de spécificité qu'un ID, plus qu'un élément/balise, et la même chose qu'une classe.</p><h3>Valeurs d'attributs insensibles à la casse</h3><p>Au cas où vous auriez besoin de corriger d'éventuelles incohérences de capitalisation dans vos data attributes, le sélecteur d'attribut dispose d'une variante insensible à la casse pour cela.</p><pre class="language-html">&lt;!-- Correspondra à
&lt;div data-state="open"&gt;&lt;/div&gt;
&lt;div data-state="Open"&gt;&lt;/div&gt;
&lt;div data-state="OPEN"&gt;&lt;/div&gt;
&lt;div data-state="oPeN"&gt;&lt;/div&gt;
--&gt;
[data-state="open" i] { }</pre><p>C'est le petit <code>i</code> à l'intérieur du sélecteur entre crochets.</p><h3>Utilisation visuelle des data attributes</h3><p>CSS vous permet d'extraire la valeur de l'attribut de données et de l'afficher si nécessaire.</p><pre class="language-css">/* &lt;div data-emoji="✅"&gt; */
[data-emoji]::before {
  content: attr(data-emoji); /* Retourne '✅' */
  margin-right: 5px;
}</pre><h3>Exemple de cas d'utilisation du style</h3><p>Vous pourriez utiliser des data attributes pour spécifier le nombre de colonnes que vous souhaitez pour un conteneur de grille.</p><pre class="language-html">&lt;div data-columns="2"&gt;&lt;/div&gt;
&lt;div data-columns="3"&gt;&lt;/div&gt;
&lt;div data-columns="4"&gt;&lt;/div&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/chriscoyier/pen/rNaEvgp">Data Attribute Based Columns</a>de chriscoyier dans<a href="https://codepen.io">CodePen</a></div><h2>Accéder aux data attributes en JavaScript</h2><p>Comme tout autre attribut, vous pouvez accéder à la valeur avec la méthode générique <code>getAttribute</code>.</p><pre class="language-js">let value = el.getAttribute('data-state')
// Vous pouvez également définir la valeur.
// Returns data-state="collapsed"
el.setAttribute('data-state', 'collapsed')</pre><p>Mais les data attributes ont également leur propre API spéciale. Admettons que vous ayez un élément avec plusieurs data attributes (ce qui est tout à fait ok) :</p><pre class="language-html">&lt;span
  data-info="123"
  data-index="2"
  data-prefix="Dr. "
  data-emoji-icon="?️♀️"
&gt;&lt;/span&gt;</pre><p>Si vous avez une référence à cet élément, vous pouvez définir (<em>set</em>) et obtenir (<em>get</em>) les attributs comme suit :</p><pre class="language-js">// GET
span.dataset.info // 123
span.dataset.index // 2
// SET
span.dataset.prefix = 'M. '
span.dataset.emojiIcon = '?'</pre><p>Notez l'utilisation du camelCase dans la dernière ligne. Elle convertit automatiquement les attributs de style kebab en HTML, comme <code>data-this-little-piggy</code>, en style camelCase en JavaScript, comme <code>dataThisLittlePiggy</code>.</p><p>Cette API n'est sans doute pas aussi agréable que <a href="https://developer.mozilla.org/fr/docs/Web/API/Element/classList"><code>classList</code></a> avec ses méthodes claires d'ajout, de suppression, de basculement (<em>toggle</em>) et de remplacement, mais c'est mieux que rien.</p><p>Vous avez également accès aux ensembles de données en ligne :</p><pre class="language-html">&lt;img src="spaceship.png"
  data-ship-id="324" data-shields="72%"
  onclick="pewpew(this.dataset.shipId)"&gt;
&lt;/img&gt;</pre><h3>Données JSON à l'intérieur des data attributes</h3><pre class="language-html">&lt;ul&gt;
  &lt;li
    data-person='
    {
      "nom" : "Chris Coyier",
      "job" : "Personne Web"
    }
  '
  &gt;&lt;/li&gt;
&lt;/ul&gt;</pre><p>Hé, pourquoi pas ? Ce n'est qu'une chaîne de caractères et il est possible de la formater en <a href="https://la-cascade.io/articles/json-pour-les-debutants">JSON</a> valide (attention aux guillemets et autres). Vous pouvez extraire ces données et les parser selon vos besoins.</p><pre class="language-js">const el = document.querySelector('li')
let json = el.dataset.person
let data = JSON.parse(json)
console.log(data.name) // Chris Coyier
console.log(data.job) // Personne Web</pre><h3>Cas d'utilisation de JavaScript</h3><p>Le concept est que vous pouvez utiliser les data attributes pour mettre dans le HTML des informations auxquelles JavaScript peut avoir besoin d'accéder pour faire certaines choses.</p><p>Un cas courant serait lié à la fonctionnalité de la base de données. Disons que vous avez un bouton "J'aime" :</p><pre class="language-html">&lt;button data-id="435432343"&gt;♡&lt;/button&gt;</pre><p>Ce bouton pourrait être doté d'un <em>click handler</em> qui exécute une requête Ajax vers le serveur pour incrémenter le nombre de <em>j'aime</em> dans une base de données à chaque clic. Il sait quel enregistrement mettre à jour car il l'obtient du data attribute.</p><h3>Spécifications</h3><ul><li><a href="https://drafts.csswg.org/selectors-4/#attribute-selectors">Sélecteurs niveau 4</a> (projet)</li>
<li><a href="https://drafts.csswg.org/selectors-3/#attribute-selectors">Sélecteurs niveau 3</a> (recommandé)</li>
<li><a href="https://www.w3.org/TR/CSS2/selector.html#attribute-selectors">Sélecteurs de niveau 2</a>, révision 1 (définition initiale)</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/data-attributes-guide-complet</link>
      <guid>https://la-cascade.io/articles/data-attributes-guide-complet</guid>
      <pubDate>Tue, 24 Jan 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Utiliser calc pour déterminer la hauteur de ligne optimale]]></title>
      <description><![CDATA[<p><em>Où l'on parle de la hauteur des lignes, de l'unité ex et de l'utilisation des mathématiques en CSS.</em></p><div class="articleContent"><p><em>Le texte qui suit est paru dans <a href="https://kittygiraudel.com/">le site</a> de <a href="https://la-cascade.io/auteurs/kitty-giraudel">Kitty Giraudel</a>, qui écrit : "voici un billet invité de Jesús Ricarte, développeur frontend et traducteur bénévole pour <a href="https://alistapart.com/es/">A List Apart en espagnol</a>. Je suis très heureux qu'il nous parle aujourd'hui de la hauteur des lignes et de l'utilisation des mathématiques en CSS !"</em></p><p class="c1">❦</p><p>Nous pouvons appliquer n'importe quelle unité CSS à la hauteur de ligne (<code>line-height</code>), cependant une valeur sans unité de <code>1.5</code> est la façon la plus recommandée de gérer cette hauteur. Pour commencer, voici une image explicative sur la façon dont la hauteur de ligne est appliquée par le navigateur :</p><figure><img src="https://la-cascade.io/images/line-height.png" alt="" /></figure><p>Comme vous pouvez le constater, chaque hauteur de ligne est répartie dans différentes zones :</p><ul><li>Une "zone de contenu", dont la hauteur serait égale à 1.</li>
<li>Une "zone d'espace", qui serait l'espace restant, réparti de manière égale en haut et en bas de la ligne. (NdT: le <a href="https://en.wikipedia.org/wiki/Leading">leading</a> ou espacement de ligne ou <a href="https://fr.wikipedia.org/wiki/Interlignage_(typographie)">interlignage</a>.</li>
</ul><p>Nous pourrions donc l'exprimer comme suit : <code>lineHeight = leading / 2 + content + leading / 2</code></p><p>ou :</p><pre class="language-css">line-height: calc(0.25 + 1 + 0.25);</pre><p>Cette approche présente toutefois un inconvénient en termes de maintenance : comme vous pouvez le constater dans la démo suivante, elle fixe une hauteur de ligne trop importante dans les grandes tailles de police. Afin d'établir une lisibilité optimale, nous devons l'ajuster manuellement à chaque incrément de <code>font-size</code>, jusqu'à <code>1.1</code> pour les très grandes tailles de police.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/supersimplenet/pen/RwWyjKV">calc line-height: demo 1</a>de super-simple.net dans<a href="https://codepen.io">CodePen</a></div><h2>À la recherche d'une formule</h2><p>Pour y voir plus clair, jetons un coup d'œil à nos chiffres de démonstration, sur un tableau de comparaison (les valeurs de hauteur de ligne calculées sont en pixels pour une meilleure compréhension) :</p><table class="specificTable"><thead><tr>
<th><strong>line-height: 1.5</strong></th>
<th>line-height: 1.1</th>
</tr></thead><tbody><tr><td>font-size: 10px</td>
<td>15px</td>
<td class="c3">11px</td>
</tr><tr><td>font-size: 50px</td>
<td class="c3">75px</td>
<td>55px</td>
</tr></tbody></table><p>Pour obtenir une hauteur de ligne optimale, nous devrons être aussi proches que possible de la valeur <code>1.5</code> (<code>15px</code>), sur les petites tailles de police, mais plus proches de <code>1.1</code> (<code>55px</code>) sur les grandes.</p><p>Attendez... <code>11px</code> est déjà assez proche de <code>15px</code>. Nous sommes à quelques pixels près.</p><p>Donc, au lieu de commencer sur une valeur de <code>1.5</code>, pourquoi ne pas inverser les choses ? Nous pourrions commencer à partir de <code>1.1</code>, en ajoutant juste les quelques pixels dont nous avons besoin, ce qui ne fera presque aucune différence visuelle dans les grandes tailles de police, seulement dans les petites.</p><p>Quelque chose comme :</p><pre class="language-css">line-height: calc(2px + 1.1 + 2px);</pre><p>Révision de notre tableau de comparaison des hauteurs de ligne calculées :</p><table class="specificTable"><thead><tr>
<th>LH 1.5</th>
<th>LH (2px + 1.1 + 2px)</th>
<th>LH 1.1</th>
</tr></thead><tbody><tr><td>font-size: 10px</td>
<td>15px</td>
<td>15px</td>
<td class="c3">11px</td>
</tr><tr><td>font-size: 50px</td>
<td class="c3">75px</td>
<td>59px</td>
<td>55px</td>
</tr></tbody></table><p>Voilà qui est mieux ! Nous avons réussi dans les petites tailles de police et nous en sommes assez proches dans les grandes.</p><p>Malheureusement, <code>line-height : calc(2px + 1.1 + 2px)</code> n'est pas un CSS valide, puisque les valeurs avec unité et sans unité ne peuvent pas être mélangées. Pourrions-nous utiliser n'importe quelle unité relative qui est calculée à environ <code>1.1</code> ?</p><p>Genre : <a href="https://developer.mozilla.org/fr/docs/Learn/CSS/Building_blocks/Values_and_units">l'unité <code>ex</code></a> est calculée à la <a href="https://en.wikipedia.org/wiki/X-height">hauteur d'x</a> de la police actuelle (la hauteur de la lettre minuscule "x"), donc nous trouvons simplement la correspondance parfaite pour notre formule.</p><p>En fait, toute unité relative (<code>em</code>, <code>rem</code>...) peut être utilisée, mais puisque nous calculons la hauteur de ligne, il est logique d'utiliser une unité de hauteur.</p><p>Comme chaque police de caractères a sa propre valeur <code>ex</code>, nous devons encore affiner nos valeurs <code>px</code> &amp; <code>ex</code>. Quoi qu'il en soit, considérez ceci comme un bon point de départ :</p><pre class="language-css">line-height: calc(2px + 2ex + 2px);</pre><p>Comme vous pouvez le voir dans la démo suivante, il définit une très belle hauteur de ligne, dans un large éventail de caractères différents :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/supersimplenet/pen/vYNjaem">calc line-height: demo 2</a>de super-simple.net dans<a href="https://codepen.io">CodePen</a></div><p>C'est du CSS valide. De plus, <a href="https://caniuse.com/mdn-css_types_length_ex">l'unité <code>ex</code> a une très bonne compatibilité navigateur</a>. Hourra !</p><h2>Éléments descendants</h2><p>Si vous appliquez la formule sur un élément parent, et que la taille de la police est modifiée sur un élément descendant, la hauteur de ligne ne sera pas affectée sur le descendant, puisqu'elle a été calculée sur la base de la taille de la police du parent :</p><pre class="language-css">.parent {
  font-size: 20px;
  line-height: calc(2px + 2ex + 2px);
  /* calculé: 2px + (2 * 20px) + 2px = 44px */
}
.parent .descendant {
  font-size: 40px;
  /* désiré:  2px + (2 * 40px) + 2px = 84px */
  /* calculé: 2px + (2 * 20px) + 2px = 44px (comme .parent) */
}</pre><p>Cela peut être résolu en appliquant la formule à tous les descendants, avec le sélecteur universel :</p><pre class="language-css">.parent * {
  line-height: calc(2px + 2ex + 2px);
}</pre><h2>De la typographie responsive</h2><p>Notre formule est également utile pour la typographie responsive. L'utilisation d'unités relatives au viewport (<code>vw</code>, <code>vh</code>, <code>vmin</code>, <code>vmax</code>) entraîne un manque de contrôle fin, de sorte que nous ne pouvons pas modifier la hauteur de ligne à chaque changement de taille de police.</p><p>Ce problème a également été abordé par la technique des <a href="https://fvsch.com/css-locks">verrous CSS</a>, qui utilise une arithmétique relativement complexe pour établir une hauteur de ligne minimale et maximale. NdT : <em>Depuis la publication, en 2016, de l'article de Florens Verschelde en lien ci-dessus, CSS a gagné une nouvelle capacité qui remplace une grande partie de l'astuce de cet article : la fonction <code>clamp()</code>.</em><em>La Cascade utilise</em> :</p><pre class="language-css">body {
  line-height: calc(1em + 0.5rem);
}</pre></div>]]></description>
      <link>https://la-cascade.io/articles/utiliser-calc-pour-determiner-la-hauteur-de-ligne-optimale</link>
      <guid>https://la-cascade.io/articles/utiliser-calc-pour-determiner-la-hauteur-de-ligne-optimale</guid>
      <pubDate>Fri, 20 Jan 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Créer des formes en CSS]]></title>
      <description><![CDATA[<p><em>Un étonnant catalogue de formes, des plus simples aux plus complexes, créées en CSS par Chris Coyier &amp; C°.</em></p><div class="articleContent"><p>CSS nous permet de créer toutes sortes de formes. Les carrés et les rectangles sont faciles, car ce sont les formes naturelles du Web. Ajoutez une largeur et une hauteur et vous obtenez la taille exacte du rectangle dont vous avez besoin. Ajoutez un rayon de bordure et vous pouvez arrondir cette forme, et avec le rayon approprié, vous pouvez transformer ces rectangles en cercles et en ovales.</p><p>Nous disposons également des <a href="https://la-cascade.io/tags/pseudo-elements">pseudo-éléments</a> <code>::before</code> et <code>::after</code> en CSS, qui nous offrent le potentiel de deux formes supplémentaires que nous pouvons ajouter à l'élément original. En faisant preuve d'ingéniosité avec le positionnement, la transformation et bien d'autres autres astuces, nous pouvons créer de nombreuses formes en CSS avec un seul élément HTML.</p><p class="is-style-explanation">De nos jours, notre meilleur atout pour dessiner des formes est soit le <a href="https://la-cascade.io/tags/svg">SVG</a>, soit l'utilisation d'un <a href="https://developer.mozilla.org/fr/docs/Web/CSS/clip-path">clip-path</a> en CSS, qui fonctionne un peu comme SVG (et peut faire référence au SVG). Par exemple, regardez <a href="https://css-tricks.com/some-new-icon-sets/">ces jeux d'icônes SVG</a>, cet <a href="https://codepen.io/stoumann/full/abZxoOM">éditeur de clip-path</a>, et cette <a href="https://www.digitalocean.com/community/tutorials/css-clipping-with-clip-path">introduction au clipping CSS</a>. Cet article a été écrit à l'origine avant que l'une ou l'autre de ces technologies ne s'impose vraiment !</p><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-square-shape" aria-hidden="true" class="aal_anchor" id="aa-square-shape"></a>Carré</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-rectangle-shape" aria-hidden="true" class="aal_anchor" id="aa-rectangle-shape"></a>Rectangle</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-circle-shape" aria-hidden="true" class="aal_anchor" id="aa-circle-shape"></a>Cercle</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-oval-shape" aria-hidden="true" class="aal_anchor" id="aa-oval-shape"></a>Ovale</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-up-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-up-shape"></a>Triangle vers le haut</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-down-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-down-shape"></a>Triangle vers le bas</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-left-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-left-shape"></a>Triangle vers la gauche</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-right-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-right-shape"></a>Triangle vers la droite</h3><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-top-left-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-top-left-shape"></a>Triangle rectangle en haut à gauche</h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-top-right-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-top-right-shape"></a>Triangle rectangle en haut à droite</h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-bottom-left-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-bottom-left-shape"></a>Triangle rectangle en bas à gauche</h3></div><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-triangle-bottom-right-shape" aria-hidden="true" class="aal_anchor" id="aa-triangle-bottom-right-shape"></a>Triangle rectangle en bas à droite</h3><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-curved-tail-arrow-shape-via-ando-razafimandimby" aria-hidden="true" class="aal_anchor" id="aa-curved-tail-arrow-shape-via-ando-razafimandimby"></a>Flèche courbe <a href="http://about.me/fwd" rel="noopener">via Ando Razafimandimby</a></h3></div><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-trapezoid-shape" aria-hidden="true" class="aal_anchor" id="aa-trapezoid-shape"></a>Trapezoïde</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-parallelogram-shape" aria-hidden="true" class="aal_anchor" id="aa-parallelogram-shape"></a>Parallèlogramme</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-star-6-points-shape" aria-hidden="true" class="aal_anchor" id="aa-star-6-points-shape"></a>Étoile (6 points)</h3><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-star-5-points-shape-via-kit-macallister" aria-hidden="true" class="aal_anchor" id="aa-star-5-points-shape-via-kit-macallister"></a>Étoile (5 points) Shape <a href="http://kitmacallister.com/2011/css-only-5-point-star/" rel="noopener">via Kit MacAllister</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-pentagon-shape" aria-hidden="true" class="aal_anchor" id="aa-pentagon-shape"></a>Pentagone</h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-hexagon-shape-via-aaron-hanson" aria-hidden="true" class="aal_anchor" id="aa-hexagon-shape-via-aaron-hanson"></a>Hexagone <a>via Aaron Hanson</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-octagon-shape" aria-hidden="true" class="aal_anchor" id="aa-octagon-shape"></a>Octogone</h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-heart-shape-via-nicolas-gallagher" aria-hidden="true" class="aal_anchor" id="aa-heart-shape-via-nicolas-gallagher"></a>Cœur <a href="http://nicolasgallagher.com/" rel="noopener">via Nicolas Gallagher</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-infinity-shape-via-nicolas-gallagher" aria-hidden="true" class="aal_anchor" id="aa-infinity-shape-via-nicolas-gallagher"></a>Infini <a href="http://nicolasgallagher.com/" rel="noopener">via Nicolas Gallagher</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-diamond-square-shape-via-joseph-silber" aria-hidden="true" class="aal_anchor" id="aa-diamond-square-shape-via-joseph-silber"></a>Carreau <a href="http://josephsilber.com" rel="noopener">via Joseph Silber</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-diamond-shield-shape-via-joseph-silber" aria-hidden="true" class="aal_anchor" id="aa-diamond-shield-shape-via-joseph-silber"></a>Diamant <a href="http://josephsilber.com" rel="noopener">via Joseph Silber</a></h3></div><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-diamond-narrow-shape-via-joseph-silber" aria-hidden="true" class="aal_anchor" id="aa-diamond-narrow-shape-via-joseph-silber"></a>Carreau resserré <a href="http://josephsilber.com" rel="noopener">via Joseph Silber</a></h3><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-cut-diamond-shape-via-alexander-futekov" aria-hidden="true" class="aal_anchor" id="aa-cut-diamond-shape-via-alexander-futekov"></a>Diamant taillé via Alexander Futekov</h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-pac-man-shape" aria-hidden="true" class="aal_anchor" id="aa-pac-man-shape"></a>Pac-Man</h3></div><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-talk-bubble-shape" aria-hidden="true" class="aal_anchor" id="aa-talk-bubble-shape"></a>Bulle</h3><div class="shape"><h3>RSS Feed <a href="https://codepen.io/lineus/pen/jOOyarv" rel="noopener">via Kevin Huff</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-12-point-burst-shape-via-alan-johnson" aria-hidden="true" class="aal_anchor" id="aa-12-point-burst-shape-via-alan-johnson"></a>Explosion 12 Points <a href="http://commondream.net/post/8848553728/pure-css-badges" rel="noopener">via Alan Johnson</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-8-point-burst-shape-via-alan-johnson" aria-hidden="true" class="aal_anchor" id="aa-8-point-burst-shape-via-alan-johnson"></a>Explosion 8 Points <a href="http://commondream.net/post/8848553728/pure-css-badges" rel="noopener">via Alan Johnson</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-yin-yang-shape-via-alexander-futekov" aria-hidden="true" class="aal_anchor" id="aa-yin-yang-shape-via-alexander-futekov"></a>Yin Yang <a>via Alexander Futekov</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-badge-ribbon-shape-via-catalin-rosu" aria-hidden="true" class="aal_anchor" id="aa-badge-ribbon-shape-via-catalin-rosu"></a>Ruban de badge <a href="https://catalin.red/" rel="noopener">via Catalin Rosu</a></h3></div><div class="shape"><h3>Space Invader Shape <a href="http://ecsspert.com/" rel="noopener">via Vlad Zinculescu</a></h3></div><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-tv-screen-shape" aria-hidden="true" class="aal_anchor" id="aa-tv-screen-shape"></a>Écran télé</h3><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-chevron-shape-via-anthony-ticknor" aria-hidden="true" class="aal_anchor" id="aa-chevron-shape-via-anthony-ticknor"></a>Chevron <a href="http://twitter.com/apticknor" rel="noopener">via Anthony Ticknor</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-magnifying-glass-shape" aria-hidden="true" class="aal_anchor" id="aa-magnifying-glass-shape"></a>Loupe</h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-facebook-icon-shape-via-nathan-swartz" aria-hidden="true" class="aal_anchor" id="aa-facebook-icon-shape-via-nathan-swartz"></a>Icone Facebook<a href="http://clicknathan.com/" rel="noopener">via Nathan Swartz</a></h3></div><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-moon-shape-via-omid-rasouli" aria-hidden="true" class="aal_anchor" id="aa-moon-shape-via-omid-rasouli"></a>Croissant de Lune <a href="http://www.blendesign.ir/" rel="noopener">via Omid Rasouli</a></h3></div><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-flag-shape-via-zoe-rooney" aria-hidden="true" class="aal_anchor" id="aa-flag-shape-via-zoe-rooney"></a>Drapeau <a href="http://codepen.io/zoerooney/pen/xIoCn" rel="noopener">via Zoe Rooney</a></h3><div class="shape"><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-cone-shape-via-omid-rasouli" aria-hidden="true" class="aal_anchor" id="aa-cone-shape-via-omid-rasouli"></a>Cône <a href="http://www.blendesign.ir/" rel="noopener">via Omid Rasouli</a></h3></div><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-cross-shape-via-kaya-basharan" aria-hidden="true" class="aal_anchor" id="aa-cross-shape-via-kaya-basharan"></a>Croix <a>via Kaya Basharan</a></h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-base-via-josh-rodgers" aria-hidden="true" class="aal_anchor" id="aa-base-via-josh-rodgers"></a>Enveloppe <a href="http://joshrodgers.com/" rel="noopener">via Josh Rodgers</a></h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-pointer-via-amsakanna-alt" aria-hidden="true" class="aal_anchor" id="aa-pointer-via-amsakanna-alt"></a>Pointeur (via Amsakanna / <a href="https://codepen.io/gditoro/pen/oNzrJeV" rel="noopener">alt</a>)</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-lock-shape" aria-hidden="true" class="aal_anchor" id="aa-lock-shape"></a>Cadenas</h3><p></p><h3><a href="https://la-cascade.io/articles/creer-des-formes-en-css#aa-reverse-corners-via-zberno" aria-hidden="true" class="aal_anchor" id="aa-reverse-corners-via-zberno"></a>Coins (via Zberno)</h3><p>NdT: et pour terminer, vous pouvez voir aussi <a href="https://slides.com/sarasoueidan/building-better-interfaces-with-svg#/5">ces diapos</a> de <a href="https://la-cascade.io/auteurs/sara-soueidan">Sara Soueidan</a> qui recommande SVG plutôt que CSS. Pour clip-path, vous pouvez consulter ici <a href="https://la-cascade.io/articles/comprendre-clip-path">Comprendre clip-path</a>. Pour <a href="https://la-cascade.io/tags/svg">SVG</a>, les articles ne manquent pas dans la Cascade, en particulier la série des "Bases de SVG".</p></div>]]></description>
      <link>https://la-cascade.io/articles/creer-des-formes-en-css</link>
      <guid>https://la-cascade.io/articles/creer-des-formes-en-css</guid>
      <pubDate>Sat, 14 Jan 2023 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Petit guide pour l'ajout d'images]]></title>
      <description><![CDATA[<p><em>Ajouter une image avec HTML n'est pas si simple, quand on commence à entrer dans les détails.</em></p><div class="articleContent"><p>Ajouter une image avec HTML c'est assez facile, n'est-ce pas ? c'est juste une simple balise, après tout...</p><pre class="language-html">&lt;img src="path/to/image.jpg" /&gt;</pre><p>Mais lorsque nous commencons à prendre en considération la performance, les tailles d'écran, l'accessibilité, la densité de pixels ou les préférences de l'utilisateur, on peut finir par se demander si HTML est suffisant à lui seul pour cette tâche... Et la réponse est oui ! Le HTML a de nombreuses options et il est suffisamment puissant pour gérer cette tâche. Cet article traitera de ce que nous devons considérer au moment d'ajouter une image à un site avec HTML.</p><h2>Considérations de base</h2><h3>Attribut <code>alt</code></h3><p>Commençons par un élément très important : votre image a besoin d'un texte alternatif. Ça permettra aux utilisateurs de lecteurs d'écran d'identifier le contenu de l'image, mais ça les aidera également lorsque l'image ne se charge pas (peut-être parce que l'image n'est pas disponible, ou peut-être parce que l'utilisateur a un réseau lent). Sinon, ils ne sauront pas ce qu'est l'image. Cela peut être fait avec l'attribut alt.</p><pre class="language-html">&lt;img
  src="path/to/image.jpg"
  alt="Un chat blanc allongé sur un canapé"
/&gt;</pre><p>Gardez à l'esprit que parfois, une image est là à des fins purement décoratives, donc la rendre visible pour les lecteurs d'écran pourrait ne pas être idéal, dans ce cas, nous pouvons utiliser un <code>alt</code> vide pour que les lecteurs d'écran ignorent cette image.</p><pre class="language-html">&lt;img src="path/to/image.jpg" alt="" /&gt;</pre><p>Que doit contenir le texte alternatif ? En général, il doit contenir une description concise de ce que contient l'image. S'il s'agit d'une image contenant des informations importantes (comme le lieu d'un événement ou une infographie complète), ces informations doivent également figurer dans le texte alternatif. Le W3C a créé <a href="https://www.w3.org/WAI/tutorials/images/decision-tree/">un arbre de décision alt</a> pour nous aider à décider des informations à ajouter.</p><h3>Attributs de largeur et de hauteur</h3><p>L'une des mesures les plus importantes des performances est le <strong>décalage cumulatif de la mise en page</strong> (<em>Cumulative Layout Shift</em>, CLS), qui évalue dans quelle mesure le contenu d'un site Web se déplace lorsqu'il est à l'écran. En d'autres termes, un CLS faible signifie que le contenu est assez stable et ne créera aucun problème avec l'interactivité de l'utilisateur. Pour en savoir plus sur ce concept, vous pouvez consulter <a href="https://web.dev/cls/">cet article sur web.dev à propos de CLS</a>.</p><p>Le chargement d'images peut créer des problèmes de décalage de mise en page et une façon de les éviter est d'utiliser les attributs <code>width</code> et <code>height</code> pour les images. Ils indiquent au navigateur la taille intrinsèque de l'image et créent le ratio d'aspect de l'image lors du chargement du site Web, ce qui réduit le décalage de mise en page qu'il peut créer. Voici à quoi cela ressemblerait dans une image.</p><pre class="language-html">&lt;img
  src="path/to/image.jpg"
  alt="Un chat blanc couché sur un canapé"
  width="1200"
  height="800"
/&gt;</pre><p>Mais ce n'est pas tout ce que nous pouvons faire pour améliorer les performances de notre site Web avec une balise <code>img</code> !</p><h3>Chargement paresseux</h3><p>Nous pouvons avoir beaucoup d'images sur notre site Web, et cela peut affecter son temps de chargement. C'est là qu'intervient le concept de chargement paresseux (<strong>lazy loading</strong>). Ça signifie que l'image ne commencera à se charger que lorsqu'elle se trouvera dans la partie visible de la fenêtre d'affichage. Il fut un temps où cela se faisait avec JavaScript mais maintenant HTML nous offre un moyen de le faire facilement en utilisant l'attribut <code>loading="lazy"</code>.</p><pre class="language-html">&lt;img
  src="path/to/image.jpg"
  alt="Un chat blanc couché sur un canapé"
  width="1200"
  height="800"
  loading="lazy"
/&gt;</pre><p>Lorsque nous utilisons <code>loading="lazy"</code> en tandem avec les attributs <code>height</code> et <code>width</code>, nous nous assurons que le site Web dispose de suffisamment d'espace pour l'image au moment du chargement, et en même temps, nous ne chargons l'image que si l'utilisateur en a besoin, ce qui est excellent pour les performances !</p><p>N'oublions pas cependant que si un utilisateur a désactivé JavaScript, <code>loading="lazy"</code> ne fonctionnera pas. Nous devons donc garder à l'esprit d'autres considérations liées aux performances, mais mettons ce sujet en veilleuse pour l'instant.</p><p>N'oublions pas non plus que l'utilisation de <code>loading="lazy"</code> dans notre élément <em>Largest Content Painting</em> (nous parlerons de cette métrique plus tard) augmentera en fait notre temps de chargement. Soyons donc prudent et testons toujours cet élément pour savoir si cet attribut donne les résultats escomptés.</p><h3>figure et figcaption</h3><p>Parfois, nous devons ajouter des informations supplémentaires qui ne tiendraient pas dans la balise <code>alt</code>, comme les crédits de l'image, ou une note importante à son sujet à laquelle nous préférons que tout le monde ait accès. Nous pouvons utiliser la balise <code>figure</code> pour envelopper l'<code>img</code>, puis ajouter une légende avec la balise <code>figcaption</code>.</p><pre class="language-html">&lt;figure&gt;
  &lt;img
    src="path/to/image.jpg"
    alt="Un chat blanc couché sur un canapé"
    width="1200"
    height="800"
    loading="lazy"
  /&gt;
  &lt;figcaption&gt;
    Les chats persans sont reconnaissables à leurs gros poils, leur
    visage rond et leur museau court
  &lt;/figcaption&gt;
  .
&lt;/figure&gt;</pre><p><code>figcaption</code> doit être un enfant direct de l'élément <code>figure</code>, sinon, il pourrait ne pas être reconnu par les technologies d'assistance. C'est un point que <a href="https://la-cascade.io/auteurs/manuel-matuzovic">Manuel</a> souligne dans son article <a href="https://www.matuzo.at/blog/2022/divs-are-bad/">divs are bad!</a>.</p><p>Garder ces considérations à l'esprit aide beaucoup lorsque nous créons une image, mais ce n'est que la partie émergée de l'iceberg. Lorsque nous commençons à prendre en considération de multiples variables comme les tailles d'écran, les formats d'image et les préférences des utilisateurs, la balise <code>img</code> commence à manquer de puissance. C'est là qu'une autre balise entre en jeu pour ajouter plus de fonctionnalités !</p><h2>La balise <code>picture</code></h2><p>Cette balise est un conteneur pour de multiples sources d'images. Selon les conditions que nous y ajoutons, le navigateur commencera à choisir le bon fichier en fonction de multiples facteurs comme la taille du viewport, le format de l'image, la densité des pixels ou les préférences de l'utilisateur. Il agit comme un emballage pour les multiples éléments de source que nous utiliserons pour déterminer la meilleure image.</p><p>Commençons par vérifier ce que nous pouvons faire avec cet élément.</p><h3>Prise en charge de différents formats d'image</h3><p>À côté des formats d'image <code>.png</code> ou <code>.jpg</code>, il existe de nouveaux formats d'image tels que <code>.avif</code>, <code>.webp</code> ou <code>.apng</code> que nous pourrions vouloir utiliser parce qu'ils ne présentent pas de perte de qualité tout en étant beaucoup moins lourds qu'un format plus courant. Cependant, les formats d'image mentionnés précédemment bénéficient d'une prise en charge plus large. Nous pouvons utiliser la balise <code>source</code> pour nous permettre d'utiliser des formats d'image plus optimisés en fonction du support du navigateur. Pour cela, nous pouvons utiliser l'attribut <code>type</code> dans l'élément <code>source</code> pour indiquer le format que nous devons évaluer.</p><pre class="language-html">&lt;picture&gt;
  &lt;source srcset="path/to/image.avif" type="image/avif" /&gt;
  &lt;source srcset="path/to/image.webp" type="image/webp" /&gt;
  &lt;img
    src="path/to/image.jpg"
    alt="Un chat blanc couché sur un canapé"
    width="1200"
    height="800"
    loading="lazy"
  /&gt;
&lt;/picture&gt;</pre><p>Dans ce cas, il commencera à vérifier si le navigateur accepte le format <code>.avif</code>, et si ce n'est pas le cas (comme Safari avant la version 16), il vérifiera si le format <code>.webp</code> est supporté. Si ce n'est pas le cas, il affichera celui de l'élément <code>img</code>. Il existe de nombreux formats d'image. Si vous voulez en savoir plus, vous pouvez consulter <a href="https://developer.mozilla.org/fr/docs/Web/Media/Formats/Image_types">la documentation de MDN</a> à ce sujet.</p><p>Vous vous souvenez que j'ai mentionné que <code>loading="lazy"</code> pourrait ne pas être suffisant pour des raisons de performances ? Ça nous aidera à prendre en compte la compatibilité navigateur pour charger l'image optimale, créant ainsi un système très robuste pour donner à l'utilisateur la meilleure qualité d'image possible <strong>et</strong> utiliser le moins de bande passante possible. C'est le meilleur des deux mondes, et c'est possible avec seulement du HTML !</p><h3>Images responsives</h3><p>Nous pourrions vouloir montrer une image différente ou une partie différente d'une image en fonction de la taille du viewport. L'élément <code>picture</code> peut nous y aider grâce à l'attribut <code>media</code>, où nous pouvons utiliser une <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Media_Queries/Using_media_queries">requête media</a> pour détecter la taille du viewport et ajouter une image différente si nécessaire.</p><pre class="language-html">&lt;picture&gt;
  &lt;source
    srcset="path/to/image-mobile.jpg"
    media="(max-width : 600px)"
  /&gt;
  &lt;img
    src="path/to/image.jpg"
    alt="Un chat blanc couché sur un canapé"
    width="1200"
    height="800"
    loading="lazy"
  /&gt;
&lt;/picture&gt;</pre><p>Nous pouvons y utiliser n'importe quelle requête média valide. Ainsi, par exemple, <code>orientation : portrait</code> et <code>orientation : landscape</code> sont des options valides lorsque nous souhaitons afficher une image différente selon que la largeur du viewport est supérieure (ou inférieure) à sa largeur. Il existe de nombreuses possibilités que nous pouvons envisager pour donner la meilleure image à l'utilisateur.</p><h3>Préférences de l'utilisateur</h3><p>Maintenant, c'est très pratique pour les performances et l'expérience utilisateur, mais c'est également utile pour l'accessibilité : nous pouvons vérifier les préférences de l'utilisateur pour aider les personnes souffrant de certains handicaps.Par exemple, certaines personnes peuvent avoir des problèmes comme des migraines et préférer utiliser le mode sombre, et une image très lumineuse pourrait déclencher une crise de migraine, donc avoir une version de votre image mieux adaptée au mode sombre serait idéal.</p><p>Ou peut-être avons-nous un <code>gif</code>, et quelqu'un a désactivé les animations sur son appareil. Nous pourrions vouloir montrer une image statique à la place afin que son expérience ne soit pas affectée. Comment faire ?</p><p>Comme je l'ai mentionné, nous pouvons utiliser n'importe quelle requête média valide, ce qui inclut les requêtes média qui vérifient les préférences de l'utilisateur comme <code>prefers-color-scheme</code> ou <code>prefers-reduced-motion</code>. Nous pouvons même les combiner avec des opérateurs logiques pour afficher l'image appropriée. Voyons comment cela fonctionne avec un exemple.</p><pre class="language-html">&lt;picture&gt;
  &lt;!-- La préférence pour le mode sombre et les animations sont désactivées --&gt;
  &lt;source
    srcset="path/to/image-dm.jpg"
    media="(prefers-reduced-motion : reduce) and (prefers-color-scheme : dark)"
  /&gt;
  &lt;!-- Image statique lorsque les animations sont désactivées --&gt;
  &lt;source
    srcset="path/to/image.jpg"
    media="(prefers-reduced-motion : reduce)"
  /&gt;
  &lt;!-- La préférence pour le mode sombre est vérifiée --&gt;
  &lt;source
    srcset="path/to/image-dm.gif"
    media="(prefers-color-scheme : dark)"
  /&gt;
  &lt;!-- Aucune de ces préférences n'est active --&gt;
  &lt;img
    src="path/to/image.gif"
    alt="Un chat qui danse"
    width="1200"
    height="800"
    loading="lazy"
  /&gt;
&lt;/picture&gt;</pre><p>Il est important de noter ici que l'ordre a de l'importance. Il est préférable d'ajouter d'abord les balises ayant des exigences plus spécifiques en matière de requête média pour être sûr qu'elles ne seront pas écrasées par celles qui apparaîtront plus tard. Gardez également à l'esprit que vous pouvez combiner tout ce que vous avez vu, il y a donc beaucoup de possibilités avec les éléments <code>picture</code> et <code>source</code>.</p><p>Cela couvre pratiquement tout ce que vous devez prendre en considération, mais il y a encore quelques points que vous pouvez prendre en compte.</p><h2>Considérations supplémentaires</h2><h3>Densité des pixels et <code>srcset</code></h3><p>L'attribut <code>srcset</code> que nous utilisons dans l'élément <code>picture</code> a une syntaxe légèrement différente si nous souhaitons donner une meilleure image en fonction de la densité de pixels de l'appareil. Pour cela, nous pouvons ajouter une liste d'images séparées par des virgules et après l'URL de l'image, nous mettrons le type de densité de pixels que nous voulons prendre en charge avec cette image. Voyons cela avec un exemple :</p><pre class="language-html">&lt;picture&gt;
  &lt;source
    srcset="
      path/to/image-mobile.jpg    1x,
      path/to/image-mobile-2x.jpg 2x,
      path/to-image-mobile-3x.jpg 3x
    "
    media="(max-width : 600px)"
  /&gt;
  &lt;img
    src="path/to/image.jpg"
    alt="Un chat blanc couché sur un canapé"
    width="1200"
    height="800"
    srcset="path/to/image-2x.jpg 2x, path/to/image-3x.jpg 3x"
    loading="lazy"
  /&gt;
&lt;/picture&gt;</pre><p>Il y a encore quelque chose que je n'ai pas mentionné et c'est le fait que nous pouvons utiliser l'attribut <code>srcset</code> dans l'élément <code>img</code>, et cela fonctionne très bien lorsque nous voulons prendre en charge des images en fonction de la densité de pixels de l'appareil. La prochaine fois que vous voudrez apporter des images de meilleure qualité pour les images en fonction de l'appareil, vous savez maintenant comment faire !</p><h3>Précharger l'image pour améliorer le LCP</h3><p>Vous vous souvenez quand j'ai mentionné LCP ? Il existe une autre métrique appelée <a href="https://web.dev/lcp/">Largest Content Paint</a> (LCP) qui mesure le temps nécessaire pour charger la plus grande image (ou bloc de texte) à rendre dans le viewport. Généralement, ce LCP est une grande image. Nous pouvons utiliser d'autres formats d'image pour diminuer la taille du LCP, mais que faire si cela ne suffit pas ? Nous avons l'alternative de précharger l'image dans le <code>head</code>, ce qui rendra l'image plus rapide, et par extension, améliorera cette métrique. Voici à quoi cela ressemblerait dans notre balise <code>head</code>.</p><pre class="language-html">&lt;head&gt;
  &lt;link rel="preload" href="path/to/image.jpg" as="image" /&gt;
&lt;/head&gt;</pre><p>Atention à ne pas abuser de cette technique cependant, car sinon, elle augmentera le temps de chargement de la page. Utilisez-la simplement pour votre ou vos images les plus importantes et testez les performances en conséquence pour vérifier si elle améliore ces métriques.</p><p>`décodage="async"``</p><p>J'ai déjà mentionné <code>loading="lazy"</code>, mais il existe un autre attribut HTML que nous pouvons utiliser pour optimiser le temps de chargement d'un site Web. Alors que <code>loading="lazy"</code> décide du <strong>moment</strong> où l'image sera chargée (au moment où elle est proche du viewport), nous avons un autre attribut qui définit <strong>comment</strong> elle sera chargée.</p><p>Normalement, tout notre site sera chargé de manière synchrone parce que le navigateur lit le HTML ligne par ligne, donc s'il trouve une grande image, le reste du site ne se téléchargera pas avant que l'image soit chargée. C'est là que <code>decoding="async"</code> entre en jeu pour donner une indication au navigateur d'essayer de télécharger l'image et en même temps de télécharger une autre partie du site.</p><pre class="language-html">&lt;img
  alt="Un chat blanc allongé sur un canapé"
  width="1200"
  height="800"
  loading="lazy"
  decoding="async"
/&gt;</pre><p>L'utilisation des deux, <code>decoding="async"</code> et <code>loading="lazy"</code>, dans une image contribuera à réduire considérablement le temps de chargement d'un site Web, et le <code>decoding</code> est un attribut largement pris en charge.</p><h2>Conclusion</h2><p>Ajouter une image à un site Web est facile... Mais les choses commencent à se compliquer lorsque nous commençons à prendre en compte les considérations de performance et d'accessibilité. Heureusement pour nous, HTML peut nous donner les outils appropriés pour aborder ces considérations sans aucun problème.</p><p>J'ai choisi ce sujet pour ce calendrier de l'Avent pour une bonne raison et c'est parce qu'il m'a fait remarquer à quel point le HTML est puissant, robuste et étonnamment complexe. Voir ce que le HTML a à offrir juste pour amener la bonne image sur votre écran avec un effort relativement faible était fascinant et cela m'a donné envie de creuser plus profondément dans ce que le HTML peut faire.</p></div>]]></description>
      <link>https://la-cascade.io/articles/petit-guide-pour-ajout-image</link>
      <guid>https://la-cascade.io/articles/petit-guide-pour-ajout-image</guid>
      <pubDate>Sat, 31 Dec 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Pas besoin de framework UI]]></title>
      <description><![CDATA[<p><em>Les développeurs utilisent souvent des frameworks UI pour donner un look professionnel à leur site, ou se faciliter la vie. Mais les choses se passent rarement comme ils l'espèrent.</em></p><div class="articleContent"><p>On me demande régulièrement des recommandations sur les frameworks d'interface utilisateur. Par "framework d'interface utilisateur", j'entends tout package tiers qui se concentre sur la fourniture de composants d'interface utilisateur stylisés. Ça comprend les frameworks CSS comme <a href="https://getbootstrap.com/">Bootstrap</a>, et les bibliothèques de composants JS comme <a href="https://mui.com/">Material UI</a> ou <a href="https://ant.design/">Ant Design</a>.</p><p>Ma réponse à cette question prend généralement les gens au dépourvu : je ne les utilise pas, et je ne pense pas qu'ils devraient être utilisés. ?</p><p>Pour être clair, je n'ai rien contre ces outils, et je pense qu'il en existe des cas d'utilisation valables. Mais j'ai vu trop de développeurs se jeter sur ces outils avec des attentes irréalistes quant aux problèmes qu'ils veulent résoudre ou à la facilité avec laquelle ils vont pouvoir créer des applications.</p><p>Dans cet article, je vais expliquer pourquoi vous n'avez probablement pas besoin de ces outils. Je vous ferai également part de quelques-unes de mes stratégies pour créer des applications d'aspect professionnel sans avoir de formation en design.</p><h2>L'attrait des frameworks</h2><p>Les raisons d'opter pour un framework d'interface utilisateur sont nombreuses. Voici les trois plus courantes que j'ai constatées :</p><ol><li>Les développeurs veulent que leur application/site ait une apparence soignée et professionnelle, et ces outils fournissent des composants d'interface utilisateur joliment conçus.</li>
<li>Ils veulent être rapidement opérationnels sans passer trop de temps à tout construire de zéro.</li>
<li>Ils reconnaissent que de nombreux composants de l'interface utilisateur, tels que les modales, les listes déroulantes et les infobulles, sont très difficiles à réaliser correctement, surtout si l'on tient compte de l'accessibilité, et ils veulent donc être sûrs de bien faire les choses.</li>
</ol><p>Ce sont des souhaits tout à fait raisonnables, et je peux absolument comprendre l'intérêt de trouver une solution à ces problèmes. Mais dans certains cas, je pense qu'il y a un décalage entre les attentes et la réalité. Dans d'autres, je pense qu'il existe de meilleurs outils pour ce travail.</p><p>Entrons dans le vif du sujet.</p><h3>Design professionnel</h3><p>Cette première raison est peut-être la plus courante. Il y a des tonnes de développeurs qui veulent construire des choses, mais qui n'ont pas de formation en design. Plutôt que de passer des années à apprendre le design, pourquoi ne pas utiliser une bibliothèque qui fournit des composants magnifiquement conçus dès la sortie de la boîte ?</p><p>Voici le problème, à mon avis : le design, c'est bien plus que de belles pièces.</p><p>Il y a quelque temps, j'ai reçu en cadeau une Nintendo Entertainment System LEGO :</p><figure><img src="https://la-cascade.io/images/lego-nintendo.webp" alt="Imge d'un LEGO Nintendo Entertainment System" /></figure><p>C'était un kit vraiment amusant à construire. Si vous êtes un fan de LEGO, je vous recommande vivement de le découvrir !</p><p>Voici le point, cependant : j'ai pu construire ce modèle parce que le kit était accompagné d'un livre de 200 pages qui me disait exactement où placer chaque brique.</p><p>Si l'on m'avait donné toutes les pièces sans instructions, mon NES aurait l'air bien pire que ce qu'il est. Il ne suffit pas d'avoir des briques de haute qualité, il faut aussi savoir comment les utiliser.</p><p>Une bibliothèque de composants peut vous donner de jolis boutons, des sélecteurs de date et des widgets de pagination, mais c'est toujours à vous de les assembler.</p><p>Les blocs d'un système de conception comme Material Design ont été construits par une équipe de design talentueuse. Cette équipe comprend le framwork et possède les compétences nécessaires pour assembler les pièces en de magnifiques interfaces. Nous avons accès aux mêmes pièces, mais cela ne signifie pas que nous obtiendrons automatiquement les mêmes résultats.</p><p>Je me souviens avoir entendu un designer dire que <em>seul Google pouvait créer des applications Material Design qui soient belles</em>. L'App Store d'Android est plein d'applications qui utilisent les mêmes composants conçus par des professionnels, mais qui n'ont pas du tout l'air professionnels.</p><p>Un bon design comporte tellement d'aspects intangibles - des choses comme l'équilibre, l'espacement et la cohérence. Pour utiliser efficacement une bibliothèque de composants, vous devez vous mettre à la place des designers qui l'ont créée et comprendre comment ils sont censés être déployés.</p><p>De plus, aussi complète que soit la bibliothèque, elle ne contiendra jamais toutes les pièces dont vous avez besoin. Chaque application, chaque site Web est unique, et il y aura toujours des exigences particulières. Créer un tout nouveau composant qui se "fond" dans un système de design existant est vraiment très difficile.</p><p>Je ne pense pas que ce soit impossible - je suis même sûr qu'il existe des exemples d'applications d'aspect professionnel utilisant des styles tiers. Mais si vous êtes capable de le faire, c'est que vous avez probablement de sacrés talents de designer et que vous n'avez pas besoin de ces outils pour commencer.</p><p>Je compatis avec les développeurs qui veulent lancer un projet d'apparence professionnelle sans aucune sorte d'intuition en matière de design... Mais cela ne fonctionne généralement pas de cette façon, d'après ce que j'ai vu.</p><h3>Gagner du temps</h3><p>La raison suivante que j'ai entendue est que les frameworks d'interface utilisateur permettent de gagner du temps. Construire toute une bibliothèque de composants à partir de zéro est une entreprise importante qui peut être évitée en s'appuyant sur un framework d'interface utilisateur.</p><p>Il y a une part de vrai dans cette affirmation, mais d'après ce que j'ai souvent constaté, l'apprentissage c'est <em>l'histoire du lièvre et de la tortue</em>. Voici mon expérience :</p><p>J'ai passé quelques années à enseigner les principes fondamentaux du design Web aux étudiants du bootcamp de l'Université Concordia. Le programme se termine par un projet personnel de deux semaines. Les étudiants décident de ce qu'ils veulent construire, et c'est à eux de le faire. En tant qu'instructeur, je répondais aux questions et je les aidais quand ils étaient bloqués.</p><p>Nous avons remarqué une tendance : les étudiants qui choisissent un cadre d'interface utilisateur comme Bootstrap ou Material UI se lancent rapidement et font des progrès rapides les premiers jours. Mais au fil du temps, ils s'enlisent. L'écart entre ce dont ils ont besoin et ce que la bibliothèque de composants fournit apparaît progressivement au grand jour. Et ils finissent par passer beaucoup de temps à essayer de plier les composants à forme voulue.</p><p>Je me souviens d'un étudiant qui a passé tout un après-midi à essayer de modifier l'entête d'un framework CSS pour soutenir sa navigation. À la fin, le groupe a décidé de supprimer le composant tiers et ils ont construit eux-mêmes une alternative en 10 minutes.</p><p>Écrire vos propres styles me semble un peu comme écrire des tests : <strong>c'est un peu plus lent au début, mais cet effort initial est payant</strong>. À long terme, vous économiserez beaucoup de temps, d'énergie et de frustration.</p><h3>Utilisabilité et accessibilité</h3><p>La dernière raison que j'ai entendue est super valable. Le Web ne dispose pas d'une "bibliothèque standard" très solide lorsqu'il s'agit de choses comme les modales, les listes déroulantes et les infobulles. Construire une modale qui fonctionne bien pour les utilisateurs de souris, de clavier et de lecteurs d'écran est incroyablement difficile.</p><p>Les frameworks d'interface utilisateur ont un bilan mitigé en matière de convivialité et d'accessibilité. Certaines bibliothèques sont en fait assez bonnes à cet égard. Mais dans la plupart des cas, il s'agit d'une préoccupation secondaire.</p><p>Heureusement, il existe une autre catégorie d'outils qui se concentrent exclusivement sur la convivialité et l'accessibilité, sans prescrire un tas de styles.</p><p>Voici quelques-uns de mes outils préférés dans cette catégorie :</p><ul><li><strong><a href="https://reach.tech/">Reach UI</a></strong>Un ensemble de primitives axées sur l'accessibilité pour React. Construit par Ryan Florence, co-créateur de React Router et Remix.</li>
<li><strong><a href="https://headlessui.com/">Headless UI</a></strong>Un ensemble de composants d'interface utilisateur non stylisés et entièrement accessibles pour React et Vue. Construit et maintenu par l'équipe Tailwind.</li>
<li><strong><a href="https://www.radix-ui.com/">Radix Primitives</a></strong>Un ensemble de composants non stylisés et axés sur l'accessibilité pour React. Cette bibliothèque possède un ensemble très large de composants inclus, beaucoup de choses vraiment intéressantes !</li>
<li><strong><a href="https://react-spectrum.adobe.com/react-aria/">React ARIA</a></strong>Une bibliothèque de crochets React que vous pouvez utiliser pour construire des composants accessibles à partir de zéro.</li>
</ul><p>Note : Je réalise que cette liste est très chargée en React ; il peut y avoir des outils similaires pour Angular, Svelte, et d'autres frameworks, mais je ne suis pas aussi actif dans ces communautés, donc je ne suis pas sûr. N'hésitez pas à m'en faire part sur Twitter si vous en connaissez !</p><p>Personne ne devrait construire une modale à partir de zéro en l'an 2022, mais cela ne signifie pas que vous ayez besoin d'un énorme framework d'interface utilisateur incluant des styles ! Il existe des outils qui résolvent précisément les défis d'accessibilité les plus importants tout en restant totalement agnostiques en matière de cosmétique et de styles.</p><h2>Réfutations</h2><p>Ça fait maintenant quelques années que je discute de ce sujet avec des développeurs, et j'ai entendu des réfutations assez convaincantes.</p><h3>Familiarité</h3><p>Tout d'abord, Daniel Schutzsmith a souligné que les outils "standard de l'industrie" comme Bootstrap ont un gros avantage : la familiarité.</p><p>Il est plus facile d'intégrer de nouveaux développeurs et designers lorsqu'on utilise des outils largement compris. Les nouveaux membres de l'équipe n'ont pas besoin de passer un temps fou à apprendre les tenants et aboutissants d'un framework personnalisé, ils peuvent être opérationnels dès le départ.</p><p>Du point de vue d'une agence qui prend de nombreux projets de court ou moyen terme, cela pourrait avoir beaucoup de sens. Ils n'ont pas besoin de démarrer chaque nouveau projet à partir de zéro. Et au fur et à mesure que l'équipe se familiarise avec l'outil, elle apprend à l'utiliser très efficacement.</p><p>Je n'ai pas beaucoup travaillé en agence, il m'est donc difficile de me prononcer. J'ai passé la majeure partie de ma carrière à travailler pour des entreprises de produits. Aucune des entreprises pour lesquelles j'ai travaillé n'a jamais utilisé un framework d'interface utilisateur. Nous avons toujours construit quelque chose en interne (par exemple, Wonder Blocks chez Khan Academy, ou Walrus chez DigitalOcean).</p><h3>Outils internes</h3><p>Je pense qu'il peut être judicieux d'utiliser un framework d'interface utilisateur lors de la création d'outils internes ou d'autres projets non destinés à la consommation publique (par exemple, des prototypes).</p><p>Si le but est de mettre rapidement quelque chose en place et de le faire fonctionner, et que vous n'avez pas besoin que l'interface utilisateur soit 100% professionnelle, je pense que cela peut être un gain de temps d'intégrer rapidement un tas de composants tiers.</p><h2>Quid de Tailwind et de Chakra UI ?</h2><p>Je ne considère pas Tailwind ou Chakra UI comme faisant partie de cette même catégorie de "frameworks UI".</p><p><a href="https://tailwindcss.com/">Tailwind</a> ne fournit pas de composants prêts à l'emploi, mais il fournit des <em>garanties</em> de design. <a href="https://mxstbr.com/thoughts/tailwind/">Comme le dit Max Stoiber</a>, Tailwind donne aux développeurs un ensemble de garde-fous. Vous avez toujours besoin d'une intuition de conception pour l'utiliser efficacement, mais ce n'est pas aussi intimidant que de concevoir quelque chose à partir de zéro.</p><p><a href="https://chakra-ui.com/">Chakra UI</a> fournit des composants stylisés prêts à l'emploi, mais ils sont très minimes et de bas niveau. La plupart du temps, ils ressemblent simplement à des versions plus agréables des paramètres par défaut de la plate-forme.</p><p>Ma bonne amie Emi m'a dit qu'elle aimait utiliser Chakra UI parce qu'il lui fournit un ensemble de valeurs par défaut raisonnables pour des choses comme les cases à cocher et les boutons radio. Elle est suffisamment douée en matière de conception pour éviter les pièges de la personnalisation, mais pas assez pour se sentir à l'aise pour créer tout un système de design à partir de zéro. Cet outil est le juste milieu idéal pour une personne dans sa situation.</p><p>Je pense que la différence est que ces solutions ne prétendent pas résoudre le design pour vous. Elles vous poussent dans la bonne direction, mais elles s'assurent que tout est personnalisable et que vous n'êtes pas enfermé dans une esthétique de design spécifique.</p><h2>Ma suggestion alternative</h2><p>Donc, si vous êtes un développeur solo qui veut créer des sites Web et des applications d'aspect professionnel, mais qui n'a pas de formation en design, que devez-vous faire ?</p><p>J'ai quelques suggestions.</p><h3>Développez une intuition du design</h3><p>Voici la mauvaise nouvelle : je pense que vous devriez consacrer un peu de temps à l'apprentissage de certains principes fondamentaux du design.</p><p>C'est l'une de ces choses pour lesquelles un petit peu suffit. Vous n'avez pas besoin d'aller dans une école d'art ou de consacrer des années à l'apprentissage d'un nouveau métier. Le design est difficile, mais nous n'essayons pas de devenir des designers de classe mondiale. Nos objectifs sont beaucoup plus modestes, et vous pourriez être surpris par la rapidité avec laquelle ils peuvent être atteints, ou par le chemin que vous avez déjà parcouru !</p><p>Même si vous n'êtes pas très intéressé par le design, je pense que développer une intuition de design est une compétence essentielle pour les développeurs front. Croyez-le ou pas, nous prenons constamment des décisions de design dans notre travail. Même à la maquette haute-fidélité la plus détaillée il manque toujours d'une tonne de contexte important.</p><p>Par exemple :</p><ul><li>Si nous avons de la chance, on peut nous donner 3 tailles d'écran, mais c'est à nous de décider comment l'interface utilisateur doit se comporter entre ces tailles d'écran.</li>
<li>Les données sont rarement aussi propres qu'elles apparaissent dans les maquettes, et nous devons décider comment gérer les longs noms, les données manquantes, etc.</li>
<li>Les états de chargement, de données manquantes et d'erreur sont souvent absents des maquettes.</li>
</ul><p>L'un de mes super-pouvoirs en tant que développeur est d'avoir suffisamment de sens du design pour pouvoir déterminer ce qu'il faut faire lorsque je me heurte à une situation qui n'est pas clairement spécifiée dans le design. Au lieu d'être bloqué, en attendant que le designer réponde à mes questions, je peux me fier à mon intuition. Je n'y arriverai pas toujours, mais c'est généralement le cas (et lorsque ce n'est pas le cas, c'est une nouvelle occasion d'améliorer mon intuition en matière de design !)</p><h4>Comment développer une intuition de design ?</h4><p>Si vous travaillez avec une équipe de produit/design, vous disposez d'une ressource formidable ! Réfléchissez de manière critique aux conceptions qu'ils produisent. Posez beaucoup de questions — la plupart des designers seront ravis de vous aider à comprendre comment les choses sont structurées, et pourquoi ils ont pris les décisions qu'ils ont prises. Traitez-le comme un défi d'ingénierie. Vous pouvez apprendre les systèmes et les processus qui mènent à de bons designs.</p><p>J'ai écrit un article de blog il y a quelque temps, intitulé "<a href="https://www.joshwcomeau.com/career/effective-collaboration/">Collaboration efficace avec le produit et le design</a>". Il approfondit certaines de ces idées.</p><p>Si vous ne travaillez pas avec des designers (ou n'avez pas d'amis designers), vous pouvez essayer de faire de l'ingénierie inverse sur les produits que vous utilisez tous les jours. Prenez note de la façon dont les choses sont espacées, et des tailles de police utilisées. Avec un œil critique, vous commencerez à voir apparaître des patterns.</p><h3>Volez</h3><p>D'accord, même avec un sens aigu du design, il est toujours <em>très</em> difficile de créer un design à partir de rien. Alors, ne faisons pas cela.</p><p>Essayons plutôt de trouver des designs professionnels qui sont similaires à ce que nous essayons de construire. Vous pouvez faire des recherches sur des sites communautaires de designers comme <a href="https://dribbble.com/">dribbble</a> ou <a href="https://www.behance.net/">behance</a> ou utiliser des archives comme <a href="https://www.awwwards.com/">awwwards</a>.</p><p>Par exemple, disons que nous créons une startup Uber pour chiens, et que nous essayons de concevoir le tableau de bord du conducteur. Une recherche sur Dribbble pour "dashboard" fait apparaître une tonne de designs intéressants :</p><figure><img src="https://la-cascade.io/images/framework2.webp" alt="Résultat d'une recherche sur le mot 'tableau de bord' dans Dribbble" /></figure><p>Dribbble a tendance à être très "design", et vous pourriez donc vouloir utiliser des produits du monde réel pour vous inspirer. Ça fonctionne aussi !</p><p>L'astuce consiste à utiliser plusieurs sources. Si vous volez 100 % d'un design, c'est du plagiat et une mauvaise forme. Les gens vont le remarquer, et ça posera des problèmes.</p><p>Au lieu de ça, on peut mélanger 3 ou 4 designs ensemble pour créer quelque chose d'unique. Par exemple, je vais peut-être prendre le schéma de couleurs d'un site, la disposition générale et l'espacement d'un autre, et les styles de typographie du troisième !</p><p>Lorsque j'ai mentionné cette stratégie à de vrais designers, ils ont ri et m'ont dit que c'est ce qu'ils font tous. Je pense que c'est leur version de la "blague" selon laquelle les programmeurs passent la moitié de leur temps à googler des choses.</p><p>Cette stratégie ressemble à un véritable life hack. Elle ne se fait pas sans effort, et elle exige quelques compétences en matière de design. Les modèles que vous utilisez pour vous inspirer ne correspondront pas à 100 % à l'objet que vous construisez, et vous devrez faire appel à votre intuition pour combler les lacunes. Mais c'est de loin le moyen le plus rapide que j'ai trouvé pour créer un design d'aspect professionnel sans avoir de formation en design.</p><h2>En résumé</h2><p>En tant que développeurs, il peut être tentant de croire qu'un framework d'interface utilisateur nous dispensera d'apprendre quoi que ce soit sur le design. Malheureusement, cela ne se passe généralement pas ainsi. Du moins, pas d'après ce que j'ai vu.</p><p>Voici la bonne nouvelle : vous pouvez tout à fait créer un produit d'aspect professionnel sans être designer ! Avec quelques modèles de référence de haute qualité et un soupçon d'intuition en matière de design, vous pouvez construire quelque chose qui atteint le seuil du "suffisamment bon", où un produit semble légitime et "réel".</p><p>Il y a un autre aspect dont nous n'avons pas vraiment parlé : CSS.</p><p>Beaucoup de développeurs <em>front</em> ont du mal avec CSS. Moi aussi, j'ai eu du mal à m'y mettre ! CSS est un langage faussement complexe, et il peut souvent sembler incohérent et frustrant, même après avoir des années d'expérience avec le langage.</p><p>C'est un problème qui me tient à cœur. J'ai passé toute l'année dernière à me consacrer à plein temps à la création et au développement d'un cours CSS, afin d'aider les développeurs à gagner en confiance avec ce langage.</p><p>Il s'appelle <a href="https://css-for-js.dev/">CSS pour les développeurs JavaScript</a>. Il est conçu spécifiquement pour les personnes qui utilisent un framework JS comme React ou Angular. Le cours vise à vous donner un modèle mental robuste afin que vous ayez une compréhension intuitive du fonctionnement de CSS.</p><p>Si vous avez l'impression que CSS est imprévisible, j'espère vraiment que vous le consulterez. Plus de 9.000 développeurs ont déjà suivi le cours, et les retours ont été extrêmement positifs.</p><p>Vous pouvez en savoir plus ici : <a href="https://css-for-js.dev/">css-for-js.dev</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/pas-besoin-de-framework-ui</link>
      <guid>https://la-cascade.io/articles/pas-besoin-de-framework-ui</guid>
      <pubDate>Fri, 30 Dec 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Guide de l'accessibilité du clavier: JavaScript (2e partie)]]></title>
      <description><![CDATA[<p><em>Un ensemble d'outils JavaScript à utiliser dans différents composants pour améliorer l'expérience des utilisateurs du clavier.</em></p><div class="articleContent"><p>Dans <a href="https://la-cascade.io/articles/guide-accessibilite-clavier-1">l'article précédent</a>, nous avons vu comment améliorer l'accessibilité pour les utilisateurs de clavier grâce à HTML et CSS. Ces langages peuvent faire le job la plupart du temps, mais certaines contraintes de design et la nature même de certains composants nécessitent des interactions plus complexes, et c'est là que JavaScript entre en jeu.</p><p>Quand on parle d'accessibilité clavier, le travail se fait essentiellement avec des outils de base. Cet article couvre un ensemble d'outils que vous pouvez utiliser de pair avec différents composants afin d'améliorer l'accessibilité pour les utilisateurs du clavier.</p><h2>Les bases</h2><p>Notre travail avec JavaScript se fera généralement avec une poignée d'outils seulement, en particulier l'utilisation d'<em>event listeners</em> (<a href="https://developer.mozilla.org/fr/docs/Web/API/EventTarget/addEventListener">écouteurs d'événements</a>) et de certaines méthodes JavaScript de quelques API Web qui peuvent nous aider dans cette tâche.</p><p>Pour ajouter de l'interactivité à nos projets, l'un des outils les plus importants à notre disposition est l'<em>événement</em>, c'est-à-dire l'exécution d'une fonction qui se déclenche lorsque l'élément que nous contrôlons reçoit un changement.</p><h3>Événement <code>keydown</code></h3><p>Un exemple d'événement que nous pouvons <em>écouter</em> avec cette API Web est l'événement <code>keydown</code>, qui vérifie quand une touche (<em>key</em>) est enfoncée.</p><p>Cet événement n'est pas utile pour ajouter l'accessibilité du clavier à des éléments tels que les boutons ou les liens car, par défaut, lorsque nous leur ajoutons un <em>event listener</em> de clic, celui-ci déclenche également l'événement lorsque nous utilisons les touches <code>Entrée</code> (pour les boutons et les liens) et <code>Espace</code> (pour les boutons uniquement). L'utilité de l'événement <code>keydown</code> apparaît lorsque nous devons ajouter une fonctionnalité <em>à d'autres touches</em>.</p><p>Pour prendre un exemple, revenons à l'infobulle que nous avons créée dans la première partie de cet article. J'ai mentionné que cette infobulle devait être fermée lorsque nous appuyons sur la touche <code>Esc</code>. Nous aurions besoin d'un <em>event listener</em> de touche enfoncée afin de vérifier si la touche enfoncée est <code>Esc</code>. Pour cela, nous devons détecter la touche enfoncée de l'événement et nous allons donc vérifier la <em>propriété</em> de la touche de l'événement.</p><p>Nous utiliserons <a href="https://www.toptal.com/developers/keycode">keycode.info</a> pour vérifier le dump d'événement pour cette touche. Si vous appuyez sur la touche <code>Esc</code> sur votre clavier, vous remarquerez que <code>e.key</code> (event.key) est égal à <code>Escape</code>.</p><p>Remarque : Il existe deux autres façons de détecter qu'une touche est enfoncée, ce sont la vérification de <code>e.keyCode</code> et <code>e.which</code> qui renvoient toutes deux un nombre. Dans le cas de la touche <code>Esc</code>, ce sera <code>27</code> (qui est affiché en gros dans la page). Mais gardez à l'esprit qu'il s'agit de solutions alternatives dépréciées, et que même si elles fonctionnent, <code>e.key</code> est aujourd'hui l'option préférée.</p><p>Avec cela, nous devons sélectionner nos boutons et ajouter l'<em>event listener</em>. Mon approche en la matière est d'utiliser cet <em>event listener</em> pour <strong>ajouter une classe au bouton</strong> et d'ajouter cette classe comme exception afin de l'afficher en utilisant <a href="https://la-cascade.io/articles/la-pseudo-classe-de-negation">la pseudo-classe de négation</a> <code>:not()</code>. Commençons en modifiant un peu notre CSS :</p><pre class="language-css">button:not(.hide-tooltip):hover + [role='tooltip'],
button:not(.hide-tooltip):focus + [role='tooltip'],
[role='tooltip']:hover {
  display: block;
}</pre><p>Cette exception étant ajoutée, créons maintenant notre <em>event listener</em> !</p><pre class="language-js">const buttons = [...document.querySelectorAll('button')]
buttons.forEach((element) =&gt; {
  element.addEventListener('keydown', (e) =&gt; {
    if (e.key === 'Escape') {
      element.classList.add('hide-tooltip')
    }
  })
})</pre><p>Et voilà ! Avec juste un soupçon de JavaScript, nous avons ajouté une fonction d'accessibilité à notre infobulle. Et ce n'était que le début de ce que nous pouvons faire avec un <em>event listener</em> <code>keydown</code>. C'est un outil crucial pour améliorer l'accessibilité au clavier de plusieurs composants. Mais il existe encore un autre <em>event listener</em> que nous devons prendre en considération.</p><h3>L'événement <code>blur</code></h3><p>Il ya un autre événement que nous allons utiliser souvent. Celui-ci détecte <em>le moment où l'élément cesse de recevoir le focus</em>. Cet <em>event listener</em> est important, la plupart du temps vous l'utiliserez pour annuler les éventuelles modifications que vous avez apportées avec l'<em>event listener</em> <code>keydown</code>.</p><p>Revenons à l'infobulle. Pour l'instant, elle présente un problème : si vous appuyez sur la touche <code>Esc</code> pour fermer l'infobulle, puis que vous mettez à nouveau le focus sur le même élément, l'infobulle n'apparaîtra pas. Pourquoi ? Parce que nous avons <em>ajouté</em> la classe <code>hide-tooltip</code> lorsque l'utilisateur appuie sur la touche <code>Esc</code>, mais nous n'avons jamais <em>supprimé</em> cette classe. C'est ici que le <em>blur</em> (flou) entre en jeu. Ajoutons un <em>event listener</em> pour rétablir cette fonctionnalité.</p><pre class="language-js">element.addEventListener('blur', (e) =&gt; {
  if (element.classList.contains('hide-tooltip')) {
    element.classList.remove('hide-tooltip')
  }
})</pre><h3>Autres Event Listeners (et pourquoi vous n'en avez peut-être pas besoin)</h3><p>J'ai mentionné que nous aurions besoin de deux <em>event listeners</em> dans notre boîte à outils, mais il en existe d'autres que vous pourriez utiliser, comme <code>focusout</code> ou <code>focus</code>. Cependant, je pense que les cas d'utilisation pour eux sont assez rares. Mention spéciale pour <code>focus</code> toutefois car même si vous pouvez trouver de bons cas d'utilisation pour lui, vous devez être très prudent : si vous ne l'utilisez pas correctement, vous pouvez provoquer un <strong>changement de contexte</strong>.</p><p>Un <a href="https://stevenmouret.github.io/web-accessibility-guidelines/accessibility/scripts/changes-of-context.html#:~:text=Explanation,navigate%20with%20a%20screen%20magnifier.">changement de contexte</a> est défini par les WCAG comme "des changements majeurs qui, s'ils sont effectués sans que l'utilisateur en soit conscient, peuvent désorienter les utilisateurs qui ne sont pas en mesure de visualiser la page entière simultanément." Voici quelques exemples de changements de contexte :</p><ul class="nestedList"><li>L'ouverture d'une nouvelle fenêtre ;</li>
<li>Une modification importante de la mise en page de votre site ;</li>
<li>Un déplacement du centre d'intérêt vers une autre partie du site.</li>
</ul><p>Il est important de garder tout cela à l'esprit, car la création d'un changement de contexte au moment où l'on se concentre sur un élément constitue un manquement au critère 3.2.1 des WCAG :</p><figure class="quote"><blockquote cite="https://www.w3.org/TR/UNDERSTANDING-WCAG20/consistent-behavior-receive-focus.html#:~:text=Specific%20Benefits%20of%20Success%20Criterion,of%20context%20will%20occur%20unexpectedly.">
<p>Lorsqu'un composant de l'interface utilisateur reçoit le focus, il ne déclenche pas de changement de contexte.</p>
</blockquote>
<figcaption><cite><a href="https://www.w3.org/TR/UNDERSTANDING-WCAG20/consistent-behavior-receive-focus.html#:~:text=Specific%20Benefits%20of%20Success%20Criterion,of%20context%20will%20occur%20unexpectedly">Critère de réussite 3.2.1: Ordre de focalisation</a></cite></figcaption></figure><p>Si vous ne faites pas attention, une mauvaise utilisation d'une fonction qui écoute l'événement focus peut créer un changement de contexte. Cela signifie-t-il que vous ne devriez pas l'utiliser ? Pas vraiment, mais pour être honnête, j'ai du mal à trouver une utilité à cet événement. La plupart du temps, vous utiliserez la pseudo-classe <code>:focus</code> pour créer des fonctionnalités similaires.</p><p>Cela dit, il existe tout de même au moins un modèle de composant qui peut bénéficier de cet écouteur d'événements dans certains cas, mais je le couvrirai plus tard lorsque je commencerai à parler des composants, alors mettons ce sujet en veilleuse pour l'instant.</p><h3>Méthode focus()</h3><p>Ah, <em>voici</em> une méthode que nous allons utiliser assez fréquemment ! Cette méthode de l'API HTMLElement nous permet d'attirer l'attention du clavier sur un élément particulier. Par défaut, elle dessine l'indicateur de focus dans l'élément et fait défiler la page jusqu'à l'emplacement de l'élément. Ce comportement peut être modifié à l'aide de quelques paramètres :</p><ul><li><code>preventScroll</code> :Lorsqu'il a la valeur <code>true</code>, le navigateur ne défile pas jusqu'à l'élément sur lequel le focus est programmé.</li>
<li><code>focusVisible</code> :Lorsqu'il est réglé sur <code>false</code>, l'élément programmatiquement ciblé n'affiche pas son indicateur de ciblage. <strong>Cette propriété ne fonctionne pour l'instant que sur Firefox</strong>.</li>
</ul><p>Gardez à l'esprit que pour mettre l'accent sur l'élément, celui-ci doit pouvoir être focusé ou tabulé. Si vous devez mettre l'accent sur un élément normalement non tabulable (comme une fenêtre de dialogue), vous devrez ajouter l'attribut tabindex avec un nombre entier négatif pour le rendre focalisable. Vous pouvez vérifier le fonctionnement de tabindex dans la <a href="https://la-cascade.io/articles/guide-accessibilite-clavier-1">première partie de ce guide</a>.</p><pre class="language-html">&lt;button id="openModal"&gt;Bring focus&lt;/button&gt;
&lt;div id="modal" role="dialog" tabindex="-1"&gt;
  &lt;h2&gt;Modal content&lt;/h2&gt;
&lt;/div&gt;</pre><p>Puis nous ajouterons un écouteur d'événement de clic au bouton pour que la fenêtre de dialogue soit focalisée :</p><pre class="language-js">const button = document.querySelector('#openModal')
const modal = document.querySelector('#modal')
button.addEventListener('click', () =&gt; {
  modal.focus()
})</pre><p>Et voilà ! Cette méthode sera très pratique dans de nombreux composants en tandem avec l'attribut <code>keydown</code>, il est donc crucial de comprendre comment les deux fonctionnent.</p><h3>Modifier les attributs HTML avec JavaScript</h3><p>Certains attributs HTML doivent être modifiés avec JavaScript pour créer l'accessibilité dans des modèles de composants complexes. Deux des plus importants pour l'accessibilité du clavier sont tabindex et le plus récemment ajouté inert. tabindex peut être modifié en utilisant setAttribute. Cet attribut requiert deux paramètres :</p><ul><li><code>name</code>Il vérifie le nom de l'attribut que vous souhaitez modifier.</li>
<li><code>value</code>Il ajoute la chaîne de caractères que cet attribut requiert s'il ne requiert pas un attribut particulier (par exemple, si vous ajoutez les attributs <code>hidden</code> ou <code>contenteditable</code>, vous devrez utiliser une chaîne vide).</li>
</ul><p>Voyons un exemple rapide de son utilisation :</p><pre class="language-js">const button = document.querySelector('button')
button.setAttribute('tabindex', '-1')</pre><p><code>setAttribute</code> est très utile pour l'accessibilité en général (je l'utilise souvent pour modifier les attributs ARIA en cas de besoin !). Mais, lorsque nous parlons d'accessibilité au clavier, <code>tabindex</code> est à peu près le seul attribut que vous modifierez avec cette méthode.</p><p>J'ai mentionné l'attribut <code>inert</code> auparavant, et celui-ci fonctionne un peu différemment car il possède sa propre propriété dans l'API Web HTMLElement. <code>HTMLElement.inert</code> est une valeur booléenne qui nous permet de basculer l'attribut <code>inert</code>.</p><p>Gardez à l'esprit deux choses avant d'utiliser cet attribut :</p><ul><li>Vous aurez besoin d'un polyfill car il n'est pas entièrement implémenté dans tous les navigateurs et est encore assez récent. <a href="https://github.com/WICG/inert">Ce polyfill</a> créé par les ingénieurs de Chrome fonctionne plutôt bien dans les tests que j'ai effectués, donc si vous avez besoin de cette propriété, c'est une approche sûre, mais gardez à l'esprit qu'elle pourrait avoir des comportements inattendus.</li>
<li>Vous pouvez également utiliser <code>setAttribute</code> pour modifier cet attribut ! Les deux fonctionnent aussi bien, même avec un polyfill. C'est à vous de décider entre les deux.</li>
</ul><pre class="language-js">const button = document.querySelector('button')
// Syntaxe avec HTMLElement.inert
button.inert = true
// Syntaxe avec Element.setAttribute()
button.setAttribute('inert', '')</pre><p>Cette combinaison d'outils sera très pratique pour l'accessibilité du clavier. Commençons maintenant à les voir en action !</p><h2>Patterns de composants</h2><h3>Toggletips</h3><figure role="group"><img src="https://la-cascade.io/images/toggletips.webp" alt="Un bouton avec focus clavier, et un message en-dessous disant 'Contenu personnalisé ici'" /><figcaption>Info-bulle de Carbon Design System</figcaption></figure><p>Nous avons appris à créer une infobulle dans la partie précédente, et j'ai mentionné comment l'améliorer avec JavaScript, mais il existe un autre modèle pour ce type de composant appelé <code>toggletip</code>, qui est une infobulle fonctionnant avec un <em>clic</em>, plutôt qu'au <em>survol</em>.</p><p>Dressons une liste rapide de ce dont nous avons besoin pour que cela se produise :</p><ul><li>Lorsque vous appuyez sur le bouton, les informations doivent être annoncées aux lecteurs d'écran. Cela devrait se produire lorsque vous appuyez à nouveau sur le bouton. Appuyer sur le bouton ne fermera pas le toggletip.</li>
<li>Le toggletip sera fermé lorsque vous cliquerez à l'extérieur du toggletip, que vous cesserez de focaliser le bouton ou que vous appuierez sur la touche <code>Esc</code>.</li>
</ul><p>Je vais adopter l'approche de <a href="https://la-cascade.io/auteurs/heydon-pickering">Heydon Pickering</a> dont il parle dans son livre <a href="https://inclusive-components.design/tooltips-toggletips/">Inclusive Components</a>. Commençons donc par le balisage :</p><pre class="language-html">&lt;p&gt;
  If you need to check more information, check here
  &lt;span class="toggletip-container"&gt;
    &lt;button class="toggletip-button"&gt;
      &lt;span class="toggletip-icon" aria-hidden="true"&gt;?&lt;/span&gt;
      &lt;div class="sr-only"&gt;Más información&lt;/div&gt;
    &lt;/button&gt;
    &lt;span role="status" class="toggletip-info"&gt;&lt;/span&gt;
  &lt;/span&gt;
&lt;/p&gt;</pre><p>L'idée est d'injecter le HTML nécessaire à l'intérieur de l'élément avec le <code>role="status"</code>. Cela permettra aux lecteurs d'écran d'annoncer le contenu lorsque vous cliquez dessus. Nous utilisons un élément <code>button</code> pour le rendre tabulable. Maintenant, créons le script pour afficher le contenu !</p><pre class="language-js">toggletipButton.addEventListener('click', () =&gt; {
  toggletipInfo.innerHTML = ''
  setTimeout(() =&gt; {
    toggletipInfo.innerHTML = toggletipContent
  }, 100)
})</pre><p>Ceci fait, il est temps d'ajouter l'accessibilité clavier à ce composant. Il n'est pas nécessaire d'afficher le contenu du <code>toggletip</code> lorsque vous appuyez sur le bouton, car une bonne sémantique HTML le fait déjà pour nous. Nous devons faire en sorte que le contenu du <code>toggletip</code> cesse de s'afficher lorsque vous appuyez sur la touche <code>Esc</code> et lorsque vous cessez le focus sur ce bouton. Cela fonctionne de manière très similaire à ce que nous avons fait pour les info-bulles dans la section précédente à titre d'exemple, alors commençons à travailler avec cela. Tout d'abord, nous allons utiliser l'écouteur d'événements <code>keydown</code> pour vérifier quand la touche <code>Esc</code> est enfoncée :</p><pre class="language-js">toggletipContainer.addEventListener('keydown', (e) =&gt; {
  if (e.key === 'Escape') {
    toggletipInfo.innerHTML = ''
  }
})</pre><p>Et maintenant, nous devons vérifier l'événement blur pour faire la même chose. Celui-ci doit être sur l'élément bouton et non sur conteneur.</p><pre class="language-js">toggletipButton.addEventListener('blur', () =&gt; {
  toggletipInfo.innerHTML = ''
})</pre><p>Et voilà le résultat !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/WNyjeJK">Toggletip demo</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><p>Comme je l'ai mentionné, ça fonctionne de manière très similaire à l'infobulle que nous avons réalisée, mais je l'ai fait pour une bonne raison. À moins que vous ne fassiez quelque chose de très peu conventionnel, ces modèles se répéteront assez souvent.</p><p>Comme Stephanie Eckles le mentionne dans son article "<a href="https://thinkdobecreate.com/articles/4-required-tests-before-shipping-new-features/">4 tests obligatoires avant de livrer de nouvelles fonctionnalités</a>", les utilisateurs du clavier s'attendent à certains comportements de la part des composants, comme la possibilité de fermer une fenêtre que vous venez d'ouvrir en appuyant sur la touche <code>Esc</code>, ou de naviguer dans un groupe d'options connexes à l'aide des touches fléchées.</p><p>Si vous gardez ces modèles à l'esprit, vous remarquerez des chevauchements dans les comportements de certains composants, et ça se répétera lorsque vous commencerez à créer du code JavaScript pour assurer l'accessibilité au clavier. Si vous gardez cette liste à l'esprit, vous comprendrez mieux les requis des composants que vous créez.</p><p>En parlant de ça, vérifions un autre modèle de composant commun.</p><h3>Onglets</h3><figure role="group"><img src="https://la-cascade.io/images/tabs.png" alt="Deux groupes d'onglets: le premier a un texte gris et une bordure en bas, et l'onglet sélectionné a un texte plus foncé et une bordure bleue. Le second groupe d'onglets a un texte gris et un arrière-plan gris, tandis que l'onglet sélectionné a un arrière-plan plus clair et une bordure supérieure bleue." /><figcaption>Tabulation de Carbon Design System</figcaption></figure><h4><code>tabindex</code> itinérant</h4><p>Les interfaces à onglets sont des modèles que vous pouvez encore voir de temps en temps. Elles présentent une fonctionnalité très intéressante pour la navigation au clavier : lorsque vous appuyez sur la touche <code>Tab</code>, vous accédez au panneau d'onglets actif. Pour naviguer dans la liste des onglets, vous devrez utiliser les touches fléchées. Il s'agit d'une technique appelée "tabindex itinérant" qui consiste à supprimer la capacité des éléments non actifs à être tabulables en ajoutant l'attribut tabindex="-1", puis à utiliser d'autres touches pour permettre la navigation entre ces éléments.</p><p>Avec les onglets, c'est le comportement attendu pour ceux-ci :</p><ul><li>Lorsque vous appuyez sur les touches <code>Flèche vers la gauche</code> ou 'Flèche vers le haut`, cela déplace le focus du clavier sur l'onglet précédent. Si le focus est sur le premier onglet, le focus sera déplacé sur le dernier onglet.</li>
<li>Lorsque vous appuyez sur les touches <code>Flèche vers la droite</code>ou<code>Flèche vers le bas</code>, le focus du clavier est déplacé vers l'onglet suivant. Si le focus est sur le premier onglet, le focus est déplacé vers le dernier onglet. La création de cette fonctionnalité est un mélange de trois techniques que nous avons vues précédemment : la modification de <code>tabindex</code> avec <code>setAttribute</code>, l'écouteur d'événement <code>keydown</code>et la méthode<code>focus()</code>. Commençons par vérifier le balisage de ce composant :</li>
</ul><pre class="language-html">&lt;ul role="tablist"&gt;
  &lt;li role="presentation"&gt;
    &lt;button id="tab1" role="tab" aria-selected="true"&gt;Tomato&lt;/button&gt;
  &lt;/li&gt;
  &lt;li role="presentation"&gt;
    &lt;button id="tab2" role="tab" tabindex="-1"&gt;Onion&lt;/button&gt;
  &lt;/li&gt;
  &lt;li role="presentation"&gt;
    &lt;button id="tab3" role="tab" tabindex="-1"&gt;Celery&lt;/button&gt;
  &lt;/li&gt;
  &lt;li role="presentation"&gt;
    &lt;button id="tab4" role="tab" tabindex="-1"&gt;Carrot&lt;/button&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;div class="tablist-container"&gt;
  &lt;section
    role="tabpanel"
    aria-labelledby="tab1"
    tabindex="0"
  &gt;&lt;/section&gt;
  &lt;section
    role="tabpanel"
    aria-labelledby="tab2"
    tabindex="0"
    hidden
  &gt;&lt;/section&gt;
  &lt;section
    role="tabpanel"
    aria-labelledby="tab3"
    tabindex="0"
    hidden
  &gt;&lt;/section&gt;
  &lt;section
    role="tabpanel"
    aria-labelledby="tab4"
    tabindex="0"
    hidden
  &gt;&lt;/section&gt;
&lt;/div&gt;</pre><p>Nous utilisons <code>aria-selected="true"</code> pour montrer quel est l'onglet actif, et nous ajoutons <code>tabindex="-1"</code> pour que les onglets non actifs ne puissent pas être sélectionnés avec la touche <code>Tab</code>. Les onglets doivent pouvoir être sélectionnés s'il n'y a pas d'élément tabulable à l'intérieur, c'est pourquoi j'ai ajouté l'attribut <code>tabindex="0"</code> et les onglets inactifs sont masqués à l'aide de l'attribut <code>hidden</code>.</p><p>Il est temps d'ajouter la navigation avec les touches fléchées. Pour cela, nous devrons créer un tableau avec les onglets et ensuite créer une fonction pour celui-ci. Notre prochaine étape consiste à vérifier quel est le premier et le dernier onglet de la liste. C'est important car l'action qui se produira lorsque vous appuierez sur une touche changera si le focus du clavier est sur l'un de ces éléments.</p><pre class="language-js">const TABS = [...TABLIST.querySelectorAll("[role='tab']")]
const createKeyboardNavigation = () =&gt; {
  const firstTab = TABS[0]
  const lastTab = TABS[TABS.length - 1]
}</pre><p>Après cela, nous ajouterons un écouteur d'événement <code>keydown</code> à chaque onglet. Je vais commencer par ajouter la fonctionnalité des flèches gauche et haut.</p><pre class="language-js">// Previous code of the createKeyboardNavigation function
TABS.forEach((element) =&gt; {
  element.addEventListener("keydown", function (e) {
    if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
      e.preventDefault();
      if (element === firstTab) {
        lastTab.focus();
      } else {
        const focusableElement = TABS.indexOf(element) - 1;
        TABS[focusableElement].focus();
      }
    }
  }
}</pre><p>Voici ce qui se passe ici :</p><ul><li>Tout d'abord, nous vérifions que la touche pressée est la flèche Haut ou Gauche. Pour cela, nous vérifions l'<code>event.key</code>.</li>
<li>Si c'est vrai, nous devons empêcher ces touches de faire défiler la page car, rappelez-vous, par défaut, elles le font. Nous pouvons utiliser <code>e.preventDefault()</code> dans ce but.</li>
<li>Si la touche focalisée est le premier onglet, le focus clavier sera automatiquement porté sur le dernier onglet. Cela se fait en appelant la méthode <code>focus()</code> pour focaliser le dernier onglet (que nous stockons dans une variable).</li>
<li>Si ce n'est pas le cas, nous devons vérifier la position de l'onglet actif. Comme nous stockons les éléments de l'onglet dans un tableau, nous pouvons utiliser la méthode <code>indexOf()</code> pour vérifier sa position.</li>
<li>Comme nous essayons de naviguer vers l'onglet précédent, nous pouvons soustraire 1 du résultat de <code>indexOf()</code>, puis rechercher l'élément correspondant dans le tableau <code>TABS</code> et le focaliser de manière programmatique avec la méthode <code>focus()</code>.</li>
</ul><p>Nous devons maintenant effectuer un processus très similaire avec les touches Flèche vers le bas et Flèche vers la droite :</p><pre class="language-js">// Code précédent de la fonction createKeyboardNavigation
else if (e.key === "ArrowDown" || e.key === "ArrowRight") {
  e.preventDefault();
  if (element == lastTab) {
    firstTab.focus();
  } else {
    const focusableElement = TABS.indexOf(element) + 1;
    TABS[focusableElement].focus();
  }
}</pre><p>Comme je l'ai mentionné, il s'agit d'un processus très similaire. Au lieu de <em>soustraire</em> 1 au résultat de <code>indexOf()</code>, nous <em>ajoutons</em> 1 car nous voulons amener le focus du clavier sur l'élément <strong>suivant</strong>.</p><h3>Affichage du contenu et modification des attributs HTML</h3><p>Nous avons créé la navigation, et maintenant nous devons afficher et masquer le contenu ainsi que manipuler les attributs <code>aria-selected</code> et <code>tabindex</code>. Rappelez-vous, nous devons faire en sorte que lorsque le focus du clavier est sur le panneau actif, et que vous appuyez sur <code>Shift + Tab</code>, le focus doit être dans l'onglet actif.</p><p>Tout d'abord, créons la fonction qui affiche le panneau :</p><pre class="language-js">const showActivePanel = (element) =&gt; {
  const selectedId = element.target.id
  TABPANELS.forEach((e) =&gt; {
    e.hidden = 'true'
  })
  const activePanel = document.querySelector(
    `[aria-labelledby="${selectedId}"]`
  )
  activePanel.removeAttribute('hidden')
}</pre><p>Ce que nous faisons ici, c'est vérifier que l'id de l'onglet est pressé, puis masquer tous les panneaux d'onglets, et enfin rechercher le panneau d'onglet que nous voulons activer. Nous saurons qu'il s'agit de l'onglet car il possède l'attribut <code>aria-labelledby</code> et utilise la même valeur que l'id de l'onglet. Ensuite, nous l'affichons en supprimant l'attribut <code>hidden</code>.</p><p>Maintenant, nous devons créer une fonction pour modifier les attributs :</p><pre class="language-js">const handleSelectedTab = (element) =&gt; {
  const selectedId = element.target.id
  TABS.forEach((e) =&gt; {
    const id = e.getAttribute('id')
    if (id === selectedId) {
      e.removeAttribute('tabindex', '0')
      e.setAttribute('aria-selected', 'true')
    } else {
      e.setAttribute('tabindex', '-1')
      e.setAttribute('aria-selected', 'false')
    }
  })
}</pre><p>Ce que nous faisons ici, c'est, encore une fois, vérifier l'attribut id et ensuite regarder chaque onglet. Nous allons vérifier si l'id de cet onglet correspond à l'id de l'élément pressé.</p><p>Si c'est le cas, nous le rendrons tabulable par le clavier soit en supprimant l'attribut <code>tabindex</code> (parce que c'est un bouton, donc par défaut il est tabulable par le clavier), soit en ajoutant l'attribut <code>tabindex="0"</code>. En outre, nous ajouterons un indicateur aux utilisateurs de lecteurs d'écran qu'il s'agit de l'onglet actif en ajoutant l'attribut <code>aria-selected="true"</code>.</p><p>Si cela ne correspond pas, <code>tabindex</code> et <code>aria-selected</code> seront respectivement définis à <code>-1</code> et <code>false</code>.</p><p>Maintenant, il ne nous reste plus qu'à ajouter un écouteur d'événements de clics à chaque onglet pour gérer les deux fonctions.</p><pre class="language-js">TABS.forEach((element) =&gt; {
  element.addEventListener('click', (element) =&gt; {
    showActivePanel(element), handleSelectedTab(element)
  })
})</pre><p>Et c'est tout ! Nous avons créé la fonctionnalité pour faire fonctionner les onglets, mais nous pouvons faire un petit quelque chose d'autre si nécessaire.</p><h3>Activer l'onglet sur le focus</h3><p>Vous vous souvenez de ce que j'ai souligné à propos de l'écouteur d'événement de focus ? Vous devez être prudent lorsque vous l'utilisez car il peut créer un <em>changement de contexte</em> par accident. Cependant, il a une certaine utilité, et ce composant est une occasion parfaite de l'utiliser !</p><p>Selon le <a href="https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_selection_follows_focus">guide des pratiques de création ARIA</a> (APG), nous pouvons faire en sorte que le contenu affiché s'affiche lorsque vous mettez le focus sur l'onglet. Ce concept est souvent appelé "follow focus" (suivre le focus) et peut être utile aux utilisateurs de claviers et de lecteurs d'écran car il permet de naviguer plus facilement dans le contenu.</p><p>Toutefois, vous devez tenir compte de quelques considérations à ce sujet :</p><p>Si afficher le contenu signifie faire beaucoup de requêtes et, par extension, rendre le réseau plus lent, faire en sorte que le contenu affiché suive le focus n'est pas souhaité.Si cela modifie la mise en page de manière significative, on peut le considérer comme un changement de contexte. Ça dépend du type de contenu que vous voulez afficher, et faire un changement de contexte sur le focus est un problème d'accessibilité, comme je l'ai expliqué précédemment.Dans le cas présent, la quantité de contenu ne suppose pas un grand changement, ni au niveau du réseau, ni à celui de la mise en page, je vais donc faire en sorte que le contenu affiché suive le focus des onglets. C'est une tâche très simple avec l'écouteur d'événement <code>focus</code>. Nous pouvons littéralement copier et coller l'écouteur d'événements que nous avons créé et simplement changer le clic en focus.</p><pre class="language-js">TABS.forEach((element) =&gt; {
  element.addEventListener('click', (element) =&gt; {
    showActivePanel(element), handleSelectedTab(element)
  })
  element.addEventListener('focus', (element) =&gt; {
    showActivePanel(element), handleSelectedTab(element)
  })
})</pre><p>Et voilà, c'est fait ! Maintenant, le contenu affiché fonctionnera sans qu'il soit nécessaire de cliquer sur l'onglet. Le choix vous revient (clic ou pas clic) et c'est étonnamment une question très nuancée. Personnellement, je m'en tiendrais à ce que cela s'affiche lorsque vous appuyez sur l'onglet car je pense que l'expérience de modifier l'attribut <code>aria-selected</code> en se concentrant simplement sur l'élément peut être légèrement déroutante. Mais ce n'est qu'une hypothèse de ma part, alors prenez ce que je dis avec un grain de sel et vérifiez toujours avec les utilisateurs.</p><h3>Écouteurs d'événements keydown supplémentaires</h3><p>Revenons un instant sur le <code>createKeyboardNavigation</code>. Il y a quelques touches que nous pouvons ajouter. Nous pouvons faire en sorte que les touches <code>Home</code> et <code>End</code> amènent le focus du clavier sur le premier et le dernier onglet, respectivement. C'est complètement facultatif, donc ce n'est pas grave si vous ne le faites pas, mais juste pour rappeler l'utilité d'un écouteur d'événements de touche, je vais le faire.</p><p>C'est une tâche très facile. Nous pouvons créer une autre paire d'instructions <code>if</code> pour vérifier si les touches <code>Home</code> et <code>End</code> sont enfoncées, et comme nous avons stocké le premier et le dernier onglet dans des variables, nous pouvons les mettre au point avec la méthode <code>focus()</code>.</p><pre class="language-js">// Code précédent de la fonction createKeyboardNavigation, puis:
else if (e.key === "Home") {
  e.preventDefault();
  firstTab.focus()
} else if (e.key === "End") {
  e.preventDefault();
  lastTab.focus()
}</pre><p>...et voilà le résultat !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/YzvVXWw">Tab demo</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><p>Avec ce code, nous avons rendu ce composant accessible aux utilisateurs de clavier et de lecteur d'écran. Cela montre à quel point les concepts de base de l'écouteur d'événement <code>keydown</code>, de la méthode <code>focus()</code> et des modifications que nous pouvons apporter avec <code>setAttribute</code> sont utiles pour manipuler des composants complexes. Voyons-en un autre, très compliqué, et comment l'attribut <code>inert</code> peut nous aider à gérer cette tâche facilement.</p><figure role="group"><img src="https://la-cascade.io/images/3-guide-keyboard-accessibility-part2.webp" alt="Une modale ouverte, avec un texte de remplissage et deux boutons qui disent 'Annuler' et 'Enregistrer'" /><figcaption>Modale de Carbon Design System</figcaption></figure><h3>Ouvrir et fermer la modale</h3><p>Les modales sont un pattern assez complexe quand on parle d'accessibilité au clavier, alors commençons par une tâche facile : ouvrir et fermer la modale.</p><p>C'est en effet facile, mais vous devez garder quelque chose à l'esprit : il est très probable que le bouton ouvre la modale, et la modale est loin dans le DOM. Vous devez donc gérer le focus de manière programmatique lorsque vous gérez ce composant. Il y a un petit piège ici : vous devez mémoriser quel élément a ouvert la modale pour pouvoir renvoyer le focus du clavier à cet élément au moment où nous le fermons.</p><p>Heureusement, il existe un moyen facile de le faire, mais commençons par créer le balisage de notre site :</p><pre class="language-html">&lt;body&gt;
  &lt;header&gt;
    &lt;!-- Header's content --&gt;
  &lt;/header&gt;
  &lt;main&gt;
    &lt;!-- Main's content --&gt;
    &lt;button id="openModal"&gt;Open modal&lt;/button&gt;
  &lt;/main&gt;
  &lt;footer&gt;
    &lt;!-- Footer's content --&gt;
  &lt;/footer&gt;
  &lt;div
    role="dialog"
    aria-modal="true"
    aria-labelledby="modal-title"
    hidden
    tabindex="-1"
  &gt;
    &lt;div class="dialog__overlay"&gt;&lt;/div&gt;
    &lt;div class="dialog__content"&gt;
      &lt;h2 id="modal-title"&gt;Modal content&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href="#"&gt;Modal link 1&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href="#"&gt;Modal link 2&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href="#"&gt;Modal link 3&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
      &lt;button id="closeModal"&gt;Close modal&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/body&gt;</pre><p>Comme je l'ai mentionné, la modale et le bouton sont très éloignés l'un de l'autre dans le DOM. Il sera donc plus facile de créer un <em>piège à focus</em> plus tard, mais pour l'instant, vérifions la sémantique de la modale :</p><ul><li><code>role="dialog"</code> donnera à l'élément la sémantique requise pour les lecteurs d'écran. Il doit avoir une étiquette pour être reconnu comme une fenêtre de dialogue, nous utiliserons donc le titre de la modale comme étiquette en utilisant l'attribut <code>aria-labelledby</code>.</li>
<li><code>aria-modal="true"</code> permet de faire en sorte qu'un utilisateur de lecteur d'écran ne puisse lire que le contenu des enfants de l'élément, ce qui bloque l'accès des lecteurs d'écran. Cependant, comme vous pouvez le voir sur la page <a href="https://a11ysupport.io/tech/aria/aria-modal_attribute">aria-modal de a11ysupport.com</a>, elle n'est pas entièrement prise en charge, donc vous ne pouvez pas vous fier uniquement à cela pour cette tâche. Elle sera utile pour les lecteurs d'écran qui la prennent en charge, mais vous verrez qu'il existe un autre moyen de s'assurer que les utilisateurs de lecteurs d'écran n'interagissent avec rien d'autre que la modale une fois qu'elle est ouverte.</li>
<li>Comme je l'ai indiqué, nous devons amener le focus du clavier sur notre modale, c'est pourquoi nous avons ajouté l'attribut <code>tabindex="-1"</code>.</li>
</ul><p>Avec cela en tête, nous devons créer la fonction pour ouvrir notre modale. Nous devons vérifier quel est l'élément qui l'a ouverte, et pour cela, nous pouvons utiliser la propriété <code>document.activeElement</code> pour vérifier quel est l'élément qui a le focus sur le clavier en ce moment et le stocker dans une variable. C'est mon approche pour cette tâche :</p><pre class="language-js">let focusedElementBeforeModal
const modal = document.querySelector("[role='dialog']")
const modalOpenButton = document.querySelector('#openModal')
const modalCloseButton = document.querySelector('#closeModal')
const openModal = () =&gt; {
  focusedElementBeforeModal = document.activeElement
  modal.hidden = false
  modal.focus()
}</pre><p>C'est très simple :</p><ol><li>Nous stockons le bouton qui a ouvert la modale ;</li>
<li>Puis nous l'affichons en supprimant l'attribut <code>hidden</code> ;</li>
<li>Puis nous mettons le focus sur la modale avec la méthode <code>focus()</code>.</li>
</ol><p>Il est essentiel de stocker le bouton <strong>avant</strong> d'amener le focus sur la modale. Sinon, l'élément qui serait stocké dans ce cas serait la modale elle-même, et ce n'est pas ce que nous voulons.</p><p>Maintenant, nous devons créer la fonction pour fermer la modale :</p><pre class="language-js">const closeModal = () =&gt; {
  modal.hidden = true
  focusedElementBeforeModal.focus()
}</pre><p>Voilà pourquoi il est important de stocker l'élément approprié. Lorsque nous fermerons la modale, nous ramènerons le focus clavier sur l'élément qui l'a ouverte. Avec ces fonctions créées, il ne nous reste plus qu'à ajouter les écouteurs d'événements pour ces fonctions ! N'oubliez pas que nous devons aussi faire en sorte que la modale se ferme lorsque nous appuyons sur la touche <code>Esc</code>.</p><pre class="language-js">modalOpenButton.addEventListener('click', () =&gt; openModal())
modalCloseButton.addEventListener('click', () =&gt; closeModal())
modal.addEventListener('keydown', (e) =&gt; {
  if (e.key === 'Escape') {
    closeModal()
  }
})</pre><p>Pour l'instant, ça paraît très simple. Mais si c'était tout, les modales ne seraient pas considérées comme un modèle complexe pour l'accessibilité, n'est-ce pas ? C'est là que nous devons créer une tâche très importante pour ce composant, et nous avons deux façons de le faire.</p><h3>Création d'un piège à focus</h3><p>Un <strong>piège à focus</strong> garantit que le focus clavier ne peut pas s'échapper du composant. C'est crucial car si un utilisateur du clavier peut interagir avec quoi que ce soit en dehors d'une modale une fois qu'elle est ouverte, cela peut créer une expérience très déroutante. Nous disposons actuellement de deux moyens pour y parvenir.</p><p>L'une d'entre elles consiste à vérifier chaque élément qui peut être tabulé avec un clavier, puis à mémoriser lesquels sont le premier et le dernier, et à faire ceci :</p><ul><li>Lorsque l'utilisateur appuie sur <code>Shift</code> + <code>Tab</code> et que le focus du clavier est sur le premier élément tabulable (rappelez-vous, vous pouvez vérifier cela avec <code>document.activeElement</code>), le focus ira sur le dernier élément tabulable.</li>
<li>Lorsque l'utilisateur appuie sur <code>Tab</code>, et que le focus du clavier est sur le dernier élément tabulable, le focus du clavier devrait aller sur le premier élément tabulable.</li>
</ul><p>Normalement, je vous aurais montré comment faire ce code, mais je pense que les solutions A11y ont fait <a href="https://a11y-solutions.stevenwoodson.com/solutions/focus/modals/">un très bon script pour créer un piège à focus</a>. Il fonctionne en quelque sorte comme la navigation au clavier avec les touches fléchées que nous avons créées pour les éléments tabulables (comme je l'ai déjà mentionné, les motifs se répètent !), je vous invite donc à consulter cette page.</p><p>Je ne veux pas utiliser cette approche comme solution principale, car elle n'est pas exactement sans défaut. Il y a certaines situations que cette approche ne couvre pas.</p><p>La première est qu'<strong>elle ne prend pas en compte les lecteurs d'écran</strong>, notamment les lecteurs d'écran mobiles. Comme le mentionne Rahul Kumar dans son article "<a href="https://medium.com/@im_rahul/focus-trapping-looping-b3ee658e5177">Focus Trapping for Accessibility (A11Y)</a>", Talkback et Voiceover permettent à l'utilisateur de faire des gestes et des doubles tapotements pour naviguer vers l'élément focalisable suivant ou précédent, et ces gestes <strong>ne peuvent pas</strong> être détectés avec un écouteur d'événements car ces gestes, techniquement parlant, ne se produisent pas dans le navigateur. Il existe une solution à ce problème, mais je vais mettre ce sujet en suspens pendant un moment.</p><p>L'autre préoccupation est que cette approche de piège à focus peut conduire à des comportements bizarres si vous utilisez certaines combinaisons d'éléments tabulables. Prenez, par exemple, cette modale :</p><figure role="group"><img src="https://la-cascade.io/images/4-guide-keyboard-accessibility-part2.webp" alt="Une modale avec le titre 'Survey' et une question disant 'Combien de personnes compte votre équipe?' et trois options de réponse sous forme de boutons radio: 1 à 3 personnes, 4 à 10 personnes, et plus de 10 personnes. En-dessous, il y a un bouton avec un intitulé 'Envoyer la réponse'" /></figure><p>Techniquement parlant, le premier élément tabulable est le premier <code>input</code>. Cependant, toutes les entrées de cet exemple doivent se concentrer sur le dernier élément tabulable (dans ce cas, l'élément <code>bouton</code>) lorsque l'utilisateur appuie sur les touches <code>Shift</code> + <code>Tab</code>. Sinon, cela pourrait provoquer un comportement bizarre si l'utilisateur appuie sur ces touches alors que le focus du clavier est sur le deuxième ou troisième <code>input</code>.</p><p>Si nous voulons créer une solution plus fiable, la meilleure approche consiste à utiliser l'attribut <code>inert</code> pour rendre le contenu externe inaccessible aux lecteurs d'écran et aux utilisateurs de clavier, en veillant à ce qu'ils puissent interagir uniquement avec le contenu de la modale. N'oubliez pas que cela nécessitera le polyfill <code>inert</code> pour ajouter plus de robustesse à cette technique.</p><p><strong>Remarque</strong> : <em>il est important de noter que malgré le fait qu'un piège à focus et l'utilisation d'<code>inert</code> contribuent en pratique à garantir l'accessibilité du clavier pour les modales, ils ne fonctionnent pas exactement de la même manière. La principale différence est que si vous définissez tous les documents, sauf la modale, comme inertes, vous pourrez toujours sortir du site Web et interagir avec les éléments du navigateur. C'est sans doute mieux pour des raisons de sécurité, mais c'est à vous de décider si vous voulez créer un piège à focus manuellement ou utiliser l'attribut <code>inert</code></em>.</p><p>Ce que nous allons faire d'abord, c'est sélectionner toutes les zones qui n'ont pas le rôle <code>dialog</code>. Comme l'attribut <code>inert</code> supprimera toute interaction du clavier et du lecteur d'écran avec les éléments <strong>et leurs enfants</strong>, nous devrons sélectionner uniquement les enfants directs de <code>body</code>. C'est pourquoi nous laissons le conteneur modal exister au même niveau que des balises comme <code>main</code>, <code>header</code> ou <code>footer</code>.</p><pre class="language-js">// Ce sélecteur fonctionne bien pour cette structure HTML spécifique. Adaptez-la selon votre projet.
const nonModalAreas = document.querySelectorAll(
  "body &gt; *:not([role='dialog'])"
)</pre><p>Nous devons maintenant revenir à la fonction <code>openModal</code>. Après avoir ouvert la modale, nous devons ajouter l'attribut <code>inert</code> à ces éléments. Ceci devrait être la dernière étape de la fonction :</p><pre class="language-js">const openModal = () =&gt; {
  // ici, le code ajouté précédemment
  nonModalAreas.forEach((element) =&gt; {
    element.inert = true
  })
}</pre><p>Qu'en est-il lorsque vous fermez la modale ? Vous devez aller dans la fonction <code>closeModal</code> et supprimer cet attribut. Cela doit se faire <strong>avant</strong> l'exécution de tout le reste du code. Sinon, le navigateur ne sera pas en mesure de mettre le focus sur le bouton qui a ouvert cette modale.</p><pre class="language-js">const closeModal = () =&gt; {
  nonModalAreas.forEach((element) =&gt; {
    element.inert = false
  })
  // ici, le code ajouté précédemment
}</pre><p>Voici le résultat :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/NWzjqYM">Test modale</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><p>Supposons que vous ne vous sentiez pas à l'aise avec l'utilisation de l'attribut <code>inert</code> pour le moment et que vous souhaitiez créer un piège à focus manuellement, comme celui de A11y Solutions. Que pouvez-vous faire pour vous assurer que les utilisateurs de lecteurs d'écran ne puissent pas sortir de la modale ? <code>aria-modal</code> peut vous aider, mais n'oubliez pas que la prise en charge de cette propriété est assez fragile, notamment pour Talkback et VoiceOver pour iOS. La prochaine meilleure chose à faire est donc d'ajouter l'attribut <code>aria-hidden="true"</code> à tous les éléments qui ne sont pas la modale. Il s'agit d'un processus très similaire à celui que nous avons suivi pour l'attribut <code>inert</code>, et vous pouvez également utiliser les mêmes éléments dans le tableau que nous avons utilisé pour cette rubrique !</p><pre class="language-js">const openModal = () =&gt; {
  // ici, le code ajouté précédemment
  nonModalAreas.forEach((element) =&gt; {
    element.setAttribute('aria-hidden', 'true')
  })
}
const closeModal = () =&gt; {
  nonModalAreas.forEach((element) =&gt; {
    element.removeAttribute('aria-hidden')
  })
  // ici, le code ajouté précédemment
}</pre><p>Ainsi, que vous décidiez d'utiliser l'attribut <code>inert</code> ou de créer manuellement un piège à focus, vous pouvez vous assurer que l'expérience utilisateur pour les utilisateurs de claviers et de lecteurs d'écran fonctionne au mieux.</p><h3>Élément <code>dialog</code></h3><p>Vous avez peut-être remarqué le balisage que j'ai utilisé et que je n'ai pas utilisé le relativement nouvel élément <code>&lt;dialog&gt;</code>, et il y a une raison à cela. Oui, cet élément aide beaucoup en gérant le focus sur la modale et sur le bouton qui l'a ouverte facilement, mais, comme Scott O'Hara le souligne dans son article "<a href="https://www.scottohara.me/blog/2019/03/05/open-dialog.html">Avoir un dialogue ouvert</a>", il présente encore quelques problèmes d'accessibilité qui, <strong>même avec un polyfill</strong>, ne sont pas encore totalement résolus. J'ai donc décidé d'utiliser une approche plus robuste avec le balisage.</p><p>Si vous n'avez pas entendu parler de cet élément, il dispose de quelques fonctions pour ouvrir et fermer le dialogue, ainsi que de quelques nouvelles fonctionnalités qui seront pratiques lorsque nous créerons des modales. Si vous voulez vérifier comment il fonctionne, vous pouvez consulter <a href="https://www.youtube.com/watch?v=TAB_v6yBXIE">la vidéo de Kevin Powell</a> sur cet élément.</p><p>Cela ne veut pas dire que vous ne devez pas l'utiliser du tout. La situation de l'accessibilité concernant cet élément s'améliore, mais gardez à l'esprit que vous devez toujours prendre en considération certains détails pour vous assurer qu'il fonctionne correctement.</p><h2>Autres modèles de composants</h2><p>Je pourrais continuer avec de nombreux modèles de composants, mais pour être honnête, je pense que cela va devenir redondant car, en fait, ces modèles sont assez similaires entre les différents types de composants que vous pouvez faire. À moins que vous ne deviez fabriquer quelque chose de très peu conventionnel, les modèles que nous avons vus ici devraient suffire !</p><p>Ceci étant dit, comment pouvez-vous savoir ce que requerra un composant ? La réponse comporte de nombreuses nuances que cet article ne peut couvrir. Il existe certaines ressources comme le <a href="https://github.com/scottaohara/accessible_components">référentiel de composants accessibles de Scott O'Hara</a> ou le <a href="https://design-system.service.gov.uk/">système de design du gouvernement britannique</a>, mais c'est une question qui n'a pas de réponse simple. La chose la plus importante à ce sujet est de <strong>toujours</strong> les tester avec des utilisateurs handicapés pour connaître les défauts qu'ils peuvent avoir en termes d'accessibilité.</p><h3>Récapitulons</h3><p>L'accessibilité du clavier peut être assez difficile, mais c'est réalisable une fois que vous comprenez comment les utilisateurs de clavier interagissent avec un site et quels principes vous devez garder à l'esprit. La plupart du temps, HTML et CSS font un excellent travail pour assurer l'accessibilité du clavier, mais parfois vous aurez besoin de JavaScript pour des modèles plus complexes.</p><p>C'est assez impressionnant tout ce qu'on peut faire pour l'accessibilité du clavier une fois qu'on a compris que la plupart du temps, le travail est fait avec les mêmes outils de base. Vous pouvez alors mélanger ces outils pour créer une expérience utilisateur formidable pour les utilisateurs de clavier !</p></div>]]></description>
      <link>https://la-cascade.io/articles/guide-accessibilite-clavier-2</link>
      <guid>https://la-cascade.io/articles/guide-accessibilite-clavier-2</guid>
      <pubDate>Mon, 26 Dec 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Subgrid]]></title>
      <description><![CDATA[<p>La valeur <code>subgrid</code> de <code>grid-template-rows</code> et de <code>grid-template-columns</code> est supportée par <a href="https://caniuse.com/css-subgrid">Firefox et Safari 16+</a> et arrive dans Chrome. Dans cet article, nous allons apprendre comment cette fonctionnalité rend la mise en page Grid encore plus puissante.</p><h2>Subgrid n'ajoute pas de complexité</h2><p>Quand on utilise subgrid, on utilise le mot-clé <code>subgrid</code> dans <code>grid-template-rows</code> et dans <code>grid-template-columns</code> à la place d'une liste de pistes.</p><p>NOTE : On n'a pas à apprendre de nouvelles propriétés ou valeurs, c'est juste une décision à prendre — est-ce que je veux que ma sous-grille imbriquée ait ses propres définitions de lignes et colonnes, ou est-ce qu'on utilisera celles de ses parents ?</p><p>Dans le premier exemple, j'ai une grille imbriquée qui crée ses propres pistes pour ses rangées et ses colonnes. Ces pistes sont indépendantes et ne s'aligneront donc pas avec celles de la grille parent.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/ZERZEJB">Nested grid without subgrid</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Le second exemple remplace la liste de pistes pour <code>grid-template-columns</code> par le mot-clé <code>subgrid</code>. Les pistes de colonne de la grille imbriquée s'alignent maintenant avec celles de son parent.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/xxzeGOG">Nested grid with subgrid</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>On peut avoir des sous-grilles de sous-grilles</h2><p>Tant que chaque parent est une grille, on peut hériter de sous-grilles.</p><p>L'exemple qui suit montre trois grilles, imbriquées l'une dans l'autre, et qui héritent des pistes de leur parent. En utilisant DevTools de Firefox, on voit le contour de chacune et la façon dont les grilles enfants et les items de grille s'alignent tous sur cette grille.</p><figure role="group"><img src="https://la-cascade.io/images/subgrids-in-sugrids.avif" alt="" /></figure><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/ExRJjWa">Subgrids in subgrids</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>On n'a pas besoin de sous-grilles dans les deux dimensions</h2><p>Lors des discussions du groupe de travail CSS autour de subgrid, il a été suggéré de le bloquer (......). La conséquence aurait été qu'il n'y aurait pas eu de grille implicite dans l'une ou l'autre direction, et subgrid aurait seulement servi si l'on savait exactement de combien de cellules de grilles on avait besoin dans la sous-grille.</p><p>Dans l'exemple suivant, j'ai créé une sous-grille sur des colonnes pour m'assurer que les items dans la grille imbriquée peuvent s'aligner avec des items directement à l'intérieur de la grille parent. Cependant, j'utilise la grille implicite pour les rangées, car il se pourrait que j'en aie beaucoup.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/GRGLpKB">Subgrid in one dimension</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Subgrid est utile quand on cible la ligne finale de la grille implicite</h2><p>L'exemple précédent montre un autre pattern utile que subgrid rend possible. Il est possible de viser la ligne finale de la grille explicite, en utilisant line -1. Malheureusement cela ne fonctionne pas pour une grille implicite.</p><p>En imbriquant des items qui se répètent dans un container, ils se positionnent tous sur une rangée dans le parent. Du coup, on a la colonne pleine, comme dans l'exemple précédent, sans avoir à connaître le nombre de de lignes d'items créées implicitement.</p><p>Si l'on inspecte l'exemple précédent avec DevTools, on peut voir comment les items de sous-grille créent des rangées implicites. Comme l'item de gauche est la grille parente, il est sur la même rangée que tous les items et donc peut devenir aussi grand que nécessaire pour s'aligner avec les rangées implicites.</p><figure role="group"><img src="https://la-cascade.io/images/subgrid-et-ligne-finale.avif" alt="" /></figure><h2>On peut aligner les choses avec les noms de ligne de la grille parent</h2><p>Si notre grille parent a des lignes nommées, celles-ci sont accessibles depuis la grille enfant. Dans l'exemple qui suit, les lignes de la grille parent sont nommées de "a" à "e". La sous-grille et un enfant de cette sous-grille sont ensuite placés en utilisant ces lignes nommées. Cette technique est utile, car elle on n'a pas besoin de garder en mémoire les numéros de lignes. On indique des noms dans le parent, et on sait qu'en plaçant un item commençant à cette ligne il s'alignera toujours avec d'autres choses commençant sur cette même ligne.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/dyKLYRK">Line names inherit into subgrids</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>On peut ajouter des noms de lignes à la sous-grille.</h2><p>Vous voulez encore des lignes nommées ? On peut ajouter des noms aux lignes à l'intérieur de la sous-grille. Certes, la syntaxe est un peu inhabituelle, du fait qu'on n'a pas une liste de pistes où mettre les noms de lignes. À la place, on ajoute les noms après le mot-clé <code>subgrid</code>.</p><pre class="language-css">.subgrid {
  display: grid;
  grid-template-columns: subgrid [line1] [line2] [line3];
}</pre><p>Ces noms serot ajoutés à tout autre nom que la ligne a déjà — puisqu'une ligne peut avoir plusieurs noms. On peut ensuite se référer à la ligne avec l'un de ses noms.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/dyKLYRK">Adding line names to the subgrid</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>On peut utiliser implicitement les zones nommées avec des lignes héritées dans notre grille et dans notre sous-grille</h2><p>Quand on nommes les lignes avec le suffixe <code>-start</code> et <code>-end</code>, on obtient une zonne nommée du nom principal utilisé. De même que les lignes sont héritées, de même les zones nommées. Dans l'exemple qui suite, j'ai denommé les lignes <code>main-start</code> et <code>main-end</code> et <code>col-start</code> et <code>col-end</code>. Cela me donne une large colonne nommée <code>main</code>, et une colonne étroite nommée <code>col</code>.</p><p>Je place l'article dans <code>grid-column: main</code>, et puis j'en fais une sous-grille. Je peux ensuite placer les contenus des articles dans la colonne étroire avec <code>grid-column: col</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/bGKJQdz">Inheriting named areas from lines</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>La sous-grille peut avoir des gouttières de tailles différentes de celles de ses parents</h2><p>La propriété <code>gap</code> sera hritée dans la sous-grille donc, par défaut, un élément de sous-grille aura les mêmes dimensions de gouttières que son parent. Si vous voulez modifier ce comportement, utilisez la propriété <code>gap</code> (ou <code>column-gap</code> ou <code>row-gap</code>) pour cela.</p><p>Dans l'exemple suivant, la grille parent a des gouttières de 20px pour les rangées et les colonnes. Dans la sous-grille, je veux juste laisser apparaître 1px de la couleur de background, c'est pourquoi j'ai modifié le <code>gap</code> dans la <code>.card</code> de la sous-grille à 1px.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/WNyWYxB">Aligning items in separate subgrids</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>On peut aligner des items qui sont dans des sous-grilles différentes</h2><p>Quand on utilise subgrid pour des rangées, les items imbriqués dans des sous-grilles séparées, comme les <code>card</code> dans l'exemple précédent, sont sur la même rangée, ce qui signifie que les items à l'iintérieur peuvent s'aligner les uns sur les autres. Si j'ajoute du contenu à l'un des titres (<code>header</code>), on voit que tous les titres de cette rangée on plus d'espace et demeurent alignés.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/WNyWYxB">Aligning items in separate subgrids</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>subgrid peut être utile en combinaison avec les container queries</h2><p>Un pattern assez courant est d'avoir une grille de 12 colonnes à chaque breakpoint, et à mesure que le viewport s'amenuise, d'avoir des items qui s'étirent sur plus de colonnes. Sur un très petit écran, un item pourrait s'étirer sur 12 colonnes, sur un ordinateur de bureau il prendrait 3 colonnes par exemple.</p><p>Avec les container queries, on peut tester pour vérifier que le container a sufisamment d'espace, puis switch vers subgrid pour que le composant utilise les pistes sur lesquelles ils s'étire. Dans l'exemple suivant, la <code>card</code> s'étale sur deux colonnes de la grille parent. À une largeur moindre, la card n'est plus une sous-grille, et l'image et le contenu s'affichent l'un après l'autre.</p><figure role="group"><img src="https://la-cascade.io/images/subgrid1.avif" alt="" /></figure><p>Une fois qu'il y a assez d'espace, la <code>card</code> devient une sous-grille et l'image et le contenu s'affichent côte à côte.</p><figure role="group"><img src="https://la-cascade.io/images/subgrid2.avif" alt="" /></figure><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/GRGLwMw">Subgrid and container queries</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h3>Ressources complémentaires sur subgrid</h3><ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Grid_Layout/Subgrid">Subgrid dans MDN</a> (en français)</li>
<li><a href="https://www.smashingmagazine.com/2018/07/css-grid-2/">CSS Grid Level 2 : Hre comes subgrid</a></li>
<li><a href="https://www.youtube.com/watch?v=rmF_iE0lMzw">Hello Subgrid ! (vidéo)</a></li>
<li><a href="https://gridbyexample.com/examples/#css-grid-level-2-examples">Exemples de Subgrid dans Grid by Example</a></li>
</ul>]]></description>
      <link>https://la-cascade.io/articles/css-subgrid</link>
      <guid>https://la-cascade.io/articles/css-subgrid</guid>
      <pubDate>Sun, 25 Dec 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[align-self]]></title>
      <description><![CDATA[<article><p>par <a href="https://la-cascade.io/auteurs/sara-cope">Sara Cope</a>, 22 décembre 2022, <a href="https://la-cascade.io/tags/flexbox">flexbox</a>, <a href="https://la-cascade.io/tags/dico">dico</a>, <a href="https://css-tricks.com/almanac/selectors/f/first-of-type/">article original</a> paru le 28 septembre 2022 dans <a href="https://css-tricks.com/">CSS-Tricks</a></p><div class="articleContent"><p>La propriété <code>align-self</code> est une sous-propriété du module Flexible Box Layout. Elle permet de remplacer la valeur <a href="https://la-cascade.io/articles/align-items">align-items</a> pour des éléments flex spécifiques.</p><p>La propriété <code>align-self</code> accepte les 5 mêmes valeurs que la propriété <code>align-items</code>.</p><h2>Syntaxe</h2><pre class="language-css">align-self: auto | flex-start | flex-end | center | baseline | stretch
  .flex-item {
  align-self: flex-end;
}</pre><h2>Démo</h2><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/GBMZKR">align-self demo</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div></div></article><p><a href="https://la-cascade.io/auteurs/sara-cope">Voir la liste des articles</a> de Sara Cope traduits dans La Cascade.</p><h3 class="autresRessources">Autres ressources</h3>
<ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/align-items">align-items</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/align-self">align-self</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/align-self">align-self</a></li>
</ul><p><a href="https://css-tricks.com/almanac/selectors/f/first-of-type/">Article original</a> paru le 28 septembre 2022 dans <a href="https://css-tricks.com/">CSS-Tricks</a>Traduit avec l'aimable autorisation de CSS-Tricks et de Sara Cope.Copyright CSS-Tricks © 2022</p>]]></description>
      <link>https://la-cascade.io/articles/align-self</link>
      <guid>https://la-cascade.io/articles/align-self</guid>
      <pubDate>Thu, 22 Dec 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[align-items]]></title>
      <description><![CDATA[<p>La propriété <code>align-items</code> est liée à la mise en page CSS. Elle affecte la façon dont les éléments sont alignés à la fois <strong>dans les mises en page <a href="https://la-cascade.io/articles/flexbox-guide-complet">Flexbox</a> et <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet">Grid</a></strong>.</p><ul><li><a href="https://la-cascade.io/articles/flexbox-guide-complet#align-items">align-items dans Flexbox</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ai">align-items dans Grid</a></li>
</ul><h2>Syntaxe</h2><pre class="language-css">align-items: flex-start | flex-end | center | baseline | stretch;</pre><p>La propriété <code>align-items</code> définit le comportement par défaut pour la disposition des éléments le long de l'axe transversal (perpendiculaire à l'axe principal).</p><p>Imaginez une mise en page flexbox horizontale. Ce flux horizontal est l'axe <em>principal</em>, donc align-items est l'alignement <em>opposé</em> à celui-ci, sur l'axe <em>vertical</em>. Gardez à l'esprit que ça change évidemment lorsque l'axe principal change, et que l'axe transversal change avec lui.</p><p>Vous pouvez considérer <code>align-items</code> comme la version <code>justify-content</code> pour l'axe transversal (perpendiculaire à l'axe principal).</p><p class="is-style-explanation">Le reste de cet article est plutôt axé sur flexbox plutôt que sur grid. Les concepts sont toujours très similaires, mais il existe quelques différences. Par exemple, dans flexbox, les axes peuvent changer, alors que dans grid ils ne le peuvent pas. Ça a pour conséquence par exemple le fait que flexbox a des valeurs comme `flex-start` alors que dans grid, c'est juste `start`.</p><h2>Démo (flexbox)</h2><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/KittyGiraudel/pen/AvXmrQ/2bfe2c024739bdd4098572f87d1bf585">CSS-Tricks: :nth-last-child</a>de Kitty Giraudel dans<a href="https://codepen.io">CodePen</a></div>]]></description>
      <link>https://la-cascade.io/articles/align-items</link>
      <guid>https://la-cascade.io/articles/align-items</guid>
      <pubDate>Thu, 22 Dec 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Pourquoi vous ne devriez jamais utiliser px pour définir la taille de police dans CSS]]></title>
      <description><![CDATA[<p><em>Comment utiliser les unités px, rem et em en connaissance de cause, et prendre en compte les configurations de l'utilisateur.</em></p><div class="articleContent"><p>Pardonnez le titre quelque peu <em>putaclic</em>... "jamais" est un mot fort, mais il s'agit d'un sujet important et mal compris.</p><p>Il circule un certain nombre d'idées fausses dans la sphère du développement Web, qui persistent alors même qu'elles sont régulièrement démenties. "<em>Les liens externes doivent toujours s'ouvrir dans de nouveaux onglets</em>" en est un bon exemple. <a href="https://css-tricks.com/use-target_blank/">CSS Tricks en a parlé en détail</a> il y a près de dix ans (tl;dr : la plupart du temps faux), mais cette idée semble encore persister dans certains coins.</p><p>Exemple concret : l'idée qu'il n'y a pas de différence fonctionnelle entre les unités <code>px</code>, et <code>em</code> ou <code>rem</code> en CSS. C'est une idée fausse que j'entends encore et encore, alors je me suis dit que j'allais l'aborder ici, dans un billet.</p><p>Soyons clairs : l'unité que vous utilisez dans votre CSS <em>est absolument importante</em>. Et vous devez éviter les <code>px</code> lorsque vous définissez la taille de la police, dans la mesure du possible.</p><p>Encore une fois : "toujours" est un mot fort, et un peu dogmatique. Mais la vérité est la suivante : si vous choisissez la mauvaise unité, vous risquez d'écraser les préférences de vos utilisateurs, de leur rendre l'utilisation de votre site Web plus difficile (voire impossible) et de nuire au design par des effets secondaires visuels involontaires.</p><h2>De quelles unités parlons-nous et que font-elles?</h2><p>Avant d'aborder les raisons pour lesquelles nous devrions éviter d'utiliser <code>px</code> pour la taille de la police, assurons-nous que nous avons bien compris de quelles unités il s'agit et comment elles se comportent en général.</p><h3>px</h3><p><code>px</code> est l'abréviation de pixel... bien qu'il ne s'agisse plus littéralement d'un pixel la plupart du temps. Il l'était autrefois, à l'époque où les écrans avaient tendance à avoir un ratio de pixels assez prévisible et de faible résolution, comme 1024×768. À cette époque, <code>1px</code> était généralement égal à un pixel réel sur l'écran physique.</p><p>Les écrans affichent les images à l'aide d'une grille de lumières colorées appelées pixels. Un pixel est une lumière colorée sur l'écran ; le plus petit "point" possible que le matériel est capable de restituer. C'est ce que j'entends par pixel "littéral", "réel" ou "périphérique" dans cette section ; un pixel dans le monde physique.</p><p>Cependant, lorsque les écrans haute résolution (parfois appelés "rétina") sont apparus et que les appareils ont commencé à contenir plus de pixels dans moins d'espace, ces pixels physiques sont devenus super petits. En naviguant sur le Web sur un écran haute résolution, il aurait été extrêmement difficile de lire quoi que ce soit si 1px en CSS correspondait encore à un pixel de périphérique littéral, car les pixels eux-mêmes se sont rapidement réduits. Les smartphones modernes ont des résolutions encore plus élevées que les téléviseurs HD, après tout.</p><p>Au lieu de cela, les navigateurs sur les écrans haute résolution mettent à l'échelle ce qu'ils affichent (zoom avant, plus ou moins), afin que les pages Web ne soient pas illisibles. Les images et autres éléments peuvent toujours être affichés dans toute leur gloire haute résolution, mais le texte et les autres éléments sont mis à l'échelle pour maintenir la lisibilité.</p><p>Ainsi, de nos jours, <code>1px</code> correspond généralement à la taille d'un pixel agrandi, "zoomé", plutôt qu'à un pixel littéral sur le matériel réel. Un élément de <code>1px</code> dans notre CSS occupera probablement plusieurs pixels physiques du matériel, et nous n'avons pas vraiment de moyen dans le CSS pur de spécifier un pixel littéral du périphérique. Mais ce n'est pas grave, car ils sont généralement trop petits pour que nous ayons envie de nous en occuper.</p><p class="is-style-explanation">Un exemple : les pixels de l'iPhone 14 Pro sont si microscopiques que 16px, en pixels de périphérique littéral, correspondraient à la taille d'une police d'écriture imprimée de `2pt`. Heureusement que les navigateurs les mettent à l'échelle pour nous !</p><p>La plupart de ces éléments ne sont pas vraiment importants dans le contexte de cette discussion, mais je pense qu'il est bon de les connaître quand même. La partie importante est la suivante : <code>1px</code> est égal à ce que le navigateur traite comme un pixel unique (même si ce n'est pas littéralement un pixel sur l'écran matériel).</p><h3>em et rem</h3><p>Cela nous amène à <code>em</code> et <code>rem</code>, qui sont similaires l'un à l'autre. Pour continuer avec les anecdotes non strictement pertinentes mais néanmoins intéressantes : "em" est un terme typographique qui précède les ordinateurs de plusieurs décennies. Typographiquement, un <code>em</code> est égal à la taille courante de la police (NdT : <em>c'est à dire relatif à la taille de police de son élément parent</em>).</p><p>Si la taille de votre police est réglée sur <code>32 pt</code> ("pt" signifie point, un autre terme typographique ancien encore parfois utilisé), alors 1em correspond à <code>32 pt</code>. Si la taille actuelle de la police est de <code>20px</code>, alors <code>1em</code> = <code>20px</code> (mais encore une fois : vous ne devriez pas définir les tailles de police en pixels — ceci est juste pour l'exemple).</p><p>Sur le Web, la taille de police par défaut est de <code>16px</code>. Certains utilisateurs ne changent jamais cette valeur par défaut, mais beaucoup le font. Mais par défaut, au moins, <code>1em</code> et <code>1rem</code> seront tous deux égaux à <code>16px</code>.</p><p class="is-style-explanation">À l'origine, Em faisait référence à la largeur d'un caractère "M", d'où son nom. Mais il fait désormais référence à la taille actuelle de la police, plutôt qu'aux dimensions d'un glyphe spécifique.</p><h2>La différence entre em et rem</h2><p>Pour différencier les deux : <code>1rem</code> est toujours égal à la taille de la police du navigateur — ou, plus précisément, à la taille de la police de l'élément <code>html</code>. <code>rem</code> signifie "root em", et la racine d'une page Web est la balise <code>&lt;html&gt;</code>. Donc, <code>1rem</code> = la taille de la police du document, quelle qu'elle soit. (Qui, encore une fois, par défaut, est de <code>16px</code>, <em>mais peut être modifiée par l'utilisateur</em>).</p><p><code>em</code>, on l'a vu, est la taille de la police de l'élément courant. Prenez le CSS suivant :</p><pre class="language-css">.container {
  font-size: 200%;
}
p {
  font-size: 1em;
}</pre><p>Avec le CSS ci-dessus, les paragraphes à l'intérieur de l'élément <code>.container</code> seraient deux fois plus grands. En effet, <code>1em</code> signifie "la taille actuelle de la police", et à l'intérieur de l'élément <code>.container</code>, cette taille est de 200 %. <code>1em</code> × 200% = <code>2em</code> (<code>32px</code> par défaut).</p><p>Toutefois, les paragraphes situés à l'extérieur de l'élément <code>.container</code> conservent la taille de police normale de <code>1em</code> (<code>16px</code> par défaut).</p><p>Si nous remplaçons <code>em</code> par <code>rem</code> dans le CSS ci-dessus, toutes les balises de paragraphe auront toujours la taille de police par défaut du navigateur, où qu'elles se trouvent.</p><p class="is-style-explanation">`font-size : 1em` est équivalent à `font-size : 100%`.</p><p>Les unités `em` et `%` ne sont pas toujours équivalentes dans d'autres contextes. Par exemple, `width : 1em` et `width : 100%` seraient très probablement bien différents, puisque dans ce cas, le pourcentage est basé sur la largeur du conteneur parent, et non sur sa taille de police. Mais `%` et `em` sont identiques en ce qui concerne la propriété font-size.</p><p>Donc, pour résumer :</p><ul><li><code>1em</code> est la taille de la police de l'élément actuel</li>
<li><code>1rem</code> (root em) est la taille de la police du document (c'est-à-dire celle du navigateur)</li>
</ul><p>Très bien ; voilà ce que signifient les unités et d'où elles viennent. Répondons maintenant à la question de savoir pourquoi il est important de savoir laquelle nous utilisons.</p><h2>Pourquoi tout cela est important</h2><p>Une fois encore, l'idée fausse la plus répandue est la suivante : puisque <code>1em</code> est de toute façon égal à <code>16px</code>, l'unité choisie n'a pas d'importance. Et cela semble logique ; si <code>16px</code> = <code>1rem</code>, alors pourquoi la façon dont vous choisissez de le taper aurait-elle de l'importance ?</p><p>Rappelez-vous, <code>em</code> et <code>rem</code> sont relatifs ; par défaut, ils sont tous deux (en fin de compte) basés sur la taille de la police du navigateur.</p><p>En revanche, <code>px</code> ne l'est pas ; il s'agit d'une valeur statique qui n'est pas basée sur ou affectée par quoi que ce soit d'autre.</p><p><code>2rem</code> correspond au double de la taille de la police du navigateur ; <code>0.5rem</code> correspond à la moitié de celle-ci, et ainsi de suite. Ainsi, si l'utilisateur modifie sa taille de police préférée (NdT : p.ex. en modifiant les réglages de son navigateur), si vous avez utilisé <code>em</code> et <code>rem</code>, tout le texte de votre site Web sera modifié en conséquence, comme il se doit. <code>2rem</code> est toujours le double de cette taille de police ; <code>0.5rem</code> est toujours la moitié de celle-ci.</p><p>En revanche, les valeurs <code>px</code> sont statiques. <code>20px</code> reste <code>20px</code>, quelle que soit la taille de la police du conteneur, du navigateur ou de l'utilisateur. Quelle que soit la taille de la police préférée de l'utilisateur, lorsque vous définissez une valeur en pixels statiques, elle écrase ce choix et le remplace par la valeur exacte que vous avez spécifiée.</p><p>Cela signifie que si votre feuille de style utilise <code>px</code> pour définir la taille de la police, il sera impossible pour l'utilisateur de modifier tout texte basé sur cette valeur.</p><p><code>em</code> et <code>rem</code> fonctionnent avec la taille de police de l'utilisateur ; <code>px</code> la remplace complètement.</p><p>C'est une très mauvaise chose. C'est inaccessible, et cela peut même empêcher quelqu'un d'utiliser le site tout court.</p><p>Ainsi, bien que ce comportement puisse être utilisé dans certains cas valables, ce n'est certainement pas ce que vous voulez comme valeur par défaut.</p><p class="is-style-explanation">C'est également une très bonne raison d'éviter les unités de visualisation, comme `vw` ou `vh`, lors de la définition de la taille de la police. Ces unités sont également statiques et impossibles à modifier par l'utilisateur.</p><p>Tout au plus, une valeur comme `calc(1rem + 1vw)` pourrait être acceptable, car elle contient toujours `rem` comme base. Mais même dans ce cas, je vous recommande d'utiliser `clamp()` ou `media queries` pour définir les valeurs minimales et maximales, car les tailles d'écran vont souvent bien au-delà de ce que nous pouvons attendre ou tester.</p><h2>Différences au-delà de la taille de la police</h2><p>Ok, parlons maintenant de la façon dont <code>px</code> et <code>em</code>/<code>rem</code> varient même lorsque nous ne traitons pas spécifiquement de la propriété <code>font-size</code>.</p><p>Les développeurs testent généralement en effectuant un zoom avant ou arrière sur la page, et je pense que <em>c'est de là que vient l'idée fausse au cœur de ce billet</em>. <strong>Lorsque vous effectuez un zoom, tout est redimensionné</strong> (ou réduit) et, dans ce scénario, le choix de <code>px</code> ou de <code>em</code>/<code>rem</code> comme unité CSS n'a généralement pas d'importance. Les deux se comportent de la même manière, en ce qui concerne le zoom. Et la plupart des développeurs privilégiés ayant une bonne vue ne se rendront probablement pas compte qu'il y a plus que cela. Cependant, la chose délicate est la suivante :</p><p>Même au-delà de la taille de la police, px ne se comporte <em>pas</em> de la même manière que <code>em</code> et <code>rem</code>.</p><p>Les unités <code>px</code> sont toujours liées à la valeur mise à l'échelle des pixels sur l'écran. <code>em</code> et <code>rem</code>, en revanche, sont liés à la taille de la police du document, et non au zoom ou à l'échelle de la page.</p><p>Pour le démontrer, jetez un coup d'œil à ce CodePen :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/collinsworth/pen/WNyvvqY">Demonstrating px, em and rem</a>de collinsworth dans<a href="https://codepen.io">CodePen</a></div><p>Nous avons quelques paragraphes, chacun avec une bordure de <code>2px</code> en bas, et une marge de <code>20px</code> entre eux. Remarquez que nous utilisons des unités <code>px</code> pour les deux.</p><p>Si vous effectuez un zoom avant ou arrière, <em>la taille et la distance des éléments restent relatives</em>. En d'autres termes, plus vous effectuez un zoom avant, plus la ligne devient épaisse et plus l'espace entre les paragraphes est grand.</p><p>Pour vous épargner la peine, voici une capture d'écran, montrant ce même codepen avec un zoom de <code>400%</code>. Le texte, la ligne et l'espacement sont tous 4 fois plus grands ; ils restent de la même taille les uns par rapport aux autres :</p><figure><img src="https://la-cascade.io/images/zoomed-in.png" alt="" /></figure><p>Lorsqu'il s'agit de faire un zoom avant ou arrière, il n'y a pas de réelle différence entre <code>px</code> et <code>em</code> ou <code>rem</code>. Mais le zoom n'est pas le seul moyen pour les utilisateurs de rendre les sites Web plus utilisables.</p><p>Comme mentionné précédemment, les utilisateurs peuvent également spécifier une taille de police par défaut et/ou minimale. Et lorsqu'ils le font, <strong>c'est là que la fonctionnalité commence à diverger</strong>.</p><p>Dans la capture d'écran ci-dessous, j'ai défini la taille de police par défaut de Firefox à <code>64px</code>. Voilà ce que ça donne :</p><figure><img src="https://la-cascade.io/images/64px-default.png" alt="" /></figure><p>Comparez le texte de cette capture d'écran avec le texte de celle qui la précède. Remarquez comment, cette fois, les lignes ne sont pas plus épaisses, et les marges entre les paragraphes n'ont pas augmenté proportionnellement. Seul le texte lui-même est plus grand. Comme la largeur de la bordure et la marge ont toutes deux été définies en <code>px</code>, elles restent telles quelles et ne sont pas mises à l'échelle.</p><p>Vous remarquerez toutefois que si vous remplacez les <code>px</code> dans le CSS par les valeurs <code>rem</code> équivalentes, <em>les lignes et les marges s'agrandissent</em> !</p><figure><img src="https://la-cascade.io/images/64px-ems.png" alt="" /></figure><p>Tout cela signifie que le choix de <code>px</code> plutôt que <code>em</code> et <code>rem</code>, ou l'inverse, répond à des motivations de design.</p><p><strong>Donc, pour résumer</strong>,</p><ul><li>les valeurs <code>px</code> n'augmentent ni ne diminuent <strong>pas</strong> lorsque l'utilisateur modifie la taille de sa police de caractères,</li>
<li>Les valeurs <code>em</code> et <code>rem</code> s'ajustent proportionnellement à la taille de la police.</li>
</ul><p>Si vous souhaitez une démonstration interactive qui relie tout cela, consultez ce CodePen final ; ajustez le curseur en haut pour voir l'effet de la modification de la taille de la police du document sur divers éléments, en fonction de l'unité CSS qu'ils utilisent.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/collinsworth/pen/KKepeMQ">The difference between px and rem in font scaling</a>de collinsworth dans<a href="https://codepen.io">CodePen</a></div><h2>Lequel choisir ?</h2><p>Donc, sachant que les valeurs <code>em</code> et <code>rem</code> s'échelonnent en fonction de la taille de la police, mais pas les valeurs <code>px</code>, où cela nous mène-t-il ? Devrions-nous simplement ne jamais utiliser les <code>px</code> pour quoi que ce soit ?</p><p>Même si je pense que vous pouvez suivre cette voie si vous le souhaitez, je pense qu'il y a une place pour les valeurs <code>px</code>.</p><p>Puisque nous savons que les valeurs <code>px</code> ne changeront pas lorsque et si l'utilisateur ajuste sa taille de police, cela signifie que les unités de pixels sont en fait un excellent choix pour certains éléments esthétiques. Peut-être avons-nous un certain espacement que nous ne voudrions pas voir s'agrandir lorsque la taille de la police est plus grande. (S'il s'agit d'un grand bloc d'espace négatif par défaut, il ne serait peut-être pas judicieux de lui permettre de passer à une taille encore plus massive).</p><p>Peut-être y a-t-il des tailles de bordure que nous ne voudrions pas modifier, ou peut-être y a-t-il des éléments décoratifs sur la page, créés avec CSS, qui ne sembleraient pas bien fonctionner à une taille plus grande, juste parce que la police est plus grande. Peut-être ne voulons-nous pas que le remplissage augmente avec la taille de la police. <code>px</code> reste un bon choix dans tous ces cas.</p><p>Personnellement, je recommande de définir toutes les tailles en utilisant <code>rem</code>. Je n'utilise <code>em</code> que lorsque je veux que quelque chose soit proportionnel à la taille courante de la police (par exemple, une icône à côté d'un texte qui doit avoir exactement la même hauteur que les caractères, et un demi-caractère sur le côté). Je n'utiliserais pas <code>px</code> n'importe où, sauf pour les éléments de design que je ne voulais pas explicitement mettre à l'échelle avec la taille de la police.</p><p>Mais une fois de plus, si vous retenez quelque chose de ce billet :</p><p>Ne définissez jamais la taille de la police en unités <code>px</code> — du moins, pas à moins d'être absolument sûr de ce que vous faites, de son comportement et de son accessibilité.</p><h3>Une note importante sur les media queries</h3><p>Il s'agit d'un addendum tardif à cet article, mais il est important d'éviter les <code>px</code> dans les <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Media_Queries/Using_media_queries">requêtes media</a> (<em>media queries</em>) pour les mêmes raisons que celles évoquées ci-dessus ; cela fonctionnera bien lorsque l'utilisateur zoome, mais une requête media qui utilise les <code>px</code> échouera lorsque les utilisateurs définiront eux-mêmes une taille de police plus grande.</p><pre class="language-css">@media (min-width: 800px) {
  /* Modifier la taille de police n'affectera pas ce breakpoint */
}
@media (min-width: 50rem) {
  /* Modifier la taille de police affectera ce breakpoint */
}</pre><p>En effet, lorsque la taille de la police augmente, <code>50rem</code> devient une valeur différente en fonction de cette préférence, alors que <code>800px</code> ne le devient pas.</p><p>La plupart du temps, lorsque nous écrivons du CSS pour des points de rupture (<em>breakpoints</em>) plus grands, nous partons du principe qu'il y a suffisamment de surface d'écran pour que les éléments puissent s'étendre. Cela peut ne pas être le cas si l'utilisateur a défini une très grande taille de police, et le fait de définir nos requêtes média en <code>rem</code> plutôt qu'en <code>px</code> nous permet d'éviter cette hypothèse et de répondre aux préférences de l'utilisateur.</p><p>J'ai rencontré ce problème sur mon site ; je définissais tous mes points de rupture en <code>px</code>. Cependant, lorsque j'ai augmenté la taille de la police par défaut, mes requêtes média n'ont pas répondu, car elles ne tenaient compte que de la largeur en pixels de l'écran. J'avais donc toujours une minuscule barre latérale, avec un texte énorme écrasé de façon illisible à l'intérieur, puisque je n'avais pas tenu compte des préférences des utilisateurs. J'ai changé pour <code>rem</code> immédiatement après, et cela a résolu le problème.</p><p>En résumé, évitez d'utiliser <code>px</code> dans les requêtes média, sauf si vous êtes sûr de savoir ce que vous faites et quel effet cela aura sur les utilisateurs qui définissent leur propre taille de police dans le navigateur.</p><h2>Un dernier mot sur l'accessibilité</h2><p>Les directives d'accessibilité stipulent généralement que les applications Web doivent être utilisables jusqu'à 200 % de zoom et/ou de taille de police. Vous remarquerez que les démos ci-dessus vont bien au-delà.</p><p>C'est en partie pour le contraste, mais il est important de noter que de nombreux utilisateurs iront bien au-delà également, en fonction de leurs besoins et de leurs préférences. Une personne ayant une mauvaise vue ne s'arrêtera pas simplement à 200 % si cela ne lui convient pas. Nous devrions faire de notre mieux pour les inclure, en construisant nos sites et nos applications pour qu'ils soient lisibles et utilisables quoi qu'il arrive.</p><p>J'ai entendu certains spécialistes de la technologie affirmer que leurs utilisateurs sont jeunes et/ou férus de technologie, et que les personnes qui ont besoin d'une grande taille de police ne font pas partie de leur public et ne doivent donc pas être prises en compte. Mais j'aimerais insister sur le fait que c'est faux, présomptueux, et franchement, handicapant.</p><p><code>16px</code> est juste une valeur par défaut. Ce n'est pas une norme, ce n'est pas une cible, et ça ne devrait pas être une supposition. Même en mettant de côté l'âgisme inhérent à cet argument, les besoins varient même chez les jeunes. L'invalidité n'a pas de seuil d'âge. Je connais personnellement une personne d'une trentaine d'années, employée comme développeur à plein temps (c'est-à-dire très jeune et très douée pour la technologie), qui doit définir une taille de police minimale nettement supérieure à la valeur par défaut à cause de sa vision. Les sites Web et les applications sont régulièrement cassés pour eux, parfois au point d'être inutilisables, parce que les développeurs ne tiennent pas compte de leurs besoins.</p><p>Je rappelle tout cela pour souligner l'importance de tester les UI comme le feraient nos utilisateurs. Ci-dessus, j'ai utilisé <code>64px</code>, et il est vrai que cela semble être une sélection assez extrême, étant quatre fois plus grande que la valeur par défaut... mais encore une fois, et si ce n'était pas le cas ? Et si un utilisateur en avait vraiment besoin ? Dire, de fait, à un utilisateur "tu as besoin de trop" n'est pas quelque chose que nous souhaitons faire.</p><p>Il y aura toujours des limites pratiques à ce que nous pouvons accommoder, bien sûr. Mais quoi qu'il en soit, nous devrions au moins aller aussi loin que possible. Même si le taux de 4 fois n'est pas toujours réalisable, il existe de nombreuses options possibles entre 100 et 400 % que les utilisateurs pourraient choisir de manière réaliste et sur lesquelles ils pourraient compter, et nous devrions faire de notre mieux pour ne pas les gêner. À défaut, ce que nous construisons sur le Web devrait au moins être suffisamment flexible pour aller bien au-delà des valeurs par défaut.</p><p><code>16px</code> n'est qu'un défaut. Ce n'est pas une norme, ce n'est pas un objectif, et cela ne devrait pas être une hypothèse. Nous pouvons, et devons, faire mieux.</p><p>NdT : voir également l'excellent <a href="https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/">article de Josh Comeau</a> (en anglais) sur le même sujet.</p></div>]]></description>
      <link>https://la-cascade.io/articles/pourquoi-vous-ne-devriez-pas-utiliser-px-pour-fixer-la-taille-de-police</link>
      <guid>https://la-cascade.io/articles/pourquoi-vous-ne-devriez-pas-utiliser-px-pour-fixer-la-taille-de-police</guid>
      <pubDate>Sun, 27 Nov 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Guide de l'accessibilité du clavier: HTML et CSS (1ère partie)]]></title>
      <description><![CDATA[<p><em>Comment utiliser HTML et CSS pour créer une expérience accessible pour les utilisateurs de claviers?</em></p><div class="articleContent"><p>L'accessibilité du clavier est un élément important de l'expérience utilisateur. Les <strong>directives d'accessibilité aux contenus Web (WCAG)</strong> contiennent de nombreux critères à ce sujet. Pourtant, il est quelque peu négligé, ce qui affecte l'expérience de nombreux utilisateurs, principalement les personnes souffrant de handicaps moteurs — toute condition qui limite les mouvements ou la coordination.</p><p>Certaines conditions telles qu'un bras cassé, la perte ou l'endommagement d'un membre, la dystrophie musculaire, l'arthrite et d'autres peuvent rendre impossible l'utilisation d'une souris pour naviguer sur un site. Par conséquent, rendre un site navigable au moyen du clavier est un élément très important pour garantir l'accessibilité et la convivialité de nos sites Web.</p><p>L'importance de rendre un site accessible aux utilisateurs souffrant de handicaps moteurs devient encore plus évidente lorsque vous apprenez qu'ils ont accès à davantage d'options technologiques d'assistance. Les claviers ne sont même pas le point central de l'assistance aux handicapés moteurs ! Il existe des outils comme les commutateurs que vous utilisez avec votre main (ou même avec votre tête) pour travailler avec n'importe quel appareil, ce qui aide beaucoup les personnes souffrant de handicaps moteurs plus graves. Vous pouvez voir comment ces technologies fonctionnent dans <a href="https://www.youtube.com/watch?v=V1yoOLhx_qA">cette démonstration faite par Rob Dodson</a> ou dans <a href="https://www.youtube.com/watch?v=cSSgndQ5mVs">cette vidéo de Christopher Hills</a>.</p><p><strong>Dans cet article, je vais vous expliquer comment utiliser HTML et CSS pour créer une expérience accessible pour les utilisateurs de claviers, et je listerai les critères WCAG que nous devons prendre en considération</strong>.</p><h2>HTML</h2><p>L'une des bases de la création d'un site Web accessible pour les utilisateurs de clavier est de savoir quels éléments doivent être navigables au clavier. Pour cela, une bonne sémantique HTML est cruciale car elle indiquera le type d'éléments sur lesquels nous voulons nous concentrer avec la navigation au clavier.</p><h3>Les bases</h3><p>Lorsqu'un utilisateur appuie sur la touche <code>Tab</code>, il peut sélectionner l'élément suivant dans le code HTML, et lorsqu'il appuie sur les touches <code>Shift + Tab</code>, il peut accéder au dernier élément. Ceci étant dit, quels éléments doivent être focalisables ? Réponse : tout ce qui nécessite une interaction avec l'utilisateur ! Vous devez pouvoir trouver, entre autres, les éléments <code>button</code>, <code>a</code>, <code>input</code>, <code>summary</code>, <code>textarea</code>, <code>select</code>, et les contrôles des éléments <code>audio</code>, et <code>video</code> (lorsque vous leur ajoutez l'attribut <code>controls</code>). En outre, certains attributs peuvent rendre un élément navigable au clavier, comme <code>contenteditable</code> ou <code>tabindex</code>. Dans le cas de Firefox, toute zone comportant un défilement sera également accessible au clavier.</p><p>En plus de cela, vous devez pouvoir :</p><ul class="nestedList"><li>Activer les éléments `button`, `select`, `summary` et `a` à l'aide de la touche `Entrée`. N'oubliez pas qu'à l'exception de l'élément `a`, vous pouvez également les activer avec la touche `Espace`.</li>
<li>Utiliser les touches fléchées pour naviguer entre les différentes `input` avec le type `radio` si elles partagent le même attribut `name`.</li>
<li>Cocher ces entrées à l'aide de la touche `Espace` (n'oubliez pas que lorsque vous naviguez avec les touches flèches, les `input` radio sont cochés dès que le clavier est activé, mais que cela ne se produit pas avec les `input` de type case à cocher).</li>
<li>Utiliser les touches flèche-vers-le-haut et flèche-vers-le-bas pour naviguer entre les différentes options d'un élément `select`.</li>
<li>Ferme la liste affichée de l'élément `select` et les diverses fenêtres contextuelles d'`input`.</li>
<li>Utiliser les touches flèches pour faire défiler verticalement ou horizontalement un document.</li>
</ul><p>Il existe probablement d'autres interactions, dont certaines dépendent des différences entre les systèmes d'exploitation et les navigateurs, mais ce que nous avons vu couvre l'essentiel de ce que vous pouvez faire avec le clavier.</p><p>Cela signifie-t-il que ces éléments sont automatiquement accessibles au clavier par défaut ? Pas tout à fait. Une bonne structure HTML est très utile, elle rend <em>l'essentiel</em> du contenu accessible par défaut, mais vous devez quand même couvrir certains problèmes.</p><p>Par exemple, certains types d'<code>input</code> comme <code>date</code>, <code>datetime-local</code>, <code>week</code>, <code>time</code> et <code>month</code> ont des popups qui peuvent fonctionner différemment selon les navigateurs. Chrome, par exemple, vous permet d'ouvrir le popup du sélecteur de date (<em>date picker</em>) en appuyant sur la touche <code>Entrée</code> ou <code>Espace</code> dans un bouton dédié dans la saisie. Cependant, avec Firefox, vous devez appuyer sur la touche <code>Entrée</code> (ou <code>Espace</code>) dans les champs du jour, du mois ou de l'année pour ouvrir la fenêtre contextuelle et modifier chaque champ à partir de là.</p><p>Ce manque de cohérence peut être un peu rebutant, et c'est peut-être juste une question de préférence personnelle. Toujours est-il que j'ai l'impression que l'expérience Firefox n'est pas très intuitive, ce qui amène à penser que, sans doute, l'une de ces expériences est plus accessible au clavier que l'autre. Donc, si vous voulez créer une bonne expérience clavier, accessible et cohérente entre les navigateurs, il vous faudra plus que du HTML pour cela. Si vous voulez essayer vous-même, consultez cette <a href="https://developer.mozilla.org/fr/docs/Web/HTML/Element/input">compilation (en français) de types d'entrée par MDN</a> et naviguez par vous-même.</p><p>En plus du point précédent, certains composants exigent que les éléments soient focalisables au clavier sans être nativement sélectionnables. Dans d'autres cas, nous devons gérer le focus clavier manuellement, et notre balisage doit nous aider à le faire. Dans les deux cas, nous devrons utiliser un <strong>attribut HTML</strong> qui nous aidera dans cette tâche.</p><h3>Attribut tabindex</h3><p>Cet attribut nous aidera à amener l'accessibilité clavier à des niveaux de configuration plus fins. Il prend un nombre entier, et son utilisation correcte nous aidera à rendre un élément DOM accessible au clavier. Avec tabindex, nous pouvons trouver trois cas différents :</p><h4>tabindex="0"</h4><p>Il fait en sorte que l'élément soit focalisable par le clavier. En général, vous ne souhaitez pas ajouter le focus clavier à un élément, sauf s'il n'est pas interactif, mais certains scénarios l'exigent.</p><p>L'un d'eux est lorsque vous avez un composant avec un défilement à côté de l'élément <code>body</code>. Sinon, les utilisateurs du clavier ne pourront pas voir le contenu dans toute son étendue. Parmi les composants susceptibles d'avoir ce problème, citons les carrousels avec défilement, les tables et les extraits de code. Pour donner un exemple, tout extrait de code créé à l'aide de <a href="https://prismjs.com/">prism.js</a> possède l'attribut <code>tabindex="0"</code>. Ouvrez le site de prism.js et naviguez-y à l'aide de la touche <code>Tab</code>. Vous pourrez avoir un focus sur les snippets et contrôler le défilement vertical et horizontal à l'aide des touches flèches.</p><figure role="group"><img src="https://la-cascade.io/images/prism.webp" alt="Copie d'écran de prismjs.com focalisé par le clavier. Un contour noir entoure l'élément, indiquant qu'il est en focus." /><figcaption>Un contour noir entoure l'élément, indiquant qu'il est en focus.</figcaption></figure><p>Certaines personnes qui s'initient à l'accessibilité du Web pensent que c'est une bonne idée d'ajouter l'attribut <code>tabindex="0"</code> à chaque élément car elles pensent que cela aidera les utilisateurs de lecteurs d'écran à naviguer facilement sur un site. Il s'agit d'une pratique terrible pour deux raisons :</p><ol><li>Les utilisateurs de lecteurs d'écran ont plusieurs façons de naviguer sur un site. Ils peuvent sauter entre les titres, les balises de repère (telles que <code>main</code>, <code>nav</code>, ou <code>aside</code>) ou les éléments de formulaire, et ils n'ont pas besoin de cette aide supplémentaire pour créer un site accessible, tant que le balisage est approprié.</li>
<li>Cela peut rendre la navigation au clavier difficile car un utilisateur devra appuyer plusieurs fois sur la touche <code>Tab</code> pour arriver au contenu souhaité, et pour certains handicaps moteurs, le fait d'avoir trop d'éléments focalisables peut créer une expérience physiquement pénible.</li>
</ol><p>Donc, pour résumer : c'est une technique utile pour certains éléments, mais la plupart du temps, vous vous en sortirez très bien si vous ne l'utilisez pas, et en tout cas, vous ne <em>devez pas</em> l'utiliser dans chaque élément de votre site.</p><h4>Tabindex négatif</h4><p>Avant de commencer, nous devons garder à l'esprit deux concepts : un élément DOM est à la fois focalisable (c'est-à-dire que vous pouvez le focaliser de manière programmatique avec JavaScript) et <em>tabulable</em> (c'est-à-dire qu'il peut être sélectionné avec la touche <code>Tab</code>).</p><p>En gardant cela à l'esprit, c'est ici que le <code>tabindex</code> négatif entre en jeu car il le retire de l'arbre d'accessibilité, il ne peut plus être tabulé, (mais vous pouvez toujours le focaliser avec JavaScript). C'est important pour des composants spécifiques car, dans certains cas, nous devons faire en sorte qu'un élément normalement tabulable ne puisse pas être tabulé, ou qu'un élément soit focalisable mais pas tabulable.</p><p>Les onglets en sont un exemple. Un modèle recommandé pour ce composant est de s'assurer que lorsque vous appuyez sur la touche <code>Tab</code> quand vous êtes situé sur l'onglet actif, cela nous amène au <code>tabpanel</code> actif plutôt que mettre le focus sur l'onglet suivant. Nous pouvons y parvenir en ajoutant un tabindex négatif à tous les onglets non actifs comme ceci :</p><pre class="language-html">&lt;ul role="tablist"&gt;
  &lt;li role="presentation"&gt;
    &lt;button role="tab" href="#panel1" id="tab1" aria-selected="true"&gt;
      Tab one
    &lt;/button&gt;
  &lt;/li&gt;
  &lt;li role="presentation"&gt;
    &lt;button role="tab" href="#panel2" id="tab2" tabindex="-1"&gt;
      Tab two
    &lt;/button&gt;
  &lt;/li&gt;
  &lt;li role="presentation"&gt;
    &lt;button role="tab" href="#panel3" id="tab3" tabindex="-1"&gt;
      Tab three
    &lt;/button&gt;
  &lt;/li&gt;
  &lt;li role="presentation"&gt;
    &lt;button role="tab" href="#panel4" id="tab4" tabindex="-1"&gt;
      Tab four
    &lt;/button&gt;
  &lt;/li&gt;
&lt;/ul&gt;</pre><p>Nous verrons plus tard d'autres exemples sur la façon dont un <code>tabindex</code> négatif nous aidera à avoir plus de contrôle sur la gestion de l'état du focus dans différents composants, mais gardez à l'esprit qu'un <code>tabindex</code> négatif sera important dans ces cas.</p><p>Enfin, vous pouvez mettre n'importe quel nombre entier négatif dans la propriété <code>tabindex</code>, et cela fonctionnera de la même manière. <code>tabindex="-1"</code> et <code>tabindex="-1000"</code> ne feront aucune différence, mais par convention, j'ai tendance à utiliser <code>-1</code> lorsque nous utilisons cet attribut.</p><h4>Tabindex positif</h4><p>Un <code>tabindex</code> positif rendra l'élément focalisable par le clavier, mais l'ordre sera défini en fonction de l'entier utilisé. Cela signifie que le clavier parcourra d'abord tous les éléments avec l'attribut <code>tabindex="1"</code>, puis ceux avec <code>tabindex="2"</code>, et après avoir parcouru tous les éléments avec un <code>tabindex</code> positif, il prendra en compte tous les éléments interactifs par défaut et ceux avec l'attribut <code>tabindex="0"</code>. C'est ce que l'on appelle le <a href="https://html.spec.whatwg.org/multipage/interaction.html#tabindex-ordered-focus-navigation-scope">scope de navigation du focus ordonné par tabindex</a>.</p><p>Maintenant, c'est une configuration que vous ne <em>devriez pas</em> utiliser. Il est préférable de placer les éléments focalisables requis dans votre site dans l'ordre nécessaire. Sinon, vous pourriez créer une expérience très déroutante pour les utilisateurs du clavier, ce qui constituerait un échec du <a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html">critère 2.4.3 des WCAG : Ordre de focalisation</a>.</p><figure class="quote"><blockquote cite="https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html">
<p>Si une page Web peut être parcourue de manière séquentielle et que les séquences de navigation affectent le sens ou le fonctionnement, les composants focalisables reçoivent la focalisation dans un ordre qui préserve le sens et le fonctionnement.</p>
</blockquote>
<figcaption><cite><a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html">Critère de réussite 3.2.1: Ordre de focalisation</a></cite></figcaption></figure><p>Cela pourrait être utile si vous voulez que les utilisateurs du clavier se concentrent sur les widgets avant d'atteindre le contenu de la page, mais cela serait un peu déroutant pour les utilisateurs de technologies d'assistance (comme les lecteurs d'écran). Donc, encore une fois, vous feriez mieux de créer un ordre logique dans le DOM.</p><h4>Attribut inerte</h4><p>Je dois noter rapidement un attribut entrant qui nous aidera beaucoup avec l'accessibilité du clavier, appelé <code>inert</code>. Cet attribut rendra le contenu inaccessible par les technologies d'assistance.</p><p>Bon, vous vous demandez peut-être comment il peut être utile que quelque chose supprime l'accessibilité du clavier, mais dans certains cas, c'est une bonne chose ! Un composant qui en bénéficiera est celui des modales. En ajoutant cet attribut à tous les éléments du site, à l'exception de cette modale, il sera facile de créer un "piège à focus". Ainsi, vous vous assurerez que l'utilisateur ne peut pas naviguer accidentellement vers d'autres parties du site à l'aide de la touche <code>Tab</code>, à moins qu'il ne ferme cette modale. Pour l'instant, la création d'un <code>piège à clavier</code> nécessite une grosse réflexion avec JavaScript (je vous expliquerai comment dans la deuxième partie de ce guide). Donc, avoir un moyen de rendre la chose plus facile avec cet attribut sera bien pratique.</p><p>Ça paraît plutôt cool, non ? Eh bien, malheureusement, l'utilisation de cet attribut n'est <em>pas encore recommandée</em>. Si vous consultez la <a href="https://caniuse.com/?search=inert">page de caniuse.com sur cet attribut</a>, vous remarquerez qu'il est très récent ; Opera ne le prend pas encore en charge. L'implémentation la plus récente de cet attribut est la version 105 de Firefox, et au moment de la rédaction de cet article, il s'agit d'une version bêta ! Il est donc encore très tôt pour le faire. Il existe un polyfill pour l'attribut inert, mais pour l'instant, il est un peu coûteux en termes de performances. Je vous suggère donc sérieusement de ne pas l'utiliser maintenant pour la production. Mais une fois que nous aurons un support adéquat pour cet attribut, certains modèles de composants seront plus faciles à créer.</p><h2>CSS</h2><p>CSS est un outil essentiel pour l'accessibilité du clavier car il nous permet de créer un niveau de personnalisation de l'expérience, ce qui est important pour la conformité aux critères WCAG 2.2. De plus, CSS possède de multiples sélecteurs qui aideront à créer une bonne expérience clavier, mais attention car une mauvaise utilisation de certaines propriétés peut être contre-productive. Plongeons dans l'utilisation de CSS pour créer une expérience accessible aux utilisateurs de clavier.</p><h3>Indicateur de focus</h3><p>Lorsque vous utilisez une souris, vous pouvez voir avec quel élément vous pouvez interagir grâce au curseur, et vous ne voudriez pas retirer le curseur à votre utilisateur, n'est-ce pas ? Cela le rendrait incapable de savoir quel élément il veut utiliser !</p><p>Nous avons un concept similaire pour la navigation au clavier, et il s'appelle un <strong>indicateur de focus</strong>, qui par défaut est un contour qui entoure un élément focalisable par le clavier lorsqu'il est sélectionné par celui-ci. Il est essentiel de s'assurer que tous vos éléments accessibles au clavier disposent d'un indicateur de focus. C'est une condition importante pour rendre un site Web accessible au clavier, selon les critères WCAG :</p><figure class="quote"><blockquote cite="https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html">
<p>Toute interface utilisateur utilisable au clavier possède un mode de fonctionnement où l'indicateur de focus clavier est visible.</p>
</blockquote>
<figcaption><cite><a href="https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html">Critère de réussite 2.4.7 : Focus visible</a></cite></figcaption></figure><p>Le style de focus est différent selon le navigateur que vous utilisez. Vous pouvez voir comment il se présente dans les différents navigateurs dans ces images par défaut et lorsque vous utilisez la propriété CSS <a href="https://developer.mozilla.org/fr/docs/Web/CSS/color-scheme">color-scheme</a> réglée sur <code>dark</code>, juste pour vérifier comment les styles par défaut se comporteraient en mode sombre.</p><figure role="group"><img src="https://la-cascade.io/images/focus-chrome.webp" alt="Contour noir sur fond blanc, et blanc sur fond noir" /><figcaption>Indicateur de focus de Chrome.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/focus-firefox.webp" alt="Contour bleu, quel que soit le fond" /><figcaption>Indicateur de focus de Firefox.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/focus-safari.webp" alt="Contour bleu sur fond blanc, gris sur fond noir" /><figcaption>Indicateur de focus de Safari.</figcaption></figure><p>Comme vous pouvez le remarquer, les navigateurs basés sur Chromium comme Chrome ou Edge ont un contour noir et blanc, qui fonctionne en mode clair et foncé. Firefox a opté pour un contour bleu qui se remarque dans les deux modes. Et Safari (et les navigateurs basés sur Webkit, car à l'heure actuelle, tous les navigateurs iOS utilisent Webkit comme moteur de navigation) a presque le même aspect que Firefox, mais avec un contour encore plus subtil pour un schéma de couleurs sombres.</p><h4>Critère 2.4.11 des WCAG #.</h4><p>Maintenant, les indicateurs de focus par défaut sont visibles, mais sont-ils suffisants ? La réponse est "non". Même si ça peut fonctionner dans certains cas, les personnes souffrant de déficiences visuelles auront du mal à le remarquer. Les WCAG ont donc créé le <strong><a href="https://w3c.github.io/wcag/understanding/focus-appearance.html">critère de réussite 2.4.11 - Apparence de focus</a></strong> pour rendre un indicateur de focus accessible. Pour l'instant, ce critère fait partie des WCAG 2.2, qui sont une recommandation candidate. Il est donc peu probable qu'il soit modifié avant la version finale, mais gardez à l'esprit qu'il est toujours susceptible d'être modifié.</p><figure class="quote"><blockquote cite="https://w3c.github.io/wcag/understanding/focus-appearance.html">
<p>Lorsque l'indicateur de focus clavier est visible, l'une des deux conditions suivantes, ou les deux, sont remplies :</p>
<ul class="nestedList"><li>L'indicateur de focus :</li>
<li>entoure la présentation visuelle du composant de l'interface utilisateur, et</li>
<li>présente un rapport de contraste d'au moins 3:1 entre les mêmes pixels dans les états focalisé et non focalisé,et</li>
<li>présente un rapport de contraste d'au moins 3:1 par rapport aux couleurs adjacentes.</li>
</ul><div>Une zone de l'indicateur de focus répond à tous les critères suivants :
<ul class="nestedList"><li>est au moins aussi grande que la zone d'un périmètre de 1 pixel CSS d'épaisseur du composant non focalisé, ou est au moins aussi grande qu'une ligne de 4 pixels CSS d'épaisseur le long du côté le plus court de la boîte de délimitation minimale du composant non focalisé, et</li>
<li>présente un rapport de contraste d'au moins 3:1 entre les mêmes pixels dans les états focalisé et non focalisé, et</li>
<li>présente un rapport de contraste d'au moins 3:1 entre les couleurs adjacentes de l'indicateur non focalisé, ou n'est pas plus mince que 2 pixels CSS.</li>
</ul></div></blockquote>
<figcaption><cite><a href="https://w3c.github.io/wcag/understanding/focus-appearance.html">critère de réussite 2.4.11 - Apparence de focus</a></cite></figcaption></figure><p>Il y a quelque chose d'important à considérer ici, et c'est la zone de l'indicateur de focus. Cette zone doit répondre aux exigences de contraste de ce critère. Pour illustrer cela, je vais utiliser un exemple que <a href="https://la-cascade.io/auteurs/sara-soueidan">Sara Soueidan</a> a réalisé pour son article <a href="https://www.sarasoueidan.com/blog/focus-indicators/">"A guide to designing accessible, WCAG-compliant focus indicators"</a>.</p><figure role="group"><img src="https://la-cascade.io/images/focus-soueidan.webp" alt="Illustration avec 3 boutons : le premier est bleu avec un label blanc, dans son état par défaut, sans focus. le deuxième est le même bouton avec un contour noir épais et la légende 'focalisé'. Le dernier est le même bouton mais avec un motif appliqué au contour, indiquant que cette zone avec motif est la zone contrastée" /></figure><p>Cet exemple utilise un contour, mais n'oubliez pas que vous pouvez utiliser d'autres propriétés pour déterminer l'état du focus, comme la couleur d'arrière-plan ou des façons créatives d'utiliser le box-shadow, tant que cela est conforme aux exigences. En tout cas, <strong>n'utilisez pas la propriété <code>outline : none</code> pour éliminer le contour de l'élément</strong>.</p><p>C'est important pour le mode de contraste élevé de Windows, car lorsqu'il est actif, les couleurs de votre site Web seront remplacées par celles choisies par l'utilisateur. Ainsi, dépendre de propriétés telles que <code>background-color</code> n'aura aucun effet à ce niveau. À la place, utilisez la déclaration CSS <code>outline-color : transparent</code> avec l'épaisseur appropriée pour respecter les critères WCAG. Vous pouvez voir des exemples de ce fonctionnement dans <a href="https://www.smashingmagazine.com/2022/06/guide-windows-high-contrast-mode/">mon article sur le mode de contraste élevé de Windows</a>.</p><h4>La taille optimale des contours</h4><p>Une façon simple de créer un indicateur de focus conforme est d'utiliser cette méthode que Stephanie Eckles a suggérée dans sa conférence <a href="https://www.youtube.com/watch?v=FfQ-JuaNO68">Modern CSS Upgrades To Improve Accessibility</a>. Tout d'abord, nous définissons des propriétés personnalisées dans les éléments interactifs. N'oubliez pas que vous pouvez ajouter d'autres éléments à la règle en fonction de la complexité de votre projet :</p><pre class="language-css">/* Ajoutez d'autres selecteurs dans cette règle :is si nécessaire */
:is(a, button, input, textarea, summary) {
  --outline-size: max(2px, 0.08em);
  --outline-style: solid;
  --outline-color: currentColor;
}</pre><p>Et ensuite, nous utilisons ces propriétés personnalisées pour ajouter une règle de focus global :</p><pre class="language-css">:is(a, button, input, textarea, summary):focus {
  contour: var(--outline-size) var(--outline-style) var(--outline-color);
  outline-offset: var(--outline-offset, var(--outline-size));
}</pre><p>L'utilisation de <code>0,08em</code> ici permet de donner une taille de contour plus grande si la police est plus grande, ce qui permet de mieux adapter la zone de contraste de l'élément à la taille de la police de l'élément.</p><p>Gardez à l'esprit que même si les WCAG mentionnent que la zone de mise au point "est au moins aussi grande que la zone d'un périmètre de <code>1</code> pixel CSS d'épaisseur de l'élément non mis au point", elles mentionnent également qu'elle doit avoir "un rapport de contraste d'au moins <code>3:1</code> par rapport aux couleurs adjacentes non indicatrices de mise au point, ou n'est <strong>pas plus fine que <code>2</code> pixels CSS</strong>". Ainsi, une épaisseur minimale de <code>2px</code> est nécessaire pour se conformer aux WCAG.</p><p>N'oubliez pas que vous pouvez avoir besoin d'une ligne plus épaisse si vous utilisez un <code>outline-offset</code> négatif, car cela réduira le périmètre du contour. De même, l'utilisation d'un contour pointillé ou en pointillé réduira la zone ciblée de moitié environ, vous devrez donc utiliser une ligne plus épaisse pour compenser.</p><p>La zone idéale du contour est liée au périmètre de l'élément. Sara Soueidan a une fois de plus fait un excellent travail en expliquant le fonctionnement de cette formule dans son <a href="https://www.sarasoueidan.com/blog/focus-indicators/#2.-minimum-contrasting-area">article sur les indicateurs de focus</a>. Consultez-le si vous voulez mieux comprendre les mathématiques qui se cachent derrière cette question et comment les appliquer.</p><h3>Sélecteur CSS liés au focus</h3><p>En CSS, vous utilisez normalement la pseudo-classe <code>:focus</code> pour appliquer un style à un élément lorsqu'il est focalisé par une tabulation clavier, et elle fait bien son travail. Mais les CSS modernes nous ont donné deux nouvelles pseudo-classes, l'une qui nous aide dans un certain cas d'utilisation et l'autre qui résout un problème se produisant lorsque nous utilisons la pseudo-classe <code>:focus</code>. Ces pseudo-classes sont <code>:focus-within</code> et <code>:focus-visible</code>. Voyons ce qu'elles font et comment elles peuvent nous aider à améliorer l'accessibilité du clavier :</p><h4>:focus-within</h4><p>Cette pseudo-classe ajoute un style à chaque fois que l'élément est focalisé ou que l'un de ses enfants l'est également. Faisons un exemple rapide pour montrer à quoi cela ressemble :</p><pre class="language-html">&lt;form&gt;
  &lt;label for="name"&gt;
    Name:
    &lt;input id="name" type="text" /&gt;
  &lt;/label&gt;
  &lt;label for="email"&gt;
    Email:
    &lt;input for="email" type="email" /&gt;
  &lt;/label&gt;
  &lt;button&gt;Submit&lt;/button&gt;
&lt;/form&gt;</pre><p><strong>Note rapide au passage</strong> : il serait préférable de ne pas utiliser <code>label</code> pour envelopper l'élément d'<code>input</code>. Ça fonctionne dans tous les navigateurs, mais ça ne fonctionne pas bien avec <a href="https://www.nuance.com/dragon.html">le logiciel de reconnaissance vocale Dragon</a> car il ne sera pas reconnu de manière correcte.</p><pre class="language-css">formulaire {
  display: grid;
  gap: 1em;
}
label {
  affichage: grille;
  gap: 1em;
  padding: 1em;
}
label:focus-within {
  background-color: rebeccapurple;
  couleur: blanc;
}</pre><figure role="group"><img src="https://la-cascade.io/images/form-1.png" alt="Un formulaire avec le code précédemment décrit. Le champ 'email' est en focus, et le label a un arrière-plan violet. L'entrée dans le label a le contour par défaut du navigateur" /></figure><p>Cette pseudo-classe est intéressante pour enrichir les styles de certains composants, comme montré précédemment, et dans d'autres, elle aide beaucoup à rendre le contenu accessible aux utilisateurs du clavier. Par exemple, j'ai créé une carte pour <a href="https://www.smashingmagazine.com/2022/03/guide-hover-pointer-media-queries/">mon article sur les media queries</a> <code>hover</code>, <code>pointer</code>, <code>any-hover</code> et <code>any-pointer</code>. Cette carte affiche le contenu lorsque l'utilisateur place le curseur dessus, mais elle affiche également le contenu lorsque vous focalisez le bouton à l'intérieur de celle-ci à l'aide de la pseudo-classe <code>:focus-within</code> en utilisant les mêmes règles qui sont déclenchées au survol. Vous pouvez consulter le code dans l'article mentionné ainsi que dans ce CodePen :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/mdLKPWZ">Keyboard accessible animated card</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><h4>:focus-visible</h4><p>D'autre part, nous avons un <em>comportement assez intéressant</em> avec les styles de focus, en raison de la façon dont le navigateur décide quand appliquer cet état à un élément. Si vous utilisez la pseudo-classe <code>:focus</code>, la plupart des navigateurs considéreront que cliquer sur l'élément revient à le focaliser, ce qui crée un "faux positif" où l'élément semble être focalisé par un clavier alors que ce n'est pas le cas.</p><p>Pour résoudre ce problème mineur, nous avons maintenant la pseudo-classe <code>:focus-visible</code> qui crée un état de focalisation si et seulement si l'élément est focalisé par un clavier. Gardez à l'esprit que ce comportement s'appliquera aux éléments comme <code>button</code> ou <code>a</code> et à <strong>la plupart</strong> des éléments d'<code>input</code> comme <code>checkbox</code>, <code>radio</code> ou <code>submit</code>. Mais les styles de focalisation seront toujours appliqués lorsque vous cliquez sur les éléments comme <code>select</code>, certains <code>input</code> qui reçoivent tout type de texte comme <code>text</code>, <code>number</code>, ou l'élément <code>textarea</code>.</p><p>Cela ne se produit plus aujourd'hui car les navigateurs modernes utilisent <code>:focus-visible</code> comme état de focalisation par défaut. Mais n'oubliez pas que vous souhaitez probablement modifier l'indicateur de focus par défaut du navigateur pour être conforme à la norme WCAG 2.4.11. Vous aurez donc besoin de <code>:focus-visible</code> pour éviter ce comportement.</p><p>Si vous consultez <a href="https://caniuse.com/?search=focus-visible">la page de caniuse.com sur la pseudo-classe <code>:focus-visible</code></a>, vous remarquerez qu'il est actif dans tous les navigateurs. Mais dans Safari, il est actif depuis une version relativement récente (15.4, qui a été publiée le 13 mars 2022), ce qui signifie que certains utilisateurs n'ont probablement pas encore mis à jour leur navigateur. Par conséquent, nous devrions offrir une sorte de solution de repli si le navigateur ne prend pas en charge cette pseudo-classe. Nous pouvons le faire en utilisant <a href="https://developer.mozilla.org/fr/docs/Web/CSS/@supports">la feature query <code>@supports</code></a>.</p><p>Précédemment, nous avons créé un bon style global pour le style focus, appliquons maintenant la pseudo-classe <code>:focus-visible</code> à cette règle :</p><pre class="language-css">@supports selector(:focus-visible) {
  *:focus {
    outline: none;
  }
  *:focus-visible {
    outline: var(--outline-size) var(--outline-style) var(--outline-color);
    outline-offset: var(--outline-offset, var(--outline-size));
  }
}</pre><p><strong>Remarque rapide</strong> : je sais que j'ai indiqué que l'utilisation de la règle <code>outline : none</code> n'était pas une bonne idée, mais comme nous la remplaçons par <code>:focus-visible</code>, il s'agit d'un scénario "acceptable" pour l'utiliser. N'oubliez pas d'utiliser outline même s'il n'est pas visible. <a href="https://www.matuzo.at/blog/2022/focus-outline/">Outline est votre ami</a> !</p><h3>Considérations sur la mise en page</h3><p>La puissance des CSS modernes pour créer des mises en page est formidable, mais il y a un ensemble de pratiques que nous devrions essayer d'utiliser avec prudence car elles peuvent rendre l'expérience de navigation au clavier problématique.</p><h4>display : contents</h4><p>Cette règle est très intéressante. Elle supprime la boîte de l'élément et fait que les enfants de l'élément agissent comme s'ils étaient des enfants directs de l'élément du grand-parent, sans supprimer la sémantique. Elle fait que les enfants d'un élément se comportent comme s'ils étaient ses frères et sœurs. Cela peut sembler un peu confus, je vais donc l'expliquer par un exemple. Supposons que nous ayons le balisage de l'en-tête de ce site :</p><pre class="language-html">&lt;header&gt;
  &lt;a href="#"&gt;Go to home&lt;/a&gt;
  &lt;nav&gt;
    &lt;ul&gt;
      &lt;li&gt;
        &lt;a href="#"&gt;Clothes&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;a href="#"&gt;Accessories&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;a href="#"&gt;Shoes&lt;/a&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/nav&gt;
&lt;/header&gt;</pre><p>Si nous ajoutions la règle <code>display : contents</code> à l'élément <code>ul</code>, nous supprimerions la boîte sans supprimer la sémantique, ce qui ferait des éléments <code>li</code> les enfants de l'élément parent de <code>ul</code> (dans ce cas, le conteneur <code>nav</code>) comme ceci :</p><pre class="language-html">&lt;header&gt;
  &lt;a href="#"&gt;Go to home&lt;/a&gt;
  &lt;nav&gt;
    &lt;li&gt;&lt;a href="#"&gt;Clothes&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;
      &lt;a href="#"&gt;Accessories&lt;/a&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="#"&gt;Shoes&lt;/a&gt;
    &lt;/li&gt;
  &lt;/nav&gt;
&lt;/header&gt;</pre><p>Et encore, c'est sans supprimer la sémantique de l'élément parent. Cela apporte quelques possibilités intéressantes pour la création de mises en page, comme l'explique Kevin Powell dans <a href="https://www.youtube.com/watch?v=cs37yx73b1o">sa vidéo sur cette propriété</a>. Cependant, elle a un comportement avec les éléments interactifs du clavier qu'il faut éviter.</p><p>Si vous l'utilisez dans un élément pouvant être focalisé par le clavier, ces éléments ne pourront pas être tabulés. Pour être juste, il est très peu probable que vous vous trouviez dans une situation où vous devez utiliser <code>display : contents</code> dans un élément focalisable par le clavier (le seul cas auquel je puisse penser si vous voulez l'utiliser pour réinitialiser les styles de ces éléments). Et les problèmes d'accessibilité de cette propriété sont pour d'autres raisons plus courantes (Safari a un bug qui supprime la sémantique pour les éléments de type <code>table</code> et <code>button</code> dans la version 16), mais si vous vous trouvez d'une manière ou d'une autre dans cette situation, évitez-la à tout prix.</p><h4>Propriété de commande de Grid et Flex</h4><p>Grid et flexbox ont changé ce que nous pouvons faire avec la création de mises en page. Ce sont des outils incroyables qui nous aident à créer des mises en page aussi compliquées que nous le souhaitons, mais n'oubliez pas qu'ils peuvent créer des problèmes d'accessibilité.</p><p>Comme <a href="https://la-cascade.io/auteurs/manuel-matuzovic">Manuel Matuzović</a> l'a mentionné dans son exposé <a href="https://www.youtube.com/watch?v=R8LZdoUbeg4">The Dark Side of the Grid</a>, lorsque nous modifions l'ordre des éléments visuellement, soit en définissant un ordre explicite dans une grille avec des propriétés telles que <code>grid-row</code> et <code>grid-column</code>, soit en utilisant la propriété <code>order</code> sur flexbox ou grid, l'ordre d'apparition des éléments dans le DOM <code>ne sera pas</code> modifié.</p><p>Ce décalage entre l'ordre DOM et l'ordre visuel peut créer une expérience déroutante pour de nombreux utilisateurs, y compris les utilisateurs de clavier. Si nous modifions trop l'ordre visuel, cela peut créer une expérience déroutante pour eux, car la navigation au clavier pourrait ne pas fonctionner logiquement. Comme je l'ai mentionné dans la section sur le <code>tabindex</code> positif, le critère <strong>WCAG 2.4.3 - Ordre de focus</strong>, cette navigation au clavier doit préserver un ordre qui "préserve le sens et l'opérabilité."</p><p>Vérifions cela à l'aide d'un exemple. Jetons un coup d'œil à ce balisage, et ordonnons-les à l'aide d'une grille :</p><pre class="language-html">&lt;ul role="list"&gt;
  &lt;li&gt;&lt;button&gt;1&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;2&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;3&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;4&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;5&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;6&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;7&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;8&lt;/button&gt;&lt;/li&gt;
  &lt;li&gt;&lt;button&gt;9&lt;/button&gt;&lt;/li&gt;
&lt;/ul&gt;</pre><pre class="language-css">button:focus {
  outline: max(2px, 0.08em) solid currentColor;
  outline-offset: -7px;
}
@supports selector(:focus-visible) {
  button:focus {
    outline: none;
  }
  button:focus-visible {
    outline: max(2px, 0.08em) solid currentColor;
    outline-offset: -7px;
  }
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-example-1.webp" alt="9 boutons bleus sur 3 colonnes, dans l'ordre numérique 1, 2, 3, puis ligne suivante 4, 5, 6, puis ligne suivante 7, 8, 9." /></figure><p>Si vous utilisez la navigation au clavier, vous remarquerez que l'ordre est assez simple. Il se lit de gauche à droite et de haut en bas, et la navigation sera la même. Utilisons maintenant les propriétés de la grille pour effectuer quelques modifications :</p><pre class="language-css">ul
  li:where(:nth-child(1), :nth-child(5), :nth-child(7), :nth-child(9)) {
  grid-row: span 2;
  grid-column: span 2;
}
ul li:where(:nth-child(1), :nth-child(5)) {
  order: 2;
}
ul li:where(:nth-child(7), :nth-child(8)) {
  order: -1;
}
ul li:nth-child(4) {
  grid-row: 3;
  grid-column: 2 / span 2;
}
ul li:nth-child(3) {
  grid-row: 5 / span 3;
  grid-column: 3;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-example-2.webp" alt="L'ordre de l'image prcédente n'est plus respecté, on 7, 8, 2, etc." /></figure><p>Maintenant, il a l'air complètement désorganisé. Bien sûr, la mise en page a l'air drôle, mais lorsque vous commencez à y naviguer avec la touche <code>Tab</code>, l'ordre est très aléatoire. Il y a un certain degré de prévisibilité maintenant parce que j'ai utilisé des chiffres comme étiquette du bouton, mais que se passe-t-il s'ils ont un contenu différent ? Il serait impossible de prédire quel sera le prochain bouton focalisé avec un clavier.</p><p>C'est le genre de scénario qu'il faut éviter. Cela ne signifie pas que vous ne pouvez pas ordonner explicitement un élément dans une grille ou utiliser la propriété <code>order</code>. Cela signifie que vous devez faire attention à la gestion de vos mises en page et vous assurer que l'ordre visuel et l'ordre du DOM correspondent autant que possible.</p><p>À propos, si vous voulez l'essayer par vous-même, vous pouvez voir la démo de ce code ici et expérimenter par vous-même cette navigation chaotique au clavier :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/GRdGZYJ">Focus order demo</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><h2>Quelques modèles de composants</h2><p>Avec ce que nous avons vu sur HTML et CSS, nous pouvons créer quelques composants simples pour améliorer l'expérience des utilisateurs de clavier.</p><h3>Accordéons</h3><p>Nous pouvons créer des accordéons accessibles au clavier avec juste du HTML grâce aux éléments <code>details</code> et <code>summary</code>. Il dispose d'une navigation au clavier par défaut, et la prise en charge des lecteurs d'écran est assez bonne. Attention toutefois à certaines interactions entre les lecteurs d'écran et les navigateurs, comme le souligne Scott O'Hara dans son <a href="https://www.scottohara.me/blog/2018/09/03/details-and-summary.html">article sur les éléments <code>details</code> et <code>summary</code></a>, certaines interactions ne montrent pas de changements importants lorsque les utilisateurs interagissent avec elles. Vous pourriez donc probablement l'améliorer avec JavaScript pour prendre en charge ces cas, mais l'accessibilité de ce composant est plutôt excellente par défaut, notamment pour la navigation au clavier, qui est notre principale préoccupation dans cet article !</p><p>Voici la structure HTML :</p><pre class="language-html">&lt;details&gt;
  &lt;summary&gt;
    &lt;h2&gt;Titre&lt;/h2&gt;
    &lt;span aria-hidden="true"&gt;&lt;/span&gt;
  &lt;/summary&gt;
  &lt;p&gt;
    &lt;!-- Contenu --&gt;
  &lt;/p&gt;
&lt;/details&gt;</pre><p>Et voici à quoi cela ressemblerait lorsque les composants sont dans leur état contracté et développé :</p><figure role="group"><img src="https://la-cascade.io/images/contracted.webp" alt="3 questions sur 3 lignes distinctes, avec chacune un bouton qui semble indiquer qu'en cliquant dessus on aura une réponse." /></figure><figure role="group"><img src="https://la-cascade.io/images/expanded.webp" alt="Le bouton a été cliqué et on a bien une réponse à la question posée." /></figure><p>Commençons maintenant à styliser ce composant ! Par défaut, cet élément utilise ce triangle pour indiquer si l'élément détails est ouvert ou fermé. Nous pouvons supprimer cela en ajoutant cette règle à l'élément <code>summary</code>.</p><pre class="language-css">summary {
  list-style: none;
}</pre><p>Mais nous aurons toujours besoin d'un indicateur visuel pour montrer s'il est ouvert ou fermé. Ma solution consiste à ajouter un deuxième élément en tant qu'enfant de <code>summary</code>. La partie importante est que cet élément aura l'attribut <code>aria-hidden="true"</code> :</p><pre class="language-html">&lt;summary&gt;
  &lt;p&gt;Combien coûte l'expédition ?&lt;/p&gt;
  &lt;span aria-hidden="true"&gt;&lt;/span&gt;
&lt;/summary&gt;</pre><p>La raison pour laquelle j'ai caché cet élément <code>span</code> est que nous allons modifier son contenu à l'aide de CSS modifiant le pseudo-élément <code>::before</code>, et que le contenu que nous ajoutons sera lu par un lecteur d'écran, à moins, bien sûr, que nous le cachions.</p><p>Cela dit, nous pouvons le modifier car le navigateur gère l'état ouvert de l'élément <code>details</code> en ajoutant l'attribut <code>open</code> au conteneur. Nous pouvons donc ajouter et modifier le contenu à l'aide de ces règles CSS :</p><pre class="language-css">summary span[aria-hidden='true']::before {
  content: '+';
}
details[open] summary span[aria-hidden='true']::before {
  content: '-';
}</pre><p>Maintenant, vous pouvez ajouter le style dont vous avez besoin pour l'adapter (n'oubliez pas d'utiliser les états de focus adéquats !). Vous pouvez consulter cette démo que j'ai réalisée pour voir comment cela fonctionne. Testez-la avec un clavier, et vous remarquerez que vous pouvez interagir avec elle sans problème.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/jOxKqgG">Details and summary demo</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><p>Comme je l'ai mentionné, cette approche ne nécessite aucun JavaScript, mais ce n'est pas le seul modèle que vous pouvez utiliser pour le balisage ! Si vous voulez en savoir plus sur le balisage des composants en accordéon, vous pouvez lire cet <a href="https://www.sarasoueidan.com/blog/accordion-markup/">article de Sara Soueidan</a> à ce sujet.</p><h3>Sauter les liens</h3><p>Parfois, lorsque vous naviguez sur un site, vous pouvez trouver de grands blocs d'éléments focalisables par le clavier, comme dans un menu, par exemple. Or bien souvent l'utilisateur veut juste interagir avec le contenu principal (<code>main</code>), donc offrir un moyen de sauter ces blocs d'éléments interactifs est important . Il existe même un critère WCAG pour ce cas.</p><figure class="quote"><blockquote cite="https://www.w3.org/WAI/WCAG21/Understanding/bypass-blocks.html">
<p>Un mécanisme est disponible pour contourner les blocs de contenu qui sont répétés sur plusieurs pages Web.</p>
</blockquote>
<figcaption><cite><a href="https://www.w3.org/WAI/WCAG21/Understanding/bypass-blocks.html">Critère de réussite 2.4.1 : Contourner les blocs</a></cite></figcaption></figure><p>C'est là que les "liens de saut" entrent en jeu ! Les liens de saut sont des liens qui ne sont généralement visibles que lorsqu'un utilisateur appuie sur la touche <code>Tab</code>, et qui vous permettent d'accéder aux points d'intérêt d'une page. Normalement, c'est pour vous amener au contenu principal, comme vous pouvez le remarquer sur YouTube, par exemple :</p><figure><img src="https://la-cascade.io/images/skip-link-yt.webp" alt="un lien de saut dans une page YouTube : 'skip navigation'" /></figure><p>Mais il peut y avoir plusieurs liens de saut dans un site qui vous mèneront à diverses parties du site, comme le fait Smashing Magazine. Lorsque vous utilisez la touche de tabulation pour naviguer sur ce site, vous remarquerez qu'il y a trois liens de saut, qui vous amènent tous à des points importants de la page :</p><figure><img src="https://la-cascade.io/images/jump-all.webp" alt="3 liens de saut, le premier vers le contenu principal, le deuxième vers la liste des articles, le troisième vers tous les sujets." /></figure><p>Ils sont généralement situés dans le <code>header</code> du site, mais ce n'est pas toujours le cas. Vous pouvez les ajouter là où c'est nécessaire, comme le montre Manuel Matuzović dans le tweet qui suit. Il a ajouté un lien de saut <code>inline</code> à un projet parce que la carte interactive comporte beaucoup d'éléments focalisables avec le clavier.</p><figure class="quote"><blockquote cite="https://www.w3.org/WAI/WCAG21/Understanding/bypass-blocks.html">
<p>Je travaille sur une fonctionnalité qui permet aux utilisateurs de sauter les zones comportant de nombreux arrêts de tabulation (lien de saut en ligne). ?</p>
<p>Vidéo alt : Une page avec un tas de liens suivis d'une carte intégrée. L'appui sur la touche `Tab` révèle un lien qui, lorsqu'il est activé, déplace le focus vers l'élément tabulable suivant, après la carte.</p>
</blockquote>
<figcaption><cite><a href="https://twitter.com/mmatuzo/status/1511744226463305733?ref_src=twsrc%5Etfw">Manuel Matuzović (@mmatuzo) 6 avril 2022</a></cite></figcaption></figure><p>Maintenant, puisque l'utilité des liens de saut est claire, créons-en un. C'est très simple, il nous suffit de créer un élément <code>a</code> qui vous amène à l'élément souhaité :</p><pre class="language-html">&lt;header&gt;
  &lt;a class="skip-link" href="#main-content"&gt;Go to main content&lt;/a&gt;
&lt;/header&gt;
&lt;main id="main-content"&gt;&lt;/main&gt;</pre><p>Ensuite, nous devons masquer visuellement l'élément <code>a</code>. Ce que je fais ici, c'est utiliser la propriété CSS <code>transform</code> pour le retirer de la portée visuelle :</p><pre class="language-css">.skip-link {
  display: block;
  transform: translate(-9999px);
}</pre><p>Ensuite, nous le déplaçons à la position nécessaire lorsque l'élément est focalisé :</p><pre class="language-css">.skip-link:focus {
  transform: translate(0);
}</pre><p>Et c'est tout ! La création d'un lien de saut est facile et bien utile pour l'accessibilité au clavier.</p><h3>Tooltips</h3><p>Ces petites bulles de texte qui affichent des informations supplémentaires sur un élément peuvent également être réalisées avec du CSS pur, mais un petit avertissement ici : il est suggéré que vous pouvez fermer une infobulle en appuyant sur la touche <code>Echap</code>, ce qui n'est possible qu'avec JavaScript. J'expliquerai comment ajouter cette fonctionnalité dans la deuxième partie de cet article, mais tout le reste peut être fait de manière très simple en utilisant uniquement HTML et CSS.</p><p>Un problème courant avec les infobulles est qu'un utilisateur du clavier ne peut pas les voir, nous devons donc nous assurer que le composant qui les déclenche est un élément focalisable par le clavier. Notre meilleure chance est d'utiliser l'élément bouton. La sémantique est vraiment simple, comme le montre <a href="https://la-cascade.io/auteurs/heydon-pickering">Heydon Pickering</a> dans son livre <a href="https://inclusive-components.design/tooltips-toggletips/">Inclusive Components</a>.</p><pre class="language-html">&lt;div class="tooltip-container"&gt;
  &lt;button&gt;&lt;/button&gt;
  &lt;div role="tooltip"&gt;&lt;/div&gt;
&lt;/div&gt;</pre><p>Le conteneur avec la classe <code>tooltip-container</code> est là juste pour nous permettre de manipuler la position du conteneur avec l'attribut <code>role="tooltip"</code> plus tard en utilisant CSS. A propos de cet élément, on pourrait penser que ce rôle ajoute suffisamment de sémantique pour le faire fonctionner, mais en fait, ce n'est pas le cas, nous devrons donc compter sur deux d'attributs <code>aria</code> pour le lier à notre bouton.</p><p>Cet attribut dépend de l'intention de l'infobulle. Si vous envisagez de l'utiliser pour <em>nommer</em> un élément, vous devez utiliser l'attribut <code>aria-labelledby</code> :</p><pre class="language-html">&lt;div class="tooltip-container"&gt;
  &lt;button aria-labelledby="tooltip1"&gt;
    &lt;svg aria-hidden="true"&gt;
      &lt;!-- Contenu du SVG --&gt;
    &lt;/svg&gt;
  &lt;/button&gt;
  &lt;div id="tooltip1" role="tooltip"&gt;Parc d'achat&lt;/div&gt;
&lt;/div&gt;</pre><p>Par contre, si vous souhaitez utiliser l'infobulle pour décrire <em>ce que fait</em> un élément, vous devrez le lier à l'aide de l'attribut <code>aria-describedby</code> :</p><pre class="language-html">&lt;div class="tooltip-container"&gt;
  &lt;button aria-label="Panier d'achat" aria-describedby="tooltip2"&gt;
    &lt;svg aria-hidden="true"&gt;
      &lt;!-- Contenu du SVG --&gt;
    &lt;/svg&gt;
  &lt;/button&gt;
  &lt;div id="tooltip2" role="tooltip"&gt;
    Vérifier, modifier et terminer votre achat
  &lt;/div&gt;
&lt;/div&gt;</pre><p>Soyez prudent avec cette approche ; utilisez-la uniquement pour donner des descriptions auxiliaires, et non pour donner des informations absolument nécessaires pour comprendre ce que fait cet élément. En effet, lorsqu'un utilisateur de lecteur d'écran génère une liste des éléments de formulaire (y compris les boutons) du site, la description ne s'affichera que si l'utilisateur se concentre sur l'élément, comme le montre Adrian Roselli dans <a href="https://adrianroselli.com/2022/04/accessible-description-exposure.html">son test</a> sur l'attribut <code>aria-description</code>.</p><p>Maintenant, il est temps de parler de ce qui nous préoccupe dans cet article : l'accessibilité au clavier ! Pour cela, nous devons masquer l'infobulle et l'afficher jusqu'à ce que l'utilisateur place le pointeur sur l'élément ou qu'il le fasse avec un clavier. Pour cela, nous utiliserons les pseudo-classes <code>:hover</code> et <code>:focus</code> en tandem avec le <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css">combinateur adjacent sibling</a>.</p><p>Par ailleurs, il est important que vous puissiez voir l'infobulle lorsque vous la survolez afin de respecter le <a href="https://www.w3.org/TR/WCAG22/#content-on-hover-or-focus">critère WCAG 1.4.13 : Content on Hover or Focus</a>. Avec ces considérations à l'esprit, voici à quoi devrait ressembler notre code :</p><pre class="language-css">[role='tooltip'] {
  position: absolute;
  bottom: 0;
  gauche: 50%;
  display: none;
  transform: translate(-50%, 100%);
}
button:hover + [role='tooltip'],
button:focus + [role='tooltip'],
[role='tooltip']:hover {
  display: block;
}</pre><p>Et voilà comment créer une infobulle accessible au clavier à l'aide de HTML et CSS. Vous pouvez vérifier le comportement des deux exemples d'infobulles dans cette démo. N'oubliez pas que ce n'est pas entièrement prêt pour la production. Vous avez besoin de JavaScript pour fermer l'infobulle lorsque vous appuyez sur la touche <code>Echap</code>. Nous aborderons ce point plus tard dans la prochaine partie de cet article, alors gardez-le à l'esprit.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/smashingmag/pen/Vwxdjbe">Tooltip demo - CSS only</a>de smashingmag dans<a href="https://codepen.io">CodePen</a></div><p>Comme le mentionne Heydon dans son livre, les infobulles ont un problème lorsque vous les utilisez pour des appareils qui n'ont pas de pointeur, comme les téléphones portables ou les tablettes, il faut alors adopter une approche différente pour elles. Vous pouvez utiliser CSS pour cela en utilisant <a href="https://www.smashingmagazine.com/2022/03/guide-hover-pointer-media-queries/">les media queries hover et pointer</a>, comme je l'explique dans mon article.</p><h3>Récapitulatif</h3><p>L'accessibilité du clavier est une partie essentielle de l'accessibilité. J'espère que cet article vous a aidé à comprendre à quel point HTML et CSS sont cruciaux pour faire de la navigation au clavier une expérience utilisateur agréable et accessible. Mais ce n'est pas la fin de l'accessibilité du clavier ! Je vais aborder la façon dont nous pouvons utiliser JavaScript pour manipuler la navigation au clavier et comment nous pouvons l'utiliser dans des modèles de composants plus complexes.</p><p><a href="https://la-cascade.io/articles/guide-accessibilite-clavier-2">Lire la deuxième partie dans La Cascade</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/guide-accessibilite-clavier-1</link>
      <guid>https://la-cascade.io/articles/guide-accessibilite-clavier-1</guid>
      <pubDate>Sat, 19 Nov 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre flex-grow, flex-shrink et flex-basis]]></title>
      <description><![CDATA[<p>Lorsque nous appliquons une propriété CSS à un élément, il se passe beaucoup de choses en coulisses. Par exemple, disons que nous avons ce HTML :</p><pre class="language-html">&lt;div class="parent"&gt;
  &lt;div class="child"&gt;Child&lt;/div&gt;
  &lt;div class="child"&gt;Child&lt;/div&gt;
  &lt;div class="child"&gt;Child&lt;/div&gt;
&lt;/div&gt;</pre><p>...et nous ajoutons ce CSS :</p><pre class="language-css">.parent {
  display: flex;
}</pre><p>Techniquement, ce ne sont pas les <em>seuls</em> styles que nous appliquons lorsque nous écrivons la ligne de CSS ci-dessus. En fait, tout un tas de propriétés seront appliquées aux éléments <code>.child</code> ici, comme si nous avions écrit ces styles nous-mêmes :</p><pre class="language-css">.child {
  flex: 0 1 auto; /* valeurs flex par défaut */
}</pre><p>Étrange ! Pourquoi ces éléments ont-ils ces styles supplémentaires qui leur sont appliqués alors que nous n'avons pas écrit ce code ? Eh bien, c'est parce que certaines propriétés ont des valeurs <em>par défaut</em> qui sont ensuite destinées à être remplacées par nous. Et si nous ne savons pas que ces styles sont appliqués lorsque nous écrivons le CSS, nos mises en page peuvent devenir assez déroutantes et difficiles à gérer.</p><p>La propriété <code>flex</code> ci-dessus est ce que l'on appelle une propriété CSS <em>abrégée</em> (ou raccourcie : <em>shorthand</em>). En fait, ce que ça fait c'est qu'on définit trois propriétés CSS distinctes en même temps. Ce que nous avons écrit ci-dessus revient donc à écrire ceci :</p><pre class="language-css">.child {
  flex-grow: 0;
  flex-shrink: 1;
  flex-basis: auto;
}</pre><p>Une propriété raccourcie est donc une façon de <em>regrouper</em> un tas de propriétés CSS différentes pour faciliter l'écriture de plusieurs propriétés à la fois, précisément comme la propriété <code>background</code> où nous pouvons écrire quelque chose comme ceci :</p><pre class="language-css">body {
  background: url(sweettexture.jpg) top center no-repeat fixed
    padding-box content-box red;
}</pre><p>J'essaie d'éviter les propriétés raccourcies car elles peuvent être assez déroutantes et j'ai souvent tendance à écrire les versions longues à la main, simplement parce que mon cerveau ne parvient pas à analyser de longues lignes de valeurs de propriétés. Mais il est <a href="https://drafts.csswg.org/css-flexbox/#flex-grow-property">recommandé</a> d'utiliser le raccourci lorsqu'il s'agit de flexbox, ce qui semble... bizarre... c'est-à-dire jusqu'à ce que vous compreniez que la propriété <code>flex</code> fait beaucoup de travail et que chacune de ses sous-propriétés interagit avec les autres.</p><p>En outre, les styles par défaut sont une bonne chose car nous n'avons pas besoin de savoir ce que font ces propriétés flexbox dans 90 % des cas. Par exemple, lorsque j'utilise flexbox, j'ai tendance à écrire quelque chose comme :</p><pre class="language-css">.parent {
  display: flex;
  justify-content: space-between;
}</pre><p>Je n'ai même pas besoin de me soucier des éléments enfants ou des styles qui leur ont été appliqués, et c'est super ! Dans ce cas, nous alignons les éléments enfants côte à côte, puis nous les espaçons de manière égale les uns des autres. Deux lignes de CSS nous donnent beaucoup de pouvoir ici et c'est ce qu'il y a de mieux avec flexbox et ces styles hérités — <em>nous n'avons pas besoin de comprendre toute la complexité sous le capot</em> si nous voulons simplement faire la même chose 90 % du temps. C'est remarquablement intelligent car toute cette complexité est cachée.</p><p>Mais qu'en est-il si nous voulons comprendre le fonctionnement réel de flexbox, y compris les propriétés <code>flex-grow</code>, <code>flex-shrink</code> et <code>flex-basis</code> ? Et quelles choses sympas pouvons-nous faire avec elles ?</p><p>Il suffit de consulter l'<a href="https://css-tricks.com/almanac/">Almanach CSS-Tricks</a>. Et c'est bon !</p><p>Nan, je plaisante. Commençons par un aperçu rapide et un peu simplifié, et revenons aux propriétés <code>flex</code> par défaut qui sont appliquées aux éléments enfants :</p><pre class="language-css">.child {
  flex: 0 1 auto;
}</pre><p>Ces styles par défaut indiquent à cet élément enfant comment s'étirer et se développer. Mais chaque fois que je vois qu'ils sont utilisés ou remplacés, je trouve utile de penser à ces propriétés abrégées comme ceci :</p><pre class="language-css">/* C'est ainsi que je vois la règle ci-dessus dans ma tête */
.child {
  flex: [flex-grow] [flex-shrink] [flex-basis];
}
/* ou bien comme ça... */
.child {
  flex: [max] [min] [taille idéale];
}</pre><p>La première valeur est <code>flex-grow</code> et elle est réglée sur 0 car, par défaut, nous ne voulons pas que nos éléments s'étendent (la plupart du temps). Nous voulons plutôt que chaque élément dépende de la taille du contenu qu'il contient. Voici un exemple :</p><pre class="language-css">.parent {
  display: flex;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/xxOjNav/bc3d06b3162c4163a9e51ccd91913986">flex-grow-default</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>J'ai ajouté la propriété <code>contenteditable</code> à chaque élément <code>.child</code> ci-dessus pour que vous puissiez cliquer dessus et saisir encore plus de contenu. Vous voyez comment ça réagit ? C'est le comportement par défaut d'un élément flexbox : <code>flex-grow</code> est défini sur 0 car nous voulons que l'élément grandisse en fonction du contenu qu'il contient.</p><p>Mais ! Si nous devions changer la valeur par défaut de la propriété flex-grow de 0 à 1, comme ceci...</p><pre class="language-css">.child {
  flex: 1 1 auto;
}</pre><p>...alors, tous les éléments prendraient une part égale de l'élément <code>.parent</code>, mais <em>seulement si les longueurs de leurs contenus sont les mêmes</em>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/Pozeryd/7aab5c7671016f4c76401020568d49b0">flex-grow-default-1</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>C'est exactement comme si j'avais écrit :</p><pre class="language-css">.child {
  flex-grow: 1;
}</pre><p>...en laissant de côté les autres valeurs parce que celles-ci ont été définies par défaut de toute façon. Je pense que cela m'a <em>longtemps</em> perturbé lorsque j'ai commencé à travailler avec des mises en page flexibles. Je voyais du code qui ajoutait juste <code>flex-grow</code> et je me demandais d'où venaient les autres styles.</p><p>Maintenant, si nous voulions qu'un seul de ces éléments croisse plus que les autres, il nous suffirait de faire :</p><pre class="language-css">.child-three {
  flex: 3 1 auto;
}
/* ou bien nous pourrions simplement écrire... */
.child-three {
  flex-grow: 3;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/zYBjQMQ/a0492e0d5913e92c2e2a6fee17e065b0">flex-grow-default-2</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>Ce code est-il étrange à regarder, même dix ans après l'arrivée de Flexbox dans les navigateurs ? Il l'est certainement pour moi. J'ai besoin d'une puissance cérébrale supplémentaire pour dire "Ah oui, max, min, taille idéale" lorsque je lis le raccourci, mais ça s'améliore avec le temps. Quoi qu'il en soit, dans l'exemple ci-dessus, les deux premiers éléments enfants occuperont proportionnellement la même quantité d'espace, mais le troisième élément essaiera de croître jusqu'à trois fois l'espace des autres.</p><p>C'est là que les choses deviennent étranges, car tout dépend du contenu des éléments enfants. Même si nous avons défini <code>flex-grow</code> à <code>3</code>, comme nous l'avons fait dans l'exemple ci-dessus, si nous ajoutons ensuite plus de contenu, la mise en page fera quelque chose d'étrange comme ceci :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/LYZmKqj/480cd39e0ef5f98f6d82706f0478a504">flex-grow-3</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>Cette deuxième colonne prend maintenant trop d'espace ! Nous y reviendrons plus tard, mais pour l'instant, il est juste important de se rappeler que le contenu d'un élément flex a un impact sur la façon dont <code>flex-grow</code>, <code>flex-shrink</code> et <code>flex-basis</code> fonctionnent ensemble.</p><p>OK, passons maintenant à <code>flex-shrink</code>. Rappelez-vous que c'est la deuxième valeur dans le raccourci :</p><pre class="language-css">.child {
  flex: 0 1 auto; /* flex-shrink = 1 */
}</pre><p><code>flex-shrink</code> indique au navigateur quelle doit être la taille minimale d'un élément. La valeur par défaut est 1, ce qui revient à dire : "Prenez la même quantité d'espace à tout moment". Cependant, si nous définissons cette valeur à 0 comme ceci :</p><pre class="language-css">.child {
  flex: 0 0 auto;
}</pre><p>...alors nous disons à cet élément de ne pas rétrécir du tout maintenant. <em>Reste à la même taille, maudit élément</em> ! c'est en substance ce que dit cette CSS, et c'est précisément ce qu'elle va faire. Nous reviendrons sur cette propriété dans un instant, une fois que nous aurons examiné la valeur finale de ce raccourci.</p><p><code>flex-basis</code> est la dernière valeur ajoutée par défaut dans le raccourci <code>flex</code>, et c'est la façon dont nous indiquons à un élément de s'en tenir à une taille idéale. Par défaut, elle est définie sur <code>auto</code>, ce qui signifie "Utilisez ma hauteur ou ma largeur". Ainsi, lorsque nous définissons un élément parent pour <code>display: flex</code>...</p><pre class="language-css">.parent {
  display: flex;
}
.child {
  flex: 0 1 auto;
}</pre><p>Nous aurons ceci par défaut dans le navigateur :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/YzWLbmp/682e040debc4ae4b12bdb50d14663047">flex-basis example 1</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>Vous avez remarqué que tous les éléments ont la largeur de leur contenu par défaut ? C'est parce qu'<code>auto</code> dit que la taille idéale de notre élément est définie par son contenu. Pour que tous les éléments occupent tout l'espace du parent, nous pouvons régler les éléments enfants sur <code>width : 100%</code>, <em>ou</em> nous pouvons régler <code>flex-basis</code> sur 100%, <em>ou</em> nous pouvons régler <code>flex-grow</code> sur 1.</p><p>Est-ce que ça fait sens pour vous ? C'est bizarre, hein ! En fait, oui, lorsqu'on y pense. Chacune de ces valeurs abrégées a un impact sur les autres et c'est pourquoi il est recommandé d'écrire ce raccourci en premier lieu plutôt que de définir ces valeurs indépendamment les unes des autres.</p><p>Bon, passons à autre chose. Lorsque nous écrivons quelque chose comme ceci...</p><pre class="language-css">.child-three {
  flex: 0 1 1000px;
}</pre><p>...ce que nous disons ici au navigateur, c'est de régler <code>flex-basis</code> sur 1000px ou "s'il vous plaît, essayez d'occuper 1000px d'espace". Si ce n'est pas possible, l'élément occupera cet espace proportionnellement aux autres éléments.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/qBNYzja/efd6a0311719f8458fcb8f3e99bf1f13">flex-basis example 2</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>Vous remarquerez peut-être que sur les petits écrans, ce troisième élément n'est pas réellement de 1000px ! C'est parce qu'il s'agit en fait d'une <em>suggestion</em>. Nous avons toujours l'option <code>flex-shrink</code> appliquée, qui indique à l'élément de se réduire à la même taille que les autres éléments.</p><p>De même, l'ajout de contenu aux autres enfants aura toujours un impact ici :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/OJXwGja/464505f57050c12f294a6269583dd663">flex-basis example 2</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>Maintenant, si nous voulions empêcher cet élément de rétrécir, nous pourrions écrire quelque chose comme ceci :</p><pre class="language-css">.child-three {
  flex: 0 0 1000px;
}</pre><p>Rappelez-vous, <code>flex-shrink</code> est la deuxième valeur ici et en la réglant à 0, nous disons, "Ne rétrécis jamais, grand idiot." Et ce n'est pas le cas. L'élément se détachera même de l'élément parent parce qu'il ne sera jamais plus petit que 1000px de large :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/BazxgwP/1a99b3fe9761e6581e3cf9a0e5e02595">flex-basis example 3</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>Maintenant, tout cela change si nous définissons <code>flex-wrap</code> sur l'élément parent :</p><pre class="language-css">.parent {
  display: flex;
  flex-wrap: wrap;
}
.child-three {
  flex: 0 0 1000px;
}</pre><p>Nous verrons quelque chose comme ça :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/robinrendle/pen/NWrMZwE/587a4f6710efcb8f0fb403791834df33">flex-basis example 4</a>de robinrendle dans<a href="https://codepen.io">CodePen</a></div><p>En effet, par défaut, les éléments flexibles essaieront de tenir sur une seule ligne, mais <code>flex-wrap : wrap</code> l'ignorera complètement. Maintenant, si ces éléments flex ne peuvent pas tenir dans le même espace, ils se sépareront sur une nouvelle ligne.</p><p>Quoi qu'il en soit, il ne s'agit là que de quelques-unes des façons dont les propriétés <code>flex</code> s'entrechoquent et de la raison pour laquelle il est si précieux de comprendre comment ces propriétés fonctionnent sous le capot. Chacune de ces propriétés peut affecter l'autre, et si vous ne comprenez pas le fonctionnement d'une propriété, alors d'une certaine façon vous ne comprenez pas du tout comment tout cela fonctionne — ce qui m'a certainement déconcerté avant que je ne commence à creuser ce sujet !</p><p>Mais pour résumer :</p><p>?? Essayez d'utiliser le raccourci flex?? Souvenez-vous de la taille maximale, minimale et idéale lorsque vous le faites?? N'oubliez pas que le contenu d'un élément peut également avoir un impact sur la façon dont ces valeurs fonctionnent ensemble.</p>]]></description>
      <link>https://la-cascade.io/articles/comprendre-flex-grow-flex-shrink-et-flex-basis</link>
      <guid>https://la-cascade.io/articles/comprendre-flex-grow-flex-shrink-et-flex-basis</guid>
      <pubDate>Tue, 25 Oct 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre WAI-ARIA, un guide complet]]></title>
      <description><![CDATA[<p><em>Dans cet article, Kate Kalcevich explique quand et comment utiliser ARIA afin d'aider les personnes handicapées utilisant des technologies d'assistance pour naviguer sur Internet. Allons-y!</em></p><div class="articleContent"><p>L'<a href="https://www.w3.org/TR/wai-aria-1.1/">Initiative pour l'accessibilité du Web - <em>Applications Internet riches accessibles (WAI-ARIA)</em></a> est une spécification technique qui fournit des directives sur la manière d'améliorer l'accessibilité des applications Web. Alors que les directives d'accessibilité au contenu Web (WCAG) se concentrent davantage sur le contenu Web statique, <strong>WAI-ARIA s'attache à rendre les interactions plus accessibles</strong>.</p><p>Les interactions sur le Web sont connues pour être inaccessibles, alors qu'elles font souvent partie des fonctions les plus critiques telles que :</p><ul><li>la soumission d'une demande d'emploi,</li>
<li>l'achat dans un magasin en ligne, ou</li>
<li>la réservation d'un rendez-vous médical.</li>
</ul><p>Je suis actuellement responsable de l'innovation en matière d'accessibilité chez <a href="https://makeitfable.com/">Fable</a>, une entreprise qui met en relation des organisations avec des personnes handicapées pour des recherches sur les utilisateurs et des tests d'accessibilité, et qui propose des formations personnalisées aux équipes numériques afin qu'elles acquièrent les compétences nécessaires à la création de produits inclusifs.</p><p>En tant qu'instructeur pour le développement Web accessible, je passe beaucoup de temps à examiner le code source des sites Web et des applications Web, et ARIA est l'une des choses que je vois les développeurs utiliser le plus mal.</p><h2>HTML</h2><p>Lorsque vous utilisez des éléments HTML tels que <code>input</code>, <code>select</code> et <code>button</code>, il se passe deux choses concernant l'accessibilité : les informations sur l'élément sont transmises au <a href="https://la-cascade.io/articles/le-dom-cest-quoi-exactement">DOM</a> (Document Object Model) et dans un <a href="https://developer.mozilla.org/fr/docs/Glossary/Accessibility_tree">arbre d'accessibilité</a>. Les technologies d'assistance peuvent accéder aux nœuds de l'arbre d'accessibilité pour comprendre :</p><ul><li>de quel type d'élément il s'agit en vérifiant son rôle, par exemple, une case à cocher ;</li>
<li>dans quel état se trouve l'élément, par exemple, coché/non coché ;</li>
<li>le nom de l'élément, par exemple, "Inscrivez-vous à notre bulletin d'information".</li>
</ul><p>L'autre chose que vous obtenez en utilisant les éléments HTML est l'<em>interactivité du clavier</em>. Par exemple, une case à cocher peut être mise en focus à l'aide de la touche de tabulation et sélectionnée à l'aide de la barre d'espacement (les interactions spécifiques peuvent varier selon le navigateur et le système d'exploitation, mais le fait est qu'elles sont disponibles et normalisées sur tous les sites Web lorsque vous utilisez des éléments HTML).</p><p>Lorsque vous n'utilisez pas les éléménts HTML modernes, par exemple, si vous construisez votre propre sélection personnalisée à l'aide de <code>&lt;div&gt;</code> et de <code>&lt;span&gt;</code> ou si vous utilisez une bibliothèque de composants, vous devez faire un travail supplémentaire pour fournir des informations sur l'élément et construire l'interactivité du clavier pour les utilisateurs de technologies d'assistance. C'est là que l'ARIA entre en jeu.</p><h2>ARIA</h2><p>Les applications Internet riches accessibles (ARIA) comprennent un ensemble de rôles et d'attributs qui définissent les moyens de rendre le contenu et les applications Web plus accessibles aux personnes handicapées.</p><p>Vous pouvez utiliser ARIA pour transmettre des informations à l'arbre d'accessibilité. Les rôles et attributs ARIA n'incluent pas d'interactivité avec le clavier. L'ajout de <code>role="button"</code> à une <code>&lt;div&gt;</code> ne le fait pas réagir lorsque vous appuyez sur la touche <strong>Entrée</strong> de votre clavier — cela, vous devez le construire en utilisant JavaScript ou un autre langage. Toutefois, le <a href="https://www.w3.org/WAI/ARIA/apg/patterns/">guide ARIA des pratiques de création de site</a> comprend une liste de l'interactivité du clavier décrivant <em>ce qui</em> qui devrait être ajouté à divers composants tels que les accordéons, les boutons, les carrousels, etc.</p><h3>Rôles</h3><p>Commençons par les rôles. Qu'est-ce que c'est que ce truc dans le code ci-dessous ?</p><pre class="language-html">&lt;div className="dd-wrapper"&gt;
  &lt;div className="dd-header"&gt;
    &lt;div className="dd-header-title"&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div className="dd-list"&gt;
    &lt;button className="dd-list-item"&gt;&lt;/button&gt;
    &lt;button className="dd-list-item"&gt;&lt;/button&gt;
    &lt;button className="dd-list-item"&gt;&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><p>Il s'agit en fait d'un extrait de code que j'ai trouvé en ligne à partir d'un élément <code>select</code> pour React. L'élément est complètement méconnaissable à partir du code, et c'est exactement le problème que rencontrerait toute technologie d'assistance — elle ne peut pas dire à l'utilisateur ce qu'est cet élément ni comment interagir avec lui car il n'y a pas de rôle ARIA.</p><p>Regardez ce que nous pouvons faire ici :</p><pre class="language-html">&lt;div className="dd-wrapper" role="listbox"&gt;&lt;/div&gt;</pre><p>Peut-être ne connaissez-vous pas bien les <em>listbox</em>, c'est un type de <code>select</code> qu'un utilisateur de lecteur d'écran pourrait reconnaître et avec lequel il saurait interagir. Maintenant, vous pourriez simplement utiliser <code>&lt;select&gt;</code>, et vous n'auriez pas à lui donner de rôle car il en a déjà un que le DOM et l'arbre d'accessibilité reconnaîtront, mais je sais que ce n'est pas toujours une option réalisable.</p><p>Un rôle indique à un utilisateur de technologie d'assistance ce qu'est la chose avec laquelle il peut interagir, alors assurez-vous d'utiliser le bon rôle. Un bouton est très différent d'une bannière. Choisissez un rôle qui correspond à la fonction du composant que vous construisez.</p><p>Une autre chose que vous devez savoir sur les rôles ARIA est qu'ils remplacent le rôle inhérent d'un élément HTML.</p><pre class="language-html">&lt;img role="button" /&gt;</pre><p>Il ne s'agit plus d'une image mais d'un bouton. Il y a très peu de raisons de faire cela, et à moins de savoir exactement ce qu'on fait et pourquoi, je m'abstiendrais de remplacer les rôles HTML existants. Il existe de nombreuses autres façons d'y parvenir qui sont plus logiques du point de vue de l'accessibilité et de la robustesse du code :</p><pre class="language-html">&lt;button&gt;&lt;img src="image.png" alt="Imprimer" /&gt;&lt;/button&gt;
&lt;input type="image" src="image.png" alt="Imprimer" /&gt;
&lt;button style="background : url(image.png)" /&gt;Imprimer&lt;/button&gt;</pre><p>Si vous créez un composant, vous pouvez consulter le modèle de ce composant dans Le guide ARIA des <a href="https://www.w3.org/WAI/ARIA/apg/patterns/">bonnes pratiques de construction de sites</a>, qui contient des informations sur le ou les rôles à utiliser. Vous pouvez également consulter <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles">tous les rôles disponibles dans la documentation Web mdn</a>.</p><p>En résumé, si vous construisez un élément qui n'a pas de balise HTML sémantique pour le décrire (c'est-à-dire tout élément interactif construit à l'aide de <code>&lt;div&gt;</code> ou <code>&lt;span&gt;</code>), il doit avoir un rôle ARIA pour que les technologies d'assistance puissent reconnaître ce qu'il est.</p><h3>États et propriétés (également appelés attributs ARIA)</h3><p>En plus de savoir ce qu'est un élément, s'il a un état (par exemple, caché, désactivé, invalide, en lecture seule, sélectionné, etc.) ou change d'état (par exemple, coché/non coché, ouvert/fermé, etc.), vous devez indiquer aux utilisateurs de technologies d'assistance quel est son état actuel et son nouvel état chaque fois qu'il change. Vous pouvez également partager certaines propriétés d'un élément. <a href="https://www.w3.org/TR/wai-aria-1.0/states_and_properties">La différence entre les états et les propriétés n'est pas vraiment claire ou importante</a>, alors appelons-les simplement des attributs.</p><p>Voici quelques-uns des attributs ARIA les plus courants que vous pourriez être amenés à utiliser :</p><ul><li><strong>aria-checked</strong>Il est utilisé avec ="true" ou ="false" pour indiquer si les cases à cocher et les boutons radio sont actuellement cochés ou non.</li>
<li><strong>aria-current</strong>Il est utilisé avec ="true" ou ="false" pour indiquer la page actuelle dans le fil d'Ariane ou la pagination.</li>
<li><strong>aria-describedby</strong>Elle est utilisée avec l'id d'un élément pour ajouter plus d'informations à un champ de formulaire en plus de son étiquette. <code>aria-describedby</code> peut être utilisée pour donner des exemples du format requis pour un champ, par exemple une date, ou pour ajouter un message d'erreur à un champ de formulaire.</li>
</ul><pre class="language-html">&lt;label for="anniversaire"&gt;Anniversaire&lt;/label&gt;
&lt;input type="text" id="birthday" aria-describedby="date-format" /&gt;
&lt;span id="date-format"&gt;MM-DD-YYYY&lt;/span&gt;</pre><ul><li><strong>aria-expanded</strong>Il est utilisé avec ="true" ou ="false" pour indiquer si le fait d'appuyer sur un bouton affichera plus de contenu. Les exemples incluent les accordéons et les éléments de navigation avec sous-menus.</li>
</ul><pre class="language-html">&lt;button aria-expanded="false"&gt;Produits&lt;/button&gt;</pre><p>Ceci indique que le menu Produits ouvrira un sous-menu (par exemple, de différentes catégories de produits). En revanche, si vous le codez comme ceci...</p><pre class="language-html">&lt;a href="/produits/"&gt;Produits&lt;/a&gt;</pre><p>...l'utilisateur s'attendra à ce qu'il s'agisse d'un lien et à ce qu'en cliquant dessus, il accède à une nouvelle page. Ce que le bouton plus <code>aria-expanded</code> dit à un utilisateur de technologie d'assistance, c'est qu'il ne va pas vers une nouvelle page, mais qu'il reste en fait sur la même page et ouvre un sous-menu. Cette simple différence entre <code>&lt;bouton&gt;</code> et <code>&lt;a&gt;</code> et l'ajout d'<code>aria-expanded</code> communique tellement sur la façon d'interagir avec les éléments et ce qui se passera lorsque vous le ferez.</p><ul><li><strong>aria-hidden</strong>Il est utilisé avec ="true" ou ="false" pour cacher quelque chose qui est visible, mais que vous ne voulez pas que les utilisateurs de technologies d'assistance connaissent. <em>Utilisez-le avec une extrême prudence</em> car il y a très peu de cas où vous ne voulez pas que des informations équivalentes soient présentées.</li>
</ul><p>Un cas d'utilisation intéressant que j'ai vu est une carte comportant à la fois une image et le titre textuel de la carte renvoyant à la même page, mais structurée comme deux liens distincts. Imaginez un grand nombre de ces cartes sur une page. Pour un utilisateur de lecteur d'écran, il entendrait chaque lien lu deux fois. Les liens d'image ont donc utilisé <code>aria-hidden="true"</code>. La solution idéale serait de combiner les liens en un seul qui contiendrait à la fois une image et le titre du texte, mais le codage dans la vie réelle n'est pas toujours idéal et vous n'avez pas toujours ce niveau de contrôle.</p><p>Notez que cela enfreint la quatrième règle d'ARIA (que nous aborderons plus tard), mais d'une manière qui ne nuit pas à l'accessibilité. Utilisez-la avec une extrême prudence lorsqu'il n'existe pas de meilleure solution de contournement et que vous l'avez testée avec des utilisateurs de technologies d'assistance.</p><ul><li><strong>aria-required</strong>Il est utilisé avec ="true" ou ="false" pour indiquer si un élément de formulaire doit être rempli pour que le formulaire puisse être soumis.</li>
</ul><p>Si vous construisez un composant, vous pouvez consulter les attributs de ce composant dans <a href="https://www.w3.org/WAI/ARIA/apg/patterns/">le guide des pratiques de création ARIA</a>. La docs web mdn couvre <a href="https://developer.mozilla.org/fr/docs/Web/Accessibility/ARIA/Attributes">les états et les propriétés ainsi que les rôles ARIA</a>.</p><p>Gardez à l'esprit que tous ces attributs ARIA indiquent quelque chose à l'utilisateur, mais que vous devez toujours coder la chose que vous lui dites. <code>aria-checked="true"</code> ne vérifie pas réellement une case à cocher ; il indique simplement à l'utilisateur que la case est cochée, donc il vaut mieux que ce soit vrai ou vous aggraverez les choses au lieu de les améliorer pour l'accessibilité. L'exception serait <code>aria-hidden="true"</code> qui supprime un élément de l'arbre d'accessibilité, le cachant effectivement à toute personne utilisant une technologie d'assistance qui ne peut pas voir.</p><p>Nous savons donc maintenant comment utiliser ARIA pour expliquer ce qu'est un élément, dans quel état il se trouve et quelles sont ses propriétés. La dernière chose que je vais aborder est la gestion du focus.</p><h2>Gestion du focus</h2><p><strong>Tout ce qui est interactif sur un site Web ou une application Web doit pouvoir recevoir le focus</strong>. Tout le monde n'utilise pas une souris, un trackpad ou un écran tactile pour interagir avec les sites. De nombreuses personnes utilisent leur clavier ou un dispositif technologique d'assistance qui émule un clavier. Cela signifie que pour tout ce sur quoi vous pouvez cliquer, vous devez également être capable d'utiliser la touche de tabulation ou les touches fléchées pour l'atteindre et la touche <em>Entrée</em>, et parfois la barre d'espacement, pour le sélectionner.</p><p>Il y a trois concepts dont vous devrez tenir compte si vous utilisez <code>&lt;div&gt;</code> et <code>&lt;span&gt;</code> pour créer des éléments interactifs :</p><ol><li>Vous devez ajouter tabindex="0" pour qu'un clavier ou un émulateur puisse se concentrer sur eux.</li>
<li>Pour tout ce qui accepte la saisie au clavier, vous devez ajouter un écouteur d'événements (<em>Event Listener</em>) pour écouter les pressions sur les touches.</li>
<li>Vous devez ajouter le rôle approprié pour qu'un utilisateur de lecteur d'écran puisse identifier l'élément que vous avez construit.</li>
</ol><p>N'oubliez pas que les contrôles HTML natifs acceptent déjà le focus et l'entrée clavier et ont des rôles inhérents. C'est exactement ce que vous devez faire lorsque vous créez des éléments personnalisés à partir de HTML non sémantique.</p><p><a href="https://la-cascade.io/auteurs/ben-myers">Ben Myers</a> fait une plongée profonde dans <a href="https://benmyers.dev/blog/clickable-divs/">la transformation d'une div en bouton</a>, et je vais partager quelques extraits de son exemple ici. Remarquez le <code>tabindex</code> et le <code>role</code> :</p><pre class="language-html">&lt;div tabindex="0" role="button" onclick="doSomething() ;"&gt;
  Cliquez sur moi !
&lt;/div&gt;</pre><p>Et vous aurez besoin de JavaScript pour écouter les pressions sur les touches :</p><pre class="language-js">const ENTER = 13
const SPACE = 32
// Sélectionnez votre bouton et enregistrez-le dans 'myButton'.
myButton.addEventListener('keydown', function (event) {
  if (event.keyCode === ENTER || event.keyCode === SPACE) {
    event.preventDefault() // Empêche les soumissions involontaires de formulaires, les défilements de pages, etc.
    doSomething(event)
  }
})</pre><p>Lorsqu'il s'agit de déterminer les touches à écouter, je vous suggère de consulter le composant que vous construisez dans le guide des pratiques de création ARIA et de suivre les recommandations relatives à l'interaction avec le clavier.</p><h2>Erreurs courantes</h2><p>Pour avoir examiné beaucoup de code au cours de ma vie, je peux attester que certaines erreurs d'accessibilité sont régulièrement commises. Voici une liste des erreurs les plus courantes que je trouve et comment les éviter :</p><h3>Utilisation d'un attribut aria-labelledby faisant référence à un ID qui n'existe pas</h3><p>Par exemple, une modale qui a un titre dans la modale mais dont l'attribut <code>aria-labelledby</code> fait référence à quelque chose d'autre qui n'existe plus. C'est probablement quelque chose qui a été supprimé par un autre développeur qui n'a pas réalisé que la connexion <code>aria-labelledby</code> était là. Pour éviter cela, le titre de la modale aurait pu être un <code>&lt;h1&gt;</code> et soit <code>aria-labelledby</code> aurait pu faire référence au <code>&lt;h1&gt;</code>, soit on aurait pu mettre le focus sur le <code>&lt;h1&gt;</code> lorsque la modale s'ouvre et, du coup, un utilisateur de lecteur d'écran pourrait savoir ce qui se passe, tant que <code>role="dialog"</code> est également utilisé. Essayez d'éviter les structures fragiles qui, si quelqu'un d'autre venait à modifier le code, se briseraient facilement.</p><h3>Ne pas déplacer le focus dans la nouvelle modale lorsqu'elle s'ouvre</h3><p>Combien de fois ai-je vu un utilisateur de lecteur d'écran continuer à naviguer sur la page située sous la modale, parce qu'il ne savait pas qu'une modale s'était ouverte, soit être complètement perdu parce qu'il ne trouvait pas le contenu de la modale. Il existe plusieurs façons de déplacer le focus au sein d'une modale, mais l'une des méthodes les plus récentes consiste à ajouter <code>inert</code> au repère <code>&lt;main&gt;</code> (et, bien sûr, s'assurer que la modale n'est pas à l'intérieur de <code>&lt;main&gt;</code>). Inert bénéficie d'<a href="https://caniuse.com/?search=inert">une meilleure prise en charge par les navigateurs</a> ces derniers temps. Pour en savoir plus, consultez l'article de Lars Magnus Klavenes intitulé <a href="https://larsmagnus.co/blog/accessible-modal-dialogs-using-inert">Accessible modal dialogs using inert</a>.</p><h3>Ajout de rôles qui font double emploi avec le HTML</h3><p>En général, il est inutile d'écrire <code>&lt;button role="button"&gt;</code>. Il existe un cas où il pourrait être judicieux de le faire. VoiceOver et Safari suppriment la sémantique des éléments de liste lorsque <code>list-style : none</code> est utilisé. C'est fait exprès car si rien n'indique à un utilisateur voyant que le contenu est une liste, pourquoi dire à un utilisateur de lecteur d'écran qu'il s'agit d'une liste ? Si vous voulez passer outre, vous pouvez ajouter un <code>role="list"</code> ARIA explicite à <code>&lt;ul&gt;</code>.</p><p><a href="https://adrianroselli.com/">Adrian Roselli</a> dit qu'une liste non stylisée n'étant pas annoncée comme une liste "...<em>peut ne pas être un gros problème à moins que les tests utilisateurs disent que vous avez vraiment besoin d'une liste</em>." Je suis d'accord avec lui sur ce point, mais je suis aussi d'accord avec la correction si vos tests utilisateurs montrent que c'est bénéfique.</p><h3>Ajout de <code>tabindex="0"</code> à tous les éléments</h3><p>Parfois, les développeurs commencent à utiliser un lecteur d'écran et supposent que la tabulation est la seule façon de naviguer et que, par conséquent, tout ce qui ne comporte pas de <code>tabindex</code> n'est pas accessible. Ce n'est PAS vrai. N'oubliez pas que si vous ne savez pas comment utiliser un lecteur d'écran, vous ne pouvez pas résoudre les problèmes d'utilisabilité. Rencontrez un utilisateur quotidien de lecteur d'écran pour les résoudre.</p><h3>Utilisation de rôles enfants sans rôles parents</h3><p>Par exemple, <code>role="option"</code> doit avoir un parent direct avec <code>role="listbox"</code>.</p><pre class="language-html">&lt;div role="listbox"&gt;
  &lt;ul&gt;
    &lt;li role="option"&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;</pre><p>Le code ci-dessus n'est pas valide car il y a un <code>&lt;ul&gt;</code> entre les éléments parent et enfant. Cela peut être corrigé en ajoutant un rôle de présentation pour essentiellement cacher le <code>&lt;ul&gt;</code> de l'arbre d'accessibilité, comme <code>&lt;ul role="presentation"&gt;</code>.</p><h3>Utilisation de role="menu" pour la navigation</h3><p>La navigation d'un site Web est en réalité une <em>table des matières</em> et non un menu. Les menus ARIA ne sont pas destinés à être utilisés pour la navigation mais pour le comportement des applications, comme les menus d'une application de bureau. Utilisez plutôt <code>&lt;nav&gt;</code>, et si vous avez des liens de navigation enfants, ceux-ci doivent être cachés jusqu'à ce qu'on appuie sur un bouton pour les afficher :</p><pre class="language-html">&lt;nav aria-label="Main menu"&gt;
  &lt;button aria-expanded="false"&gt;Produits&lt;/button&gt;
  &lt;ul hidden&gt;
    &lt;li&gt;Pyjama chat&lt;/li&gt;
    ...
  &lt;/ul&gt;
&lt;/nav&gt;</pre><p>Si vous voulez en savoir plus, <a href="https://la-cascade.io/auteurs/heydon-pickering/">Heydon Pickering</a> fait une plongée profonde dans la <a href="https://la-cascade.io/articles/creer-des-systemes-de-menu-accessibles">construction de systèmes de menus accessibles</a> dans son article de Smashing Magazine.</p><p>En ce qui concerne la navigation, utiliser <code>&lt;nav&gt;</code> plusieurs fois sur une page sans donner à chaque instance une étiquette unique signifie que les utilisateurs de lecteurs d'écran devront explorer chaque région de navigation pour trouver celle qu'ils recherchent. Un simple <code>aria-label</code> sur chaque <code>&lt;nav&gt;</code> rendra les choses beaucoup plus faciles.</p><pre class="language-html">&lt;nav aria-label="Service client"&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href="#"&gt;Aide&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Suivi des commandes&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Expédition et livraison&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Retours&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Nous contacter&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="#"&gt;Trouver un magasin&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;</pre><h2>Comment valider ARIA</h2><p>Utilisez des vérificateurs d'accessibilité automatisés comme <a href="https://www.deque.com/axe/browser-extensions/">Axe</a> ou les <a href="https://wave.webaim.org/extension/">extensions WAVE</a> lorsque vous exécutez votre code dans un navigateur. Les vérificateurs d'accessibilité comme <a href="https://marketplace.visualstudio.com/items?itemName=deque-systems.vscode-axe-linter">Axe pour Visual Studio Code</a> ou <a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y">ESLint pour les éléments JSX</a> vérifieront votre code à mesure que vous l'écrivez.</p><p>Écoutez votre code avec un lecteur d'écran. De même que vous ne publierez jamais un code sans l'exécuter dans un navigateur pour vous assurer qu'il fonctionne, de même l'utilisation d'un lecteur d'écran vous permettra de vérifier qu'il fonctionne pour tous les publics. <a href="https://www.nvaccess.org/">NVDA</a> est gratuit pour Windows, et <a href="https://www.apple.com/ca/accessibility/vision/">VoiceOver</a> est intégré aux Mac et iPhones. <a href="https://support.google.com/accessibility/android/topic/3529932?hl=en&amp;ref_topic=9078845">TalkBack</a> est intégré aux téléphones Android.</p><p><strong>Testez avec des utilisateurs de technologies d'assistance</strong>. Je considère cela comme obligatoire pour toute grande organisation qui dispose d'un budget pour l'accessibilité (et elles devraient toutes le faire). Il existe des entreprises qui peuvent recruter des utilisateurs de technologies d'assistance pour les tests ou effectuer des tests utilisateurs pour vous, et l'entreprise pour laquelle je travaille peut fournir des délais de 2 jours pour les tests utilisateurs qui sont, ou non, modérés par vous pour soutenir les tests d'accessibilité à grande échelle.</p><h3>Frameworks et bibliothèques de composants</h3><p>Si vous utilisez un framework Web, une façon d'alléger un peu le travail de construction pour l'accessibilité est d'utiliser une bibliothèque de composants intégrant l'accessibilité. J'ajouterai une mise en garde toutefois : l'accessibilité peut être complexe et tout ce qui se prétend accessible n'est pas toujours utilisable par les utilisateurs de technologies d'assistance. La meilleure façon de garantir l'accessibilité est de toujours <strong>tester avec les utilisateurs</strong> pour lesquels vous construisez.</p><p>Voici quelques points de départ pour votre recherche :</p><ul><li><a href="https://react-spectrum.adobe.com/react-aria/index.html">React Aria</a></li>
<li><a href="https://vue-a11y.com/">Vue A11y</a></li>
<li><a href="https://m3.material.io/">Material Design 3</a></li>
<li><a href="https://lion-web.netlify.app/">Lion</a></li>
<li><a href="https://open-ui.org/">Open UI</a></li>
</ul><h2>Conclusion</h2><p>Avec un peu de chance, cet article aura démystifié ARIA pour vous. Comme un langage secret connu de la seule l'élite de l'accessibilité, il a ses propres règles Fight Club-esque.</p><p>La première règle de l'ARIA est "N'utilisez pas l'ARIA". Un <code>&lt;button&gt;</code> sera toujours mieux que <code>&lt;div role="button"&gt;</code>.Deuxièmement, ne remplacez pas la sémantique native. Au lieu de <code>&lt;button role="heading"&gt;</code>, utilisez <code>&lt;h3&gt;&lt;button&gt;</code>.Enfin, n'oubliez jamais que tous les éléments interactifs ARIA doivent fonctionner avec le clavier.N'utilisez pas <code>role="presentation"</code> ou <code>aria-hidden="true"</code> sur un élément focalisable. <code>&lt;button role="presentation"&gt;</code> signifie que vous cachez ce bouton uniquement aux utilisateurs de technologies d'assistance. Ce n'est pas seulement inaccessible, c'est carrément exclure certains utilisateurs.Dernier point, mais non le moindre, tous les éléments interactifs doivent avoir un nom accessible. Il existe de nombreuses façons de le faire, et en voici quelques-unes :</p><pre class="language-html">&lt;button&gt;Imprimer&lt;/button&gt; (le nom est le texte du bouton)
&lt;div aria-label="Settings"&gt;&lt;svg&gt;&lt;/div&gt; (l'aria-label attribue un nom)
&lt;div aria-labelledby="myName"&gt;
  &lt;h1 id="myName"&gt;La rubrique&lt;/h1&gt;
&lt;/div&gt;
&lt;label for="name"&gt;Nom&lt;/label&gt;
&lt;input type="text" id="name" /&gt;</pre><p>Je pense volontiers à ARIA comme à un outil utilisé par l'équipe d'élite des opérations spéciales à laquelle vous faites appel pour vos défis d'accessibilité les plus difficiles. Peut-être ai-je juste toujours voulu faire des pompes à un bras comme Emily Blunt dans Edge of Tomorrow, et c'est ce qui s'en rapproche le plus. Quoi qu'il en soit, j'espère que tout ceci vous a été utile et que vous n'êtes plus confus au sujet d'ARIA. Allez-y et construisez des choses accessibles !</p></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-wai-aria-un-guide-complet</link>
      <guid>https://la-cascade.io/articles/comprendre-wai-aria-un-guide-complet</guid>
      <pubDate>Sat, 01 Oct 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[justify-content]]></title>
      <description><![CDATA[<p>La propriété <code>justify-content</code> est une sous-propriété du module Flexible Box Layout.</p><p>Elle définit l'alignement le long de l'axe principal. Elle permet de répartir l'espace libre restant lorsque tous les éléments flexibles d'une ligne sont inflexibles, ou sont flexibles mais ont atteint leur taille maximale. Elle exerce également un certain contrôle sur l'alignement des éléments lorsqu'ils débordent de la ligne.</p><p>La propriété <code>justify-content</code> accepte six valeurs différentes :</p><ul><li><code>flex-start</code> (<em>valeur par défaut</em>) : les éléments sont alignés sur la ligne de départ.</li>
<li><code>flex-end</code> : les éléments sont regroupés vers la ligne de fin</li>
<li><code>center</code> : les éléments sont centrés le long de la ligne</li>
<li><code>space-between</code> : les éléments sont répartis uniformément sur la ligne ; le premier élément est sur la ligne de début, le dernier élément sur la ligne de fin.</li>
<li><code>space-around</code> : les articles sont répartis uniformément sur la ligne avec un espace égal autour d'eux.</li>
<li><code>space-evenly</code> : les éléments sont répartis de manière à ce que l'espacement entre deux sujets d'alignement adjacents, avant le premier sujet d'alignement et après le dernier sujet d'alignement soit le même.</li>
</ul><h2>Syntaxe</h2><pre class="language-css">justify-content: flex-start | flex-end | center | space-between |
  space-around | space-evenly .flex-item {
  justify-content: center;
}</pre><h2>Démo</h2><p>La démo suivante montre comment les éléments flex se comportent en fonction de la valeur <code>justify-content</code> :</p><ul><li>La liste rouge est définie sur flex-start</li>
<li>La liste jaune est réglée sur flex-end</li>
<li>La liste bleue est réglée sur center</li>
<li>La liste verte est réglée sur space-between</li>
<li>La liste rose est réglée sur space-around</li>
<li>Le vert clair est réglé sur space-evenly</li>
</ul><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/zzJMGJ">Flexbox &amp; justify-content</a>de team/css-tricks dans<a href="https://codepen.io">CodePen</a></div>]]></description>
      <link>https://la-cascade.io/articles/justify-content</link>
      <guid>https://la-cascade.io/articles/justify-content</guid>
      <pubDate>Fri, 30 Sep 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Des styles de listes créatifs]]></title>
      <description><![CDATA[<p><em>Un aperçu de quelques façons utiles et créatives de styliser une liste.</em></p><div class="articleContent"><p>Que nous vient-il à l'esprit lorsque nous pensons à une liste ? Le premier exemple peut-être, le plus évident, est la liste de courses — la plus simple des listes, une collection d'articles sans ordre particulier. Mais nous utilisons les listes de toutes sortes de façons sur le Web. Une série de concerts à venir ? Très probablement une liste. Un processus de réservation en plusieurs étapes ? Sans doute une liste. Une galerie d'images ? Même elle pourrait être considérée comme une <em>liste d'images avec des légendes</em>.</p><p>Dans cet article, nous allons nous plonger dans les différents types de listes HTML disponibles sur le Web et savoir quand les utiliser, y compris certains attributs que vous ne connaissez peut-être pas. Nous examinerons également quelques façons utiles et créatives de leur appliquer un style avec CSS.</p><h2>Quand utiliser une liste ?</h2><p>Un élément de liste HTML doit être utilisé lorsque des éléments doivent être regroupés de manière sémantique. Les technologies d'assistance (comme les lecteurs d'écran) signaleront à l'utilisateur la présence d'une liste et le nombre d'éléments. Si vous pensez, par exemple, à une grille de produits sur un site d'achat, connaître cette information serait très utile. Par conséquent, l'utilisation d'un élément de liste pourrait être un bon choix.</p><h2>Types de liste</h2><p>En ce qui concerne le balisage, nous avons le choix entre trois éléments de liste différents :</p><ul><li>Liste non ordonnée</li>
<li>Liste ordonnée</li>
<li>Liste de description</li>
</ul><p>Le choix de l'une ou l'autre dépend du cas d'utilisation.</p><h2>Liste non ordonnée (ul)</h2><p>L'élément liste non ordonnée (<code>&lt;ul&gt;</code>) est le plus utile lorsque les éléments de la liste ne correspondent à aucun ordre particulier. Par défaut, il s'affiche sous la forme d'une liste à puces. Un exemple est une liste de courses, où l'ordre n'a pas d'importance.</p><figure><img src="https://la-cascade.io/images/unordered-list.avif" alt="Une liste de courses, non ordonnée" /></figure><p>Un exemple plus courant sur le Web est le menu de navigation. Quand on crée un menu, il convient d'envelopper le <code>ul</code> dans un élément <code>nav</code> et d'identifier le menu avec une étiquette, pour aider les technologies d'assistance. Nous devons également identifier la page actuelle dans le menu, ce que nous pouvons faire en utilisant l'attribut <code>aria-current</code> :</p><pre class="language-html">&lt;nav aria-label="Navigation principale"&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;a href="/page-1" aria-current="page"&gt;Elément de menu 1&lt;/a&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="/page-2"&gt;Elément de menu 2&lt;/a&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;a href="/page-2"&gt;Menu élément 2&lt;/a&gt;
    &lt;/li&gt;
    ...
  &lt;/ul&gt;
&lt;/nav&gt;</pre><p>Cet <a href="https://www.w3.org/WAI/tutorials/menus/structure/">article sur la structure des menus</a> présente un certain nombre de recommandations pour garantir que nos menus de navigation soient accessibles à tous.</p><h2>Liste ordonnée (ol)</h2><p>Un élément de liste ordonnée (<code>&lt;ol&gt;</code>) est le meilleur choix lorsque l'ordre des éléments est important, comme dans le cas d'un processus en plusieurs étapes. Par défaut, les éléments de la liste sont numérotés. Un exemple pourrait être un ensemble d'instructions, où les étapes doivent être accomplies dans l'ordre.</p><figure><img src="https://la-cascade.io/images/ordered-list.avif" alt="Une liste d'instructions pour préparer le thé, avec un numéro d'ordre" /></figure><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/mdxjLEd">Ordered list</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><p>Les éléments <code>&lt;ol&gt;</code> et <code>&lt;ul&gt;</code> ne peuvent contenir que des éléments <code>&lt;li&gt;</code> comme enfants directs.</p><h2>Liste de description (dl)</h2><p>Une liste de description contient des termes (éléments <code>&lt;dt&gt;</code>) et des descriptions (<code>&lt;dd&gt;</code>). Chaque terme peut être accompagné de plus d'une description. Les cas d'utilisation possibles pourraient inclure un glossaire de termes, ou peut-être un menu de restaurant. Les listes de descriptions ne sont pas affichées avec des marqueurs par défaut, bien que les navigateurs aient tendance à indenter l'élément <code>&lt;dd&gt;</code>.</p><p>En HTML, il est permis de regrouper des termes avec les descriptions qui les accompagnent à l'aide d'un élément <code>&lt;div&gt;</code>. Cela peut être utile à des fins de style, comme nous le verrons plus tard.</p><pre class="language-html">&lt;dl&gt;- Ceci est valide --&gt;
&lt;dl&gt;
    &lt;dt&gt;Terme 1&lt;/dt&gt;
    &lt;dd&gt;C'est la première description du premier terme de la liste&lt;/dt&gt;.
    &lt;dd&gt;C'est la deuxième description du premier terme de la liste&lt;/dt&gt;
    &lt;dt&gt;Terme 2&lt;/dt&gt;
    &lt;dd&gt;C'est la description du deuxième terme de la liste&lt;/dd&gt;
&lt;/dl&gt;
&lt;!-- Ceci est également valable --&gt;
&lt;dl&gt;
    &lt;div&gt;
        &lt;dt&gt;Terme 1&lt;/dt&gt;
        &lt;dd&gt;C'est la première description du premier terme de la liste&lt;/dd&gt;.
        &lt;dd&gt;C'est la deuxième description du premier terme de la liste&lt;/dd&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;dt&gt;Terme 2&lt;/dt&gt;
        &lt;dd&gt;C'est la description du deuxième terme de la liste&lt;/dd&gt;
    &lt;/div&gt;
&lt;/dl&gt;</pre><h2>Style de liste simple</h2><p>L'une des utilisations les plus simples d'une liste est dans un bloc de texte du <code>&lt;body&gt;</code>. Très souvent, ces listes simples n'ont pas besoin d'un style élaboré, mais nous pourrions vouloir personnaliser les marqueurs d'une liste ordonnée ou non ordonnée dans une certaine mesure, par exemple avec une couleur de marque (<em>brand</em>), ou en utilisant une image personnalisée pour nos puces. Nous pouvons faire beaucoup de choses avec <code>list-style</code> et le pseudo-élément <code>::marker</code> !</p><p><em>Pour vous rafraîchir la mémoire sur les bases du style de liste, consultez le tutoriel de web.dev <a href="https://web.dev/learn/css/lists/">Apprendre le CSS</a>, ainsi qu'une plongée en profondeur dans l'utilisation de <code>::marker</code> dans ce guide sur les <a href="https://web.dev/css-marker-pseudo-element/">puces personnalisées</a>. Continuez à lire pour découvrir des choses que vous ne savez peut-être pas encore !</em></p><h2>::marker</h2><p>En plus de donner à nos marqueurs de liste un style de base, nous pouvons créer des puces cycliques. Ici, nous utilisons trois URL d'images différentes pour la valeur de contenu du pseudo-élément <code>::marker</code>, ce qui ajoute à l'aspect manuscrit de notre exemple de liste de courses (au lieu d'utiliser une seule image pour tout) :</p><pre class="language-css">::marker {
  content: url('/marker-1.svg') ' ';
}
li:nth-child(3n)::marker {
  content: url('/marker-2.svg') ' ';
}
li:nth-child(3n - 1)::marker {
  content: url('/marker-3.svg') ' ';
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/poLZVbr">Handwritten shopping list with custom markers</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><h2>Compteur personnalisé</h2><p>Pour certaines listes ordonnées, nous pourrions vouloir utiliser la valeur du compteur, mais y ajouter une autre valeur. Nous pouvons utiliser le compteur <code>list-item</code> comme valeur pour la propriété <code>content</code> de notre marqueur et y ajouter tout autre contenu :</p><pre class="language-css">::marker {
  content: counter(list-item) '? ';
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/zYWLjBa">Handwritten list with custom markers</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><p>Nos compteurs s'incrémentent automatiquement de un, mais nous pouvons leur permettre de s'incrémenter d'une valeur différente si nous le souhaitons, en définissant la propriété <code>counter-increment</code> sur l'élément de la liste. Par exemple, ceci incrémentera nos compteurs de trois à chaque fois :</p><pre class="language-css">li {
  counter-increment: list-item 3;
}</pre><p>Nous pourrions approfondir bien d'autres choses avec les compteurs. L'article <a href="https://la-cascade.io/articles/listes-css-marqueurs-et-compteurs">Listes, marqueurs et compteurs CSS</a> de <a href="https://la-cascade.io/auteurs/rachel-andrew">Rachel Andrew</a> explique certaines des possibilités plus en détail.</p><h2>Limites de la stylisation de ::marker</h2><p>Nous souhaitons parfois avoir plus de contrôle sur la position et le style de nos marqueurs. Il n'est pas possible de positionner le marqueur à l'aide de <a href="https://la-cascade.io/tags/flexbox">flexbox</a> ou de <a href="https://la-cascade.io/tags/cssgrid">grid</a>, par exemple, ce qui peut parfois être un inconvénient si vous avez besoin d'un autre alignement. <code>::marker</code> expose un nombre limité de propriétés CSS pour le style. Si notre conception nécessite autre chose qu'un style de base, il est préférable d'utiliser un autre pseudo-élément.</p><h2>Styliser des listes qui ne ressemblent pas à des listes</h2><p>Parfois, nous souhaitons donner à nos listes un style totalement différent du style par défaut. C'est souvent le cas avec un menu de navigation, par exemple, où nous souhaitons généralement supprimer tous les marqueurs, et pourrions afficher notre liste horizontalement, à l'aide de flexbox. Une pratique courante consiste à régler la propriété <code>list-style</code> sur <code>none</code>. Cela signifie que le pseudo-élément <code>::marker</code> ne sera plus accessible dans le DOM.</p><blockquote>
<p><strong>Attention</strong><em>Un mot d'avertissement :</em> <code>list-style : none</code> <em>fera que Safari ne reconnaîtra plus une liste non ordonnée dans l'arbre d'accessibilité, et par conséquent qu'un lecteur d'écran n'annoncera plus les informations utiles telles que le nombre d'éléments. Une solution simple (en supposant que votre liste doive être lue comme telle) consiste à utiliser</em> <code>role="list"</code> sur l'élément* <code>&lt;ul&gt;</code> <em>ou</em> <code>&lt;ol&gt;</code> *de votre HTML, <a href="https://www.scottohara.me/blog/2019/01/12/lists-and-safari.html">comme le recommande l'expert en accessibilité Scott O'Hara</a>.*</p>
</blockquote><h2>Marqueurs personnalisés avec ::before</h2><p>L'utilisation du pseudo-élément <code>::before</code> était un moyen courant de créer des marqueurs de liste personnalisés avant l'arrivée de <code>::marker</code>. Mais même aujourd'hui, il peut nous offrir plus de flexibilité, lorsque nous en avons besoin, pour le style visuellement complexe des listes.</p><p>Comme pour <code>::marker</code>, nous pouvons ajouter nos propres styles de puce personnalisés en utilisant l'attribut <code>content</code>. Contrairement à l'utilisation de <code>::marker</code>, nous devons effectuer un positionnement manuel, car nous ne bénéficions pas des avantages automatiques offerts par <code>list-style-position</code>. Mais nous pouvons la positionner relativement facilement avec <a href="https://la-cascade.io/tags/flexbox">flexbox</a>, ce qui ouvre un plus grand nombre de possibilités d'alignement. Par exemple, nous pourrions alterner la position du marqueur :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/OJvwZRM">Alternating list</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><p>Si nous stylisons une liste ordonnée à l'aide de l'élément <code>::before</code>, nous pouvons également souhaiter utiliser des compteurs pour ajouter nos marqueurs numériques.</p><pre class="language-css">li::before {
  counter-increment: list-item;
  content: counter(list-item);
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/NWYBMRb">Alternating list</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><p>L'utilisation de <code>::before</code> au lieu de <code>::marker</code> nous permet d'accéder pleinement aux propriétés CSS pour un style personnalisé, ainsi que de permettre des animations et des transitions — pour lesquelles la compatibilité est limitée pour <code>::marker</code>.</p><h2>Attributs de liste</h2><p>Les éléments de listes ordonnées acceptent certains attributs facultatifs, qui peuvent nous aider dans bon nombre de cas d'utilisation.</p><h3>Listes inversées</h3><p>Si nous disposons d'une liste des 10 meilleurs albums de l'année dernière, nous pourrions vouloir effectuer un compte à rebours de 10 à 1. Nous pourrions utiliser des compteurs personnalisés pour cela, et les incrémenter négativement. Ou bien nous pourrions simplement utiliser l'attribut <code>reversed</code> dans le HTML. Je dirais qu'il est généralement plus judicieux, d'un point de vue sémantique, d'utiliser l'attribut <code>reversed</code> plutôt que d'incrémenter négativement le compteur dans le CSS, à moins que les compteurs n'aient qu'une valeur de présentaton. Si le CSS ne se charge pas, vous verrez quand même les chiffres décomptés correctement dans le HTML. En outre, nous devons tenir compte de la manière dont un lecteur d'écran interpréterait la liste.</p><p>Prenez cette démonstration des 10 meilleurs albums de 2021. Si les compteurs étaient incrémentés uniquement à l'aide de CSS, une personne accédant à la page à l'aide d'un lecteur d'écran pourrait en conclure que les chiffres comptent vers le haut, de sorte que le numéro 10 est en fait le numéro 1.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/qBoyYaL">Reversed list</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><p>Vous pouvez voir dans la démo qu'en utilisant l'attribut inversé, nos marqueurs ont déjà la valeur correcte, sans aucun effort supplémentaire de notre part ! Mais si nous créons des marqueurs de liste personnalisés en utilisant le pseudo-élément <code>::before</code>, nous devons ajuster nos compteurs. Il nous suffit d'indiquer à notre compteur <code>list-item</code> de s'incrémenter négativement :</p><pre class="language-css">li::before {
  counter-increment: list-item -1;
  content: counter(list-item);
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/QWmBrGp">Reversed list with ::before</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><h2>Diviser les listes</h2><p>L'attribut <code>start</code> nous permet de spécifier la valeur numérique à partir de laquelle la liste doit commencer. Cela peut notamment être utile dans les cas où vous souhaitez diviser une liste en groupes.</p><p>Reprenons notre exemple des 10 meilleurs albums. Peut-être voulons-nous en fait décompter les 20 meilleurs albums, mais par groupes de 10. Entre les deux groupes, il y a un autre contenu de page.</p><figure><img src="https://la-cascade.io/images/2-groups.avif" alt="Une liste partagée en deux, avec un autre contenu entrte les deux." /></figure><p>Nous devrons créer deux listes distinctes dans notre HTML, mais comment nous assurer que les compteurs seront corrects ? Dans l'état actuel de notre balisage, les deux listes compteront de 10 à 1, ce qui n'est pas ce que nous voulons. Cependant, dans notre HTML, nous pouvons spécifier une valeur d'attribut de début (<code>start</code>). Si nous ajoutons une valeur de départ de 20 à notre première liste, les marqueurs seront à nouveau mis à jour automatiquement !</p><pre class="language-css">&lt;ol reversed start="20"&gt;
  &lt;li&gt;...&lt;/li&gt;
  &lt;li&gt;...&lt;/li&gt;
  &lt;li&gt;...&lt;/li&gt;
&lt;/ol&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/JjLBvbw">Reversed and split list</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/YzajLpm">Reversed and split list with ::before</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><h2>Affichage de la liste sur plusieurs colonnes</h2><p>La disposition en plusieurs colonnes se prête parfois bien à nos listes, comme vous pouvez le constater dans les démos précédentes. En définissant une largeur de colonne, nous pouvons faire en sorte que notre liste soit automatiquement réactive et ne s'étende sur deux colonnes ou plus que lorsque l'espace est suffisant. Nous pouvons également définir un espace entre les colonnes et, pour une touche supplémentaire, ajouter une règle de colonne stylisée (en utilisant une abréviation similaire à la propriété <code>border</code>) :</p><pre class="language-css">ol {
  columns: 25rem;
  column-gap: 7rem;
  column-rule: 4px dotted turquoise;
}</pre><p>En utilisant des colonnes, nous pouvons parfois nous retrouver avec des ruptures disgracieuses dans nos éléments de liste — pas toujours l'effet recherché.</p><figure><img src="https://la-cascade.io/images/column-list.avif" alt="Une liste répartie sur plusieurs colonnes." /></figure><p>Nous pouvons empêcher ces ruptures forcées en utilisant <code>break-inside : avoid</code> sur nos éléments de liste :</p><pre class="language-css">li {
  break-inside: avoid;
}</pre><h2>Propriétés personnalisées</h2><p>Les propriétés personnalisées CSS offrent un large éventail de possibilités pour le style des listes. Si nous connaissons l'index de l'élément de la liste, nous pouvons l'utiliser pour calculer les valeurs des propriétés. À l'heure actuelle malheureusement, il n'existe aucun moyen de déterminer l'index de l'élément (de manière utilisable en CSS uniquement, en tout cas). Les compteurs nous permettent uniquement d'utiliser leur valeur dans la propriété <code>content</code>, et ne permettent pas les calculs.</p><p>Mais nous pouvons définir l'index de l'élément dans l'attribut <code>style</code> de notre HTML, ce qui peut rendre les calculs plus réalisables, surtout si nous utilisons un langage de templating. Cet exemple montre comment nous pourrions définir cela en utilisant <a href="https://mozilla.github.io/nunjucks/">Nunjucks</a> :</p><pre class="language-html">&lt;ol style="--length : items|length"&gt;
  {% for item in items %}
  &lt;li style="--i : {{ loop.index }}"&gt;...&lt;/li&gt;
  {% endfor %}
&lt;/ol&gt;</pre><p><a href="https://splitting.js.org/">Splitting.js</a> est une bibliothèque qui exécute une fonction similaire du côté client.</p><p>En utilisant la valeur de la propriété personnalisée, la progression dans une liste peut être affichée de différentes manières. Une façon pourrait être une barre de progression pour une liste d'étapes. Dans cet exemple, nous utilisons un pseudo-élément avec un <a href="https://la-cascade.io/articles/les-degrades-css">dégradé linéaire</a> afin de créer une barre pour chaque élément qui indique à quel point l'utilisateur est avancé dans la liste.</p><pre class="language-css">li::before {
  --stop: calc(100% / var(--longueur) * var(--i));
  --color1: deeppink;
  --couleur2: rose;
  content: '';
  background: linear-gradient(
    to right,
    var(--color1) var(--stop),
    var(--color2) 0
  );
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/BarPxpz">Custom properties step progress indicator</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><p>Nous pouvons également ajuster la teinte à mesure qu'on progresse dans la liste, en utilisant <a href="https://la-cascade.io/articles/utiliser-hsl-pour-vos-couleurs">la fonction de couleur <code>hsl()</code></a>. Nous pouvons calculer la valeur de la teinte en utilisant notre propriété personnalisée.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/jOzpxyw">Custom properties step progress indicator</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><h2>Stylisation de la liste des descriptions</h2><p>Comme nous l'avons mentionné précédemment, nous pouvons choisir d'envelopper les termes et leurs définitions dans une <code>div</code> ou dans une <code>dl</code>, pour nous donner plus d'options de style. Par exemple, nous pourrions vouloir afficher notre liste sous forme de <a href="https://la-cascade.io/tags/cssgrid">grille</a>. Si vous définissez <code>display : grid</code> sur la liste sans placer une <code>div</code> autour de chaque groupe, les termes et les descriptions seront placés dans des <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridcell">cellules de grille</a> différentes. C'est parfois utile, comme dans l'exemple suivant, qui montre un menu de tartes avec leurs descriptions.</p><p>Nous pouvons définir une grille sur la liste elle-même et nous assurer que les termes et les descriptions seront toujours alignés en colonnes, la largeur de la colonne étant déterminée par le terme le plus long.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/vYRajmB">Pie menu</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><p>D'un autre côté, si nous voulons regrouper distinctement les termes avec leurs descriptions à la manière d'une carte, un wrapper <code>&lt;div&gt;</code> est très utile.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/web-dot-dev/pen/OJvwZmN">Pie menu</a>de Web.dev dans<a href="https://codepen.io">CodePen</a></div><h3>Ressources complémentaires</h3><ul><li><a href="https://web.dev/learn/css/lists/">Listes</a>, Une introduction de web.dev aux listes et à ::marker</li>
<li><a href="https://developer.mozilla.org/fr/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#listes">Listes, dans les Fondamentaux du texte HTML par MDN</a></li>
<li><a href="https://web.dev/css-marker-pseudo-element/">Marqueurs personnalisés à l'aide de ::marker</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/::marker">::marker, par MDN</a></li>
<li><a href="https://la-cascade.io/articles/listes-css-marqueurs-et-compteurs">Listes CSS avec compteurs</a>, de Rachel Andrew</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/des-styles-de-listes-creatifs</link>
      <guid>https://la-cascade.io/articles/des-styles-de-listes-creatifs</guid>
      <pubDate>Mon, 05 Sep 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Grille CSS et formes personnalisées, 1]]></title>
      <description><![CDATA[<p><em>Combinez les techniques de grille CSS et ajoutez-y un peu de magie clip-path et de masque CSS pour créer des grilles d'images fantaisistes pour pratiquement toutes les formes que vous pouvez imaginer !</em></p><div class="articleContent"><p>Dans un article précédent, j'ai examiné <a href="https://la-cascade.io/articles/css-grid-grille-implicite-et-placement-automatique">la capacité de CSS Grid à créer des mises en page complexes en utilisant ses pouvoirs d'auto-placement</a>. Je suis allé plus loin dans un autre article qui ajoutait <a href="https://la-cascade.io/articles/zoomer-les-images-dans-une-grille">un effet de zoom au survol des images dans une disposition en grille</a>. À présent, je veux me plonger dans un autre type de grille, celle qui fonctionne avec des formes.</p><p>Par exemple, que faire si les images ne sont pas parfaitement carrées mais ont plutôt la forme d'hexagones ou de losanges ? spoiler : nous pouvons le faire. En fait, nous allons combiner les techniques de grille CSS que nous avons déjà examinées et ajouter un peu de magie CSS de type <a href="https://la-cascade.io/articles/la-propriete-css-clip-path">clip-path</a> et <a href="https://developer.mozilla.org/fr/docs/Web/CSS/mask">mask</a> pour créer des grilles d'images fantaisistes pour pratiquement toutes les formes que vous pouvez imaginer !</p><h2>Commençons par un balisage</h2><p>La plupart des mises en page que nous allons examiner peuvent sembler faciles à réaliser à première vue, mais <em>le défi consiste à les réaliser avec le même balisage HTML</em>. Nous pouvons utiliser beaucoup de wrappers, de divs et autres, mais l'objectif de cet article est d'utiliser la même quantité de code HTML, et la plus petite possible, pour obyenir toutes les différentes grilles. Après tout, qu'est-ce que CSS sinon un moyen de séparer le style et le balisage ? Notre style ne doit pas dépendre du balisage, et vice versa.</p><p>Ceci étant dit, commençons :</p><pre class="language-html">&lt;div class="gallery"&gt;
  &lt;img src="..." alt="..." /&gt;
  &lt;img src="..." alt="..." /&gt;
  &lt;img src="..." alt="..." /&gt;
  &lt;img src="..." alt="..." /&gt;
  &lt;!-- autant de fois que l'on veut --&gt;
&lt;/div&gt;</pre><p>Tout ce dont nous avons besoin ici, c'est d'un conteneur avec des images. Rien de plus !</p><h2>Grille CSS d'hexagones</h2><p>Cette grille est aussi parfois appelée "nid d'abeille".</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/XWEWoYW">Honeycomb image gallery</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Il y a déjà beaucoup d'autres articles de blog qui montrent comment faire cela. J'en ai même <a href="https://css-tricks.com/hexagons-and-beyond-flexible-responsive-grid-patterns-sans-media-queries/">écrit un ici</a> sur CSS-Tricks ! Cet article est toujours bon et explique en détail comment créer une mise en page réactive. Mais pour ce cas précis, nous allons nous appuyer sur une approche CSS beaucoup plus simple.</p><p>Tout d'abord, utilisons le <code>clip-path</code> sur les images pour créer la forme hexagonale et plaçons-les toutes dans la même zone de grille pour qu'elles se chevauchent.</p><pre class="language-cs">.gallery {
  --s : 150px ; /* contrôle la taille */
  display : grid ;
}
.gallery &gt; img {
  grid-area : 1/1 ;
  width : var(--s) ;
  aspect-ratio : 1.15 ;
  object-fit : couverture ;
  clip-path : polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%) ;
}</pre><figure role="group"><img src="https://la-cascade.io/images/hexagone_1.webp" alt="" /><figcaption><small>clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%)</small></figcaption></figure><p>Rien de bien original pour l'instant. Toutes les images sont des hexagones et sont superposées. Il semble que nous n'ayons qu'un seul élément d'image en forme d'hexagone, mais en réalité il y en a sept.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/mdxMqmK/d9c9d84f1e83aea575610acfddd85105">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>L'étape suivante consiste à appliquer une translation aux images pour les placer correctement sur la grille.</p><figure><img src="https://la-cascade.io/images/hexagons_1.webp" alt="" /></figure><p>Remarquez que nous voulons toujours qu'une des images reste au centre. Les autres sont placées autour d'elle en utilisant <a href="https://developer.mozilla.org/fr/docs/Web/CSS/transform-function/translate">CSS translate</a> et la bonne vieille géométrie. Voici les formules que j'ai créées pour chaque image de la grille :</p><pre class="language-css">translate((height + gap)*sin(0deg), (height + gap)*cos(0))
translate((height + gap)*sin(60deg), (height + gap)*cos(60deg))
translate((height + gap)*sin(120deg), (height + gap)*cos(120deg))
translate((height + gap)*sin(180deg), (height + gap)*cos(180deg))
translate((height + gap)*sin(240deg), (height + gap)*cos(240deg))
translate((height + gap)*sin(300deg), (height + gap)*cos(300deg))</pre><p>Quelques calculs et optimisations plus tard (sautons cette partie ennuyeuse, d'accord ?), nous obtenons le CSS suivant :</p><pre class="language-css">.gallery {
  --s: 150px; /* contrôle de la taille */
  --g: 10px; /* contrôle de l'espacement */
  display: grid;
}
.gallery &gt; img {
  grid-area: 1/1;
  width: var(--s);
  aspect-ratio: 1.15;
  object-fit: cover;
  clip-path: polygon(
    25% 0%,
    75% 0%,
    100% 50%,
    75% 100%,
    25% 100%,
    0 50%
  );
  transform: translate(var(--_x, 0), var(--_y, 0));
}
.gallery &gt; img:nth-child(1) {
  --_y: calc(-100% - var(--g));
}
.gallery &gt; img:nth-child(7) {
  --_y: calc(100% + var(--g));
}
.gallery &gt; img:nth-child(3),
.gallery &gt; img:nth-child(5) {
  --_x: calc(-75% - 0.87 * var(--g));
}
.gallery &gt; img:nth-child(4),
.gallery &gt; img:nth-child(6) {
  --_x: calc(75% + 0.87 * var(--g));
}
.gallery &gt; img:nth-child(3),
.gallery &gt; img:nth-child(4) {
  --_y: calc(-50% - 0.5 * var(--g));
}
.gallery &gt; img:nth-child(5),
.gallery &gt; img:nth-child(6) {
  --_y: calc(50% + 0.5 * var(--g));
}</pre><p>?? <em>Ce sera peut-être plus facile lorsque nous aurons de vraies fonctions de trigonométrie en CSS !</em></p><p>Chaque image est traduite par les variables <code>--_x</code> et <code>--_y</code> qui sont basées sur ces formules. Seule la deuxième image (<code>nth-child(2)</code>) est indéfinie dans tout sélecteur car c'est celle qui se trouve au centre. Il peut s'agir de n'importe quelle image si vous décidez d'utiliser un ordre différent. Voici l'ordre que j'utilise :</p><figure><img src="https://la-cascade.io/images/hexagons_2.webp" alt="" /></figure><p>Avec seulement quelques lignes de code, nous obtenons une super grille d'images. À cela, j'ai ajouté un petit effet de survol aux images pour rendre les choses plus fantaisistes.</p><p>Et devinez quoi ? Nous pouvons obtenir une autre grille hexagonale en mettant simplement à jour quelques valeurs.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/xxWLJOR">Another hexagon grid</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Si vous vérifiez le code et le comparez avec le précédent, vous remarquerez que j'ai simplement interverti les valeurs à l'intérieur de <code>clip-path</code> et que j'ai permuté entre <code>--x</code> et <code>--y</code>. C'est tout !</p><h2>Grille CSS de losanges</h2><p>Ce losange est juste un carré qui a subi une rotation de 45 degrés.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/KKowpYz">Rhombus image gallery</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Même HTML, vous vous souvenez ? Nous commençons par définir une grille d'images 2×2 en CSS :</p><pre class="language-css">.gallery {
  --s: 150px; /* contrôle la taille */
  display: grid;
  gap: 10px;
  grid: auto-flow var(--s) / repeat(2, var(--s));
  place-items: center;
}
.gallery &gt; img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
}</pre><p>La première chose qui pourrait attirer votre attention est la propriété grid. Elle n'est pas souvent utilisée, mais elle est très utile car il s'agit d'un raccourci qui nous permet de définir une grille complète en une seule déclaration. Ce n'est pas la propriété la plus intuitive — sans parler de la lisibilité — mais nous sommes ici pour apprendre et découvrir de nouvelles choses, alors utilisons-la plutôt que d'écrire toutes les propriétés individuelles de la grille.</p><pre class="language-css">grid: auto-flow var(--s) / repeat(2, var(--s));
/* est équivalent à ceci : */
grid-template-columns: repeat(2, var(--s));
grid-auto-rows: var(--s);</pre><p>Cela définit deux colonnes de largeur égale à la variable <code>--s</code> et fixe la hauteur de toutes les lignes à <code>--s</code> également. Comme nous avons quatre images, nous obtiendrons automatiquement une grille de 2×2.</p><p>Voici une autre façon dont nous aurions pu l'écrire :</p><pre class="language-css">grid-template-columns: repeat(2, var(--s));
grid-template-rows: repeat(2, var(--s));</pre><p>...ce qui peut être réduit avec le raccourci grid :</p><pre class="language-css">grid: repeat(2, var(--s)) / repeat(2, var(--s));</pre><p>Après avoir défini la grille, nous la faisons pivoter ainsi que les images avec des transformations CSS et nous obtenons ceci :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/gOexjRd/81e863cc4d71bd6047a7cd9be29062a3">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Notez comment je les fais pivoter tous les deux de 45deg, mais dans la direction opposée.</p><pre class="language-css">.gallery {
  /* etc. */
  transform: rotate(45deg);
}
.gallery &gt; img {
  /* etc. */
  transform: rotate(-45deg);
}</pre><p>La rotation des images dans le sens négatif les empêche de subir une rotation avec la grille, elles restent donc droites. Maintenant, nous appliquons un <code>clip-path</code> pour découper une forme de losange à partir des images.</p><figure role="group"><img src="https://la-cascade.io/images/losange.webp" alt="" /><figcaption><small>clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%)</small></figcaption></figure><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/qBoXyVX/36921e398a269bbfb6a143d969e1b1a1">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Nous avons presque terminé ! Nous devons rectifier la taille des images pour qu'elles s'emboîtent. Sinon, elles sont très espacées au point que cela ne ressemble pas à une grille d'images.</p><figure><img src="https://la-cascade.io/images/losanges.webp" alt="" /></figure><p>L'image se trouve à l'intérieur de la limite du cercle vert, qui est le cercle inscrit de la zone de la grille où l'image est placée. Ce que nous voulons, c'est agrandir l'image pour qu'elle rentre dans le cercle rouge, qui est le cercle circonscrit de la zone de la grille.</p><p>Ne vous inquiétez pas, je ne présenterai pas de géométrie plus ennuyeuse. Tout ce que vous devez savoir, c'est que le rapport entre le rayon de chaque cercle est la racine carrée de 2 (sqrt(2)). C'est la valeur dont nous avons besoin pour augmenter la taille de nos images afin de remplir la zone. Nous utiliserons <code>100%*sqrt(2) = 141%</code> et le tour est joué !</p><pre class="language-css">.gallery {
  --s: 150px; /* contrôle de la taille */
  display: grid;
  grid: auto-flow var(--s) / repeat(2, var(--s));
  gap: 10px;
  place-items: center;
  transform: rotate(45deg);
}
.gallery &gt; img {
  width: 141%; /* 100%*sqrt(2) = 141% */
  aspect-ratio: 1;
  object-fit: cover;
  transform: rotate(-45deg);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}</pre><p>Comme pour la grille hexagonale, nous pouvons rendre les choses plus fantaisistes avec ce bel effet de survol de zoom :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/KKowpYz">Rhombus image gallery</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><h2>Grille CSS de formes triangulaires</h2><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/PoRGPoW">Triangular grid of images</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Vous savez probablement maintenant que la grande astuce consiste à déterminer le <code>clip-path</code> pour obtenir les formes que nous voulons. Pour cette grille, chaque élément a sa propre valeur de <code>clip-path</code> alors que les deux dernières grilles utilisaient des formes cohérentes. Donc, cette fois-ci, c'est comme si nous travaillions avec plusieurs formes triangulaires différentes qui s'assemblaient pour former une grille rectangulaire d'images.</p><figure role="group"><img src="https://la-cascade.io/images/triangles_1.webp" alt="" /><figcaption><small>Les trois images en haut.</small></figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/triangles_2.webp" alt="" /><figcaption><small>Les trois images en bas.</small></figcaption></figure><p>Nous les plaçons dans une grille 3×2 avec le CSS suivant :</p><pre class="language-css">.gallery {
  display : grid ;
  gap : 10px ;
  grid-template-columns : auto auto auto ; /* 3 colonnes */
  place-items : center ;
}
.gallery &gt; img {
  width : 200px ; /* contrôle la taille */
  aspect-ratio : 1 ;
  object-fit : cover ;
}
/* les valeurs de clip-path */
.gallery &gt; img:nth-child(1) { clip-path : polygon(0 0, 50% 0, 100% 100% ,0 100%) ; }
.gallery &gt; img:nth-child(2) { clip-path : polygon(0 0, 100% 0, 50% 100%) ; }
.gallery &gt; img:nth-child(3) { clip-path : polygon(50% 0, 100% 0, 100% 100%, 0 100%) ; }
.gallery &gt; img:nth-child(4) { clip-path : polygon(0 0, 100% 0, 50% 100%, 0 100%) ; }
.gallery &gt; img:nth-child(5) { clip-path : polygon(50% 0, 100% 100%, 0% 100%) ; }
.gallery &gt; img:nth-child(6) { clip-path : polygon(0 0, 100% 0 ,100% 100%, 50% 100%) ; } } }</pre><p>Voici ce que nous obtenons :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/abYygLB/ec7e8106f450cf7ddb9e3d7796108e0a">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>La touche finale consiste à rendre la largeur de la colonne centrale égale à 0 pour se débarrasser des espaces entre les images. C'est le même genre de problème d'espacement que nous avions avec la grille de losanges, mais avec une approche différente pour les formes que nous utilisons maintenant :</p><pre class="language-css">grid-template-columns: auto 0 auto;</pre><p>J'ai dû jouer avec les valeurs de <code>clip-path</code> pour m'assurer qu'elles s'emboîtent toutes comme un puzzle. Les images originales se chevauchent lorsque la colonne du milieu a une largeur nulle, mais après avoir découpé les images, l'illusion est parfaite :</p><figure><img src="https://la-cascade.io/images/result.webp" alt="" /></figure><h2>Grille CSS en pizza</h2><p>Devinez quoi ? Nous pouvons obtenir une autre grille cool en ajoutant simplement <code>border-radius</code> et <code>overflow</code> à notre grille ou à nos formes triangulaires. ?</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/abYygRW">Pizza-like grid</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><h2>Grille CSS de pièces de puzzle</h2><p>Cette fois, nous allons jouer avec la propriété CSS <code>mask</code> pour que les images ressemblent aux pièces d'un puzzle.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/OJvWKPm">Puzzle-like grid of images</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Note : si vous n'avez pas encore utilisé <code>mask</code> avec <a href="https://la-cascade.io/articles/les-degrades-css">les dégradés CSS</a>, je vous recommande vivement <a href="https://css-tricks.com/css-borders-using-masks/">cet autre article</a> que j'ai écrit sur le sujet car il vous aidera pour la suite. Pourquoi des dégradés ? Parce que c'est ce que nous utilisons pour obtenir les encoches rondes dans les formes des pièces du puzzle.</p><p>La configuration de la grille devrait être un jeu d'enfant maintenant, alors concentrons-nous plutôt sur la partie masque.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/mdxBXwP/e13c06c572e0c93d95d92e98995d05e0">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Comme illustré dans la démo ci-dessus, nous avons besoin de deux dégradés pour créer la forme finale. Un dégradé crée un cercle (la partie verte) et l'autre crée la bonne courbe tout en remplissant la partie supérieure.</p><pre class="language-css">--g: 6px; /* contrôle le gap */
--r: 42px; /* contrôle les formes circulaires */
background: radial-gradient(
    var(--r) at left 50% bottom var(--r),
    green 95%,
    #0000
  ),
  radial-gradient(
      calc(var(--r) + var(--g)) at calc(100% + var(--g)) 50%,
      #0000 95%,
      red
    ) top/100% calc(100% - var(--r)) no-repeat;</pre><p>Deux variables contrôlent la forme. La variable --g n'est rien d'autre que <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcg">la gouttière de la grille</a>. Nous devons tenir compte de celle-ci pour placer correctement nos cercles afin qu'ils se chevauchent parfaitement lorsque le puzzle entier est assemblé. La variable --r contrôle la taille des parties circulaires de la forme du puzzle.</p><figure><img src="https://la-cascade.io/images/encoche.webp" alt="" /></figure><p>Maintenant, nous prenons le même CSS et mettons à jour quelques valeurs dans celui-ci pour créer les trois autres formes :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/JjLrByR/c51f0db4eb02c1d75ca1709c1dc0a4a1">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Nous avons les formes, mais pas les bords superposés dont nous avons besoin pour les faire s'emboîter. Chaque image est limitée à la cellule de la grille dans laquelle elle se trouve, il est donc logique que les formes soient en quelque sorte mélangées pour le moment :</p><figure><img src="https://la-cascade.io/images/puzzle_2.webp" alt="" /></figure><p>Nous devons créer un débordement en augmentant la hauteur/largeur des images. D'après la figure ci-dessus, nous devons augmenter la hauteur de la première et de la quatrième image tandis que nous augmentons la largeur de la deuxième et de la troisième. Vous avez probablement déjà deviné que nous devons les augmenter en utilisant la variable --r.</p><pre class="language-css">.gallery &gt; img:is(:nth-child(1), :nth-child(4)) {
  width: 100%;
  height: calc(100% + var(--r));
}
.gallery &gt; img:is(:nth-child(2), :nth-child(3)) {
  height: 100%;
  largeur: calc(100% + var(--r));
}</pre><p>On s'approche !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/dymVjdz/839e965687fb03aff15cf4d11fc21e09">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Nous avons créé le chevauchement mais, par défaut, nos images se chevauchent soit à droite (si nous augmentons la largeur), soit en bas (si nous augmentons la hauteur). Mais ce n'est pas ce que nous voulons pour les deuxième et quatrième images. La solution est d'utiliser <code>place-self: end</code> sur ces deux images et notre code complet devient :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/OJvWKPm">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Voici un autre exemple où j'utilise un dégradé conique au lieu d'un dégradé radial. Cela nous donne des pièces de puzzle triangulaires tout en gardant les mêmes HTML et CSS sous-jacents.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/RwMLmjr">Puzzle Grid of images</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Un petit dernier pour la route ! Cette fois-ci, j'utilise le <code>clip-path</code>, et comme il s'agit d'<a href="https://la-cascade.io/articles/comprendre-clip-path">une propriété que nous pouvons animer</a>, nous obtenons un survol cool en mettant simplement à jour la propriété personnalisée qui contrôle la forme.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/gOezMrY">Puzzle Grid of images with hover effect</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div></div>]]></description>
      <link>https://la-cascade.io/articles/grille-css-et-formes-personnalisees-1</link>
      <guid>https://la-cascade.io/articles/grille-css-et-formes-personnalisees-1</guid>
      <pubDate>Sun, 28 Aug 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Utiliser :has() comme sélecteur de parent et bien plus]]></title>
      <description><![CDATA[<p><em>Appliquer un style css à un élément en fonction de ce qui se passe à l'intérieur de cet élément : la révolution css :has(), le sélecteur parent.</em></p><div class="articleContent"><p>Depuis longtemps les développeurs <em>front</em> rêvent d'avoir un moyen d'appliquer le CSS à un élément en fonction de ce qui se passe à l'intérieur de cet élément.</p><p>Nous pourrions vouloir par exemple disposer un élément d'article d'une certaine façon s'il y a une image "héros" en haut, et d'une autre façon s'il n'y a pas d'image "héros". Ou peut-être voulons-nous appliquer des styles différents à un formulaire en fonction de l'état de l'un de ses champs de saisie. Que diriez-vous de donner à une barre latérale une couleur d'arrière-plan si un certain composant est présent dans cette barre latérale, et une couleur d'arrière-plan différente si ce composant n'est pas présent ? Les cas d'utilisation de ce type existent depuis longtemps et les développeurs Web ont approché à plusieurs reprises le groupe de travail CSS, les suppliant d'inventer un "sélecteur de parent".</p><p>Au cours des <a href="https://lists.w3.org/Archives/Public/www-style/2002May/0037.html">vingt dernières années</a>, le groupe de travail CSS a discuté de cette possibilité à de très nombreuses reprises. Le besoin était clair et bien compris. Définir la syntaxe était une tâche réalisable. Mais trouver comment un moteur de navigateur pourrait traiter des patterns circulaires potentiellement très complexes et effectuer les calculs assez rapidement semblait impossible. Les premières versions d'un sélecteur de parent ont été ébauchées pour CSS3, mais elles ont été reportées. Finalement, la pseudo-classe <code>:has()</code> a été officiellement définie dans les <a href="https://www.w3.org/TR/selectors-4/#relational">sélecteurs CSS de niveau 4</a>. Mais le fait de disposer d'une norme Web ne suffit pas à faire de <code>:has()</code> une réalité. Nous avions encore besoin d'une équipe chargée des navigateurs pour relever le défi très réel des performances. Pendant ce temps, les ordinateurs continuaient à devenir plus puissants et plus rapides chaque année.</p><p>En 2021, <a href="https://www.igalia.com/">Igalia</a> a commencé à plaider en faveur de <code>:has()</code> auprès des équipes d'ingénierie des navigateurs, en <a href="https://bkardell.com/blog/canihas.html">prototypant leurs idées</a> et en <a href="https://github.com/Igalia/explainers/tree/main/css/has">documentant leurs conclusions</a> concernant les performances. Le regain d'intérêt pour <code>:has()</code> a attiré l'attention des ingénieurs qui travaillent sur WebKit chez Apple. Nous avons commencé à implémenter la pseudo-classe, en réfléchissant aux possibilités d'amélioration des performances nécessaires pour que cela fonctionne. Nous avons discuté pour savoir s'il fallait commencer par une version plus rapide avec un champ d'application très limité, puis essayer de supprimer ces limites si possible... ou commencer par quelque chose qui n'avait aucune limite, et n'appliquer de restrictions que si nécessaire. Nous nous sommes lancés et avons implémenté la version la plus puissante. Nous avons développé un certain nombre de nouvelles optimisations de mise en cache et de filtrage spécifiques à <code>:has</code>, et nous avons exploité les stratégies d'optimisation avancées existantes de notre moteur CSS. Et notre approche a fonctionné, prouvant qu'après deux décennies d'attente, il est enfin possible d'implémenter un tel sélecteur avec des <a href="https://twitter.com/anttikoivisto/status/1473251189181591554">performances fantastiques</a>, même en présence de grands arbres DOM et d'un grand nombre de sélecteurs <code>:has()</code>.</p><p>L'équipe WebKit a livré <code>:has()</code> dans l'<a href="https://webkit.org/blog/12156/release-notes-for-safari-technology-preview-137/">aperçu technologique 137 de Safari</a> en décembre 2021, et dans Safari 15.4 le 14 mars 2022. Igalia a effectué le travail d'ingénierie pour implémenter <code>:has()</code> dans Chromium, qui sera livré dans <a href="https://groups.google.com/a/chromium.org/g/blink-dev/c/bRsbl3wLuyk/m/mt3iSKNHBQAJ?pli=1">Chrome 105</a> le 30 août 2022. On peut supposer que les <a href="https://caniuse.com/?search=%3Ahas()">autres navigateurs</a> construits sur Chromium ne seront pas loin derrière. Mozilla <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=418039">travaille actuellement</a> sur l'implémentation de Firefox.</p><p>Voyons donc, étape par étape, ce que les développeurs Web peuvent faire avec <a href="https://2020.stateofcss.com/en-US/opinions/#currently_missing_from_css">cet outil tant désiré</a>. Il s'avère que la pseudo-classe <code>:has()</code> n'est pas seulement un "sélecteur de parent". Après des décennies d'impasses, <strong>ce sélecteur peut faire bien plus</strong>.</p><h2>Les bases de <code>:has()</code> comme sélecteur de parent</h2><p>Commençons par les bases. Imaginons que nous voulions appliquer un style à un élément <code>&lt;figure&gt;</code> en fonction du type de contenu de l'image. Parfois, notre <em>figure</em> n'englobe qu'une image.</p><pre class="language-css">&lt;figure&gt;
  &lt;img src="flowers.jpg" alt="fleurs de printemps"&gt;
&lt;/figure&gt;</pre><p>Alors que d'autres fois, l'image comporte une légende.</p><pre class="language-css">&lt;figure&gt;
  &lt;img src="chien.jpg" alt="chien noir souriant au soleil"&gt;
  &lt;figcaption&gt;Maggie adore être dehors sans laisse.&lt;/figcaption&gt;
&lt;/figure&gt;</pre><p>Appliquons maintenant quelques styles à la <em>figure</em> qui ne s'appliqueront que s'il y a une <em>figcaption</em> à l'intérieur de la figure.</p><pre class="language-css">figure:has(figcaption) {
  background: white;
  padding: 0.6rem;
}</pre><p>Ce sélecteur décrit exactement ce qu'il dit — tout élément <em>figure</em> ayant une <em>figcaption</em> sera sélectionné.</p><p>Voici la démo, si vous souhaitez modifier le code et voir ce qui se passe. Veillez à utiliser <a href="https://caniuse.com/css-has">un navigateur qui prend en charge <code>:has()</code></a> — à ce jour, on parle de Safari.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/jensimmons/pen/eYGKNYy">:has() Demo #1 — Figure variations</a>de jensimmons dans<a href="https://codepen.io">CodePen</a></div><p>Dans cette démo, je cible également tout élément <code>&lt;figure&gt;</code> qui contient un élément <code>&lt;pre&gt;</code> en utilisant <code>figure:has(pre)</code>.</p><pre class="language-css">figure:has(pre) {
  background: rgb(252, 232, 255);
  border: 3px solid white;
  padding: 1rem;
}</pre><p>Et j'utilise une <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Conditional_Rules/Using_Feature_Queries">requête de fonctionnalité</a> de sélecteur (<em>Feature Query</em>) pour masquer un rappel sur la prise en charge par le navigateur lorsque le navigateur actuel prend en charge <code>:has()</code>.</p><pre class="language-css">@supports selector(:has(img)) {
  small {
    display: none;
  }
}</pre><p>La règle-@ (<em>at-rule</em>) <code>@supports selector()</code> est elle-même <a href="https://caniuse.com/mdn-css_at-rules_supports_selector">très bien prise en charge</a>. Elle peut être incroyablement utile chaque fois que vous voulez utiliser une <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Conditional_Rules/Using_Feature_Queries">requête de fonctionnalité</a> pour tester la prise en charge par le navigateur d'un sélecteur particulier.</p><p>Et enfin, dans cette première démo, j'écris également un sélecteur complexe à l'aide de <a href="https://la-cascade.io/articles/sur-not-et-la-specifite">la pseudo-classe <code>:not()</code></a>. Je veux appliquer <code>display : flex</code> à la figure, mais seulement si le seul contenu est une image. Flexbox fait alors en sorte que l'image s'étire pour remplir tout l'espace disponible.</p><p>J'utilise un sélecteur pour cibler tout élément <code>&lt;figure&gt;</code> qui n'a pour enfant aucun élément autre que <code>&lt;img&gt;</code>. Si la figure a une <code>figcaption</code>, <code>pre</code>, <code>p</code> ou un <code>h1</code> — ou tout autre élément que <code>img</code> — le sélecteur ne s'applique pas.</p><pre class="language-css">figure:not(:has(:not(img))) {
  affichage: flex;
}</pre><p><code>:has()</code> est sacrément puissant !</p><h2>Un exemple pratique utilisant :has() avec CSS Grid</h2><p>Regardons une deuxième démo où j'ai utilisé <code>:has()</code> comme sélecteur de parent pour résoudre facilement un besoin très pratique.</p><p>J'ai plusieurs <em>cards</em> (<em>cartes</em> ou <em>encarts</em>) pour des article mis en page à l'aide de <a href="https://la-cascade.io/tags/cssgrid">CSS Grid</a>. Certaines cartes ne contiennent que des titres et du texte, tandis que d'autres ont également une image. Je veux que les cartes avec des images prennent plus de place sur la grille que celles sans image.</p><p>Je ne veux pas avoir à faire un travail supplémentaire pour que mon système de gestion de contenu applique une classe ou utilise JavaScript pour la mise en page. Je veux juste écrire un simple sélecteur en CSS qui indiquera au navigateur de faire en sorte que toute carte contenant une image occupera deux lignes et deux colonnes dans la grille.</p><p>Avec la pseudo-classe <code>:has()</code> c'est très simple :</p><pre class="language-css">article:has(img) {
  grid-column: span 2;
  grid-row: span 2;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/jensimmons/pen/bGoMydw">:has() Demo #2 — Teaser cards</a>de jensimmons dans<a href="https://codepen.io">CodePen</a></div><p>Ces deux premières démos utilisent des <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Type_selectors">sélecteurs d'éléments</a> simples datant des premiers jours de CSS, mais tous les sélecteurs peuvent être combinés avec <code>:has()</code>, y compris le <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Class_selectors">sélecteur de classe</a>, le <a href="https://developer.mozilla.org/fr/docs/Web/CSS/ID_selectors">sélecteur d'ID</a>, le <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Attribute_selectors">sélecteur d'attribut</a> — et de puissants combinateurs, comme nous allons le voir maintenant.</p><h2>Utiliser :has() avec le combinateur enfant</h2><p>Tout d'abord, un bref rappel de la différence entre le <a href="https://www.w3.org/TR/selectors-4/#descendant-combinators">combinateur descendant</a> et le <a href="https://www.w3.org/TR/selectors-4/#child-combinators">combinateur enfant</a> (&gt;). (?? NdT : pour un tour complet de la question, vous pouvez consulter l'article <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css">Combinateurs et pseudo-classes</a> ici-même).</p><p>Le combinateur descendant existe depuis le tout début de CSS. Il s'écrit en mettant un espace entre deux sélecteurs simples :</p><pre class="language-css">a img {
  ...;
}</pre><p>Cela cible tous les éléments <code>img</code> qui sont contenus dans un élément <code>a</code>, quelle que soit la distance entre le <code>a</code> et l'<code>img</code> dans l'arbre DOM HTML.</p><pre class="language-html">&lt;a&gt;
  &lt;figure&gt;
    &lt;img
      src="photo.jpg"
      alt="n'oublie pas le texte alternatif"
      width="200"
      height="100"
    /&gt;
  &lt;/figure&gt;
&lt;/a&gt;</pre><p>Le combinateur sécrit en mettant un <code>&gt;</code> entre deux sélecteurs — ce qui indique au navigateur de cibler tout ce qui correspond au deuxième sélecteur, mais uniquement lorsque le deuxième sélecteur est <em>un enfant direct du premier</em>.</p><pre class="language-css">a &gt; img {
  ...;
}</pre><p>Par exemple, ce sélecteur cible tous les éléments <code>img</code> enveloppés par un élément <code>a</code>, mais uniquement lorsque l'<code>img</code> se trouve immédiatement après le <code>a</code> dans le HTML.</p><pre class="language-html">&lt;a&gt;
  &lt;img
    src="photo.jpg"
    alt="n'oublie pas le texte alternatif"
    width="200"
    height="100"
  /&gt;
&lt;/a&gt;</pre><p>En gardant cela à l'esprit, examinons la différence entre les deux exemples suivants. Les deux sélectionnent l'élément <code>a</code>, plutôt que l'<code>img</code>, puisque nous utilisons <code>:has()</code>.</p><pre class="language-css">a:has(img) {
  ...;
}
a:has(&gt; img) {
  ...;
}</pre><p>La première sélectionne tout élément <code>a</code> avec une <code>img</code> à l'intérieur — n'importe où dans la structure HTML. Alors que la seconde sélectionne un élément uniquement si l'<code>img</code> est un enfant direct de l'élément <code>a</code>.</p><p>Les deux peuvent être utiles ; ils accomplissent des choses différentes.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/jensimmons/pen/BaYoWea">:has() Demo #3 — Descendant combinator vs Child combinator</a>de jensimmons dans<a href="https://codepen.io">CodePen</a></div><p>Il existe encore deux autres types de combinateurs — tous deux sont des frères et sœurs. Et c'est grâce à eux que <code>:has()</code> devient plus qu'un sélecteur de parent.</p><h2>Utiliser :has() avec des combinateurs frères et sœurs</h2><p>Passons en revue les deux sélecteurs de relations "fraternelles". Il y a le combinateur de <em><a href="https://www.w3.org/TR/selectors-4/#adjacent-sibling-combinators">next-siblings</a></em> (<code>+</code>) et le combinateur <em><a href="https://www.w3.org/TR/selectors-4/#general-sibling-combinators">subsequent-siblings</a></em> (<code>~</code>) de frères et sœurs suivants.</p><p>Le combinateur next-sibling (<code>+</code>) sélectionne <em>uniquement</em> les paragraphes qui suivent <em>directement</em> un élément h2 :</p><pre class="language-css">h2 + p</pre><pre class="language-html">&lt;h2&gt;Les titres&lt;/h2&gt;
&lt;p&gt;
  Paragraphe qui est sélectionné par "h2 + p", car il se trouve
  directement après "h2".
&lt;/p&gt;
.</pre><p>Le combinateur subsequent-siblings (<code>~</code>) sélectionne tous les paragraphes qui viennent après un élément h2. Ils doivent être frères et sœurs, mais il peut y avoir un nombre quelconque d'autres éléments HTML entre les deux.</p><pre class="language-css">h2 ~ p</pre><pre class="language-html">&lt;h2&gt;Les titres&lt;/h2&gt;
&lt;h3&gt;Autre chose&lt;/h3&gt;
&lt;p&gt;Paragraphe qui est sélectionné par "h2 ~ p".&lt;/p&gt;
&lt;p&gt;Ce paragraphe est également sélectionné.&lt;/p&gt;</pre><p>Notez que <code>h2 + p</code> et <code>h2 ~ p</code> sélectionnent tous deux les éléments paragraphes, et non les titres h2. Comme d'autres sélecteurs (pensez à <code>img</code>), c'est le dernier élément listé qui est ciblé par le sélecteur. Mais que faire si nous voulons cibler le h2 ? Eh bien nous pouvons utiliser les combinateurs frères et sœurs avec <code>:has()</code>.</p><p>Combien de fois avez-vous souhaité pouvoir ajuster les marges d'un titre en fonction de l'élément qui le suit ? C'est maintenant facile. Ce code nous permet de sélectionner tout h2 ayant un p immédiatement après lui.</p><pre class="language-css">h2:has(+ p) {
  margin-bottom: 0;
}</pre><p>Incroyable.</p><p>Et si nous voulions faire cela pour les six éléments de titre, sans écrire six copies du sélecteur. Nous pouvons utiliser <code>:is()</code> pour simplifier notre code.</p><pre class="language-css">:is(h1, h2, h3, h4, h5, h6):has(+ p) {
  margin-bottom: 0;
}</pre><p>Mais que faire si nous voulons écrire ce code pour plus d'éléments que de simples paragraphes ? Éliminons la marge inférieure de tous les titres lorsqu'ils sont suivis de paragraphes, de légendes, d'exemples de code et de listes :</p><pre class="language-css">:is(h1, h2, h3, h4, h5, h6):has(+ :is(p, figcaption, pre, dl, ul, ol)) {
  margin-bottom: 0;
}</pre><p>La combinaison de <code>:has()</code> avec les combinateurs descendants, les combinateurs enfants (<code>&gt;</code>), les combinateurs frères et sœurs suivants (<code>+</code>) et les combinateurs frères et sœurs subséquents (<code>~</code>) ouvre un monde de possibilités. Mais ce n'est encore que le début.</p><h2>Styler les états de formulaire sans JS</h2><p>Il y a beaucoup de <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Pseudo-classes">pseudo-classes</a> fantastiques qui peuvent être utilisées à l'intérieur de <code>has:()</code>. En fait, cela révolutionne ce que les pseudo-classes peuvent faire. Auparavant, les pseudo-classes n'étaient utilisées que pour styler un élément en fonction d'un état spécial, ou pour styler l'un de ses enfants. Maintenant, <strong>les pseudo-classes peuvent être utilisées pour capturer un état</strong>, sans JavaScript, et styler n'importe quoi dans le DOM en fonction de cet état.</p><p>Les champs de saisie des formulaires constituent un moyen puissant de capturer un tel état. Les pseudo-classes spécifiques aux formulaires incluent <code>:autofill</code>, <code>:enabled</code>, <code>:disabled</code>, <code>:read-only</code>, <code>:read-write</code>, <code>:placeholder-shown</code>, <code>:default</code>, <code>:checked</code>, <code>:indeterminate</code>, <code>:valid</code>, <code>:invalid</code>, <code>:in-range</code>, <code>:out-of-range</code>, <code>:required</code> et <code>:optional</code>.</p><p>Résolvons l'un des cas d'utilisation que j'ai décrits dans l'introduction — le besoin de longue date de styler une étiquette de formulaire en fonction de l'état du champ de saisie. Commençons par un formulaire de base.</p><pre class="language-html">&lt;form&gt;
  &lt;div&gt;
    &lt;label for="name"&gt;Nom&lt;/label&gt;
    &lt;input type="text" id="name" /&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;label for="site"&gt;Site web&lt;/label&gt;
    &lt;input type="url" id="site" /&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;label for="email"&gt;Email&lt;/label&gt;
    &lt;input type="email" id="email" /&gt;
  &lt;/div&gt;
&lt;/form&gt;</pre><p>J'aimerais appliquer un arrière-plan à l'ensemble du formulaire lorsque l'un des champs est en focus.</p><pre class="language-css">form:has(:focus-visible) {
  background: antiquewhite;
}</pre><p>J'aurais pu utiliser <code>form:focus-within</code> à la place, mais cela se comporterait comme <code>form:has(:focus)</code>. <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:focus">La pseudo-classe <code>:focus</code></a> applique toujours le CSS lorsqu'un champ est en focus. <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:focus-visible">La pseudo-classe <code>:focus-visible</code></a> fournit un moyen fiable de styler un indicateur de focus uniquement lorsque le navigateur en dessinerait un nativement, en utilisant <a href="https://webkit.org/blog/12179/the-focus-indicated-pseudo-class-focus-visible/">la même heuristique complexe que le navigateur</a> utilise pour déterminer s'il faut ou non appliquer un anneau de focus.</p><p>Maintenant, imaginons que je veuille styler les autres champs, ceux qui ne sont pas en focus — en changeant la couleur du texte de leur étiquette et la couleur de la bordure de l'entrée. Avant <code>:has()</code>, cela nécessitait JavaScript. Maintenant, nous pouvons utiliser ce CSS.</p><pre class="language-css">form:has(:focus-visible) div:has(input:not(:focus-visible)) label {
  color: peru;
}
form:has(:focus-visible) div:has(input:not(:focus-visible)) input {
  border: 2px solid peru;
}</pre><p>Que dit ce sélecteur ? Si l'un des contrôles de ce formulaire a le focus, et que l'élément d'entrée de ce contrôle de formulaire particulier n'a pas le focus, alors change la couleur du texte de cette étiquette en <code>peru</code>. Et change la bordure du champ de saisie pour qu'elle soit <code>2px solid peru</code>.</p><p>Vous pouvez voir ce code en action dans la démo suivante en cliquant à l'intérieur d'un des champs de texte. L'arrière-plan du formulaire change, comme je l'ai décrit précédemment. Et les couleurs de l'étiquette et de la bordure de saisie des champs qui ne sont pas en focus changent également.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/jensimmons/pen/BarwGpV">:has() Demo #4 — Form fields</a>de jensimmons dans<a href="https://codepen.io">CodePen</a></div><p>Dans cette même démo, j'aimerais aussi améliorer l'avertissement à l'utilisateur lorsqu'il y a une erreur dans la façon dont il a rempli le formulaire. Depuis longtemps déjà, nous pouvons facilement mettre un encadré rouge autour d'une entrée invalide avec ce CSS.</p><pre class="language-css">input:invalid {
  outline: 4px solid red;
  border: 2px solid red;
}</pre><p>Maintenant, avec <code>:has()</code>, nous pouvons également rendre le texte de l'étiquette rouge :</p><pre class="language-css">div:has(input:invalid) label {
  color: red;
}</pre><p>Vous pouvez voir le résultat en tapant quelque chose dans le champ du site Web ou de l'adresse électronique qui n'est pas une URL ou une adresse électronique entièrement formée. Les deux sont invalides et déclenchent donc une bordure rouge et une étiquette rouge, avec un "X".</p><h2>Basculement en mode sombre sans JS</h2><p>Et enfin, dans cette même démo, j'utilise une case à cocher pour permettre à l'utilisateur de basculer entre un thème clair et un thème foncé.</p><pre class="language-css">body:has(input[type='checkbox']:checked) {
  background: blue;
  --primary-color: white;
}
body:has(input[type='checkbox']:checked) form {
  border: 4px solid white;
}
body:has(input[type='checkbox']:checked) form:has(:focus-visible) {
  background: navy;
}
body:has(input[type='checkbox']:checked) input:focus-visible {
  outline: 4px solid lightsalmon;
}</pre><p>J'ai stylé la case à cocher du mode sombre à l'aide de styles personnalisés, mais elle ressemble toujours à une case à cocher. Avec des styles plus complexes, je pourrais <a href="https://codepen.io/jemin/pen/RwaqNoz?editors=1100">créer une bascule (toggle) en CSS</a>.</p><p>De la même façon, je pourrais utiliser un menu de sélection pour proposer à un utilisateur <a href="https://adactio.com/about/site/">plusieurs thèmes</a> pour mon site.</p><pre class="language-css">body:has(option[value='pony']:checked) {
  --font-family: cursive;
  --text-color: #b10267;
  --body-background: #ee458e;
  --main-background: #f4b6d2;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/jensimmons/pen/vYdKKbL">:has() Demo #5 — Theme picker via Select</a>de jensimmons dans<a href="https://codepen.io">CodePen</a></div><p>Chaque fois qu'il y a une occasion d'utiliser CSS au lieu de JavaScript, je la saisis. Cela permet d'obtenir une expérience plus rapide et un site Web plus robuste. JavaScript peut faire des choses incroyables, et nous devrions l'utiliser quand c'est le bon outil pour le travail. Mais si nous pouvons obtenir le même résultat en utilisant uniquement HTML et CSS, c'est encore mieux.</p><h2>Et plus encore</h2><p>En regardant <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Pseudo-classes">les autres pseudo-classes</a>, il y en a tellement qui peuvent être combinées avec <code>:has()</code>. Imaginez les possibilités avec <code>:nth-child</code>, <code>:nth-last-child</code>, <code>:first-child</code>, <code>:last-child</code>, <code>:only-child</code>, <code>:nth-of-type</code>, <code>:nth-last-of-type</code>, <code>:first-of-type</code>, <code>:last-of-type</code>, <code>:only-of-type</code>. <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:modal">La toute nouvelle pseudo-classe <code>:modal</code></a> est déclenchée lorsqu'un dialogue est dans l'état ouvert. Avec <code>:has(:modal)</code>, vous pouvez donner un style à n'importe quoi dans le DOM selon que le dialogue est ouvert ou fermé.</p><p>Cependant, toutes les pseudo-classes ne sont pas actuellement prises en charge dans <code>:has()</code> dans tous les navigateurs, alors testez votre code dans plusieurs navigateurs. Actuellement, les pseudo-classes dynamiques de médias ne fonctionnent pas, comme <code>:playing</code>, <code>:paused</code>, <code>:muted</code>, etc. Elles pourraient très bien fonctionner à l'avenir, alors si vous lisez ceci dans quelques temps, testez-les ! De plus, la prise en charge de l'invalidation des formulaires est actuellement absente dans certaines situations spécifiques, donc les changements d'état dynamiques de ces pseudo-classes peuvent ne pas être mis à jour avec <code>:has()</code>.</p><p>Safari 16 ajoutera la prise en charge de <code>:has(:target)</code>, ce qui ouvrira des possibilités intéressantes pour écrire du code qui recherche dans l'URL actuelle un fragment correspondant à l'ID d'un élément spécifique. Par exemple, si un utilisateur clique sur une table des matières en haut d'un document et descend jusqu'à la section de la page correspondant à ce lien, <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:target"><code>:target</code> permet de styler ce contenu de manière unique</a>, en se basant sur le fait que l'utilisateur a cliqué sur le lien pour y arriver. Et <code>:has()</code> ouvre la voie aux possibilités d'un tel style.</p><p><strong>À noter : le groupe de travail CSS <a href="https://github.com/w3c/csswg-drafts/issues/7463">a décidé</a> d'interdire tous les pseudo-éléments existants à l'intérieur de :has()</strong>. Par exemple, article:has(p::first-line) et ol:has(li::marker) ne fonctionneront pas. Idem pour ::before et ::after.</p><h2>La révolution :has()</h2><p>C'est une petite révolution dans la façon d'écrire les sélecteurs CSS, qui ouvre un monde de possibilités jusqu'alors impossibles ou souvent sans intérêt. On a l'impression que même si nous reconnaissons immédiatement l'utilité de <code>:has()</code>, nous n'avons aucune idée de ce qui est vraiment possible. Au cours des prochaines années, les personnes qui réalisent des démonstrations et se plongent dans ce que CSS peut faire trouveront des idées incroyables, étirant <code>:has()</code> jusqu'à ses limites.</p><p>Michelle Barker a créé <a href="https://codepen.io/michellebarker/pen/vYRVbQX?editors=1100">une démo fantastique</a> qui déclenche l'animation des tailles de pistes d'une grille css grâce à l'utilisation de <code>:has()</code> et des états de survol. Vous pouvez en savoir plus à ce sujet dans <a href="https://css-irl.info/animated-grid-tracks-with-has/">son article de blog</a>. La prise en charge des pistes de grille animées sera disponible dans <a href="https://webkit.org/blog/12824/news-from-wwdc-webkit-features-in-safari-16-beta/">Safari 16</a>. Vous pouvez essayer cette démo aujourd'hui dans <a href="https://developer.apple.com/safari/resources/">Safari Technology Preview</a> ou Safari 16 beta.</p><p><strong>La partie la plus difficile de <code>:has()</code> sera d'ouvrir nos esprits à ses possibilités. Nous nous sommes tellement habitués aux limites que nous impose l'absence de sélecteur de parent. Nous devons maintenant briser ces habitudes</strong>.</p><p>C'est aussi une raison supplémentaire d'utiliser le CSS pur sucre, et de ne pas se limiter aux classes définies dans un framework. En écrivant votre propre CSS, personnalisé pour votre projet, vous pouvez tirer pleinement parti de toutes les puissantes capacités des navigateurs d'aujourd'hui.</p><p>À quoi allez-vous utiliser <code>:has()</code> ? En décembre dernier, j'ai <a href="https://twitter.com/jensimmons/status/1474060698124697606">demandé sur Twitter</a> quels cas d'utilisation les gens pourraient avoir pour <code>:has()</code>, et j'ai reçu de nombreuses réponses avec des idées incroyables. J'ai hâte de voir les vôtres.</p></div>]]></description>
      <link>https://la-cascade.io/articles/utiliser-css-has</link>
      <guid>https://la-cascade.io/articles/utiliser-css-has</guid>
      <pubDate>Thu, 25 Aug 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Zoomer les images dans une grille]]></title>
      <description><![CDATA[<p><em>Temani Afif ajoute un effet de survol aux images dans une grille implicite, pas si simple, mais Temani a le don rare de décortiquer les pbs pour les résoudre simplement.</em></p><div class="articleContent"><p>Il est facile de créer une grille d'images, grâce à <a href="https://la-cascade.io/tags/cssgrid">CSS Grid</a>. Mais il n'est pas toujours évident de faire des choses amusantes avec la grille une fois les images placées.</p><p>Par exemple, vous voulez ajouter un effet de survol aux images pour qu'elles grandissent et s'agrandissent au-delà des rangées et des colonnes où elles se trouvent ? Nous pouvons le faire !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/MWVyaMe">CSS grid with expandable images</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Cool, non ? Si vous vérifiez le code, vous ne trouverez pas de JavaScript, ni de sélecteurs complexes, ni même de <a href="https://css-tricks.com/magic-numbers-in-css/">chiffres magiques</a>. Et ce n'est qu'un exemple parmi tant d'autres que nous allons explorer !</p><h2>Création de la grille</h2><p>Le code HTML pour créer la grille est aussi simple qu'une liste d'images dans un conteneur. Nous n'avons pas besoin de plus que cela.</p><pre class="language-html">&lt;div class="gallery"&gt;
  &lt;img /&gt;
  &lt;img /&gt;
  &lt;img /&gt;
  &lt;!-- etc. --&gt;
&lt;/div&gt;</pre><p>Pour le CSS, nous commençons par définir la grille en utilisant ce qui suit :</p><pre class="language-css">.gallery {
  --s: 150px; /* contrôle la taille */
  --g: 10px; /* contrôle les gouttières (gap) */
  display: grid;
  gap: var(--g);
  width: calc(
    3 * var(--s) + 2 * var(--g)
  ); /* 3 fois la taille plus 2 fois la gouttière */
  aspect-ratio: 1;
  grid-template-columns: repeat(3, auto);
}</pre><p>En résumé, nous avons deux variables, l'une qui contrôle la taille des images et l'autre qui définit la taille de l'espace entre les images. L'<a href="https://css-tricks.com/almanac/properties/a/aspect-ratio/">aspect-ratio</a> permet de garder les choses en proportion.</p><p>Vous vous demandez peut-être pourquoi nous ne définissons que trois colonnes et aucune rangée. Non, je n'ai pas oublié les rangées, mais nous n'avons pas besoin de les définir explicitement. CSS Grid est capable de <a href="https://la-cascade.io/articles/css-grid-grille-implicite-et-placement-automatique">placer automatiquement des éléments sur des rangées et des colonnes implicites</a>, ce qui signifie qu'il nous fournit autant de rangées que nécessaire, quel que soit le nombre d'images que nous lui envoyons. Nous pouvons définir explicitement les rangées si nous le voulons, mais dans ce cas nous devons ajouter <code>grid-auto-flow : column</code> pour nous assurer que le navigateur créera les colonnes nécessaires pour nous.</p><p>Voici un exemple pour illustrer les deux cas. La différence est que l'un suit un flux dans le sens des rangées et l'autre dans le sens des colonnes.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/GRxZVyL">difference between row/column</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Maintenant que notre grille est en place, il est temps d'ajouter un peu de style à nos images :</p><pre class="language-css">.gallery &gt; img {
  width: 0;
  height: 0;
  min-height: 100%;
  min-width: 100%;
  object-fit: cover;
}</pre><p>L'effet de survol que nous réalisons repose sur ce CSS. Il vous semblera probablement étrange que nous créions des images sans largeur ni hauteur, mais avec une largeur et une hauteur minimales de 100 %. Mais vous verrez qu'il s'agit d'une astuce assez pratique pour ce que nous essayons de réaliser.</p><p>Ce que je fais ici, c'est dire au navigateur que les images doivent avoir une largeur et une hauteur nulles, mais qu'elles doivent aussi avoir une hauteur minimale égale à 100 %... mais 100 % de quoi ? Lorsqu'on utilise des pourcentages, la valeur est <em><a href="https://css-tricks.com/its-all-relative/">relative à quelque chose d'autre</a></em>. Dans notre cas, l'image est placée à l'intérieur d'une <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/#gridcell">cellule de la grille</a> et nous devons connaître sa taille pour savoir à quoi correspond le pourcentage de 100 %.</p><p>Le navigateur ignorera d'abord la valeur <code>min-height : 100%</code> pour calculer la taille des cellules de la grille, mais il utilisera la valeur <code>height : 0</code> dans son calcul. Cela signifie que nos images ne contribueront pas à la taille des cellules de la grille... <em>car elles n'ont techniquement aucune taille physique</em>. Il en résultera trois colonnes et rangées égales basées sur la taille de la grille (que nous avons définie sur la largeur et le ratio d'aspect de la galerie). La hauteur de chaque cellule de la grille n'est rien d'autre que la variable <code>--s</code> que nous avons définie tout à l'heure (idem pour la largeur).</p><figure><img src="https://la-cascade.io/images/grid_cells.webp" alt="" /></figure><p>Maintenant que nous avons les dimensions des cellules de notre grille, le navigateur va l'utiliser avec <code>min-height : 100%</code> (et <code>min-width : 100%</code>) ce qui va forcer les images à remplir complètement l'espace de chaque cellule de la grille. Tout cela peut sembler un peu confus, mais l'idée principale est de s'assurer que la grille définit la taille des images plutôt que l'inverse. Je ne veux pas que l'image définisse la taille de la grille et vous comprendrez pourquoi lorsque nous aurons ajouté l'effet de survol.</p><h2>Création de l'effet au survol</h2><p>Ce que nous devons faire, c'est augmenter l'échelle des images lorsqu'elles sont survolées. Pour ce faire, nous pouvons ajuster la largeur et la hauteur de l'image au moment du <code>:hover</code> :</p><pre class="language-css">.gallery {
  --f: 1.5; /* contrôle le facteur d'échelle */
}
.gallery img:hover {
  width: calc(var(--s) * var(--f));
  height: calc(var(--s) * var(--f));
}</pre><p>J'ai ajouté une nouvelle variable personnalisée, <code>--f</code>, au mélange comme facteur d'échelle pour contrôler la taille au survol. Remarquez que je multiplie la variable de taille, <code>--s</code>, par celle-ci pour calculer la nouvelle taille de l'image.</p><blockquote>
<p><em>Mais tu avais dit que la taille de l'image doit être de 0. Que se passe-t-il ? Je suis perdu...</em></p>
</blockquote><p>Ce que j'ai dit reste vrai, mais je fais une exception pour l'image survolée. Je dis au navigateur qu'une seule image aura une taille différente de zéro — elle contribuera donc à la dimension de la grille — tandis que toutes les autres resteront égales à 0.</p><figure><img src="https://la-cascade.io/images/two-grids.webp" alt="" /></figure><p>La partie gauche montre la grille dans son état naturel, sans aucune image survolée, ce que montre la partie droite. Toutes les cellules de la grille sur le côté gauche sont de taille égale puisque toutes les images n'ont pas de dimensions physiques.</p><p>Sur le côté droit, la deuxième image de la première rangée est survolée, ce qui lui donne des dimensions qui affectent la taille de la cellule de la grille. Le navigateur agrandit cette cellule de grille spécifique au survol, ce qui contribue à la taille globale. Et comme la taille de l'ensemble de la grille est définie (puisque nous avons défini une largeur fixe pour la <code>.galerie</code>), les autres cellules de la grille vont logiquement répondre en devenant plus petites afin de conserver la taille globale de la <code>.galerie</code>.</p><p>C'est notre effet de zoom en action ! En augmentant la taille d'une seule image, nous affectons l'ensemble de la configuration de la grille, et nous avons dit précédemment que la grille définit la taille des images de sorte que chaque image s'étire dans sa cellule de grille pour remplir tout l'espace.</p><p>À cela, nous ajoutons une touche de transition et utilisons <a href="https://la-cascade.io/articles/utiliser-css-object-fit">objet-fit</a> pour éviter la distorsion des images et l'illusion est parfaite !</p><p>Je sais que la logique de cette astuce n'est pas facile à comprendre. Ne vous inquiétez pas si vous ne la comprenez pas complètement. Le plus important est de comprendre la structure du code utilisé et comment le modifier pour obtenir plus de variations. C'est ce que nous allons faire maintenant !</p><h2>Ajout d'images supplémentaires</h2><p>Nous avons créé une grille 3×3 pour expliquer l'astuce principale, mais vous avez deviné que nous n'avions pas besoin de nous arrêter là. Nous pouvons faire varier le nombre de colonnes et de rangées et ajouter autant d'images que nous le souhaitons.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/abYNPaG">Variable columns/rows</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><pre class="language-css">.gallery {
  --n: 3; /* nombre de lignes*/
  --m: 4; /* nombre de colonnes */
  --s: 150px; /* contrôle de la taille */
  --g: 10px; /* contrôle des gouttières */
  --f: 1.5; /* contrôle le facteur d'échelle */
  display: grid;
  gap: var(--g);
  width: calc(var(--m) * var(--s) + (var(--m) - 1) * var(--g));
  height: calc(var(--n) * var(--s) + (var(--n) - 1) * var(--g));
  grid-template-columns: repeat(var(--m), auto);
}</pre><p>Nous avons deux nouvelles variables pour le nombre de lignes et de colonnes. Ensuite, nous définissons simplement la largeur et la hauteur de notre grille en les utilisant. Même chose pour <code>grid-template-columns</code> qui utilise la variable <code>--m</code>. Et comme précédemment, nous n'avons pas besoin de définir explicitement les rangées puisque la fonction de placement automatique de la grille CSS fera le travail pour nous, quel que soit le nombre d'éléments d'image que nous utilisons.</p><p>Pourquoi pas des valeurs différentes pour la largeur et la hauteur ? Nous pouvons le faire :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/ExEKGGL">Variable width/height</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><pre class="language-css">.gallery {
  --n: 3; /* nombre de rangées*/
  --m: 4; /* nombre de colonnes */
  --h: 120px; /* contrôle de la hauteur */
  --w: 150px; /* contrôle la largeur */
  --g: 10px; /* contrôle des gouttières */
  --f: 1.5; /* contrôle le facteur d'échelle */
  display: grid;
  gap: var(--g);
  width: calc(var(--m) * var(--w) + (var(--m) - 1) * var(--g));
  height: calc(var(--n) * var(--h) + (var(--n) - 1) * var(--g));
  grid-template-columns: repeat(var(--m), auto);
}
.gallery img:hover {
  width: calc(var(--w) * var(--f));
  height: calc(var(--h) * var(--f));
}</pre><p>Nous remplaçons <code>--s</code> par deux variables, une pour la largeur, <code>--w</code>, et une autre pour la hauteur, <code>--h</code>. Puis nous ajustons tout le reste en conséquence.</p><p>Nous avons donc commencé par une grille avec une taille et un nombre d'éléments fixes, mais nous avons ensuite créé un nouvel ensemble de variables pour obtenir la configuration que nous voulons. Tout ce que nous avons à faire est d'ajouter autant d'images que nous le souhaitons et d'ajuster les variables CSS en conséquence. Les combinaisons sont illimitées !</p><h2>Une galerie d'images en plein écran</h2><p>Et pourquoi pas une version plein écran ? Oui, c'est également possible. Tout ce dont nous avons besoin c'est de savoir quelles valeurs nous devons attribuer à nos variables. Si nous voulons N rangées d'images et que nous voulons que notre grille soit en plein écran, nous devons d'abord résoudre une hauteur de <code>100vh</code> :</p><pre class="language-css">var(--n) * var(--h) + (var(--n) - 1) * var(--g) = 100vh</pre><p>Même logique pour la largeur, mais en utilisant <code>vw</code> au lieu de <code>vh</code> :</p><pre>var(--m) * var(--w) + (var(--m) - 1) * var(--g) = 100vw</pre><p>On fait le calcul pour obtenir :</p><pre class="language-css">--w : (100vw - (var(--m) - 1) * var(--g)) / var(--m)
--h : (100vh - (var(--n) - 1) * var(--g)) / var(--n)</pre><p>C'est fait !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/eYMZbwy">Full screen grid</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Il s'agit exactement du même code HTML, mais avec quelques variables mises à jour qui modifient la taille et le comportement de la grille.</p><p>Notez que j'ai omis la formule que nous avions précédemment définie pour la largeur et la hauteur du <code>.gallery</code> et que je l'ai remplacée par <code>100vw</code> et <code>100vh</code>, respectivement. La formule nous donnera le même résultat mais comme nous savons quelle valeur nous voulons, nous pouvons nous débarrasser de toute cette complexité supplémentaire.</p><p>Nous pouvons également simplifier les formules <code>--h</code> et <code>--w</code> en supprimant la gouttière de l'équation en faveur de ceci :</p><pre class="language-css">--h: calc(
  100vh / var(--n)
); /* Hauteur de la fenêtre divisée par le nombre de rangées */
--w: calc(
  100vw / var(--m)
); /* Largeur de la fenêtre divisée par le nombre de colonnes */</pre><p>L'image survolée sera donc un peu plus grande que dans l'exemple précédent, mais ce n'est pas grave puisque nous pouvons contrôler l'échelle avec la variable <code>--f</code> que nous utilisons comme multiplicateur.</p><p>Et puisque les variables sont utilisées à un seul endroit, nous pouvons encore simplifier le code en les supprimant complètement :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/eYMZxYV">Simplifying the formula #2</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Il est important de noter que cette optimisation s'applique uniquement à l'exemple en plein écran et non aux exemples que nous avons couverts. Cet exemple est un cas particulier où nous pouvons alléger le code en supprimant une partie du travail de calcul complexe dont nous avions besoin dans les autres exemples.</p><p>Nous disposons en fait de tout ce dont nous avons besoin pour créer le modèle populaire de panneaux extensibles :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/WNzxeOO">One dimension grid</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><h2>Creusons encore plus profond</h2><p>Avez-vous remarqué que notre facteur d'échelle peut être inférieur à 1 ? Nous pouvons définir la taille de l'image survolée comme étant inférieure à <code>--h</code> ou <code>--w</code>, mais l'image s'agrandit au survol.</p><p>La taille initiale de la cellule de la grille est égale à <code>--w</code> et <code>--h</code>, alors pourquoi une valeur plus petite rend-elle la cellule de la grille plus grande ? La cellule ne devrait-elle pas devenir plus petite, ou au moins conserver sa taille initiale ? Et quelle est la taille finale de la cellule de la grille ?</p><p>Nous devons approfondir la manière dont l'algorithme CSS Grid calcule la taille des cellules de la grille. Et cela implique de comprendre l'alignement extensible (<em>stretch alignment</em>) par défaut de CSS Grid.</p><p>Voici un exemple pour comprendre la logique.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/YzaWKYX/e4ecf08477c67eb6406a99b10653ee0e">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Dans la partie gauche de la démo, j'ai défini une double colonne avec une largeur automatique. Nous obtenons le résultat intuitif : deux colonnes égales (et deux cellules de grille égales). Mais la grille que j'ai définie sur le côté droit de la démo, où je mets à jour l'alignement à l'aide de <code>place-content : start</code>, semble ne rien avoir.</p><p>DevTools nous aide en montrant ce qui se passe réellement dans les deux cas :</p><figure><img src="https://la-cascade.io/images/dt-grids1.webp" alt="" /></figure><p>Dans la deuxième grille, nous avons deux colonnes, mais leurs largeurs sont égales à zéro, de sorte que nous obtenons deux cellules de grille qui sont effondrées dans le coin supérieur gauche du conteneur de la grille. Il ne s'agit pas d'un bogue mais du résultat logique de l'alignement de la grille. Lorsque nous dimensionnons une colonne (ou une rangée) avec <code>auto</code>, cela signifie que c'est son contenu qui dicte sa taille — mais nous avons une <code>div</code> vide sans contenu à placer.</p><p>Cependant, comme l'alignement par défaut est l'alignement <code>stretch</code> et que nous avons suffisamment d'espace à l'intérieur de notre grille, le navigateur va étirer les deux cellules de la grille de manière égale pour couvrir toute cette zone. C'est ainsi que la grille de gauche se retrouve avec deux colonnes égales.</p><p>Extrait de la <a href="https://www.w3.org/TR/css-grid-1/#grid-align">spécification</a> :</p><blockquote>
<p><em>Notez que certaines valeurs de <a href="https://www.w3.org/TR/css-align-3/#propdef-justify-content">justify-content</a> et <a href="https://www.w3.org/TR/css-align-3/#propdef-align-content">align-content</a> peuvent entraîner l'espacement des pistes (<a href="https://www.w3.org/TR/css-align-3/#valdef-align-content-space-around">space-around</a>, <a href="https://www.w3.org/TR/css-align-3/#valdef-align-content-space-between">space-between</a>, <a href="https://www.w3.org/TR/css-align-3/#valdef-align-content-space-evenly">space-evenly</a>) ou leur redimensionnement (<a href="https://www.w3.org/TR/css-align-3/#valdef-align-content-stretch">stretch</a>)</em>.</p>
</blockquote><p>Notez le mot "redimensionner" qui est la clé ici. Dans le dernier exemple, j'ai utilisé <code>place-content</code>, qui est l'abréviation de <code>justify-content</code> et <code>align-content</code>.</p><p>Et ceci est caché quelque part dans les spécifications de l'<a href="https://www.w3.org/TR/css-grid-1/#algo-stretch">algorithme de redimensionnement de la grille</a> :</p><blockquote>
<p><em>Cette étape développe les pistes qui ont une fonction de <a href="https://www.w3.org/TR/css-grid-1/#max-track-sizing-function">dimensionnement de piste max</a> automatique en divisant tout <a href="https://www.w3.org/TR/css-grid-1/#free-space">espace libre</a> positif et <a href="https://www.w3.org/TR/css-sizing-3/#definite">défini</a> restant</em> de manière égale entre elles. <em>Si l'espace libre est <a href="https://www.w3.org/TR/css-sizing-3/#indefinite">indéfini</a>, mais que le <a href="https://www.w3.org/TR/css-grid-1/#grid-container">conteneur de la grille</a> a une <a href="https://www.w3.org/TR/CSS2/visudet.html#propdef-min-width">largeur/hauteur minimale</a> définie, utilisez cette taille pour calculer l'espace libre pour cette étape</em>.</p>
</blockquote><p>L'expression "de manière égale" explique pourquoi nous nous retrouvons avec des cellules de grille égales, mais elle s'applique à "l'espace libre", qui est très important.</p><p>Reprenons l'exemple précédent et ajoutons du contenu à l'une des <code>div</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/YzaWKLy/fafb5ed1e0f73bb07f99bbd8feca8c1a">Untitled</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div><p>Nous avons ajouté une image carrée de 50px. Voici une illustration de la façon dont chaque grille de notre exemple réagit à cette image :</p><figure><img src="https://la-cascade.io/images/dt-grids2.webp" alt="" /></figure><p>Dans le premier cas, nous pouvons voir que la première cellule (en rouge) est plus grande que la seconde (en bleu). Dans le deuxième cas, la taille de la première cellule change pour s'adapter à la taille physique de l'image tandis que la deuxième cellule reste sans dimension. L'espace libre est divisé de manière égale, mais la première cellule a plus de contenu, ce qui la rend plus grande.</p><p>Voici le calcul pour déterminer notre espace libre :</p><pre class="language-css">(largeur de la grille) - (espace) - (largeur de l'image) = (espace libre)
200px - 5px - 50px = 145px</pre><p>Divisé par deux — le nombre de colonnes — nous obtenons une largeur de 72,5px pour chaque colonne. Mais nous ajoutons la taille de l'image, 50px, à la première colonne, ce qui nous laisse une colonne de 122,5px et la seconde de 72,5px.</p><p>La même logique s'applique à notre grille d'images. Toutes les images ont une taille égale à 0 (aucun contenu), tandis que l'image survolée contribue à la taille — même si ce n'est que de 1px — rendant sa cellule de grille plus grande que les autres. Pour cette raison, le facteur d'échelle peut être n'importe quelle valeur supérieure à 0, même les décimales entre 0 et 1.</p><p>Pour obtenir la largeur finale des cellules de la grille, nous effectuons le même calcul pour obtenir ce qui suit :</p><pre>(largeur du conteneur) - (somme de tous les espaces) - (largeur de l'image survolée) = (espace libre)</pre><p>La largeur du conteneur est définie par :</p><pre class="language-css">var(--m)*var(--w) + (var(--m) - 1)*var(--g)</pre><p>...et tous les espaces libres sont égaux à :</p><pre class="language-css">(var(--m) - 1)*var(--g)</pre><p>...et pour l'image survolée nous avons :</p><pre class="language-css">var(--w)*var(--f)</pre><p>Nous pouvons calculer tout cela avec nos variables :</p><pre class="language-css">var(--m)*var(--w) - var(--w)*var(--f) = var(--w)*(var(--m) - var(--f))</pre><p>Le nombre de colonnes est défini par <code>--m</code> ,donc nous divisons cet espace libre de manière égale pour obtenir :</p><pre class="language-css">var(--w)*(var(--m) - var(--f))/var(--m)</pre><p>...ce qui nous donne la taille des images non survolées. Pour les images survolées, nous avons ceci :</p><pre class="language-css">var(--w)*(var(--m) - var(--f))/var(--m) + var(--w)*var(--f)
var(--w)*((var(--m) - var(--f))/var(--m) + var(--f))</pre><p>Si nous voulons contrôler la taille finale de l'image survolée, nous utilisons la formule ci-dessus pour obtenir la taille exacte que nous voulons. Si, par exemple, nous voulons que l'image soit deux fois plus grande :</p><pre class="language-css">(var(--m) - var(--f))/var(--m) + var(--f) = 2</pre><p>Ainsi, la valeur de notre multiplicateur d'échelle, <code>--f</code>, doit être égale à :</p><pre class="language-css">var(--m)/(var(--m) - 1)</pre><p>Pour trois colonnes, nous aurons 3/2 = 1,5 et c'est le facteur d'échelle que j'ai utilisé dans la première démo de cet article car je voulais que l'image soit deux fois plus grande au survol !</p><p>La même logique s'applique au calcul de la hauteur et dans le cas où nous voulons contrôler les deux indépendamment, nous devrons considérer deux facteurs d'échelle pour nous assurer que nous avons une largeur et une hauteur spécifiques au survol.</p><pre class="language-css">.gallery {
  /* même chose que précédemment */
  --fw: 1.5; /* contrôle le facteur d'échelle pour la largeur */
  --fh: 1.2; /* contrôle le facteur d'échelle pour la hauteur */
  /* même chose qu'avant */
}
.gallery img:hover {
  width: calc(var(--w) * var(--fw));
  height: calc(var(--h) * var(--fh));
}</pre><p>Vous connaissez maintenant tous les secrets pour créer n'importe quel type de grille d'images avec un effet de survol cool, tout en contrôlant la taille que vous souhaitez à l'aide des calculs que nous venons de voir.</p><h2>Conclusion</h2><p>Dans mon <a href="https://la-cascade.io/articles/css-grid-grille-implicite-et-placement-automatique">dernier article</a>, nous avons créé une grille d'aspect complexe avec quelques lignes de CSS qui mettaient à profit les fonctionnalités de grille implicite et de placement automatique de CSS Grid. Dans cet article, nous nous sommes appuyés sur une astuce de dimensionnement de CSS Grid pour créer une grille fantaisiste dans laquelle les images s'agrandissent au survol de l'écran, entraînant l'ajustement de la grille en conséquence. Tout cela avec un code simplifié et facile à ajuster à l'aide de variables CSS !</p><p>Dans le prochain article, nous allons jouer avec les formes ! Nous allons combiner la grille CSS avec <code>mask</code> et <code>clip-path</code> pour obtenir une grille d'images originale.</p></div>]]></description>
      <link>https://la-cascade.io/articles/zoomer-les-images-dans-une-grille</link>
      <guid>https://la-cascade.io/articles/zoomer-les-images-dans-une-grille</guid>
      <pubDate>Tue, 09 Aug 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Grid : grille implicite et placement automatique]]></title>
      <description><![CDATA[<p>Lorsqu'on travaille avec <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet">CSS Grid</a>, la première chose à faire est de définir <code>display : grid</code> sur l'<a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#griditem">élément</a> (<em>item</em>) qui doit devenir un <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridcontainer">conteneur</a> de grille. Ensuite, on définit explicitement la grille en utilisant une combinaison de <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gtc">grid-template-columns, grid-template-rows</a> et <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gta">grid-template-areas</a>. Et à partir de là, l'étape suivante consiste à placer les éléments à l'intérieur de la grille.</p><p>C'est l'approche classique à utiliser et je la recommande également. Cependant, il existe une autre approche pour créer des grilles <strong>sans définition explicite</strong>. Nous l'appelons <strong>la grille implicite</strong>.</p><p>En clair, le navigateur génère automatiquement des rangées et des colonnes supplémentaires si des éléments sont placés en dehors de la grille définie.</p><p>Tout comme le concept de grille implicite, l'<a href="https://www.w3.org/TR/css-grid-1/#common-uses-auto-placement">auto-placement</a> est la capacité du navigateur à placer automatiquement les éléments à l'intérieur de la grille. Nous n'avons pas toujours besoin de donner la position de chaque élément.</p><p>A travers différents cas d'utilisation, nous allons voir comment ces fonctionnalités peuvent nous aider à créer des grilles complexes et dynamiques avec quelques lignes de code.</p><p>Ici, nous avons trois mises en page différentes, mais nous n'avons qu'une seule configuration de grille qui fonctionne pour toutes.</p><p>Une seule colonne occupe tout l'espace libre. Il s'agit de notre grille "explicite". Elle est configurée pour contenir un élément de la grille dans le conteneur principal de la grille. C'est tout. Une colonne et une rangée :</p><p>Mais que se passerait-il si nous décidions d'y déposer un autre élément, disons un <code>aside</code> (notre barre latérale dynamique). Telle qu'elle est actuellement (et explicitement) définie, notre grille devra s'ajuster automatiquement pour trouver un emplacement pour cet élément. Et si nous ne faisons rien d'autre avec notre CSS, voici ce que DevTools nous dit qu'il se passe.</p><div><img src="https://la-cascade.io/images/implicit-grid-tracks.webp" alt="" /><figure><p>L'élement 1 prend toute la colonne explicitement définie dans le container et le 2e se place sur une nouvelle rangée entre les lignes de grille implicites étiquetées 2 et 3. Notez que j'utilise un espace de 20px pour aider à séparer les choses visuellement.</p>
</figure><p>Nous pouvons déplacer le <code>&lt;aside&gt;</code> vers une colonne à côté de la <code>&lt;section&gt;</code> :</p>
<pre class="language-css">aside {
  grid-column-start: 2;
}</pre>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/geoffgraham/pen/PoRpZbj">untitled</a>de Geoff Graham dans<a href="https://codepen.io">CodePen</a></div>
<p>Et voici ce que nous dit maintenant DevTools :</p>
<figure role="group"><img src="https://la-cascade.io/images/implcit-grid-column.webp" alt="" /><figcaption>L'élément se trouve entre la première et la deuxième ligne de colonne de la grille. Il commence à la deuxième ligne de colonne de la grille et se termine à une troisième ligne que nous n'avons jamais déclarée.</figcaption></figure><p>Nous plaçons notre élément dans la deuxième colonne mais... attendez, nous n'avons pas de deuxième colonne ! C'est bizarre, non ? Nous n'avons jamais déclaré de deuxième colonne sur le conteneur de grille <code>&lt;main&gt;</code>, mais le navigateur en a créé une pour nous ! C'est la partie-clé de la spécification que nous avons examinée :</p>
<blockquote>
<p><em>Lorsque les éléments de la grille sont positionnés en dehors de ces limites, le conteneur de grille génère des pistes de grille implicites en ajoutant des lignes de grille implicites à la grille.</em></p>
</blockquote>
<p>Cette puissante fonctionnalité nous permet d'avoir des mises en page dynamiques. Si nous avons seulement l'élément <code>&lt;section&gt;</code>, tout ce que nous obtenons est une colonne. Mais si nous ajoutons un élément <code>&lt;aside&gt;</code> au mélange, une colonne supplémentaire est créée pour le contenir.</p>
<p>Nous pourrions placer l'élément <code>&lt;aside&gt;</code> avant l'élément <code>&lt;section&gt;</code> comme ceci :</p>
<pre class="language-css">aside {
  grid-column-end: -2;
}</pre>
<p>Cela crée la colonne implicite au début de la grille, contrairement au code précédent qui plaçait la colonne implicite à la fin.</p>
<figure role="group"><img src="https://la-cascade.io/images/explanation-image.webp" alt="" /><figcaption>Nous pouvons avoir une sidebar à gauche ou à droite.</figcaption></figure><p>Nous pouvons faire la même chose plus facilement en utilisant la propriété <code>grid-auto-flow</code> pour définir que toutes les pistes implicites s'écoulent (<em>flow</em>) dans une direction <code>column</code> :</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/bGvNxbW/c53c1762286176b403f5e59fc0493ee0">implicit grid #2</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Maintenant, il n'est plus nécessaire de spécifier <code>grid-column-start</code> pour placer l'élément <code>&lt;aside&gt;</code> à droite de la <code>&lt;section&gt;</code> ! En fait, tout autre élément de la grille que nous décidons d'y jeter à tout moment s'écoulera désormais dans le sens de la colonne, chacun étant placé dans ses propres pistes de grille implicites. Parfait pour les situations où le nombre d'éléments de la grille n'est pas connu à l'avance !</p>
<p>Cela dit, nous avons toujours besoin de <code>grid-column-end</code> si nous voulons le placer dans une colonne à sa gauche car, sinon, le <code>&lt;aside&gt;</code> occupera la colonne explicite qui, à son tour, pousse la <code>&lt;section&gt;</code> en dehors de la grille explicite et l'oblige à prendre la colonne implicite.</p>
<p>Je sais, je sais. C'est un peu alambiqué. Voici un autre exemple que nous pouvons utiliser pour mieux comprendre cette petite bizarrerie :</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/bGvNxNW/54fd420773f2335f049210994a4f5360">with/without grid-column-end</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Dans le premier exemple, nous n'avons pas spécifié de placement. Dans ce cas, le navigateur placera d'abord l'élément <code>&lt;aside&gt;</code> dans la colonne explicite puisqu'il vient en premier dans le DOM. L'élément <code>&lt;section&gt;</code>, quant à lui, est automatiquement placé dans la colonne de grille que le navigateur crée automatiquement (ou implicitement) pour nous.</p>
<p>Dans le deuxième exemple, nous plaçons l'élément <code>&lt;aside&gt;</code> en dehors de la grille explicite :</p>
<pre class="language-css">aside {
  grid-column-end: -2;
}</pre>
<p>Maintenant, il importe peu que <code>&lt;aside&gt;</code> vienne en premier dans le HTML. En réaffectant <code>&lt;aside&gt;</code> ailleurs, nous avons rendu l'élément <code>&lt;section&gt;</code> disponible pour prendre la colonne explicite.</p>
<h2 id="grille-dimages">Grille d'images</h2>
<p>Essayons quelque chose de différent avec une grille d'images où nous avons une grande image et quelques vignettes à côté (ou en-dessous).</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/xxLYLNW">Big Image + thumbnails</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Nous avons deux configurations de grille. Mais devinez quoi ? Je ne définis aucune grille du tout, nada ! Tout ce que je fais, c'est ça :</p>
<pre class="language-css">.grid img:first-child {
  grid-area: span 3 / span 3;
}</pre>
<p>Il est surprenant que nous n'ayons besoin que d'une seule ligne de code pour réaliser quelque chose comme ça, alors disséquons ce qui se passe et vous verrez que c'est plus facile que vous ne le pensez. Tout d'abord, <code>grid-area</code> est une propriété raccourcie qui combine les propriétés suivantes en une seule déclaration :</p>
<ul><li><code>grid-row-start</code></li>
<li><code>grid-row-end</code></li>
<li><code>grid-column-start</code></li>
<li><code>grid-column-end</code></li>
</ul><blockquote>
<p><em>Attendez ! <a href="https://css-tricks.com/simple-named-grid-areas/">grid-area</a> n'est-elle pas la propriété que nous utilisons pour définir des <a href="https://css-tricks.com/simple-named-grid-areas/">zones nommées</a> au lieu de l'endroit où les éléments commencent et finissent sur la grille ?</em></p>
</blockquote>
<p>Oui, mais elle fait plus. Nous pourrions écrire beaucoup de choses sur <code>grid-area</code>, mais dans ce cas particulier :</p>
<pre class="language-css">.grid img:first-child {
  grid-area: span 3 / span 3;
}
/* ...est équivalent à : */
.grid img:first-child {
  grid-row-start: span 3;
  grid-column-start: span 3;
  grid-row-end: auto;
  grid-column-end: auto;
}</pre>
<p>Nous pouvons constater la même chose en ouvrant DevTools pour développer la version abrégée :</p>
<figure><img src="https://la-cascade.io/images/devtools_image.webp" alt="" /></figure><p>Cela signifie que le premier élément image de la grille doit couvrir <strong>trois colonnes et trois rangées</strong>. Mais comme nous n'avons pas défini de colonnes ou de rangées, le navigateur le fait pour nous.</p>
<figure><img src="https://la-cascade.io/images/dog_image.webp" alt="" /></figure><p>Pour le dire simplement, nous avons placé la première image dans le HTML pour qu'elle occupe une grille de 3⨉3. Cela signifie que toutes les autres images seront placées automatiquement dans ces mêmes trois colonnes sans qu'il soit nécessaire de spécifier quoi que ce soit de nouveau.</p>
<figure><img src="https://la-cascade.io/images/dogs_image.webp" alt="" /></figure><p>En résumé, nous avons indiqué au navigateur que la première image devait occuper l'espace de trois colonnes et de trois rangées que nous n'avons jamais définies explicitement lors de la configuration du conteneur de grille. Le navigateur a défini ces colonnes et ces rangées pour nous. En conséquence, <strong>les autres images du HTML s'insèrent directement dans la grille en utilisant les mêmes trois colonnes et rangées</strong>. Et comme la première image occupe les trois colonnes de la première rangée, les autres images s'insèrent dans des rangées supplémentaires contenant chacune trois colonnes, où chaque image occupe une seule colonne.</p>
<p>Tout cela à partir d'une seule ligne de CSS ! C'est la puissance de la grille "implicite" et du placement automatique.</p>
<p>Pour la deuxième configuration de la grille dans cette démo, tout ce que j'ai fait est de changer la direction du flux automatique en utilisant <code>grid-auto-flow : column</code> de la même manière que nous l'avons fait précédemment en plaçant un élément <code>&lt;aside&gt;</code> à côté d'une <code>&lt;section&gt;</code>. Cela oblige le navigateur à créer une quatrième colonne qu'il peut utiliser pour placer les images restantes. Et puisque nous avons trois rangées, les images restantes sont placées à l'intérieur de la même colonne verticale.</p>
<figure><img src="https://la-cascade.io/images/lion_image.webp" alt="" /></figure><p>Nous devons ajouter quelques propriétés aux images pour nous assurer qu'elles s'intègrent bien dans la grille sans débordement :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-gap: 10px;
}
/* pour la deuxième configuration de la grille */
.horizontal {
  grid-auto-flow: column;
}
/* La grande image 3⨉3 */
.grid img:first-child {
  grid-area: span 3 / span 3;
}
/* Aide à prévenir les images étirées ou déformées */
img {
  width: 100%;
  hauteur: 100%;
  object-fit: cover;
}</pre>
<p>Et bien sûr, nous pouvons facilement mettre à jour la grille pour prendre en compte plus d'images en ajustant une valeur. Il s'agit de la valeur 3 dans les styles pour la grande image. Nous avons ceci :</p>
<pre class="language-css">.grid img:first-child {
  grid-area: span 3 / span 3;
}</pre>
<p>Mais nous pourrions ajouter une quatrième colonne en la remplaçant simplement par 4 :</p>
<pre class="language-css">.grid img:first-child {
  grid-area: span 4 / span 4;
}</pre>
<p>Mieux encore : définissons cette propriété comme une propriété personnalisée pour faciliter encore plus la mise à jour.</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/YzaPOrW/4d9af8f949d672715c6762758082b4c6">Variable grid with thumbnail</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<h2 id="dynamique">Mises en page dynamiques</h2>
<p>Le premier cas d'utilisation avec la barre latérale était notre première mise en page dynamique. Nous allons maintenant nous attaquer à des mises en page plus complexes où le nombre d'éléments dictera la configuration de la grille.</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/yLKyxWr/58d4e3558c4fbd00626b4a5891bf97bb">Dynamic layout #1</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Dans cet exemple, nous pouvons avoir de un à quatre éléments et la grille s'ajuste de manière à s'adapter au nombre d'éléments sans laisser de vides ou d'espaces manquants.</p>
<p>Lorsque nous n'avons qu'un seul élément, nous ne faisons rien. L'élément s'étire pour remplir la seule rangée et la seule colonne créées automatiquement par la grille.</p>
<p>Mais lorsque nous ajoutons le deuxième élément, nous créons une autre colonne (implicite) en utilisant <code>grid-column-start : 2</code>.</p>
<p>Lorsque nous ajoutons un troisième élément, il doit occuper la largeur de deux colonnes — c'est pourquoi nous avons utilisé <code>grid-column-start : span 2</code>, mais seulement s'il s'agit du <code>:last-child</code> car si nous ajoutons un quatrième élément, celui-ci ne doit occuper qu'une seule colonne.</p>
<p>En additionnant tout cela, nous avons <strong>quatre configurations de grille</strong> avec seulement <strong>deux déclarations</strong> et la magie de la grille implicite :</p>
<pre class="language-css">.grid {
  display: grid;
}
.grid :nth-child(2) {
  grid-column-start: 2;
}
.grid :nth-child(3):last-child {
  grid-column-start: span 2;
}</pre>
<p>Essayons-en un autre :</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/YzaPJKQ/9f6e805701fcb0774333a580212d2e19">Dynamic layout #2</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Nous ne faisons rien pour les premier et deuxième cas où nous n'avons qu'un ou deux éléments. En revanche, lorsque nous ajoutons un troisième élément, nous indiquons au navigateur que, tant qu'il s'agit du <code>:last-child</code>, il doit s'étendre sur deux colonnes. Lorsque nous ajoutons un quatrième élément, nous indiquons au navigateur que cet élément doit être placé dans la deuxième colonne.</p>
<pre class="language-css">.grid {
  display: grid;
}
.grid :nth-child(3):last-child {
  grid-column-start: span 2;
}
.grid :nth-child(4) {
  grid-column-start: 2;
}</pre>
<p>Vous commencez à comprendre le truc ? Nous donnons au navigateur des instructions spécifiques basées sur le nombre d'éléments (en utilisant <code>:nth-child</code>) et, parfois, une seule instruction peut changer complètement la mise en page.</p>
<p>Il convient de noter que le dimensionnement ne sera pas le même lorsque nous travaillons avec des contenus différents :</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/poLvBJa/2d4b881ab5de5c6fc75098c6d9dea565">Different content</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Comme nous n'avons pas défini de taille pour nos éléments, le navigateur les dimensionne automatiquement pour nous en fonction de leur contenu et nous pouvons nous retrouver avec une taille différente de celle que nous venons de voir. Pour y remédier, nous devons spécifier explicitement que toutes les colonnes et les rangées ont la même taille :</p>
<pre class="language-css">grid-auto-rows: 1fr;
grid-auto-columns: 1fr;</pre>
<p>Hé, nous n'avons pas encore joué avec ces propriétés ! <code>grid-auto-rows</code> et <code>grid-auto-columns</code> définissent la taille des rangées et des colonnes implicites, respectivement, dans un conteneur de grille. Ou, comme l'explique la spécification :</p>
<blockquote>
<p><em>Les propriétés <a href="https://drafts.csswg.org/css-grid/#propdef-grid-auto-columns">grid-auto-columns</a> et <a href="https://drafts.csswg.org/css-grid/#propdef-grid-auto-rows">grid-auto-rows</a> spécifient la taille des pistes auxquelles une taille n'est pas attribuée par <a href="https://drafts.csswg.org/css-grid/#propdef-grid-template-rows">grid-template-rows</a> ou <a href="https://drafts.csswg.org/css-grid/#propdef-grid-template-columns">grid-template-columns</a>.</em></p>
</blockquote>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/wvmBZoe/cad8346d9375fe78d197912ad0dff131">Same size items</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Voici un autre exemple où nous pouvons aller jusqu'à six éléments. Cette fois, je vais vous laisser disséquer le code. Ne vous inquiétez pas, les sélecteurs peuvent sembler complexes mais la logique est assez simple.</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/JjLomYR/993766536bfd0b7591edb2ac615a175f">Dynamic layout #3</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Même avec six éléments, nous n'avons eu besoin que de deux déclarations. Imaginez toutes les mises en page complexes et dynamiques que nous pouvons réaliser avec quelques lignes de code !</p>
<blockquote>
<p><em>Que se passe-t-il avec ce <code>grid-auto-rows</code> et pourquoi prend-il trois valeurs ? Sommes-nous en train de définir trois rangées ?</em></p>
</blockquote>
<p>Non, nous ne définissons pas trois rangées. Mais nous définissons <em>de fait</em> trois valeurs comme modèle pour nos rangées implicites. La logique est la suivante :</p>
<ul><li>Si nous avons une rangée, elle sera dimensionnée avec la première valeur.</li>
<li>Si nous avons deux rangées, la première reçoit la première valeur et la seconde la seconde.</li>
<li>Si nous avons trois rangées, les trois valeurs seront utilisées.</li>
<li>Si nous avons quatre rangées (et voici la partie intéressante), nous utilisons les trois valeurs pour les trois premières rangées et nous réutilisons la première valeur pour la quatrième rangée. C'est pourquoi il s'agit d'une sorte de modèle que nous répétons pour dimensionner toutes les rangées implicites.</li>
<li>Si nous avons 100 rangées, elles seront dimensionnées trois par trois pour avoir <code>2fr 2fr 1fr 2fr 2fr 1fr 2fr 2fr 1fr</code>, etc.</li>
</ul><p>Contrairement à <code>grid-template-rows</code> qui définit le nombre de rangées et leur taille, <code>grid-auto-rows</code> ne dimensionne que les rangées qui peuvent être créées en cours de route.</p>
<p>Si nous revenons à notre exemple, la logique est d'avoir une taille égale lorsque deux rangées sont créées (nous utiliserons le <code>2fr 2fr</code>), mais si une troisième rangée est créée, nous la rendons un peu plus petite.</p>
<h2 id="motifs">Motifs de grille</h2>
<p>Pour ce dernier point, nous allons parler de motifs. Vous avez probablement vu ces mises en page à deux colonnes où une colonne est plus large que l'autre, et où chaque rangée alterne le placement de ces colonnes.</p>
<p>Ce type de disposition peut être difficile à réaliser sans connaître exactement la quantité de contenu à traiter, mais les pouvoirs implicites de placement automatique de CSS Grid en font un jeu d'enfant.</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/YzaPJVY/c462c7a29acbbb257e5b147c686f2d51">Alternate CSS grid</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Jetez un coup d'œil au code. Il peut sembler complexe, mais décomposons-le car il est finalement assez simple.</p>
<p>La première chose à faire est d'identifier le modèle. Demandez-vous : "Après combien d'éléments le modèle doit-il se répéter ?" Dans ce cas, c'est tous les quatre éléments. Donc, pour l'instant, n'utilisons que quatre éléments :</p>
<figure><img src="https://la-cascade.io/images/masonry1.webp" alt="" /></figure><p>Maintenant, définissons la grille et mettons en place le modèle général en utilisant le sélecteur <code>:nth-child</code> pour alterner entre les éléments :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-auto-columns: 1fr; /* toutes les colonnes sont égales */
  grid-auto-rows: 100px; /* toutes les rangées sont égales à 100px */
}
.grid :nth-child(4n + 1) {
  /* ? ?? */
}
.grid :nth-child(4n + 2) {
  /* ? ?? */
}
.grid :nth-child(4n + 3) {
  /* ? ?? */
}
.grid :nth-child(4n + 4) {
  /* ? ?? */
}</pre>
<p>Nous avons dit que notre motif se répète tous les quatre éléments, nous utiliserons donc logiquement 4n + x où x va de 1 à 4. Il est un peu plus facile d'expliquer le motif de cette façon :</p>
<pre>4(0) + 1 = 1 = 1er élément /* on commence avec n = 0 */
4(0) + 2 = 2 = 2ème élément
4(0) + 3 = 3 = 3ème élément
4(0) + 4 = 4 = 4e élément
4(1) + 1 = 5 = 5ème élément /* notre modèle se répète ici à n = 1 */
4(1) + 2 = 6 = 6ème élément
4(1) + 3 = 7 = 7ème élément
4(1) + 4 = 8 = 8e élément
4(2) + 1 = 9 = 9ème élément /* notre modèle se répète ici à n = 2 */
etc.</pre>
<p>C'est parfait, non ? Nous avons quatre éléments, et nous répétons le motif sur le cinquième élément, le neuvième élément et ainsi de suite.</p>
<p>Ces sélecteurs <code>:nth-child</code> peuvent être délicats ! Chris a expliqué de manière très utile <a href="https://la-cascade.io/articles/nth-child">comment tout cela fonctionne</a>, y compris <a href="https://css-tricks.com/useful-nth-child-recipies/">des recettes pour créer différents modèles</a>.</p>
<p>Maintenant, nous configurons chaque élément de la manière suivante :</p>
<ol><li>Le premier élément doit prendre deux colonnes et commencer à la première colonne (grid-column : 1/span 2).</li>
<li>Le deuxième élément est placé dans la troisième colonne (grid-column-start : 3).</li>
<li>Le troisième élément est placé à la première colonne : (grid-column-start : 1).</li>
<li>Le quatrième élément prend deux colonnes et commence à la deuxième colonne : (grid-column : 2/span 2).</li>
</ol><p>Voici ce que cela donne en CSS :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-auto-columns: 1fr; /* toutes les colonnes sont égales */
  grid-auto-rows: 100px; /* toutes les rangées sont égales à 100px */
}
.grid :nth-child(4n + 1) {
  grid-column: 1 / span 2;
}
.grid :nth-child(4n + 2) {
  grid-column-start: 3;
}
.grid :nth-child(4n + 3) {
  grid-column-start: 1;
}
.grid :nth-child(4n + 4) {
  grid-column: 2 / span 2;
}</pre>
<p>Nous pourrions nous arrêter ici et ce serait bon... mais nous pouvons faire mieux ! Plus précisément, nous pouvons supprimer certaines déclarations et compter sur les pouvoirs de placement automatique de la grille pour faire le travail à notre place. C'est la partie la plus délicate à appréhender et il faut beaucoup de pratique pour pouvoir identifier ce qui peut être supprimé.</p>
<p>La première chose que nous pouvons faire est de mettre à jour <code>grid-column : 1 /span 2</code> et d'utiliser uniquement <code>grid-column : span 2</code> puisque, par défaut, le navigateur placera le premier élément dans la première colonne. Nous pouvons également supprimer cet élément :</p>
<pre class="language-css">.grid :nth-child(4n + 3) {
  grid-column-start: 1;
}</pre>
<p>En plaçant les premier, deuxième et quatrième éléments, la grille place automatiquement le troisième élément au bon endroit. Cela signifie que nous nous retrouvons avec ceci :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-auto-rows: 100px; /* toutes les rangées sont égales à 100px */
  grid-auto-columns: 1fr; /* toutes les colonnes sont égales */
}
.grid :nth-child(4n + 1) {
  grid-column: span 2;
}
.grid :nth-child(4n + 2) {
  grid-column-start: 3;
}
.grid :nth-child(4n + 4) {
  grid-column: 2 / span 2;
}</pre>
<p>Mais allez, on peut faire mieux ! Nous pouvons aussi supprimer ceci :</p>
<pre class="language-css">.grid :nth-child(4n + 2) {
  grid-column-start: 3;
}</pre>
<p>Pourquoi ? Si nous plaçons le quatrième élément dans la deuxième colonne tout en lui permettant d'occuper deux colonnes complètes, nous forçons la grille à créer une troisième colonne implicite, ce qui nous donne un total de trois colonnes sans le lui dire explicitement. Le quatrième élément ne peut pas aller dans la première rangée puisque le premier élément prend également deux colonnes, il passe donc à la rangée suivante. Cette configuration nous laisse avec une colonne vide dans la première rangée et une colonne vide dans la deuxième rangée.</p>
<figure><img src="https://la-cascade.io/images/masonry2.webp" alt="" /></figure><p>Je pense que vous connaissez la fin de l'histoire. Le navigateur placera automatiquement les deuxième et troisième éléments dans ces emplacements vides. Notre code devient donc encore plus simple :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-auto-columns: 1fr; /* toutes les colonnes sont égales */
  grid-auto-rows: 100px; /* toutes les rangées sont égales à 100px */
}
.grid :nth-child(4n + 1) {
  grid-column: span 2;
}
.grid :nth-child(4n + 4) {
  grid-column: 2 / span 2;
}</pre>
<p>Il suffit de cinq déclarations pour créer un motif très cool et très souple. La partie optimisation peut être délicate, mais on s'y habitue et on gagne quelques astuces avec la pratique.</p>
<blockquote>
<p><em>Pourquoi ne pas utiliser <code>grid-template-columns</code> pour définir des colonnes explicites puisque nous connaissons le nombre de colonnes ?</em></p>
</blockquote>
<p>Nous pouvons le faire ! Voici le code correspondant :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-template-columns: repeat(
    3,
    1fr
  ); /* toutes les colonnes sont égales */
  grid-auto-rows: 100px; /* toutes les rangées sont égales à 100px */
}
.grid :nth-child(4n + 1),
.grid :nth-child(4n + 4) {
  grid-column: span 2;
}</pre>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/ExEazLZ/73bf8a38c32f834321ea9e63510e23c9">Another alternative</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Comme vous pouvez le constater, le code est nettement plus intuitif. Nous définissons trois colonnes de grille explicites et nous indiquons au navigateur que les premier et quatrième éléments doivent prendre deux colonnes. Je recommande vivement cette approche ! Mais le but de cet article est d'explorer de nouvelles idées et astuces que nous obtenons grâce aux pouvoirs implicites et d'auto-placement de CSS Grid.</p>
<p>L'approche explicite est plus directe, tandis qu'une grille implicite vous oblige à combler les lacunes là où CSS effectue un travail supplémentaire en coulisse. En fin de compte, je pense qu'une bonne compréhension des grilles implicites vous aidera à mieux comprendre l'algorithme CSS Grid. Après tout, nous ne sommes pas ici pour étudier ce qui est évident — nous sommes ici pour explorer des territoires sauvages !</p>
<p>Essayons un autre modèle, un peu plus rapide cette fois :</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/YzxaJom">Alternate CSS grid</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Notre schéma se répète tous les six éléments. Les troisième et quatrième éléments doivent occuper chacun deux rangées complètes. Si nous plaçons le troisième et le quatrième éléments, il semble que nous n'ayons pas besoin de toucher aux autres, alors essayons ce qui suit :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-auto-columns: 1fr;
  grid-auto-rows: 100px;
}
.grid :nth-child(6n + 3) {
  grid-area: span 2/2; /* grid-row-start : span 2 &amp;&amp; grid-column-start : 2 */
}
.grid :nth-child(6n + 4) {
  grid-area: span 2/1; /* grid-row-start : span 2 &amp;&amp; grid-column-start : 1 */
}</pre>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/gOebJNq/bfb026fdd80549f4b5e1d72e6bdf5e13">Premier essai</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Hmm, pas terrible. Nous devons placer le deuxième élément dans la première colonne. Sinon, la grille le placera automatiquement dans la deuxième colonne.</p>
<pre class="language-css">.grid :nth-child(6n + 2) {
  grid-column: 1; /* grid-column-start : 1 */
}</pre>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/BaryeXg/658adad08195ed95cd50e53de42494f2">Deuxième essai</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>C'est mieux, mais il y a encore du boulot. Nous devons déplacer le troisième élément vers le haut. Il est tentant d'essayer de le placer dans la première rangée de cette façon :</p>
<pre class="language-css">.grid :nth-child(6n + 3) {
  grid-area: 1/2 / span 2;
  /* Équivalent à :
       grid-row-start : 1 ;
       grid-row-end : span 2 ;
       grid-column-start : 2 
     */
}</pre>
<p>Mais cela ne fonctionne pas car cela oblige tous les 6n + 3 éléments à être placés dans la même zone, ce qui donne une disposition désordonnée. La véritable solution consiste à conserver la définition initiale du troisième élément et à ajouter <code>grid-auto-flow : dense</code> pour combler les vides. <a href="https://developer.mozilla.org/fr/docs/Web/CSS/grid-auto-flow">Extrait du MDN en français</a> :</p>
<blockquote>
<p><em>L'algorithme de placement automatique utilisera une méthode de « regroupement dense » où il essaie de remplir les trous dans la grille si des éléments plus petits arrivent ensuite. De fait, on peut obtenir une impression de désordre alors qu'il s'agit simplement du comblement des espaces libres.</em><em>Si cette valeur est absente, le moteur utilisera un algorithme simple qui ne fait que se déplacer vers l'avant, sans revenir vers les espaces vides. De cette façon, les éléments apparaitront nécessairement dans l'ordre mais pourront laisser des trous.</em></p>
</blockquote>
<p>Je sais que cette propriété n'est pas très intuitive mais ne l'oubliez jamais lorsque vous êtes confronté à un problème de placement. Avant d'essayer en vain différentes configurations, ajoutez-la, car elle peut réparer votre mise en page sans effort supplémentaire.</p>
<blockquote>
<p><em>Pourquoi ne pas toujours ajouter cette propriété par défaut ?</em></p>
</blockquote>
<p>Je ne le recommande pas car, dans certains cas, nous ne voulons pas de ce comportement. Notez que l'explication de MDN mentionne que cela entraîne la circulation d'éléments "en désordre" pour remplir les trous laissés par des éléments plus grands. L'ordre visuel est généralement tout aussi important que l'ordre des sources, en particulier lorsqu'il s'agit d'interfaces accessibles, et <code>grid-auto-flow : dense</code> peut parfois provoquer un décalage entre l'ordre visuel et l'ordre des sources.</p>
<p>Notre code final est donc :</p>
<pre class="language-css">.grid {
  display: grid;
  grid-auto-columns: 1fr;
  grid-auto-flow: dense;
  grid-autorows: 100px;
}
.grid :nth-child(6n + 2) {
  grid-column: 1;
}
.grid :nth-child(6n + 3) {
  grid-area: span 2/2;
}
.grid :nth-child(6n + 4) {
  grid-row: span 2;
}</pre>
<p>Encore un petit ? Allez on y va !</p>
<figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/t_afif/pen/MWEOMdr">Alternating row CSS Grid</a>de Temani Afif dans<a href="https://codepen.io">CodePen</a></div>
<p>Pour celui-ci, je ne vais pas trop parler et plutôt vous montrer une illustration du code que j'ai utilisé. Essayez de voir si vous comprenez comment j'ai obtenu ce code :</p>
<figure><img src="https://la-cascade.io/images/grille1.webp" alt="" /></figure><p>Les éléments en noir sont implicitement placés dans la grille. Il faut noter que l'on peut obtenir la même disposition de plusieurs manières différentes. Pouvez-vous aussi les comprendre ? Qu'en est-il de l'utilisation de <code>grid-template-columns</code> ?</p>
<p>Je vais vous laisser avec un dernier modèle :</p>
<figure><img src="https://la-cascade.io/images/grille2.webp" alt="" /></figure><p>J'ai <a href="https://codepen.io/t_afif/pen/bGoLyXQ/c235fd09a97c0873d31cd9b7d5530dd5">une solution</a> pour celui-ci mais c'est à vous de vous entraîner. Prenez tout ce que nous avons appris et essayez de le coder vous-même, puis comparez-le avec ma solution. Ne vous inquiétez pas si vous terminez par quelque chose de verbeux - le plus important est de trouver une solution qui fonctionne.</p>
<h2 id="plus">Vous en voulez encore ?</h2>
<p>Avant de terminer, je voudrais partager avec vous quelques questions de Stack Overflow liées à CSS Grid, auxquelles j'ai répondu en utilisant plusieurs des techniques que nous avons abordées ici. C'est une bonne liste qui montre combien de cas d'utilisation réels et de situations concrètes se présentent où ces choses sont utiles :</p>
<ul><li><a href="https://stackoverflow.com/questions/61196568/change-the-number-of-columns-and-rows-in-a-grid-as-the-number-of-items-increase/61197351#61197351">Modifier le nombre de colonnes et de rangées d'une grille à mesure que le nombre d'éléments augmente</a>.</li>
<li><a href="https://stackoverflow.com/questions/58478216/css-grid-2x2-grid-always-taking-up-the-full-width-when-possible/58478256#58478256">Grille CSS - Grille 2×2 occupant toujours toute la largeur lorsque cela est possible</a></li>
<li><a href="https://stackoverflow.com/questions/52898785/how-to-repeat-a-css-grid-layout-pattern">Comment répéter un modèle de grille CSS ?</a></li>
<li><a href="https://stackoverflow.com/questions/60087680/create-css-grid-layout-with-pure-css/60090576#60090576">Créer une grille CSS en pur CSS</a></li>
<li><a href="https://stackoverflow.com/questions/61329229/css-grid-vs-dynamic-definition-list-autoplacement/61330399#61330399">Grille CSS vs. placement automatique dynamique des listes de définition</a></li>
<li><a href="https://stackoverflow.com/questions/61141411/css-grid-alternate-order-of-elements-only-on-desktop/61141540#61141540">Grille CSS - ordre alterné des éléments uniquement pour ordi (pas écrans réduits)</a></li>
<li><a href="https://stackoverflow.com/questions/51078651/image-tile-using-css-grid/51079015#51079015">Carrelage d'images à l'aide d'une grille CSS</a></li>
<li><a href="https://stackoverflow.com/questions/69452147/how-to-fix-this-complex-css-grid-of-photos-based-on-4-columns">Comment réparer cette grille CSS complexe de photos basée sur 4 colonnes ?</a></li>
<li><a href="https://stackoverflow.com/questions/63807091/repeating-grid-layout-with-unknown-amount-of-items/63807293#63807293">Mise en page d'une grille répétitive avec un nombre inconnu d'éléments</a></li>
<li><a href="https://stackoverflow.com/questions/70947162/creating-a-repeating-css-grid-layout/70947263#70947263">Création d'une grille CSS répétitive</a></li>
<li><a href="https://stackoverflow.com/questions/56101028/is-it-possible-to-make-every-second-row-in-a-css-grid-to-have-different-number-o/56103169#56103169">Est-il possible de faire en sorte qu'une rangée sur deux d'une grille CSS ait un nombre différent de colonnes ?</a></li>
<li><a href="https://stackoverflow.com/questions/65504567/place-items-in-pairs-in-two-rows-using-css-grid/65504637#65504637">Placer des éléments par paires sur deux rangées à l'aide d'une grille CSS</a></li>
<li><a href="https://stackoverflow.com/questions/61786083/how-to-set-up-a-dynamic-grid-based-on-flex-or-grid/61786201#61786201">Comment mettre en place une grille dynamique basée sur Flex ou Grid ?</a></li>
<li><a href="https://stackoverflow.com/questions/62110278/css-complex-grid-auto-layout/62113491#62113491">Mise en page automatique d'une grille CSS complexe</a></li>
<li><a href="https://stackoverflow.com/questions/73093172/can-i-stack-a-right-hand-set-of-columns-with-css-grid-instead-of-flex">Puis-je empiler un ensemble de colonnes à droite avec CSS Grid au lieu de Flex ?</a></li>
<li><a href="https://stackoverflow.com/questions/73044810/change-grid-layout-depending-on-number-of-elements">Modifier la disposition de la grille en fonction du nombre d'éléments</a></li>
</ul><h2 id="conclusion">Pour conclure</h2>
<p>CSS Grid existe depuis des années, mais il existe encore de nombreuses astuces peu connues et utilisées qui ne sont pas largement discutées. La grille implicite et les fonctions de placement automatique sont deux d'entre elles !</p>
<p>Et oui, cela peut devenir un défi ! Il m'a fallu beaucoup de temps pour comprendre la logique des grilles implicites et j'ai encore du mal avec le placement automatique. Si vous voulez passer plus de temps à vous faire une idée des grilles explicites et implicites, voici quelques explications et exemples supplémentaires qui valent la peine d'être consultés :</p>
<ul><li><a href="https://css-tricks.com/understanding-the-difference-between-grid-template-and-grid-auto/">Understanding the difference between grid-template and grid-auto</a> de Chris Coyier</li>
<li><a href="https://css-tricks.com/collection-interesting-facts-css-grid-layout/">A Collection of Interesting Facts about CSS Grid Layout</a> de Manuel Matuzovic</li>
<li><a href="https://css-tricks.com/almanac/properties/g/grid-auto-columns/">grid-auto-columns</a></li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/css-grid-grille-implicite-et-placement-automatique</link>
      <guid>https://la-cascade.io/articles/css-grid-grille-implicite-et-placement-automatique</guid>
      <pubDate>Wed, 03 Aug 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Écrire HTML à la manière HTML (pas XHTML)]]></title>
      <description><![CDATA[<p><em>Avec Jens Oliver Meiert, redécouvrez le HTML et participez à l'élaboration d'une nouvelle méthode moderne d'écriture du HTML.</em></p><div class="articleContent"><p>Vous n'utilisez peut-être pas (ou plus) le XHTML, mais lorsque vous écrivez du HTML, vous êtes peut-être plus influencé par le XHTML que vous ne le pensez. Vous écrivez très probablement du HTML <em>à la manière de XHTML</em>.</p><p>Qu'est-ce que <em>la façon XHTML</em> d'écrire du HTML, et qu'est-ce que <em>la façon HTML</em> d'écrire du HTML ? Voyons cela.</p><h2>HTML, XHTML, HTML</h2><p>Dans les années 1990, il y avait le HTML. Dans les années 2000, il y a eu le XHTML. Puis, dans les années 2010, nous sommes revenus au HTML. C'est une histoire simple...</p><p>Les dates approximatives des spécifications sont également révélatrices : HTML "1" 1992, HTML 2.0 1995, HTML 3.2 1997, HTML 4.01 1999 ; XHTML 1.0 2000, XHTML 1.1 2001 ; "HTML5" <a href="https://en.wikipedia.org/wiki/HTML5#Timeline">2007</a>.</p><p>Le XHTML est devenu populaire lorsque tout le monde croyait que le XML et ses dérivés étaient l'avenir. "XML tout court". Pour le HTML, cela a eu un effet profond et durable : celui de nous apprendre à l'écrire à la façon XHTML.</p><h2>La façon XHTML d'écrire le HTML</h2><p>La méthode XHTML est bien documentée, car XHTML 1.0 la décrit en détail dans sa section "<a href="https://www.w3.org/TR/xhtml1/#diffs">Différences avec HTML 4</a>" :</p><ul><li>Les documents doivent être bien formés.</li>
<li>Les noms des éléments et des attributs doivent être en minuscules.</li>
<li>Pour les éléments non vides, les balises de fin sont obligatoires.</li>
<li>Les valeurs des attributs doivent toujours être citées.</li>
<li>La <a href="https://www.w3.org/TR/xhtml1/#h-4.5">minimisation des attributs</a> n'est pas prise en charge.</li>
<li>Les éléments vides doivent être fermés.</li>
<li>Le traitement des espaces blancs dans les valeurs d'attributs est effectué conformément à XML.</li>
<li>Les éléments de script et de style doivent comporter des sections CDATA.</li>
<li>Les exclusions SGML ne sont pas autorisées.</li>
<li>Les éléments ayant des attributs id et name, comme a, applet, form, frame, iframe, img et map, ne doivent utiliser que id.</li>
<li>Les attributs ayant des ensembles de valeurs prédéfinies sont sensibles à la casse.</li>
<li>Les références aux entités comme les valeurs hexadécimales doivent être en minuscules.</li>
</ul><p>Cela vous semble-t-il familier ? À l'exception du balisage du contenu CDATA, ainsi que du traitement des exclusions SGML, vous suivez probablement toutes ces règles. <strong>Toutes ces règles</strong>.</p><p>Bien que le XHTML soit mort, nombre de ces règles n'ont jamais été remises en question. Certaines ont même été élevées au rang de "bonnes pratiques" pour le HTML.</p><p>C'est la façon XHTML d'écrire du HTML, et son impact durable sur le domaine.</p><h2>La façon d'écrire du HTML</h2><p>Une façon de nous ramener en arrière est de reformuler négativement les règles imposées par le XHTML. Faisons cela (sans la partie SGML, car <a href="https://html.spec.whatwg.org/multipage/parsing.html#parsing">HTML n'est plus basé sur SGML</a>) :</p><ul><li>Les documents peuvent ne pas être bien formés.</li>
<li>Les noms des éléments et des attributs peuvent ne pas être en minuscules.</li>
<li>Pour les éléments non vides, les balises de fin ne sont pas toujours nécessaires.</li>
<li>Les valeurs des attributs ne sont pas toujours citées.</li>
<li>La minimisation des attributs est prise en charge.</li>
<li>Les éléments vides n'ont pas besoin d'être fermés.</li>
<li>Le traitement des espaces blancs dans les valeurs d'attributs n'est pas réalisé conforment à XML.</li>
<li>Les éléments de script et de style n'ont pas besoin de sections CDATA.</li>
<li>Les éléments ayant des attributs <code>id</code> et <code>name</code> ne peuvent pas utiliser uniquement id.</li>
<li>Les attributs dont les valeurs sont prédéfinies ne sont pas sensibles à la casse.</li>
<li>Les références aux entités comme les valeurs hexadécimales peuvent ne pas être uniquement en minuscules.</li>
</ul><p>Supprimons les points ésotériques et ceux qui ne semblent pas pertinents. Il s'agit de la gestion des espaces blancs XML, des sections CDATA, du doublement des valeurs des attributs de nom, de la casse des ensembles de valeurs prédéfinis et des références d'entités en hexadécimal :</p><ul><li>Les documents peuvent ne pas être bien formés.</li>
<li>Les noms des éléments et des attributs peuvent ne pas être en minuscules.</li>
<li>Pour les éléments non vides, les balises de fin ne sont pas toujours requises.</li>
<li>Les valeurs des attributs ne sont pas toujours citées.</li>
<li>La minimisation des attributs est prise en charge.</li>
<li>Les éléments vides n'ont pas besoin d'être fermés.</li>
</ul><p>Si l'on fait abstraction de ces règles, on a beaucoup moins l'impression de travailler avec du XML, mais plutôt avec du HTML. Mais nous n'avons pas encore terminé.</p><p>"Les documents peuvent ne pas être bien formés" semble suggèrer qu'il serait <em>acceptable</em> que le code HTML soit invalide. Il était tout à fait cohérent que XHTML soit pointilleux sur la conformité de la forme en raison de sa gestion stricte des erreurs (par XML). Mais même si les documents HTML fonctionnent encore lorsqu'ils contiennent de graves problèmes de syntaxe et de conformité, il n'est <em>pas utile</em>, ni pour le professionnel ni pour notre domaine d'user et d'abuser de cette résilience. (J'ai déjà plaidé cette cause dans mon article "<a href="https://meiert.com/en/blog/critical-frontend-development/">In Critical Defense of Frontend Development</a>".</p><p>La <em>façon HTML</em> ne suggére donc pas que "les documents peuvent ne pas être bien formés". Il devrait également être clair que non seulement les balises de fin, mais aussi celles de début ne sont pas toujours nécessaires. Si nous reformulons et réorganisons, voici l'essentiel :</p><ul><li>Les balises de début et de fin ne sont pas toujours nécessaires.</li>
<li>Les éléments vides n'ont pas besoin d'être fermés.</li>
<li>Les noms des éléments et des attributs peuvent être en minuscules ou en majuscules.</li>
<li>Les valeurs des attributs ne sont pas toujours entre guillemets.</li>
<li>La minimisation des attributs est prise en charge.</li>
</ul><h2>Exemples</h2><p>Comment cela se présente-t-il en pratique ? Pour les balises de début et de fin, sachez que de nombreuses balises sont facultatives. Un paragraphe et une liste, par exemple, s'écrivent comme ceci en XHTML :</p><pre class="language-xhtml">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Praesent augue nisl&lt;/li&gt;
  &lt;li&gt;Lobortis nec bibendum ut&lt;/li&gt;
  &lt;li&gt;Dictum ac quam&lt;/li&gt;
&lt;/ul&gt;</pre><p>En HTML, vous pouvez l'écrire avec ce code (qui est parfaitement valide) :</p><pre class="language-html">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.
&lt;ul&gt;
  &lt;li&gt;Praesent augue nisl
  &lt;li&gt;Lobortis nec bibendum ut
  &lt;li&gt;Dictum ac quam
&lt;/ul&gt;</pre><p>Les développeurs ont également appris à écrire les éléments vides comme ceci : <code>&lt;br /&gt;</code>. C'est encore une chose que le XHTML a apporté au HTML, mais la barre oblique n'ayant aucun effet sur les éléments vides, vous n'avez besoin que de ceci : <code>&lt;br&gt;</code>.</p><p>En HTML vous pouvez tout écrire en majuscules :</p><pre class="language-html">&lt;A HREF="https://css-tricks.com/"&gt;CSS-Tricks&lt;/A&gt;</pre><p>Bon, évidemment, on dirait que vous criez et vous n'aimerez sans doute pas cela, mais enfin il n'est pas interdit de l'écrire comme ça.</p><p>Lorsque vous voulez condenser ce lien, le HTML vous offre la possibilité de <a href="https://meiert.com/en/blog/optional-html/#toc-quotes">laisser de côté certains guillemets</a> :</p><pre class="language-html">&lt;A HREF=https://css-tricks.com/&gt;CSS-Tricks&lt;/A&gt;</pre><p>Note : <em>En règle générale, lorsque la valeur de l'attribut ne contient pas d'espace ou de signe égal, il est possible de supprimer les guillemets.</em></p><p>Enfin, le HTML-HTML - et non le XHTML-HTML - permet également de minimiser les attributs. C'est-à-dire qu'au lieu de marquer un élément <code>input</code> comme requis et en lecture seule, comme ceci :</p><pre class="language-html">&lt;input type="text" required="required" readonly="readonly" /&gt;</pre><p>Vous pouvez minimiser les attributs :</p><pre class="language-html">&lt;input type="text" required readonly /&gt;</pre><p>Si vous profitez non seulement du fait que les guillemets ne sont pas nécessaires, mais aussi du fait que le texte est la valeur par défaut de l'attribut type ici (il existe d'autres combinaisons attribut-valeur inutiles), vous obtenez un exemple qui montre le HTML dans toute sa beauté minimale :</p><pre class="language-html">&lt;input required readonly /&gt;</pre><h2>Écrire du HTML, à la manière du HTML</h2><p>Ce qui précède n'est pas une représentation de ce qu'était le HTML dans les années 90. À l'époque, le HTML était chargé d'éléments <code>&lt;table&gt;</code> pour la mise en page, rempli de code de présentation, largement invalide (comme c'est encore le cas aujourd'hui), et la compatibilité des agents utilisateurs était très variable. Pourtant, c'est l'essence même de ce que nous aurions voulu conserver si XML et XHTML n'étaient pas arrivés.</p><p>Si vous êtes ouvert à une suggestion de ce à quoi pourrait ressembler une manière plus complète et contemporaine d'écrire le HTML, j'en ai une ! (Le HTML étant mon principal domaine d'intérêt, je complète ce texte par des liens vers certains de mes articles).</p><ol><li><strong>Respectez la syntaxe et la sémantique</strong>.
<ul><li><a href="https://meiert.com/en/blog/the-frontend-developer-test/">Validez votre HTML</a>, et n'envoyez que du HTML valide, utilisez <a href="https://validator.w3.org/nu/">le validateur du W3C</a></li>
</ul></li>
<li><strong>Utilisez les options que vous offre le HTML, du moment que vous le faites de manière cohérente</strong>.
<ul><li>N'oubliez pas que les noms des éléments et des attributs peuvent être en minuscules ou en majuscules.</li>
</ul></li>
<li><strong>Limitez l'utilisation du HTML au strict minimum</strong>
<ul><li>Rappelez-vous que le balisage de présentation et de comportement doit être traité par CSS et JavaScript.</li>
<li>Rappelez-vous que les balises de début et de fin ne sont <a href="https://meiert.com/en/blog/optional-html/#toc-tags">pas toujours nécessaires</a>.</li>
<li>Rappelez-vous que les éléments vides n'ont pas besoin d'être fermés.</li>
<li>N'oubliez pas que certains attributs ont des valeurs par défaut qui permettent d'<a href="https://meiert.com/en/blog/optional-html/#toc-attribute-values">omettre ces paires attribut-valeur</a>.</li>
<li>N'oubliez pas que les valeurs des attributs n'ont <a href="https://meiert.com/en/blog/optional-html/#toc-quotes">pas toujours besoin d'être entre guillemets</a>.</li>
<li>N'oubliez pas que la minimisation des attributs est prise en charge.</li>
</ul></li>
</ol><p>Ce n'est pas une coïncidence si cela ressemble aux <a href="https://meiert.com/en/blog/rules-for-html/">trois règles de base du HTML</a>, si cela fonctionne selon le principe qu'un <a href="https://meiert.com/en/blog/html-performance/">poids réduit de fichier conduit également à des sites plus rapides</a>, et si cela suit l'<a href="https://meiert.com/en/blog/minimal-web-development/">école du développement web minimal</a>. Rien de tout cela n'est nouveau - notre domaine pourrait simplement décider de le redécouvrir. Des outils sont également disponibles : <a href="https://github.com/kangax/html-minifier">html-minifier</a> est probablement le plus connu et le plus à même de gérer toutes les optimisations HTML.</p><p>Vous avez appris le HTML à la manière du XHTML. HTML n'est pas XHTML. Redécouvrez le HTML et participez à l'élaboration d'une nouvelle méthode moderne d'écriture du HTML, qui reconnaît le XML sans en faire un dogme intangible.</p></div>]]></description>
      <link>https://la-cascade.io/articles/ecrivez-html-comme-du-html</link>
      <guid>https://la-cascade.io/articles/ecrivez-html-comme-du-html</guid>
      <pubDate>Tue, 26 Jul 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Une table des matières parfaite avec HTML et CSS]]></title>
      <description><![CDATA[<p><em>Créer une table des matières pour un document à imprimer s'avère légèrement compliqué, Nicholas C. Zakas propose ici une solution simple en purs HTML et CSS.</em></p><div class="articleContent"><p>Au début de cette année, j'ai auto-publié un ebook intitulé <em>Understanding JavaScript Promises</em> (<a href="https://ebooks.humanwhocodes.com/promises">téléchargeable gratuitement</a>). Je n'avais pas l'intention d'en faire un livre imprimé, mais pas mal de personnes m'ayant contacté pour me demander une version imprimée, j'ai décidé de l'auto-publier également. Je me disais qu'il ne serait pas trop compliqué d'utiliser HTML et CSS pour générer un PDF et l'envoyer à l'imprimeur. Ce que je n'avais pas encore réalisé, c'est que je n'avais pas de solution pour gérer une partie importante d'un livre imprimé : la table des matières.</p><h2>La composition d'une table des matières</h2><p>À la base, une table des matières est assez simple. Chaque ligne représente une partie d'un livre ou d'une page Web et indique où vous pouvez trouver ce contenu. En général, les lignes contiennent trois parties :</p><ol><li>Le titre du chapitre ou de la section</li>
<li>Des amorces (c'est-à-dire des points, des tirets ou des lignes) qui relient visuellement le titre au numéro de page.</li>
<li>Le numéro de page</li>
</ol><p>On peut facilement générer une table des matières à l'aide d'outils de traitement de texte comme Microsoft Word ou Google Docs, mais comme mon contenu était en format Markdown, puis transformé en HTML, ce n'était pas une bonne option pour moi. Je voulais quelque chose d'automatisé qui fonctionne avec HTML pour générer la table des matières dans un format adapté à l'impression. Je voulais également que chaque ligne soit un lien afin de pouvoir l'utiliser dans les pages Web et les PDF pour naviguer dans le document. Je voulais aussi que le titre et le numéro de page soient précédés de points.</p><p>J'ai donc commencé à faire des recherches.</p><p>Je suis tombé sur deux excellents articles de blog sur la création d'une table des matières avec HTML et CSS. Le premier, intitulé "<a href="https://pagedjs.org/posts/build-a-table-of-contents-from-your-html/">Build a Table of Contents from your HTML</a>", est signé Julie Blanc. Julie a travaillé sur <a href="https://pagedjs.org/">PagedJS</a>, un polyfill pour les fonctionnalités de médias paginés manquantes dans les navigateurs Web qui formate correctement les documents pour l'impression. J'ai commencé par l'exemple de Julie, mais j'ai trouvé qu'il ne fonctionnait pas vraiment pour moi. J'ai ensuite trouvé le billet de Christoph Grabo intitulé "<a href="https://markentier.tech/posts/2021/03/responsive-toc-leader-lines-with-css/">Responsive TOC leader lines with CSS</a>", qui présentait le concept d'utilisation de CSS Grid (par opposition à l'approche basée sur les <code>float</code> de Julie) pour faciliter l'alignement. Une fois de plus, cependant, son approche ne correspondait pas tout à fait à mes besoins.</p><p>Mais après avoir lu ces deux articles, j'ai eu le sentiment d'avoir une compréhension suffisante des problèmes de mise en page pour me lancer dans mon propre projet. J'ai utilisé des éléments des deux articles du blog et j'ai ajouté quelques nouveaux concepts HTML et CSS à mon approche pour arriver à un résultat qui me convient.</p><h2>Choix du balisage</h2><p>Lorsque j'ai décidé du balisage correct d'une table des matières, j'ai surtout pensé à la sémantique correcte. Fondamentalement, une table des matières consiste à associer un titre (chapitre ou sous-section) à un numéro de page, presque comme une paire clé-valeur. Cela m'a conduit à deux options :</p><p>La première option consiste à utiliser un tableau (<code>&lt;table&gt;</code>) avec une colonne pour le titre et une colonne pour la page. Ensuite, il y a l'élément liste de définition (<code>&lt;dl&gt;</code>), souvent inutilisé et oublié. Il fait également office de carte clé-valeur. Ainsi, une fois encore, la relation entre le titre et le numéro de page serait évidente.</p><p>Ces deux options semblaient bonnes jusqu'à ce que je me rende compte qu'elles ne fonctionnent vraiment que pour les tables des matières à un seul niveau, c'est-à-dire uniquement si je voulais avoir une table des matières contenant uniquement les noms des chapitres. En revanche, si je voulais afficher les sous-sections dans la table des matières, je n'avais pas de bonnes options. Les éléments de tableau ne sont pas très adaptés aux données hiérarchiques et, bien que les listes de définitions puissent techniquement être imbriquées, la sémantique ne semblait pas correcte. Je suis donc retourné à la planche à dessin.</p><p>J'ai décidé de m'inspirer de l'approche de Julie et d'utiliser une liste ; cependant, j'ai opté pour une liste ordonnée (<code>&lt;ol&gt;</code>) au lieu d'une liste non ordonnée (<code>&lt;ul&gt;</code>). Je pense qu'une liste ordonnée est plus appropriée dans ce cas. Une table des matières représente une liste de chapitres et de sous-titres dans l'ordre dans lequel ils apparaissent dans le contenu. L'ordre a de l'importance et ne doit pas se perdre dans le balisage.</p><p>Malheureusement, l'utilisation d'une liste ordonnée implique la perte de la relation sémantique entre le titre et le numéro de page. L'étape suivante consistait donc à rétablir cette relation dans chaque élément de la liste. Le moyen le plus simple de résoudre ce problème est d'insérer le mot "page" avant le numéro de page. De cette façon, la relation entre le numéro et le texte est claire, même sans autre distinction visuelle.</p><p>Voici un squelette HTML simple qui a servi de base à mon balisage :</p><pre class="language-html">&lt;ol class="toc-list"&gt;
  &lt;li&gt;
    &lt;a href="#link_to_heading"&gt;
      &lt;span class="title"&gt;Chapître ou titres de sous-sections&lt;/span&gt;
      &lt;span class="page"&gt;Page 1&lt;/span&gt;
    &lt;/a&gt;
    &lt;ol&gt;
      &lt;!-- sous-sections --&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;</pre><h2>Application de styles à la table des matières</h2><p>Une fois que j'ai établi le balisage que je prévoyais d'utiliser, l'étape suivante consistait à appliquer certains styles.</p><p>Tout d'abord, j'ai supprimé les numéros générés automatiquement. Vous pouvez choisir de conserver les numéros générés automatiquement dans votre propre projet si vous le souhaitez, mais il est fréquent que les livres aient des avant et après-mots non numérotés inclus dans la liste des chapitres, ce qui rend les numéros générés automatiquement incorrects.</p><p>Pour mon cas, je remplirais les numéros de chapitre manuellement, puis j'ajusterais la mise en page de façon à ce que la liste de premier niveau n'ait pas de remplissage (ce qui l'aligne sur les paragraphes) et que chaque liste intégrée soit indentée de deux espaces. J'ai choisi d'utiliser une valeur de remplissage de 2 ch parce que je n'étais pas encore tout à fait sûr de la police que j'allais utiliser. L'unité de longueur ch permet au remplissage d'être relatif à la largeur d'un caractère - quelle que soit la police utilisée - plutôt qu'à une taille absolue en pixels qui pourrait donner un aspect incohérent.</p><p>Voici le CSS que j'ai obtenu :</p><pre class="language-css">.toc-list,
.toc-list ol {
  list-style-type: none;
}
.toc-list {
  padding: 0;
}
.toc-list ol {
  padding-inline-start: 2ch;
}</pre><p><a href="https://www.sarasoueidan.com/">Sara Soueidan</a> m'a fait remarquer que les navigateurs WebKit suppriment la sémantique des listes lorsque <code>list-style-type</code> est <code>none</code>. J'ai donc dû ajouter <code>role="list"</code> dans le HTML pour la préserver :</p><pre class="language-html">&lt;ol class="toc-list" role="list"&gt;
  &lt;li&gt;
    &lt;a href="#link_to_heading"&gt;
      &lt;span class="title"&gt;Chapître ou titres de sous-sections&lt;/span&gt;
      &lt;span class="page"&gt;Page 1&lt;/span&gt;
    &lt;/a&gt;
    &lt;ol role="list"&gt;
      &lt;!-- sous-sections --&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/nzakas/pen/GRQWEox">Table of Contents - Start</a>de Nicholas C. Zakas dans<a href="https://codepen.io">CodePen</a></div><h2>Stylisation du titre et du numéro de page</h2><p>La liste étant stylisée à mon goût, il était temps de passer au style d'un élément individuel de la liste. Pour chaque élément de la table des matières, le titre et le numéro de page doivent être sur la même ligne, avec le titre à gauche et le numéro de page aligné à droite.</p><p>Vous vous dites peut-être : "Pas de problème, c'est à ça que sert le flexbox !" Vous n'avez pas tort ! Flexbox permet en effet d'obtenir un alignement correct du titre et de la page. Mais il y a quelques problèmes d'alignement délicats lorsque les leaders sont ajoutés, j'ai donc opté pour l'approche de Christoph qui utilise une grille, ce qui est un bonus car cela aide aussi avec les titres multilignes. Voici le CSS pour un article individuel :</p><pre class="language-css">.toc-list li &gt; a {
  text-decoration: none;
  display: grid;
  grid-template-columns: auto max-content;
  align-items: end;
}
.toc-list li &gt; a &gt; .page {
  text-align: right;
}</pre><p>La grille comporte deux colonnes, dont la première est automatiquement dimensionnée pour remplir toute la largeur du conteneur, moins la deuxième colonne, qui est dimensionnée au contenu maximal. Le numéro de page est aligné sur la droite, comme il est de coutume dans une table des matières.</p><p>La seule autre modification que j'ai apportée à ce stade a été de masquer le texte "Page". Ce texte est utile pour les lecteurs d'écran, mais inutile sur le plan visuel. J'ai donc utilisé une <a href="https://css-tricks.com/inclusively-hidden/#screen-reader-only">classe traditionnelle de type "visually-hidden"</a> pour le masquer :</p><pre class="language-css">.visually-hidden {
  clip: rect(0 0 0 0);
  clip-path: inset(100%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  width: 1px;
  white-space: nowrap;
}</pre><p>Et, bien entendu, le HTML doit être mis à jour pour utiliser cette classe :</p><pre class="language-html">&lt;ol class="toc-list" role="list"&gt;
  &lt;li&gt;
    &lt;a href="#link_to_heading"&gt;
      &lt;span class="title"&gt;Chapître ou titres de sous-sections&lt;/span&gt;
      &lt;span class="page"
        &gt;&lt;span class="visually-hidden"&gt;Page&lt;/span&gt; 1&lt;/span
      &gt;
    &lt;/a&gt;
    &lt;ol role="list"&gt;
      &lt;!-- sous-sections --&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;</pre><p>Cette base étant posée, je suis passé à la question des lignes pointillées entre le titre et la page.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/nzakas/pen/mdXWwmL">Table of Contents - Étape 2</a>de Nicholas C. Zakas dans<a href="https://codepen.io">CodePen</a></div><h2>Création de lignes pointillées</h2><p>Les lignes pointillées sont si courantes dans les médias imprimés que vous vous demandez peut-être pourquoi le CSS ne les prend pas déjà en charge. La réponse est : c'est le cas. Enfin, plus ou moins...</p><p>Il existe en fait une fonction <code>leader()</code> définie dans la spécification <a href="https://www.w3.org/TR/css-gcpm-3/#leaders">CSS Generated Content for Paged Media</a>. Toutefois, comme c'est le cas pour la plupart des spécifications relatives aux médias paginés, cette fonction n'est implémentée dans aucun navigateur, ce qui l'exclut de toute option (du moins au moment où j'écris ces lignes). Elle n'est même pas répertoriée sur <a href="https://caniuse.com/">caniuse.com</a>, sans doute parce que personne ne l'a implémentée et qu'il n'y a aucun plan ou signe indiquant qu'ils le feront.</p><p>Heureusement, Julie et Christoph ont déjà abordé ce problème dans leurs articles respectifs. Pour insérer les lignes pointillées, ils ont tous deux utilisé un pseudo-élément <code>::after</code> dont la propriété de contenu est définie comme une très longue chaîne de points, comme ceci :</p><pre class="language-css">.toc-list li &gt; a &gt; .title {
  position: relative;
  overflow: hidden;
}
.toc-list li &gt; a .title::after {
  position: absolute;
  padding-left: 0.25ch;
  content: ' . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . ';
  text-align: right;
}</pre><p>Le pseudo-élément <code>::after</code> est placé dans une position absolue pour le sortir du flux de la page et éviter qu'il ne revienne à la ligne. Le texte est aligné sur la droite parce que nous voulons que les derniers points de chaque ligne soient alignés sur le numéro en fin de ligne. (Nous reviendrons plus tard sur les complexités de cette question.) L'élément <code>.title</code> est configuré pour avoir une position relative afin que le pseudo-élément <code>::after</code> ne sorte pas de sa boîte. Pendant ce temps, le débordement est masqué pour que tous ces points supplémentaires soient invisibles. Le résultat est une jolie table des matières avec des lignes pointillées.</p><p>Cependant, il y a encore autre chose à prendre en considération.</p><p>Sara m'a également fait remarquer que tous ces points sont considérés comme du texte par les lecteurs d'écran. Et du coup, qu'est-ce qu'on entend ? "Introduction point point point point..." jusqu'à ce que tous les points soient annoncés. C'est une expérience terrible pour les utilisateurs de lecteurs d'écran.</p><p>La solution consiste à insérer un élément supplémentaire dont l'<code>aria-hidden</code> est réglé sur <code>true</code>, puis à utiliser cet élément pour insérer les points. Ainsi, le HTML devient :</p><pre class="language-html">&lt;ol class="toc-list" role="list"&gt;
  &lt;li&gt;
    &lt;a href="#link_to_heading"&gt;
      &lt;span class="title"
        &gt;Chapître ou titres de sous-sections&lt;span
          class="leaders"
          aria-hidden="true"
        &gt;&lt;/span
      &gt;&lt;/span&gt;
      &lt;span class="page"
        &gt;&lt;span class="visually-hidden"&gt;Page&lt;/span&gt; 1&lt;/span
      &gt;
    &lt;/a&gt;
    &lt;ol role="list"&gt;
      &lt;!-- sous-sections --&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;</pre><p>Et le CSS devient :</p><pre class="language-css">.toc-list li &gt; a &gt; .title {
  position: relative;
  overflow: hidden;
}
.toc-list li &gt; a .leaders::after {
  position: absolute;
  padding-left: 0.25ch;
  content: ' . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . '
    '. . . . . . . . . . . . . . . . . . . . . . . ';
  text-align: right;
}</pre><p>Désormais, les lecteurs d'écran ignoreront les points et épargneront aux utilisateurs la frustration d'entendre l'annonce de plusieurs points.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/nzakas/pen/ZEreyJb">Table of Contents - Étape 3</a>de Nicholas C. Zakas dans<a href="https://codepen.io">CodePen</a></div><h2>Touches finales</h2><p>À ce stade, le composant table des matières est plutôt bien conçu, mais il pourrait bénéficier de quelques petites retouches. Pour commencer, la plupart des livres décalent visuellement les titres des chapitres de ceux des sous-sections. J'ai donc mis les éléments de premier niveau en gras et introduit une marge pour séparer les sous-sections des chapitres qui suivent :</p><pre class="language-css">.toc-list &gt; li &gt; a {
  font-weight: bold;
  margin-block-start: 1em;
}</pre><p>Ensuite, je voulais nettoyer l'alignement des numéros de page. Tout se passait bien lorsque j'utilisais une police à largeur fixe, mais pour les polices à largeur variable, les points de repère peuvent finir par former un motif en zigzag lorsqu'ils s'adaptent à la largeur d'un numéro de page. Par exemple, les numéros de page comportant un 1 sont plus étroits que les autres, ce qui entraîne un désalignement des points d'amorce par rapport aux points des lignes précédentes ou suivantes.</p><figure><img src="https://la-cascade.io/images/misaligned.webp" alt="" /></figure><p>Pour résoudre ce problème, j'ai réglé <a href="https://css-tricks.com/almanac/properties/f/font-variant-numeric/"><code>font-variant-numeric</code></a> sur <code>tabular-nums</code> afin que tous les chiffres soient traités avec la même largeur. En fixant également la largeur minimale à <code>2ch</code>, je me suis assuré que tous les chiffres à un ou deux chiffres étaient parfaitement alignés. (Si votre projet compte plus de 100 pages, il est préférable de fixer cette valeur à <code>3ch</code>). Voici le CSS final pour le numéro de page :</p><pre class="language-css">.toc-list li &gt; a &gt; .page {
  min-width: 2ch;
  font-variant-numeric: tabular-nums;
  text-align: right;
}</pre><figure><img src="https://la-cascade.io/images/aligned.webp" alt="" /></figure><p>Et voilà, la table des matières est complète !</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/nzakas/pen/rNJaeMo">Table of Contents - Final</a>de Nicholas C. Zakas dans<a href="https://codepen.io">CodePen</a></div><h2>Conclusion</h2><p>La création d'une table des matières avec rien d'autre que du HTML et du CSS a été un défi plus important que prévu, mais je suis très satisfait du résultat. Non seulement cette approche est suffisamment souple pour s'adapter aux chapitres et aux sous-sections, mais elle permet de gérer les sous-sous-sections sans mettre à jour le CSS. L'approche globale fonctionne sur les pages Web où vous souhaitez créer des liens vers les différents emplacements du contenu, ainsi que sur les PDF où vous souhaitez que la table des matières renvoie à différentes pages. Et bien sûr, elle est également très belle à l'impression si vous souhaitez l'utiliser dans une brochure ou un livre.</p><p>Je tiens à remercier Julie Blanc et Christoph Grabo pour leurs excellents articles de blog sur la création d'une table des matières, car ils m'ont été d'une aide précieuse lorsque j'ai commencé. J'aimerais également remercier Sara Soueidan pour ses commentaires sur l'accessibilité pendant que je travaillais sur ce projet.</p></div>]]></description>
      <link>https://la-cascade.io/articles/une-table-des-matieres-parfaite-avec-html-et-css</link>
      <guid>https://la-cascade.io/articles/une-table-des-matieres-parfaite-avec-html-et-css</guid>
      <pubDate>Mon, 25 Jul 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[La différence entre :nth-child et :nth-of-type]]></title>
      <description><![CDATA[<p><em>La différence entre nth-child et nth-of-type n'est pas forcément évidente et pourtant elle est fondamentale.</em></p><div class="articleContent"><p>Supposons que nous ayons ce HTML :</p><pre class="language-html">&lt;section&gt;
  &lt;p&gt;Little&lt;/p&gt;
  &lt;p&gt;Piggy&lt;/p&gt;
  &lt;!-- nous voulons celui-ci --&gt;
&lt;/section&gt;</pre><p>Les deux CSS qui suivent feront exactement la même chose :</p><pre class="language-css">p:nth-child(2) {
  color: red;
}</pre><pre class="language-css">p:nth-of-type(2) {
  color: red;
}</pre><p>Pourtant, il y aura une différence évidemment.</p><p>La définition de notre sélecteur <code>:nth-child</code>, en bon français, signifie <em>sélectionne un élément si</em> :</p><ol><li>c'est un élément paragraphe</li>
<li>c'est le deuxième enfant de son élément parent</li>
</ol><p>La définition de notre sélecteur <code>:nth-of-type</code>, en bon français, signifie :</p><ol><li>sélectionne le deuxième paragraphe enfant de son élément parent</li>
</ol><p><code>:nth-of-type</code> est donc, comment dire... <em>moins conditionnel</em>.</p><p>Supposons que notre balisage soit maintenant :</p><pre class="language-html">&lt;section&gt;
  &lt;h1&gt;Words&lt;/h1&gt;
  &lt;p&gt;Little&lt;/p&gt;
  &lt;p&gt;Piggy&lt;/p&gt;
  &lt;!-- nous voulons celui-ci --&gt;
&lt;/section&gt;</pre><p>Ceci ne fonctionne plus :</p><pre class="language-css">p:nth-child(2) {
  color: red;
} /*  incorrect */</pre><p>Ceci fonctionne :</p><pre class="language-css">p:nth-of-type(2) {
  color: red;
} /* fonctionne */</pre><p>Par "incorrect", je veux dire que le sélecteur <code>:nth-child</code> sélectionne maintenant le mot "Little" au lieu de "Piggy" parce que cet élément est à la fois 1) le second enfant et 2) un élément paragraphe. Par "fonctionne", je veux dire que "Piggy" est toujours sélectionné parce qu'il est <em>le deuxième paragraphe dans cet élément parent</em>.</p><p>Si j'ajoutais un titre <code>&lt;h2&gt;</code> après le titre principal <code>&lt;h1&gt;</code>, le sélecteur <code>:nth-child</code> <em>ne sélectionnerait rien du tout</em> puisque maintenant le deuxième enfant n'est plus un paragraphe, et donc le sélecteur ne trouve rien.Le <code>:nth-of-type</code>, lui, fonctionne comme attendu.</p><p>Mon sentiment est que <code>:nth-of-type</code> est moins fragile et plus utile en général, même si <code>:nth-child</code> est plus souvent utilisé (semble-t-il). Combien de fois vous êtes-vous demandé "je veux sélectionner le deuxième enfant d'un élément parent s'il se trouve être un paragraphe" ? Parfois, peut-être, mais il est plus probable que vous vouliez "sélectionner le deuxième paragraphe" ou "sélectionner chaque troisième rangée d'un tableau", qui sont des cas où <code>:nth-of-type</code> est un choix plus solide (là encore, de mon point de vue).</p><p>J'ai l'impresson que mes moments de "Grrrr... mais pourquoi ce sélecteur <code>:nth-child</code> ne marche pas ?!" viennent du fait que j'ai qualifié le sélecteur avec un tag et que le numéro d'ordre de l'enfant ne correspond pas à ce tag. Par conséquent, lorsque j'utilise <code>:nth-child</code>, je me rends compte qu'il est préférable de spécifier le parent et de laisser <code>:nth-child</code> non qualifié.</p><pre class="language-css">dl :nth-child(2) {
} /* est mieux que */
dd:nth-child(2) {
} /* ceci */</pre><p>Mais bien sûr tout dépend de la situation exacte.</p><p>Vous pouvez jouer avec <a href="https://css-tricks.com/examples/nth-child-tester/">ce super outil de test</a> ! Voir également <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:last-of-type">la page MDN de :last-of-type</a> et <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:nth-child">la page MDN de :nth-child</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/la-difference-entre-nth-child-et-nth-of-type</link>
      <guid>https://la-cascade.io/articles/la-difference-entre-nth-child-et-nth-of-type</guid>
      <pubDate>Sun, 24 Jul 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[:last-of-type]]></title>
      <description><![CDATA[<p><em>La pseudo-classe last-of-type cible un élément qui est le dernier enfant d'un type donné dans la liste des enfants de l'élément parent.</em></p><div class="articleContent"><p>Le sélecteur <code>:last-of-type</code> nous permet de cibler la dernière occurrence d'un élément à l'intérieur de son élément parent. Il est défini dans la spécification <a href="https://www.w3.org/TR/selectors/">Selectors Level 4</a> comme une "pseudo-classe structurelle", c'est à dire qu'il est utilisé pour ajouter un style à un contenu en fonction de sa relation avec son élément parent ou ses éléments frères.</p><p>Admettons que nous ayons un article qui comporte un titre, plusieurs paragraphes et une image :</p><pre class="language-html">&lt;article&gt;
  &lt;h1&gt;Un Titre&lt;/h1&gt;
  &lt;p&gt;Paragraphe 1&lt;/p&gt;
  &lt;p&gt;Paragraphe 2&lt;/p&gt;
  &lt;p&gt;Paragraphe 3&lt;/p&gt;
  &lt;img src="..." /&gt;
&lt;/article&gt;</pre><p>Nous voulons que le dernier paragraphe soit affiché en plus petit, pour apparaître comme une conclusion (comme une note du rédacteur). Plutôt que de l'associer à une classe, nous pouvons utiliser <code>:last-of-type</code> pour le sélectionner :</p><pre class="language-css">p:last-of-type {
  font-size: 0.75em;
}</pre><p><code>:last-of-type</code> fonctionne à peu près comme <code>:nth-of-child</code> mais avec une différence essentielle : il est <a href="https://la-cascade.io/articles/la-difference-entre-nth-child-et-nth-of-type">moins spécifique</a>. Dans l'exemple qui précède, si nous avions utilisé <code>p:nth-last-child(1)</code>, il ne se serait rien passé car le paragraphe n'est pas le dernier enfant de son élément parent. C'est là qu'apparaît la puissance de <code>:last-of-type</code> : il cible un type particulier d'élément dans un arrangement spécifique, <em>en relation avec des enfants similaires, plutôt qu'avec tos les enfants</em>.</p><p>L'exemple plus complexe qui suit montre l'utilisation de <code>:last-of-type</code> et d'une pseudo-classe qui lui ressemble, <code>:first-of-type</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/zakkain/pen/DwGXKv">:first-of-type and :last-of-type</a>de Sara Cope dans<a href="https://codepen.io">CodePen</a></div><p>Voir également <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:last-of-type">la page de MDN</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/last-of-type</link>
      <guid>https://la-cascade.io/articles/last-of-type</guid>
      <pubDate>Sat, 23 Jul 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Comment apprendre CSS]]></title>
      <description><![CDATA[<p><em>Pas besoin d'apprendre par cœur chaque propriété CSS, l'important est de comprendre les fondamentaux : cet article de Rachel Andrew vous guidera dans votre apprentissage de CSS.</em></p><div class="articleContent"><p>Beaucoup de gens me demandent de leur recommander des tutoriels sur divers aspects de CSS ou me demandent <em>comment apprendre CSS</em>. Je vois aussi beaucoup de personnes qui ont du mal à comprendre certaines parties de CSS, en raison parfois d'idées dépassées sur le langage. Le langage CSS a considérablement évolué ces dernières années, c'est donc le moment idéal pour rafraîchir nos connaissances. Même si le CSS ne représente qu'une petite partie de votre travail, c'est grâce au CSS que les choses finissent par ressembler à ce que nous voulons à l'écran, et il vaut donc la peine d'être raisonnablement à jour.</p><p>Cet article a pour but de présenter les principes fondamentaux de CSS et les ressources à consulter pour approfondir les domaines essentiels du développement CSS moderne. La plupart de ces ressources se trouvent ici même (<em>sur <a href="https://www.smashingmagazine.com/">Smashing Magazine</a></em>), mais j'ai également sélectionné d'autres ressources et des personnes à suivre dans des domaines-clés du CSS. Il ne s'agit pas d'un guide complet pour les débutants, ni d'un guide destiné à couvrir absolument tous les aspects de CSS. Mon objectif est de <strong>couvrir l'essentiel du CSS moderne</strong> en me concentrant sur quelques domaines qui vous aideront à accéder au reste du langage.</p><h2>Notions fondamentales du langage</h2><p>Pour l'essentiel de CSS, vous n'avez pas à vous soucier d'apprendre les propriétés et les valeurs par cœur, vous pourrez les retrouver (NdT : <a href="https://developer.mozilla.org/fr/docs/Web/CSS">sur MDN</a> par exemple) lorsque vous en aurez besoin. Cependant, il existe certains fondamentaux du langage, sans lesquels vous aurez du mal à vous y retrouver. Il vaut vraiment la peine de consacrer un peu de temps à vous assurer que vous comprenez ces éléments, vous gagnerez du temps et vous éviterez beaucoup de frustration à long terme.</p><h2>Les sélecteurs, plus qu'une simple classe</h2><p>Un sélecteur fait ce qu'il est censé faire : il <em>sélectionne</em> une partie de votre document afin que vous puissiez lui appliquer des règles CSS. L'utilisation d'une classe ou l'application d'un style à un élément HTML tel que <code>body</code>, est généralement familière à tous, mais il existe un grand nombre de sélecteurs plus avancés qui peuvent sélectionner des éléments en fonction de leur emplacement dans le document, par exemple parce qu'ils viennent directement après un élément ou que ce sont les rangées impaires d'un tableau.</p><p>Les sélecteurs faisant partie de la spécification de niveau 3 (vous avez peut-être déjà entendu parler d'eux sous le nom de <strong>sélecteurs de niveau 3</strong>) sont <a href="https://caniuse.com/css-sel3">très bien pris en charge par les navigateurs</a>. Pour un examen détaillé des différents sélecteurs que vous pouvez utiliser, consultez <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Selectors">la référence MDN</a>.</p><p>Certains sélecteurs agissent <em>comme si</em> vous aviez appliqué une <strong>classe</strong> à un élément du document. Par exemple, <code>p:first-child</code> se comporte comme si vous aviez ajouté une classe au premier élément <code>p</code>. Ces sélecteurs sont connus sous le nom de <strong>sélecteurs de pseudo-classe</strong>.</p><p>Les <strong>sélecteurs de pseudo-éléments</strong> quant à eux agissent comme si un <strong>élément</strong> était inséré dynamiquement, par exemple <code>::first-line</code> agit de la même manière que si vous aviez enveloppé la première ligne de texte dans un <code>span</code>. Toutefois, il s'applique à nouveau si la longueur de la ligne change, ce qui ne serait pas le cas si vous insériez l'élément. Ces sélecteurs peuvent être assez complexes. Dans le CodePen ci-dessous, vous trouverez un exemple de pseudo-élément enchaîné avec une pseudo-classe. Nous ciblons le premier élément <code>p</code> avec une pseudo-classe <code>:first-child</code>, puis le sélecteur <code>::first-line</code> sélectionne la première ligne de cet élément, agissant comme si un <code>span</code> était ajouté autour de cette première ligne afin de la mettre en gras et d'en changer la couleur.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/wRdJdQ/">first-line</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>L'héritage et la cascade</h2><p>La cascade définit <em>la règle qui l'emporte</em> lorsque plusieurs règles peuvent s'appliquer à un élément. Si vous avez déjà été dans une situation où vous ne compreniez pas pourquoi certains CSS ne semblaient pas s'appliquer, il est probable que la cascade en soit responsable. La cascade est étroitement liée à l'héritage, qui définit quelles propriétés sont héritées par les éléments enfants de l'élément auquel elles sont appliquées. Elle est également liée à la spécificité ; les différents sélecteurs ont une spécificité différente qui détermine lequel l'emporte lorsque plusieurs sélecteurs peuvent s'appliquer à un élément.</p><p>Remarque : pour bien comprendre toutes ces notions, je vous suggère de lire la section <a href="https://developer.mozilla.org/fr/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade et héritage</a> dans l'intro à CSS de MDN.</p><p>??  <em>La Cascade recommande aussi la lecture de <a href="https://openweb.eu.org/articles/cascade_css">Cascade et priorité des sélecteurs</a> de Laurent Denis dans openweb</em>.</p><p>Si vous avez du mal à appliquer un CSS à un élément, les DevTools de votre navigateur sont le meilleur endroit pour commencer vos investigations. Regardez l'exemple ci-dessous dans lequel j'ai un élément <code>h1</code> ciblé par le sélecteur d'élément <code>h1</code> et qui rend le titre orange. J'utilise également une classe, qui donne à l'élément <code>h1</code> la couleur <code>rebeccapurple</code>. La classe est plus spécifique et le <code>h1</code> est donc violet et non orange. Dans DevTools, vous pouvez voir que le sélecteur d'élément est barré car il ne s'applique pas. Une fois que vous avez constaté que le navigateur reçoit votre CSS (mais que quelque chose d'autre a pris le dessus), vous pouvez commencer à chercher à savoir pourquoi.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/yGbMoL/">spécificité</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><figure role="group"><img src="https://la-cascade.io/images/smashing-css-specificity.webp" alt="Informations de devtools" /><figcaption>DevTools nous permet de voir pourquoi certaines règles CSS ne sont pas appliquées à un élément</figcaption></figure><h2>Le modèle de boîte</h2><p>Les CSS sont des boîtes. Tout ce qui est affiché à l'écran a une boîte, et le <a href="https://la-cascade.io/articles/controler-le-modele-de-boite">modèle de boîte</a> décrit la façon dont la taille de cette boîte est calculée, en tenant compte des marges, du padding et des bordures. Le modèle de boîte CSS standard prend la largeur que vous avez donnée à un élément, puis ajoute à cette largeur le padding et la bordure, ce qui signifie que l'espace occupé par l'élément est plus grand que la largeur que vous lui avez donnée.</p><p>Plus récemment, nous avons pu choisir d'utiliser un autre modèle de boîte qui utilise la largeur donnée à l'élément comme la largeur de l'élément visible à l'écran. Tout padding ou bordure insère le contenu de la boîte à partir des bords. Cela est beaucoup plus logique pour de nombreuses mises en page.</p><p>Dans la démo ci-dessous, j'ai deux boîtes. Elles ont toutes deux une largeur de 200 pixels, une bordure de 5 pixels et un padding de 20 pixels. La première boîte utilise le modèle de boîte standard et occupe donc une largeur totale de 250 pixels. La seconde utilise le modèle de boîte alternatif et a donc une largeur de 200 pixels.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/xmdqjd/">modèle de boîte</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Là encore, les DevTools du navigateur peuvent nous aider à comprendre le modèle de boîte utilisé. Dans l'image ci-dessous, j'utilise Firefox DevTools pour inspecter une boîte utilisant le modèle de boîte <code>content-box</code> par défaut. Les outils m'indiquent qu'il s'agit du modèle de boîte utilisé, et je peux voir le dimensionnement et la façon dont la bordure et le remplissage sont ajoutés à la largeur que j'ai attribuée.</p><figure role="group"><img src="https://la-cascade.io/images/smashing-css-box-model.webp" alt="Informations de devtools" /><figcaption>DevTools nous permet de voir pourquoi une boîte a une certaine taille, et quel modèle de boîte est utilisé</figcaption></figure><p>Remarque : avant IE6, Internet Explorer utilisait <a href="https://en.wikipedia.org/wiki/CSS_box_model#History">un autre modèle de boîte</a>, avec un padding et des bordures insérant le contenu en dehors de la largeur donnée. Pendant un certain temps, les navigateurs ont donc utilisé des modèles de boîtes différents ! Lorsque vous rencontrez des problèmes d'interopérabilité aujourd'hui, réjouissez-vous que les choses se soient améliorées et que les navigateurs ne calculent pas la largeur des objets de manière différente.</p><p>Vous trouverez une bonne explication du modèle de boîte et du dimensionnement des boîtes <a href="https://css-tricks.com/box-sizing/">dans CSS Tricks</a>, ainsi qu'une explication de la meilleure façon d'<a href="https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/">utiliser globalement le modèle de boîte</a> alternatif dans votre site.</p><p>??  <em>La Cascade recommande aussi la lecture de <a href="https://la-cascade.io/articles/controler-le-modele-de-boite">Contrôler le modèle de boîte</a> d'Ire Aderinokun, et de <a href="https://la-cascade.io/articles/box-sizing-pour-les-nuls">Box-sizing pour les nuls</a> de Paula Borowska, publiés ici même</em>.</p><h2>Flux normal</h2><p>Si vous avez un document dont le contenu est balisé par du HTML et que vous le visualisez dans un navigateur, il sera, avec un peu de chance, lisible. Les titres et les paragraphes commencent sur une nouvelle ligne, les mots s'affichent comme une phrase avec un seul espace blanc entre eux. Les balises de mise en forme, telles que <code>em</code>, n'interrompent pas le flux de la phrase. Ce contenu s'affiche <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Flow_Layout">en mode Normal Flow</a> ou Block Flow Layout. Chaque partie du contenu est décrite comme étant "en flux" ; elle connaît le reste du contenu et ne se chevauche donc pas.</p><p>Si vous travaillez avec ce comportement plutôt que contre lui, votre vie sera beaucoup plus facile. C'est l'une des raisons pour lesquelles il est très utile de commencer par <a href="https://brucelawson.co.uk/2018/the-practical-value-of-semantic-html/">un document HTML correctement balisé</a>. En effet, grâce au flux normal et aux feuilles de style intégrées des navigateurs qui le respectent, votre contenu commence à être lisible.</p><h2>Contextes de formatage</h2><p>Une fois que vous avez un document dont le contenu est en flux normal, vous pouvez souhaiter modifier l'apparence d'une partie de ce contenu. Pour ce faire, vous devez modifier le <strong>contexte de mise en forme de l'élément</strong>. Par exemple, si vous souhaitez que tous vos paragraphes soient regroupés et ne commencent pas sur une nouvelle ligne, vous pouvez changer l'élément <code>p</code> en <code>display : inline</code>, ce qui le fait passer d'un contexte de bloc à un contexte de mise en forme en ligne.</p><p>Les contextes de mise en forme définissent essentiellement <strong>un type externe et un type interne</strong>. Le type externe contrôle le comportement de l'élément par rapport aux autres éléments de la page, tandis que le type interne contrôle l'apparence des enfants. Ainsi, par exemple, lorsque vous dites <code>display : flex</code>, vous définissez le contexte extérieur comme étant un contexte de formatage de bloc et les enfants comme ayant un contexte de formatage de flex.</p><p>Remarque : La dernière version de la spécification d'affichage modifie les valeurs de <code>display</code> pour déclarer explicitement la valeur intérieure et extérieure. Par conséquent, à l'avenir, vous pourrez dire <code>display : block flex</code> ; (<code>block</code> étant la valeur externe et <code>flex</code> la valeur interne).</p><p>Pour en savoir plus sur l'affichage, rendez-vous <a href="https://developer.mozilla.org/fr/docs/Web/CSS/display">sur MDN</a>.</p><h2>Être dans ou hors du flux</h2><p>Les éléments CSS sont décrits comme étant "dans le flux" ou "hors du flux". Les éléments dans le flux sont dotés d'un espace et cet espace est respecté par les autres éléments dans le flux. Si vous sortez un élément du flux, en le faisant flotter ou en le positionnant, l'espace de cet élément ne sera plus respecté par les autres éléments dans le flux.</p><p>Cela se remarque surtout avec les éléments positionnés de manière absolue. Si vous donnez à un élément une <code>position : absolute</code>, il est sorti du flux, vous devrez alors vous assurer que vous n'avez pas une situation dans laquelle l'élément hors du flux chevauche et rend illisible une autre partie de votre mise en page.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/Ormgzj/">positionnement absolu hors du flux</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Quant aux éléments flottants, ils sont également retirés du flux et, même si le contenu qui suit semble s'enrouler autour d'eux, on peut voir en plaçant une couleur de fond sur la boîte des éléments suivants qu'en réalité ils se sont élevés, ont raccourci leurs lignes, et ignorent l'espace utilisé par l'élément flottant.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/BvRZYw/">élément flottant hors du flux</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Vous pouvez en savoir plus sur <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Flow_Layout/In_Flow_and_Out_of_Flow">les éléments en flux et hors flux sur MDN</a>. Ce qu'il faut retenir, c'est que si vous retirez un élément du flux, vous devez gérer vous-même le chevauchement, car les règles habituelles de mise en page du flux de blocs ne s'appliquent plus.</p><h2>Mise en page</h2><p>Pendant plus de quinze ans, nous avons fait de la mise en page en CSS sans système de mise en page conçu pour ce travail. Cela a changé. Nous disposons désormais d'un système de mise en page parfaitement adapté, qui comprend la grille (Grid) et le Flexbox, mais aussi la mise en page en colonnes multiples et les anciennes méthodes de mise en page utilisées à bon escient. Si la mise en page CSS est un mystère pour vous, rendez-vous sur <a href="https://developer.mozilla.org/fr/docs/Learn/CSS/CSS_layout">le tutoriel MDN Learn Layout</a>, ou lisez mon article <a href="https://www.smashingmagazine.com/2018/05/guide-css-layout/">Getting Started With CSS Layout</a> dans Smashing Magazine.</p><p>N'imaginez pas que des méthodes telles que Grid et Flexbox soient de quelque façon concurrentes. Pour bien utiliser Layout, vous constaterez parfois qu'un composant est meilleur en tant que composant Flexbox et parfois en tant que Grid. À l'occasion, vous voudrez le comportement de flux de colonnes de multicol. Tous ces choix sont valables. Si vous avez l'impression de vous battre contre le comportement d'un élément, c'est en général un très bon signe qu'il vaut sans doute la peine de prendre du recul et d'essayer une approche différente. <em>Nous avons tellement l'habitude de bidouiller les CSS pour leur faire faire ce que nous voulons que nous risquons d'oublier que nous avons pas mal d'autres options à disposition</em>.</p><p>La mise en page est mon principal domaine d'expertise et j'ai écrit un certain nombre d'articles dans Smashing Magazine et ailleurs pour essayer d'aider à apprivoiser le nouveau paysage de la mise en page. En plus de l'article sur la mise en page mentionné ci-dessus, j'ai tout une série d'articles sur Flexbox - commencez par <a href="https://la-cascade.io/articles/que-se-passe-t-il-quand-on-cree-un-flexbox-flex-container">Que se passe-t-il quand on crée un Flexbox Flex Container</a>. Dans l'article <a href="https://gridbyexample.com/">Grid By Example</a>, je propose toute une série de petits exemples de CSS Grid, ainsi qu'un tutoriel vidéo.</p><p>En outre, et surtout pour les designers, jetez un coup d'œil à <a href="https://twitter.com/jensimmons">Jen Simmons</a> et à sa série de vidéos <a href="https://www.youtube.com/channel/UC7TizprGknbDalbHplROtag">Layout Land</a>.</p><h2>Alignement</h2><p>J'ai séparé l'alignement de la mise en page en général car, bien que la plupart d'entre nous aient été initiés à l'alignement dans le cadre de Flexbox, <strong>ces propriétés s'appliquent à toutes les méthodes de mise en page</strong> et il est utile de les comprendre dans ce contexte plutôt que de penser à "l'alignement Flexbox" ou "l'alignement CSS Grid". Nous disposons d'un ensemble de propriétés d'alignement qui fonctionnent de manière commune dans la mesure du possible ; elles présentent ensuite quelques différences dues au comportement des différentes méthodes de mise en page.</p><p>Sur MDN, vous pouvez étudier l'<a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Box_Alignment">alignement des boîtes</a> et la manière dont il est mis en œuvre pour la grille, Flexbox, Multicol et la disposition en blocs. Dans Smashing Magazine, j'ai un article qui traite spécifiquement de l'alignement dans Flexbox : <a href="https://la-cascade.io/articles/css-flexbox-et-lalignement-guide-complet">CSS Flexbox et l'alignement, guide complet</a>.</p><h2>Dimensionnement</h2><p>J'ai passé une grande partie de 2018 à parler de la spécification de dimensionnement intrinsèque et extrinsèque, et de la façon dont elle se rapporte à Grid et à Flexbox en particulier. Sur le web, nous sommes habitués à définir le dimensionnement en longueurs ou en pourcentages, car c'est ainsi que nous avons pu réaliser des mises en page de type Grid à l'aide de nombres flottants. Toutefois, les méthodes de mise en page modernes peuvent effectuer une grande partie de la répartition de l'espace à notre place, si nous les laissons faire. Il vaut la peine de comprendre comment Flexbox attribue l'espace (ou comment fonctionne l'unité <code>fr</code> Grid).</p><p>Dans Smashing Magazine, j'ai écrit sur <a href="https://www.smashingmagazine.com/2018/01/understanding-sizing-css-layout/">le dimensionnement dans la mise en page en général</a> et aussi pour Flexbox dans <a href="https://www.smashingmagazine.com/2018/09/flexbox-sizing-flexible-box/">How Big Is That Flexible Box</a> ?</p><h2>Conception réactive</h2><p>Nos nouvelles méthodes de mise en page (Grid et Flexbox) nous permettent souvent d'utiliser moins de media queries qu'avec nos anciennes méthodes, car elles sont flexibles et répondent aux changements de taille des fenêtres ou des composants sans que nous ayons besoin de modifier la largeur des éléments. Cependant, il y aura des endroits où vous voudrez ajouter des <em>breakpoint</em> pour améliorer votre design.</p><p>Pour les <em>media queries</em>, en général, consultez mon article <a href="https://www.smashingmagazine.com/2018/02/media-queries-responsive-design-2018/">Utiliser les media queries pour le Responsive Design en 2018</a>. J'y jette un coup d'œil à ce que les media queries peuvent faire pour nous, et je montre également les nouvelles fonctionnalités à venir pour les media queries dans le niveau 4 de la spécification.</p><h2>Polices et typographie</h2><p>Parallèlement à la mise en page, l'utilisation des polices sur le web a subi d'énormes changements l'année dernière. Les polices variables, qui permettent à un seul fichier de police d'avoir des variations illimitées, sont là. Pour avoir un aperçu de ce qu'elles sont et de leur fonctionnement, regardez cet excellent exposé de Mandy Michael : <a href="https://www.youtube.com/watch?v=luAqYCd_TC8">Variable Fonts and the Future of Web Design</a> . Je vous recommande également <a href="https://noti.st/jpamental/WNNxqQ/dynamic-typography-with-modern-css-variable-fonts">Dynamic Typography With Modern CSS and Variable Fonts</a> de Jason Pamental.</p><p>Pour explorer les polices variables et leurs capacités, il existe une démo amusante de Microsoft ainsi qu'un certain nombre de terrains de jeu pour tester les polices variables - <a href="https://www.axis-praxis.org/specimens/__DEFAULT__">Axis Praxis</a> étant le plus connu (j'aime aussi le <a href="https://play.typedetail.com/">Font Playground</a>).</p><p>Une fois que vous aurez commencé à travailler avec des polices variables, <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide">ce guide sur MDN</a> vous sera d'une grande utilité. Pour apprendre à mettre en œuvre une solution de repli pour les navigateurs qui ne prennent pas en charge les polices variables, lisez <a href="https://pimpmytype.com/variable-font-fallback/">Implementing a Variable Font With Fallback Web Fonts</a> d'Oliver Schöndorfer. <a href="https://firefox-source-docs.mozilla.org/devtools-user/page_inspector/how_to/edit_fonts/index.html">L'éditeur de polices de Firefox DevTools</a> permet également de travailler avec des polices variables.</p><h2>Transformations et animations</h2><p>Les transformations et les animations CSS sont des sujets que je consulte en fonction de mes besoins. Je n'ai pas souvent besoin de les utiliser, et la syntaxe semble me sortir de la tête entre deux utilisations. Heureusement, la référence sur MDN m'aide et je suggère de commencer par les guides sur <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Transforms/Using_CSS_transforms">l'utilisation des transformations CSS</a> et <a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Animations/Using_CSS_animations">l'utilisation des animations CSS</a>. Zell Liew a également rédigé <a href="https://zellwk.com/blog/css-transitions/">un article intéressant</a> qui explique en détail les transitions CSS.</p><p>Pour avoir une idée de tout ce qu'on peut faire, jetez un coup d'œil au site d'<a href="https://animista.net/">Animista</a>.</p><p>L'une des choses qui peut prêter à confusion avec les animations, c'est l'approche à adopter. En plus de ce qui est pris en charge par CSS, vous pouvez avoir besoin d'impliquer JavaScript, SVG ou l'API d'animation Web, et tous ces éléments ont tendance à être mis dans le même panier. Dans son exposé intitulé "<a href="https://aneventapart.com/news/post/choose-your-animation-adventure-by-val-head-aea-video">Choose Your Animation Adventure</a>" enregistré à An Event Apart, <a href="https://twitter.com/vlh">Val Head</a> explique les différentes options.</p><h2>Utilisez les antisèches comme un aide-mémoire, pas comme un outil d'apprentissage !</h2><p>Lorsque je mentionne des ressources relatives à Grid ou Flexbox, je reçois souvent des réponses indiquant qu'il est impossible d'utiliser Flexbox sans une antisèche. Je n'ai aucun problème avec les antisèches en tant qu'aide-mémoire pour consulter la syntaxe, et j'en ai publié quelques-unes moi-même. Le problème, si l'on s'en remet entièrement à elles, c'est que l'on risque de ne pas comprendre <em>pourquoi les choses fonctionnent</em> en copiant la syntaxe. Ensuite, lorsque vous rencontrez un cas où cette propriété semble se comporter différemment, cette incohérence apparente semble déconcertante, ou un défaut du langage.</p><p>Si vous vous trouvez dans une situation où CSS semble faire quelque chose de très étrange, demandez-vous pourquoi. Créez un scénario de test réduit qui met en évidence le problème, demandez à quelqu'un qui connaît mieux la spécification. La plupart des problèmes CSS sur lesquels on me pose des questions sont dus au fait que la personne concernée pense qu'une propriété fonctionne d'une manière différente de celle qu'elle utilise en réalité. C'est la raison pour laquelle je parle beaucoup de choses comme l'alignement et le dimensionnement, car c'est là que réside souvent cette confusion.</p><p>Oui, il y a des choses étranges dans CSS. C'est un langage qui a évolué au fil des ans, et il y a des choses que nous ne pouvons pas changer - <a href="https://wiki.csswg.org/ideas/mistakes">jusqu'à ce que nous inventions une machine à remonter le temps</a>. Cependant, une fois que vous aurez acquis quelques notions de base et que vous comprendrez pourquoi les choses se comportent comme elles le font, vous aurez beaucoup plus de facilité avec les notions plus pointues.</p><p>??  <em>NdT : La Cascade a traduit de nombreux articles de Rachel Andrew, dont vous trouverez la liste dans <a href="https://la-cascade.io/auteurs/rachel-andrew">la page de l'auteur</a>. Par ailleurs, les pages de tags sont enrichies de nombreuses ressources (autrefois listées dans la page Ressources de La Cascade), voyez par exemple <a href="https://la-cascade.io/tags/css">la page CSS</a> ou <a href="https://la-cascade.io/tags/flexbox">la page Flexbox</a>.</em></p></div>]]></description>
      <link>https://la-cascade.io/articles/comment-apprendre-css</link>
      <guid>https://la-cascade.io/articles/comment-apprendre-css</guid>
      <pubDate>Wed, 22 Jun 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Contrôler l'affichage du texte]]></title>
      <description><![CDATA[<p><em>Comment gérer le retour à la ligne ou les césures ? Il y a beaucoup plus de façons qu'on ne le pense, et plein d'astuces possibles.</em></p><div class="articleContent"><p>Nous allons voir différentes façons de contrôler (ou pas) le flux du texte sur une page Web. CSS nous offre de nombreux outils pour assurer ce flux — retour à la ligne, coupure de mots — mais nous verrons également plusieurs astuces utilisant HTML et les caractères spéciaux.</p><h2>Protection de la mise en page</h2><p>Normalement, le texte retourne à la ligne dès que l'opportunité se présente, c'est-à-dire aux endroits où l'on s'attend à ce que le texte s'interrompe naturellement, entre les mots ou après un trait d'union. Mais on a parfois affaire à de longues portions de texte qui ne présentent pas de possibilités de retour à la ligne, comme des mots très longs ou des URL. Cela peut entraîner toutes sortes de problèmes de mise en page. Par exemple, le texte peut déborder de son conteneur ou forcer le conteneur à devenir trop large et pousser des éléments hors de leur place.</p><p>Un bon codage défensif consiste à <strong>anticiper les problèmes liés à l'absence de rupture explicite du texte</strong>, et CSS nous fournit quelques outils à cet effet.</p><h2>Faire en sorte que le texte retourne à la ligne</h2><p>En plaçant <code>overflow-wrap : break-word</code> sur un élément, le texte pourra être interrompu au milieu du mot si nécessaire. L'algorithme essaiera d'abord de garder un mot intact en le déplaçant à la ligne suivante, mais il coupera le mot s'il n'y a toujours pas assez de place.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/dydPWvo">overflow-wrap: break-word</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Il y a également <code>overflow-wrap : anywhere</code>, qui coupe les mots de la même manière. La différence réside dans la façon dont il affecte le calcul de la taille du contenu minimal de l'élément sur lequel il se trouve. L'effet est assez évident quand on fixe la largeur à <code>min-content</code> :</p><pre class="language-CSS">.top {
  width: min-content;
  overflow-wrap: break-word;
}
.bottom {
  width: min-content;
  overflow-wrap: anywhere;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/vYdEmxG">overflow-wrap + min-content</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Le premier élément avec <code>overflow-wrap : break-word</code> calcule le contenu minimal comme si aucun mot n'était coupé, de sorte que sa largeur devient la largeur du mot le plus long. L'élément du bas avec <code>overflow-wrap : anywhere</code> calcule le contenu minimal avec toutes les coupures qu'il peut créer. Vu qu'une coupure peut se produire n'importe où, le contenu minimal correspond à la largeur d'un seul caractère.</p><p>N'oubliez pas que ce comportement ne se produit que lorsque <code>min-content</code> est impliqué. Si nous avions donné une valeur fixe à la largeur, nous verrions le même résultat de coupure de mots dans les deux cas de figure.</p><h2>Couper les mots sans pitié</h2><p>Une autre option pour créer une césure est <code>word-break: break-all</code>. Celle-ci n'essaiera même pas de garder les mots entiers — elle les coupera immédiatement. Voici ce que ça donne :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/GRQgmWN">word-break: break-all</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez comment le mot long n'est pas déplacé à la ligne suivante, comme il l'aurait été en utilisant <code>overflow</code>. Remarquez aussi comment "words" est coupé, même s'il aurait pu être placé sur la ligne suivante.</p><p><code>word-break : break-all</code> n'a aucun problème à couper les mots, mais il reste toujours prudent avec la ponctuation. Par exemple, il évitera de commencer une ligne avec le point de la fin d'une phrase. Si vous voulez une rupture vraiment impitoyable, même avec la ponctuation, utilisez <code>line-break : anywhere</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/PoQwmpp">word-break: break-all vs line-break: anywhere</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Vous avez vu comment <code>word-break : break-all</code> déplace le "k" vers le bas pour éviter de commencer la deuxième ligne avec "." ? Mais <code>line-break : anywhere</code> , lui, s'en moque.</p><h2>Ponctuation excessive</h2><p>Voyons comment les propriétés CSS que nous avons abordées jusqu'à présent traitent les signes de ponctuation excessivement longs.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/OJQPmpm">Ponctuation excessive</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p><code>overflow-wrap : break-word</code> et <code>line-break : anywhere</code> sont capables de contenir les choses, mais il y a ensuite <code>word-break : break-all</code> qui est de nouveau bizarre avec la ponctuation — cette fois-ci, le résultat est un texte qui déborde.</p><p>C'est une chose à garder à l'esprit. Si vous ne voulez absolument pas que le texte déborde, sachez que <code>word-break : break-all</code> n'empêchera pas la ponctuation de dépasser.</p><h2>Spécifier où les mots peuvent être coupés</h2><p>Pour plus de contrôle, vous pouvez insérer manuellement des possibilités de coupure de mots dans votre texte avec <code>&lt;wbr&gt;</code>. Vous pouvez également utiliser un "espace de largeur nulle", fourni par l'entité HTML <code>&amp;ZeroWidthSpace;</code> (oui, il faut des majuscules comme vous le voyez !).</p><p>Voyons ces éléments en action avec une longue URL qui ne serait normalement pas retournée à la ligne, en insérant des césures entre les segments.</p><pre class="language-HTML">  &lt;!-- normal --&gt;
  &lt;p&gt;https://subdomain.somewhere.co.uk&lt;/p&gt;
  &lt;!-- &lt;wbr&gt; --&gt;
  &lt;p&gt;https://subdomain&lt;wbr&gt;.somewhere&lt;wbr&gt;.co&lt;wbr&gt;.uk&lt;/p&gt;
  &lt;!-- &amp;ZeroWidthSpace; --&gt;
  &lt;p&gt;https://subdomain&amp;ZeroWidthSpace;.somewhere&amp;ZeroWidthSpace;.co&amp;ZeroWidthSpace;.uk&lt;/p&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/wvyBdJq">Manual Word Break Opportunities</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><h2>Trait d'union automatique</h2><p>Vous pouvez demander au navigateur de couper les mots avec un trait d'union lorsque nécessaire en utilisant l'option <code>hyphens: auto</code>. Les règles de césure sont déterminées par la langue. Vous devez donc indiquer au navigateur la langue à utiliser. Pour ce faire, vous devez spécifier l'attribut <code>lang</code> dans le HTML, soit directement dans l'élément concerné, soit dans la balise <code>&lt;html&gt;</code>.</p><pre class="language-HTML">&lt;p lang="en"&gt;This is just a bit of arbitrary text to show hyphenation in action.&lt;/p&gt;
</pre><pre class="language-CSS">  p {
    -webkit-hyphens: auto; /* pour Safari */
    hyphens: auto;
  }</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/NWyPjpw">hyphens: auto</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><h2>Trait d'union manuel</h2><p>Vous pouvez également prendre les choses en main et insérer un "tiret doux" manuellement avec l'entité HTML <code>&amp;shy;</code>. Il ne sera pas visible, à moins que le navigateur ne décide de l'insérer, auquel cas un trait d'union apparaîtra. Remarquez dans la démo suivante que nous utilisons deux fois l'entité <code>&amp;shy;</code> mais qu'elle n'apparaît qu'une seule fois, là où le texte doit effectivement retourner à la ligne.</p><pre class="language-HTML">&lt;p lang="en"&gt;Magic? Abraca&amp;shy;dabra? Abraca&amp;shy;dabra!&lt;/p&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/jOZEmBz">Trait d'union doux</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p><code>hyphens</code> doit être réglé sur <code>auto</code> ou <code>manual</code> pour que <code>&amp;shy;</code> s'affiche correctement. Par commodité, la valeur par défaut est <code>hyphens : manual</code>, ce qui devrait vous permettre de vous passer de tout CSS supplémentaire (à moins que quelque chose quelque part n'ait déclaré <code>hyphens : none</code> pour une raison quelconque).</p><h2>Empêcher le texte de revenir à la ligne</h2><p>Changeons de sujet. Il peut arriver que vous ne souhaitiez pas que le texte retourne librement à la ligne, afin de mieux contrôler la façon dont votre contenu est présenté. Il existe quelques outils pour vous aider.</p><p>Le premier est <code>white-space : nowrap</code>. Placez-le sur un élément pour empêcher son texte de revenir à la ligne naturellement.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/qBxEmVE">white-space: nowrap</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><h2>Préformater le texte</h2><p>Il existe également la fonction <code>white-space : pre</code>, qui permet d'afficher un retour à la ligne du texte tel que vous l'avez saisi dans votre HTML. Prenez garde toutefois, car il conservera également les espaces de votre HTML, donc faites attention à votre formatage. Vous pouvez également utiliser une balise <code>&lt;pre&gt;</code> pour obtenir les mêmes résultats (elle comporte un <code>white-space : pre</code> par défaut).</p><pre class="language-HTML">&lt;!-- le formatage de ce HTML a pour conséquence un espace blanc supplémentaire --&gt;
&lt;p&gt;
  What's worse, ignorance or apathy?
  I don't know and I don't care.
&lt;/p&gt;
&lt;!-- un formatage plus serré qui "embrasse" le texte --&gt;
&lt;p&gt;What's worse, ignorance or apathy?
I don't know and I don't care.&lt;/p&gt;
&lt;!-- comme ci-dessus, mais avec &lt;pre&gt; --&gt;
&lt;pre&gt;What's worse, ignorance or apathy?
I don't know and I don't care.&lt;/pre&gt;</pre><pre class="language-CSS">p {
  white-space: pre;
}
pre {
  /* &lt;pre&gt; sets font-family: monospace, but we can undo that */
  font-family: inherit;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/LYQEyOV">Texte préformaté</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><h2>Un retour à la ligne dans un insécable ?</h2><p>Pour les sauts de ligne, vous pouvez utiliser <code>&lt;br&gt;</code> à l'intérieur d'un élément avec <code>white-space: nowrap</code> ou <code>white-space: pre</code>. Le texte retournera à la ligne.</p><p>Mais que se passe-t-il si vous utilisez <code>&lt;wbr&gt;</code> dans un tel élément ? C'est une question piège… parce que les navigateurs ne sont pas d'accord ! Chrome/Edge reconnaîtra le <code>&lt;wbr&gt;</code> et retournera à la ligne potentiellement, mais pas Firefox/Safari.</p><p>En ce qui concerne l'espace de largeur nulle <code>&amp;ZeroWidthSpace;</code>, les navigateurs sont cohérents. Aucun ne renverra à la ligne avec <code>white-space: nowrap</code> ou <code>white-space: pre</code>.</p><pre class="language-HTML">&lt;p&gt;Darth Vader: Nooooooooooooo&lt;br&gt;oooo!&lt;/p&gt;
&lt;p&gt;Darth Vader: Nooooooooooooo&lt;wbr&gt;oooo!&lt;/p&gt;
&lt;p&gt;Darth Vader: Nooooooooooooo&amp;ZeroWidthSpace;oooo!&lt;/p&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/dydPWZG">white-space: nowrap + breaking lines</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><h2>Espaces insécables</h2><p>Parfois, vous souhaiterez peut-être que le texte retourne librement à la ligne, sauf à des endroits très spécifiques. Bonne nouvelle ! Il existe quelques entités HTML spécialisées qui vous permettent de faire exactement cela.</p><p>Un "espace insécable" (<code>&amp;nbsp;</code>) est souvent utilisé pour conserver un espace entre les mots, mais n'autorise pas de saut de ligne entre eux (ils forment alors un tout insécable).</p><pre class="language-HTML">&lt;p&gt;Something I've noticed is designers don't seem to like orphans.&lt;/p&gt;
&lt;p&gt;Something I've noticed is designers don't seem to like&amp;nbsp;orphans.&lt;/p&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/YzePVEW">Espaces insécables</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>?? <em>NdT : un exemple courant (et recommandé) d'utilisation de l'espace insécable est l'espace précédant un signe de ponctuation, par exemple un point d'exclamation ! ou le suivant, par exemple : — un tiret cadratin. Nous ne contrôlons pas la largeur des écrans de nos utilisateurs, l'espace insécable évite les signes de ponctuation orphelins en début ou en fin de ligne</em>.</p><h2>Jointures de mots et traits d'union insécables</h2><p>Un texte peut retourner naturellement à la ligne même sans espaces, par exemple après un trait d'union à l'intérieur d'un mot. Pour empêcher le retour à la ligne, vous pouvez utiliser <code>&amp;NoBreak;</code> (sensible à la casse !) qui agit comme un "agrégateur de mots". Pour les traits d'union en particulier, vous pouvez obtenir un "trait d'union insécable" avec <code>&amp;#8209;</code> (il n'a pas de joli nom d'entité HTML).</p><pre class="language-HTML">  &lt;p&gt;Turn right here to get on I-85.&lt;/p&gt;
  &lt;p&gt;Turn right here to get on I-&amp;NoBreak;85.&lt;/p&gt;
  &lt;p&gt;Turn right here to get on I&amp;#8209;85.&lt;/p&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/vYdEmWX">Word Joiners and Non-Breaking Hyphens</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><h2>Texte CJC et mots de rupture</h2><p>Le texte CJC (chinois/japonais/coréen) se comporte à certains égards différemment du texte non CJC. Certaines propriétés et valeurs CSS peuvent être utilisées pour un contrôle supplémentaire du retour à la ligne du texte CJC spécifiquement.</p><p>Le comportement par défaut du navigateur permet de couper des mots dans le texte CJC. Cela signifie que <code>word-break: normal</code> (par défaut) et <code>word-break: break-all</code> vous donneront les mêmes résultats. Cependant, vous pouvez utiliser <code>word-break: keep-all</code> pour empêcher le texte CJC de revenir à la ligne au milieu des mots (le texte non CJC ne sera pas affecté).</p><p>Voici un exemple en coréen. Notez comment le mot "자랑스럽게" se coupe ou ne se coupe pas.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/MWQYmVZ">CJK Text + word-break</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Attention toutefois, le chinois et le japonais n'utilisent pas d'espaces entre les mots comme le fait le coréen, donc <code>word-break: keep-all</code> peut facilement provoquer un long débordement de texte s'il n'est pas géré autrement.</p><h2>Texte CJC et règles de saut de ligne</h2><p>Nous avons parlé de <code>line-break: anywhere</code> tout à l'heure avec du texte non CJC et du fait qu'il n'a aucun problème à couper à la ponctuation. Il en va de même avec le texte CJC.</p><p>Voici un exemple en japonais. Notez comment "。" est ou n'est pas autorisé à commencer une ligne.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/ZErYKxw">CJK Text + line-break</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Il existe d'autres valeurs pour <code>line-break</code> qui affectent la façon dont le texte CJC retourne à la ligne : <code>loose</code>, <code>normal</code> et <code>strict</code>. Ces valeurs indiquent au navigateur les règles à utiliser pour décider où insérer des sauts de ligne. Le W3C <a href="https://drafts.csswg.org/css-text-3/#line-break-property">décrit plusieurs règles</a> et il est également possible pour les navigateurs d'ajouter leurs propres règles.</p><h2>À mentionner : Débordement d'élément</h2><p>La propriété CSS <code>overflow</code> n'est pas spécifique au texte, mais est souvent utilisée pour s'assurer que le texte ne s'affiche pas en dehors d'un élément dont la largeur ou la hauteur est délimitée.</p><pre class="language-CSS">.top {
  white-space: nowrap;
  overflow: auto;
}
.bottom {
  white-space: nowrap;
  overflow: hidden;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/rNJamdb">Element Overflow</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Comme vous pouvez le voir, une valeur <code>auto</code> permet de faire défiler le contenu (<code>auto</code> n'affiche les barres de défilement qu'en cas de besoin, <code>scroll</code> les affiche toujours). Une valeur de <code>hidden</code> coupe simplement le contenu et en reste là.</p><p><code>overflow</code> est en fait un raccourci pour définir à la fois <code>overflow-x</code> et <code>overflow-y</code>, respectivement pour le débordement horizontal et vertical. N'hésitez pas à utiliser ce qui vous convient le mieux.</p><p>Nous pouvons compléter <code>overflow: hidden</code> en ajoutant <code>text-overflow: ellipsis</code>. Le texte sera toujours coupé, mais nous aurons de jolis points de suspension à titre indicatif.</p><pre class="language-CSS">p {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/XWZJREw">text-overflow: ellipsis</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><h2>Astuce bonus : saut de ligne en pseudo-élément</h2><p>Vous pouvez forcer un saut de ligne avant et/ou après un élément ìnline<code>, tout en le gardant comme élément</code> inline`, avec une astuce de pseudo-élément.</p><p>Tout d'abord, définissez le <code>content</code> d'un pseudo-élément <code>::before</code> ou <code>::after</code> sur <code>'\A'</code>, ce qui vous donnera le caractère de <em>nouvelle ligne</em>. Ensuite, définissez <code>white-space: pre</code> pour vous assurer que le caractère de nouvelle ligne est respecté.</p><pre class="language-HTML">&lt;p&gt;Things that go &lt;span&gt;bump&lt;/span&gt; in the night.&lt;/p&gt;</pre><pre class="language-CSS">span {
  background-color: #000;
}
span::before, span::after {
  content: '\A';
  white-space: pre;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/eYVmWMX">Pseudo-Element Line Breaks</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Nous aurions pu simplement mettre <code>display: block</code> sur le <code>&lt;span&gt;</code> pour obtenir les mêmes retours à la ligne, mais il ne serait plus <code>inline</code>. Le <code>background-color</code> permet de voir facilement qu'avec cette méthode, nous avons toujours un élément <code>inline</code>.</p><h2>Notes bonus</h2><ul><li>Il existe une ancienne propriété CSS nommée <code>word-wrap</code>. Elle n'est pas standard et les navigateurs la traitent désormais comme un alias pour <code>overflow-wrap</code>.</li>
<li>La propriété CSS <code>white-space</code> a <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/white-space#values">d'autres valeurs</a> que nous n'avons pas couvertes : <code>pre-wrap</code>, <code>pre-line</code> et <code>break-spaces</code>. Contrairement à celles que nous avons couvertes, celles-ci n'empêchent pas le retour à la ligne du texte.</li>
<li>La spécification CSS Text Module Level 4 <a href="https://www.w3.org/TR/css-text-4/#text-wrap">décrit</a> une propriété CSS <code>text-wrap</code> qui semble intéressante, mais au moment de la rédaction, aucun navigateur ne l'implémente.</li>
</ul><h2>Il est temps de conclure</h2><p>Il y a <a href="https://raphlinus.github.io/text/2020/10/26/text-layout.html#line-breaking">tellement de choses à dire à propos du texte fluide</a> sur une page Web. La plupart du temps, vous n'avez pas vraiment besoin d'y penser, car les navigateurs le gèrent pour vous. Si vous avez besoin de plus de contrôle, il est bon de savoir que vous avez beaucoup d'options.</p><p>Écrire cet article a définitivement été un puits sans fond pour moi car je trouvais à chaque fois plus de choses à raconter. J'espère que je vous en ai montré assez pour que votre texte se coupe et s'écoule comme vous le souhaitez.</p><p>Merci d'avoir lu !</p></div>]]></description>
      <link>https://la-cascade.io/articles/controler-affichage-du-texte</link>
      <guid>https://la-cascade.io/articles/controler-affichage-du-texte</guid>
      <pubDate>Sun, 08 May 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Améliorer un texte à faible contraste]]></title>
      <description><![CDATA[<p><em>Le contraste insuffisant d'un texte est un obstacle grave pour les utilisateurs malvoyants ou simplement à la vue déclinante. Et pourtant, ce problème d'accessibilité lié au contraste est encore très (trop) répandu !</em></p><div class="articleContent"><p>Le premier principe d'accessibilité du contenu dans les <em><a href="https://www.w3.org/TR/WCAG22/">Web Content Accessible Guidelines</a></em> est que le contenu doit être <strong>perceptible</strong>. Après tout, vous ne pourrez pas accéder à l'information ou à la fonctionnalité si vous ne savez pas qu'elle est là ! Et apparemment, le moyen le plus efficace de s'assurer que les utilisateurs ne pourront pas distinguer votre contenu est de le définir dans une couleur qui ne se démarque pas de son arrière-plan — en d'autres termes, d'avoir un faible contraste de couleur.</p><p>Nous pouvons tous rencontrer un problème lié à un contraste insuffisant, pour diverses raisons — par exemple à cause du reflet du soleil sur notre écran — mais le contraste insuffisant d'un texte a un impact <em>démesuré</em> sur les utilisateurs malvoyants tels que ceux qui ont des problèmes de vision ou qui sont daltoniens. Et pourtant, le texte à faible contraste est partout. Le rapport <a href="https://webaim.org/projects/million/">WebAIM Million pour 2022</a> a révélé que près de 84 % des 1 million de pages d'accueil les plus populaires avaient au moins une violation de contraste insuffisant, avec une moyenne de 31,6 instances distinctes de texte faiblement contrasté par page d'accueil. <a href="https://accessibility.deque.com/hubfs/Accessibility-Coverage-Report.pdf#page=6">Un rapport de 2021 de Deque Systems (PDF)</a> a révélé que le texte à faible contraste représentait 30 % des défauts d'accessibilité automatiquement détectables, ce qui en fait de loin le défaut d'accessibilité le plus courant.</p><p>Corriger l'insuffisance de contraste pourrait grandement contribuer à <strong>rendre le Web plus utilisable</strong>. Nous allons voir comment mesurer le contraste, corriger facilement un faible contraste et assurer un contraste suffisant dans nos sites à l'avenir.</p><h2>Obtenez un ratio</h2><p>Le plus simple pour commencer est d'utiliser un contrôleur de contraste de couleur. Des outils tels que <a href="https://webaim.org/resources/contrastchecker/">WebAIM Contrast Checker</a> prennent une paire de couleurs que vous leur donnez et vous retournent un rapport de contraste. En attendant, si vous avez déjà déployé votre site et vos couleurs en direct pour le monde, vous pouvez utiliser des outils d'analyse d'accessibilité pleine page tels que l'extension <a href="https://www.deque.com/axe/devtools/">ax DevTools</a>, et ils effectueront des opérations de contraste des couleurs pour chaque bit de texte et d'arrière-plan sur votre page et identifieront les éléments spécifiques de votre page dont le contraste est insuffisant. Dans tous les cas, vous obtiendrez un rapport de contraste des couleurs.</p><p>Ces ratios prennent le format <code>&lt;un certain nombre&gt;:1</code>, allant de <code>1:1</code> (pas de contraste — vous avez comparé une couleur à elle-même) à <code>21:1</code> (contraste maximum, uniquement obtenu en comparant le noir et blanc). Plus le premier chiffre est élevé, plus il y a de contraste entre les deux couleurs.</p><p>Ce rapport n'est pas vraiment un score de la différence entre les deux couleurs, mais plutôt un score de la façon dont une couleur serait perceptible par dessus l'autre. Par exemple, en tant que personne non daltonienne, les couleurs CSS tomato <code>#ff6347</code> et cornflowerblue <code>#6495ed</code> me semblent très différentes :</p><section class="demo" aria-label="Démo : deux cercles, un rouge tomate et l'autre bleu clair"><p>Et pourtant, la tomate et le bleuet ont ensemble un très mauvais rapport de contraste des couleurs : seulement environ 1,009:1. C'est à peine mieux que la comparaison de n'importe quelle couleur avec elle-même ! Si nous empilons ces couleurs l'une sur l'autre (avec nos excuses anticipées !), nous pouvons voir qu'ensemble elles sont difficiles, voire carrément douloureuses, à lire :</p><p><strong>Qui a envie de lire ça ?</strong></p><p>Les algorithmes de contraste de couleurs actuelllement disponibles pour obtenir ces rapports n'essaient pas de nous donner la différence mathématique pure entre deux couleurs, mais décrivent plutôt une différence plus subjective entre les deux couleurs, basée sur la perception humaine. Plus précisément, ils comparent la <a href="https://fr.wikipedia.org/wiki/Luminance">luminance</a> relative des deux couleurs, ce qui revient essentiellement à savoir si une couleur est plus claire ou plus lumineuse que l'autre. Ici, la tomate et le bleuet sont à peu près aussi brillants, c'est pourquoi ils sont difficiles à lire ensemble.</p><h3>Utilisation des ratios</h3><p>Maintenant que nous avons une idée de la façon dont on mesure le contraste entre deux couleurs, comment savons-nous quand le contraste est suffisant ?</p><p>Dans le <a href="https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html">critère de réussite 1.4.3</a> des directives pour l'accessibilité des contenus Web, le World Wide Web Consortium définit deux points de repère clés dont nous devons nous souvenir :</p><ul><li>La plupart des textes ont besoin d'un rapport d'au moins 4,5:1 par rapport à leur arrière-plan.</li>
<li>Les règles pour les textes plus volumineux sont un peu plus souples — un texte volumineux n'a besoin que de respecter un rapport de 3:1 par rapport à son arrière-plan.</li>
</ul><h2>Comment améliorer votre score</h2><p>Vous avez donc mesuré votre texte et déterminé qu'il ne répond pas aux exigences de contraste des couleurs. Que pouvez-vous faire pour régler la situation sans chambouler votre design ?</p><p>En règle générale, j'aborde la correction du contraste des couleurs de deux manières différentes, au cas par cas :</p><ul><li>Choisir des couleurs plus claires et plus foncées</li>
<li>Agrandir le texte</li>
</ul><h3>Passez du côté Clair/Obscur</h3><p>Votre approche principale pour résoudre les problèmes de contraste des couleurs consistera à modifier les couleurs sous-jacentes elles-mêmes.</p><p>En général cependant, vous vous retrouverez limité dans ce que vous pouvez faire si vous abordez le problème en modifiant les <em>teintes</em> des couleurs. D'une part, les guides de style des marques ou des sites ont généralement des palettes de couleurs assez strictes, et le changement de teintes créera souvent des couleurs qui s'en écartent. D'autre part, comme l'a montré l'exemple précédent de tomate et bleuet, les teintes des couleurs ont souvent un impact très minime sur le rapport entre ces deux couleurs, surtout si ces couleurs ont des luminosités très similaires.</p><p>Au lieu de cela, il me semble que rendre une couleur plus claire et/ou l'autre couleur plus foncée a un impact plus profond sur le contraste, tout en restant plus cohérent avec le reste des composantes du design et plus proche de la sensibilité générale du site.</p><h3>L'agrandissement est parfaitement acceptable</h3><p>Un texte plus grand et plus épais a tendance à être beaucoup plus facile à lire, même sur des arrière-plans à faible contraste, qu'un texte plus petit et plus fin. Par exemple, dans l'exemple suivant, les deux lignes de texte sont de la même couleur, mais si vous arrivez à discerner le texte, il sera plus facile d'en distinguer la première ligne, dont les caractères sont plus grands et plus gras :</p><section class="gris" aria-label="Exemple: Text gris clair sur un fond gris encore plus clair: le texte en gras est à peu près lisible, le texte en petits caractères est illisible."><p><strong>Je suis plutôt plus facile à lire !</strong></p><p><small>Je suis bien plus difficile à lire !</small></p></section><p>C'est à cause de cette différence que le WCAG est un peu plus indulgent pour le texte volumineux, qu'il définit comme un texte d'au moins <code>18 pt</code> ou, alternativement, comme un texte en gras et d'au moins <code>14 pt</code>. N'oubliez pas que <code>pt</code> est une unité de taille de police définie par le navigateur de l'utilisateur (un peu comme <code>rem</code>) — ce qui signifie, dans les paramètres par défaut de la plupart des navigateurs, que le seuil est d'environ 24 pixels, ou à la fois "en gras <em>et</em> d'environ 19 pixels". Le texte qui répond à ce critère de dimensionnement n'a besoin que d'un rapport de <code>3:1</code> par rapport à son arrière-plan, selon le WCAG.</p><p>Vous pourrez parfois utiliser ce seuil plus indulgent à votre avantage, car au lieu de devoir choisir différentes couleurs, vous pourrez peut-être augmenter la taille ou le poids de votre police. Si vous utilisez uniquement cette approche pour atteindre vos seuils minimaux, ce correctif ayant tendance à être très contextuel ne s'appliquera probablement qu'à des éléments tels que les titres. Cependant, l'accessibilité ne consiste pas seulement à atteindre des seuils. Le WCAG est la barre minimale à franchir, mais une fois que vous avez franchi ces seuils minimaux, vous pouvez utiliser des tactiques telles que l'augmentation de la taille de la police, l'augmentation du poids de la police ou le choix d'une police de caractères plus épaisse pour offrir une expérience plus lisible, même s'ils n'améliorent pas votre score de contraste.</p><h2>Construire des approches systémiques pour assurer le contraste des couleurs</h2><p>Ces approches fonctionnent bien pour ajouter des couleurs uniques à une page ou pour corriger un texte à faible contraste mis en évidence par un audit, mais ce n'est pas très durable pour les grands sites ou organisations.</p><p>De nombreuses organisations se tournent vers les systèmes de design pour communiquer leurs pratiques UI et UX, y compris leurs palettes de couleurs, ainsi que leurs connaissances institutionnelles sur le moment et la manière dont chaque couleur desdites palettes doit être utilisée. Ces systèmes de design sont un excellent endroit pour coder les connaissances sur les appariements de couleurs acceptables. Par exemple, un système de design peut déterminer des couleurs d'arrière-plan et des couleurs de texte acceptables pour les boutons, et ces couleurs auront certainement été choisies en fonction de rapports de contraste acceptables. Les designers et les développeurs peuvent tirer parti de ces décisions sans même avoir <em>vraiment besoin</em> du contexte d'arrière-plan complet de la façon dont ces couleurs ont été choisies — il y a un <a href="https://blog.codinghorror.com/falling-into-the-pit-of-success/">puits de succès</a> large et facile.</p><p>?? <em>NdT : comme rappelé dans l'article en lien ci-dessus, notre objectif n'est pas que l'utilisateur remporte une brillante victoire au terme de multiples épreuves et surprises, mais qu'il</em> tombe simplement dans des pratiques gagnantes <em>en utilisant notre plateforme et nos frameworks. Faciliter les ennuis, c'est courir à l'échec</em>.</p><p>J'ai également entendu parler de systèmes de design qui deviennent encore plus explicites dans la façon dont ils communiquent des associations de couleurs accessibles. Une astuce que j'ai apprise de <a href="https://www.mikeaparicio.com/">Mike Aparicio</a> réside dans la façon dont il nomme les nuances du coloris d'un système de design. Dans ses systèmes de design, chaque nuance d'une couleur reçoit un nombre de 100 à 900, où 100 est la nuance la plus claire, 600 est la nuance "de base", 900 est la nuance la plus foncée et les autres couleurs sont remplies entre les deux comme de besoin. Ses échelles de couleurs sont calculées de manière à ce que les couleurs "200" et plus claires soient toujours suffisamment claires pour contraster avec la teinte de base "600". Cette règle est assez facile à retenir pour les designers et les développeurs, ce qui garantit qu'ils sont beaucoup plus susceptibles de choisir des appariements acceptables. Vous pouvez l'entendre parler de cette approche sur <a href="https://frontend.horse/episode/lets-make-a-design-system">Frontend Horse</a> et dans <a href="https://www.youtube.com/watch?v=wX3z42LbfbI">ma propre émission Some Antics</a>.</p><h2>Encore quelques éléments à garder en tête à propos du contraste</h2><p>Les systèmes de rapport de contraste actuels sont assez soigneusement vérifiés, mais il y a quelques limitations, dont les suivantes :</p><ul><li>Les algorithmes actuels ne prennent pas en compte la question de savoir quelle couleur est au premier plan et laquelle est en arrière-plan, même si dans certaines paires de couleurs telles que le marron et le rose, une couleur est définitivement plus appropriée comme premier plan et non comme arrière-plan.</li>
<li>Le gras de certaines polices de caractères n'est pas toujours très gras, ce qui signifie que vous pouvez répondre à la <em>lettre</em> de l'exigence de texte en gras sans en respecter l'<em>esprit</em>.</li>
</ul><p>Une future version des Directives pour l'accessibilité du contenu Web peut utiliser <a href="https://github.com/Myndex/SAPC-APCA">un algorithme de contraste de couleur différent</a> qui utilise plus de facteurs tels que ceux-ci, mais <a href="https://yatil.net/blog/wcag-3-is-not-ready-yet">cela nécessite encore plus de vérification</a>. Si vous rencontrez certaines de ces limitations dans votre design et si vous pensez que votre design est techniquement conforme, je vous encourage à faire des tests utilisateur si possible, de préférence avec des utilisateurs malvoyants, pour vérifier si votre contenu est ou non lisible pour de vrais gens.</p><p>De plus, la couleur peut être une chose difficile à équilibrer ! Si vous avez du mal à distinguer différents contenus avec des couleurs, envisagez de vous appuyer sur d'autres leviers et d'utiliser des outils tels que des icônes ou différentes tailles de police pour faire passer votre message ! Cela garantit que vous <a href="https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html">ne comptez pas uniquement sur la couleur</a> pour transmettre du sens, et la création de moyens redondants pour intégrer des informations dans votre design conduira presque toujours à une expérience plus accessible.</p><h2>Points à retenir en conclusion</h2><p>Les problèmes de contraste des couleurs sont partout, et les éliminer réduirait considérablement les barrières d'accès sur le Web. Au cas par cas, je trouve plus simple de corriger un faible insuffisant en ajustant la luminosité ou l'obscurité des couleurs, plutôt que leur teinte ou leur saturation. Dans <em>certains</em> cas (notamment les textes proéminents tels que les titres), vous pourrez peut-être tirer parti de la taille et de l'épaisseur de la police. À l'avenir, le contraste devrait être traité de manière systémique, typiquement par le biais de systèmes de design codifiés et, idéalement, contrôlé par des tests utilisateurs.</p></section></div>]]></description>
      <link>https://la-cascade.io/articles/ameliorer-un-texte-a-faible-contraste</link>
      <guid>https://la-cascade.io/articles/ameliorer-un-texte-a-faible-contraste</guid>
      <pubDate>Fri, 29 Apr 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Une taille de police enfantine]]></title>
      <description><![CDATA[<p><em>Défense et illustration des tailles de police plus grandes pour nos utilisateurs, par Tyler Sticka. La Cascade ne peut que plussoyer.</em></p><div class="articleContent"><p>En matière de <code>font-size</code>, on peut dire qu'on a fait du chemin. Je me rappelle une époque où il était encore courant d'utiliser une taille d'affichage de 10 pixels (ou moins), afin d'entasser autant de texte que possible dans un espace disponible de 640x480. De nos jours, les arguments en faveur d'une ligne de base de 16 pixels (<a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#f1">1</a>) sont assez largement acceptés. <a href="https://www.smashingmagazine.com/2011/10/16-pixels-body-copy-anything-less-costly-mistake/">De nombreuses données confirment sa lisibilité</a>, elle peut <a href="https://css-tricks.com/16px-or-larger-text-prevents-ios-form-zoom/">empêcher le zoom accidentel dans les navigateurs de portables</a>, et c'est <a href="https://imalov.dev/articles/golden-document-root-size/">la valeur par défaut dans la plupart des navigateurs</a> depuis maintenant plusieurs années.</p><p>Pourtant, de nombreux arguments militent en faveur de tailles de polices encore plus grandes :</p><ul><li>Des études ont montré que les polices plus grandes amélioraient la compréhension. Dans <a href="https://pielot.org/pubs/Rello2016-Fontsize.pdf">une étude de 2012</a>, la taille idéale était estimée entre 18 et 22 pixels. (<a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#f2">2</a>)</li>
<li>Des polices plus grandes sont plus accessibles. Le Ministère de la Santé américain recommande une taille de police d'<a href="https://health.gov/healthliteracyonline/display/section-3-3/">au moins 19 pixels</a> si votre lectorat comprend des personnes ayant des difficultés de lecture ou ayant un certain âge.</li>
<li>La tendance actuelle va déjà dans ce sens : les sites offrant beaucoup de contenu, comme <a href="https://medium.com/">Medium</a>, <a href="https://www.vox.com/">Vox</a> et le <a href="https://www.washingtonpost.com/">Washington Post</a> (pour n'en citer que quelques-uns) vont bien au-delà de 16 pixels pour le corps de texte, même sur les écrans réduits.</li>
<li><a href="https://www.imarc.com/blog/best-font-size-for-any-device">Certaines polices semblent plus petites</a> que d'autres à 16 pixels. Si votre police est fine, condensée ou si elle a une faible <a href="https://fr.wikipedia.org/wiki/Hauteur_d%27x">hauteur d'x</a>, 16 pixels ne suffiront pas.</li>
<li>Grâce à des fonctionnalités comme <a href="https://www.smashingmagazine.com/2022/01/modern-fluid-typography-css-clamp/">CSS clamp</a>, nos tailles de polices peuvent être aussi fluides que nos mises en page, et s'agrandir depuis un minimum lisible jusqu'à un maximum que nous choisissons selon les paliers responsifs voulus.</li>
</ul><p>Malgré ces arguments, j'ai constaté une certaine résistance à l'utilisation d'une taille de police supérieure. Ce n'est pas du tout surprenant, on voit de même certaines fonctionnalités de navigateurs ou de bonnes pratiques d'usabilité prendre du temps pour être adoptées, et tout ce qui n'est pas familier est difficile à vendre.</p><p>Sur quelques projets bien différents, avec des publics, des identités visuelles et des polices de caractères très divers, la réaction que j'entends le plus souvent concernant les polices plus grandes est qu'elles semblent assez <em>enfantines</em>, "on dirait un livre pour enfants".</p><p>Tirés de leur contexte, ces termes pourraient avoir l'air péjoratifs, mais je veux le dire clairement : nos clients sont polis, aimables, et nous leur demandons un retour franc et sans filtre. C'est pour moi un succès d'obtenir un avis honnête, qui est une marque de confiance, plutôt que des formulations indirectes. Et ça rend les patterns de feedbacks comme celui-ci bien plus faciles à repérer !</p><p>Alors, pourquoi "enfantin" ? Je pense que si cette réponse revient fréquemment c'est qu'elle renvoie à une expérience partagée. Nous avons tous été enfants, nous avons tous vu des livres pour enfants, et les astuces qui rendent la typographie accessible aux enfants sont les mêmes que celles qui aident les adultes ayant des niveaux variables d'alphabétisation, d'acuité visuelle et d'attention : des polices ayant une hauteur d'x généreuse, un espacement équilibré des mots et des lignes, des longueurs de ligne raisonnables, un alignement cohérent et un contraste adéquat. (<a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#f3">3</a>)</p><figure role="group"><img src="https://la-cascade.io/images/mrs-peter-rabbit.jpeg" alt="" /><figcaption>Double-page d'une édition de 1919 de "The Tale of Peter Rabbit" <small>(<a href="https://read.gov/books/peter_rabbit.html">Library of Congress</a>)</small></figcaption></figure><p>Mais si ces caractéristiques aident aussi bien les enfants que les adultes, pourquoi le texte de nos magazines imprimés, de nos romans, journaux et modes d'emploi est-il plus petit ?</p><p>En partie sans doute à cause du contenu : plus le lecteur est expérimenté, plus l'information peut être complexe. Les passages de texte plus longs bénéficient de sections et de titres, avec des tailles (plus grandes et plus petites) et des styles (graisse, casse, etc.) contrastés pour établir la hiérarchie. Des tableaux, des graphiques et des figures peuvent être utilisés pour faire comprendre des relations complexes, nécessitant une certaine densité d'informations pour être utiles. Ces considérations sont toujours pertinentes dans nos expériences numériques.</p><p>Mais je soupçonne malgré tout que la principale explication du rétrécissement typographique des longs formulaires se résume aux limites physiques de la page imprimée. Un texte plus gros signifie plus de pages, ce qui signifie plus de papier, d'encre et de matériaux de reliure… plus de travail et de carburant pour concevoir, imprimer, assembler et expédier… plus d'espace occupé sur nos étagères et dans nos bagages. Il n'est tout simplement pas pratique pour votre roman préféré d'augmenter considérablement sa taille de police sans augmenter son coût, ou devenir physiquement difficile à lire lorsqu'on est allongé sur le canapé.</p><p>Le design Web quant à lui a aussi ses limites, mais le nombre de pages n'en est pas une : nos navigateurs sont des fenêtres sur un <a href="https://scottmccloud.com/4-inventions/canvas/">canevas infini</a> de contenu. Nous nous fichons bien que <a href="https://en.wikipedia.org/wiki/Wikipedia:Size_in_volumes">Wikipedia remplisse plus de 3 000 volumes imprimés</a>, car il n'a jamais à le faire : nos appareils ne grossiront pas ou ne s'alourdiront pas en le lisant sur notre navigateur, quelle que soit la taille de la police.</p><figure role="group"><img src="https://la-cascade.io/images/infinite-canvas.jpeg" alt="" /><figcaption>Scott McCloud discute des opportunités de la "toile infinie" dans ces panneaux de son roman graphique de 2000 <small>(<a href="https://scottmccloud.com/2-print/2-rc/index.html">Reinventing comics</a>)</small></figcaption></figure><p>Donc, à moins d'entendre un argument plus convaincant, je vais continuer à préconiser des tailles de police plus grandes pour des passages de contenu plus longs, en prenant soin de préserver la hiérarchie et la densité de l'information, le cas échéant. 18 ou 20 pixels peuvent sembler assez grands à première vue pour nous qui sommes tellement habitués à plisser les yeux à 16 ou moins, mais les données sont claires et les avantages de lisibilité sont immédiats. (<a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#f4">4</a>)</p><p><small>    <strong id="f1">1</strong> - J'utilise les pixels tout au long de cet article pour la clarté, mais <a href="https://www.w3.org/TR/WCAG20-TECHS/C14.html">vous devriez probablement utiliser les unités proportionnelles</a> (<code>em</code>, <code>rem</code>, etc.) quand c'est possible.</small> <a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#a1">↩</a></p><p><small>    <strong id="f2">2</strong> - L'étude utilise des points, mais ce sont des points CSS, ils correspondent donc à des pixels. Les points sont d'une taille différente à l'impression (environ un tiers plus grand ?), j'ai donc utilisé le terme "pixels" ici pour plus de cohérence dans l'article</small> <a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#a2">↩</a></p><p><small>    <strong id="f3">3</strong> - Une de mes premières hypothèses était que les polices plus grandes exposaient plus de similitudes entre les polices de caractères d'entreprise et celles des livres ou des produits pour enfants, mais cette idée s'est effondrée lorsque je me suis familiarisé à nouveau avec la variété stupéfiante des traitements typographiques dans les œuvres pour enfants.</small> <a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#a3">↩</a></p><p><small>    <strong id="f4">4</strong> - Certains pourraient dire que c'est un point discutable… nos utilisateurs les plus avertis peuvent redimensionner le texte comme ils le souhaitent. Pour moi, c'est comme demander à nos utilisateurs de tenir l'écran plus près de leur visage : c'est toujours une option, mais une défense fragile pour une décision de design.</small> <a href="https://la-cascade.io/articles/une-taille-de-police-enfantine#a4">↩</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/une-taille-de-police-enfantine</link>
      <guid>https://la-cascade.io/articles/une-taille-de-police-enfantine</guid>
      <pubDate>Wed, 27 Apr 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre CSS Grid : Grid template areas]]></title>
      <description><![CDATA[<p><em>Dans cette nouvelle série, Rachel Andrew analyse la spécification CSS Grid Layout. Elle poursuit ici avec les zones de grille.</em></p><div class="articleContent"><p>Avec Grid, on peut toujours placer les items entre une ligne de grille et une autre. Mais il existe une autre façon de décrire notre mise en page, une façon plus <em>visuelle</em>. Dans ce troisième volet de notre série nous allons voir comment utiliser la propriété <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gta">grid-template-areas</a> pour définir un placement sur la grille et nous découvrirons comme elle fonctionne réellement.</p><h2>Décrire une mise en page avec grid-template-areas</h2><p>La propriété <code>grid-template-areas</code> accepte pour valeur une ou plusieurs chaînes de caractères. Chacune, entourée de guillemets, représente une rangée de notre grille. Nous pouvons utiliser la propriété sur une grille définie avec <code>grid-template-rows</code> et <code>grid-template-columns</code>, ou nous pouvons créer notre mise en page, auquel cas toutes les rangées seront automatiquement dimensionnées.</p><p>La propriété et les valeurs qui suivent décrivent une grille comportant quatre zones — chacune s'étend sur deux pistes de colonnes et deux pistes de rangées. Une zone (<em>area</em>) peut s'étendre sur plusieurs pistes lorsqu'on en répète le nom dans toutes les cellules qu'on veut couvrir :</p><pre>grid-template-areas: "one one two two"
                     "one one two two"
                     "three three four four"
                     "three three four four";
</pre><p>Les items sont placés dans la mise en page en étant nommés dans la propriété <code>grid-area</code>. Si nous voulons placer un élément ayant une classe <code>test</code> dans la zone de la grille qui s'appelle <code>one</code>, il suffit d'écrire :</p><pre>.test {
  grid-area: one;
}</pre><p>Regardons cela en action dans le codepen qui suit. J'ai quatre items, avec des classes nommées un à quatre (one to four), qui sont assignées aux zones de grille correspondantes via la propriété <code>grid-area</code> et qui s'affichent donc dans les boîtes correctes de la grille.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/VwLLRKE/">Grid template areas : exemple simple</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si vous utilisez l'inspecteur Grid de Firefox, vous pouvez voir les noms des zones et les lignes de grille, montrant que chaque item s'étend en effet sur deux rangées et deux colonnes — le tout sans faire aucun positionnement basé sur les lignes pour l'item lui-même.</p><figure role="group"><img src="https://la-cascade.io/images/smashing-grid-area1.webp" alt="chaque item s'étend sur deux rangées et deux colonnes" /></figure><h2>Règles d'utilisation de grid-template-areas</h2><p>Il ya des règles à suivre lorsqu'on crée une mise en page de cette façon. Ne pas les respecter rendra les valeurs invalides et notre mise en page ne fonctionnera pas. La première règle est que <strong>nous devons décrire une grille complète</strong>, chaque cellule de la grille doit être remplie.</p><p>Si l'on veut laisser une ou plusieurs cellules vides, on exprime ce choix en insérant un point <code>.</code> ou une série de points <code>...</code> sans espace entre eux.</p><p>Si je change les valeurs de notre grille ainsi :</p><pre>grid-template-areas: "one one two two"
                     "one one two two"
                     ". . four four"
                     "three three four four";
</pre><p>j'ai maintenant deux cellules sans contenu à l'intérieur. L'item <code>three</code> n'est affiché que dans la dernière rangée de la grille.</p><figure role="group"><img src="https://la-cascade.io/images/smashing-grid-area2.webp" alt="il y a maintenant un espace vide dans notre grille" /></figure><p><strong>Nous ne pouvons définir chaque zone qu'une seule fois</strong>, c'est à dire que nous ne pouvons utiliser cette propriété pour copier du contenu à deux endroits sur la grille ! Les valeurs qui suivent seraient invalides et la propriété dans son ensemble serait ignorée, car nous avons dupliqué la zone <code>three</code> :</p><pre>grid-template-areas: "one one three three"
                     "one one two two"
                     "three three four four"
                     "three three four four";</pre><p>On ne peut pas non plus créer une zone non-rectangulaire, la propriété ne peut pas être utilisée pour créer une zone en forme de T ou de L, et les valeurs ci-dessous sont également invalides :</p><pre>grid-template-areas: "one one two two"
                     "one one one one"
                     "three three four four"
                     "three three four four";</pre><h2>Formater les chaînes de caractères</h2><p>Dans mon CSS, j'aime bien afficher les valeurs de <code>grid-template-area</code> comme je le fais ci-dessus, avec chaque chaîne de caractères qui représente une rangée et chacune disposée en-dessous de la rangée précédente, car cela me donne une représentation visuelle de ma mise en page.</p><p>Pour améliorer encore la visualisation, on peut ajouter des espaces entre chaque cellule, mais aussi des points multiples pour les cellules vides, ainsi tout est bien aligné :</p><pre>grid-template-areas: "one   one   two  two"
                     "one   one   two  two"
                     "..... ..... four four"
                     "three three four four";</pre><p>Ceci étant, on peut, de manière tout à fait valide, aligner toutes les chaînes de caractères sur une seule ligne, on pourrait donc écrire :</p><pre>grid-template-areas: "one one two two" "one one two two" "three three four four" "three three four four";</pre><h2>Expliquer grid-template-areas et grid-area</h2><p>La raison pour laquelle chaque zone doit être un rectangle complet est qu'elle doit avoir la même forme que si elle avait été créée par un placement basé sur les lignes. Si nous poursuivons avec notre exemple précédent, nous pourrions réaliser cette mise en page avec des lignes de grille comme dans le codepen ci-dessous. Ici, j'ai créé ma grille comme avant. Cette fois par contre, j'ai utilisé les lignes de grille pour positionner via les propriétés (raccourcies) <code>grid-column-start</code>, <code>grid-column-end</code>, <code>grid-row-start</code> et <code>grid-row-end</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/LYEdOdB/">Grid template areas : placement basé sur les lignes</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Note : si vous avez lu mon précédent article <a href="https://la-cascade.io/articles/comprendre-cssgrid-lines">Comprendre CSS Grid : les lignes Grid</a> vous savez déjà qu'il est possible d'utiliser <code>grid-area</code> comme un raccourci pour déclarer les quatre lignes en une fois.</p><p>Cela signifie que nous pourrions aussi créer notre mise en page avec l'ordre de lignes suivant :</p><ul><li><code>grid-row-start</code></li>
<li><code>grid-column-start</code></li>
<li><code>grid-row-end</code></li>
<li><code>grid-column-end</code></li>
</ul><pre>.one {
  grid-area: 1 / 1 / 3 / 3;
}
.two {
  grid-area: 1 / 3 / 3 / 5;
}
.three {
  grid-area: 3 / 1 / 5 / 3;
}
.four {
  grid-area: 3 / 3 / 5 / 5;
}</pre><p>la propriété <code>grid-area</code> est intéressante en ce qu'elle peut prendre des numéros de ligne ou des noms de ligne. Mais il est important de comprendre comment elle fonctionne dans chaque mode.</p><h3>Utiliser grid-area avec des numéros de ligne</h3><p>Si vous utilisez la propriété <code>grid-area</code> avec des numéros de ligne, alors les lignes seront assignées dans l'ordre décrit ci-dessus.</p><p>Si vous omettez des valeurs — en ne fournissant qu'un, deux, ou trois numéros de ligne — les valeurs manquantes sont réglées sur <code>auto</code> ce qui signifie que la zone s'étendra sur une piste (ce qui est la valeur par défaut). Donc le CSS suivant placerait un item <code>grid-row-start: 3</code> avec toutes les autres valeurs réglées sur <code>auto</code>, et donc, l'item serait auto-placé dans la première piste de colonne disponible, et s'étendrait sur une piste de rangée et une piste de colonne.</p><pre>grid-area: 3;</pre><h3>Utiliser grid-area avec des idents</h3><p>Si nous utilisons <strong>ident</strong> (qui est la façon pour Grid Layout d'appeller une zone nommée), alors la propriété <code>grid-area</code> prend aussi quatre lignes. Si vous avez des lignes nommées dans votre grille, comme décrit dans <a href="https://la-cascade.io/articles/comprendre-cssgrid-creer-un-container-grid">Comprendre CSS Grid : créer un container Grid</a>, alors vous pouvez utiliser ces lignes nommées tout comme les lignes numérotées.</p><p>Attention cependant car, selon que vous utilisez ident avec des lignes nommées ou numérotées, le comportement sera différent dans le cas où vous omettez quelques lignes.</p><p>Ci-dessous, j'ai créé une grille avec des lignes nommées et utilisé <code>grid-area</code> pour placer un item (en omettant la valeur finale) :</p><pre>.grid {
  display: grid;
  grid-template-columns:
      [one-start three-start] 1fr 1fr
      [one-end three-end two-start four-start] 1fr 1fr [two-end four-end];
  grid-template-rows:
    [one-start two-start] 100px 100px
    [one-end two-end three-start four-start] 100px 100px [three-end four-end];;
}
.two {
  grid-area: two-start / two-start / two-end;
}</pre><p>Il nous manque donc le nom de ligne pour <code>grid-column-end</code>. La spécification dit que dans cette situation, <code>grid-column-end</code> doit utiliser une copie de <code>grid-column-start</code>. Si <code>grid-column-end</code> et <code>grid-column-start</code> sont identiques, alors la ligne finale est oubliée, et la valeur est réglée sur <code>auto</code>, donc l'item s'étend sur une piste, comme dans la version numérotée.</p><p>La même chose se produit si nous omettons la troisième valeur <code>grid-row-end</code> ; elle devient la même que <code>grid-row-start</code> et donc devient <code>auto</code>.</p><p>Jetez un œil à cet exemple codepen de la façon dont <code>grid-area</code> est utilisé et comment il change ensuite la mise en page de l'item :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/oNXXOvR/">Grid template areas : idents manquants dans grid-area</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Ceci explique pourquoi <code>grid-area</code> fonctionne avec une seule valeur ident représentant une zone nommée.</p><p>Quand nous créons une zone nommée avec la propriété <code>grid-template-areas</code>, le bord de chaque zone peut être référencé par un nom de ligne qui est le même que le nom de la zone utilisée. Dans notre cas, nous avons pu prendre notre zone nommée <code>one</code> et placer notre item en utilisant des lignes nommées comme suit :</p><pre>.one {
  grid-row-start: one;
  grid-row-end: one;
  grid-column-start: one;
  grid-row-end: one;
}</pre><p>Quand nous disons <code>grid-area: one</code>, nous omettons les trois dernières valeurs du raccourci <code>grid-area</code> ; elles finissent comme des copies de notre première valeur — toutes, dans notre cas deviennent <code>one</code> et l'item est placé exactement comme dans la version longue de notre css.</p><p>Le fonctionnement du nommage dans Grid layout est très intelligent et permet des choses bien intéressantes que j'ai décrites dans mes articles précédents <a href="https://www.smashingmagazine.com/2017/10/naming-things-css-grid-layout/">Naming Things In CSS Grid Layout</a> et <a href="https://www.smashingmagazine.com/2019/10/editorial-design-patterns-css-grid-subgrid-naming/">Editorial Design Patterns With CSS Grid And Named Columns</a> (en anglais).</p><h2>Mettre en page des items avec grid-template-areas</h2><p>Avec <code>grid-template-areas</code>, une cellule ne peut être occupée que par un seul nom, cependant nous pouvons toujours ajouter des items à la grille après avoir réalisé notre mise en page principale de cette manière. Pour cela, nous avons les lignes numérotées, comme d'habitude.</p><p>Dans l'exemple codepen suivant, j'ai ajouté un item supplémentaire et je l'ai placé par-dessus les items déjà présents en utilisant le positionnement basé sur les numéros de lignes.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/bGddJRr/">Grid template areas : placer un item avec des numéros de lignes</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Nous pouvons également utiliser les noms de lignes définis lorsque nous avons créé nos colonnes ou rangées. Mieux encore, nous aurons des noms de lignes créés par la formation des zones. Nous avons déjà vu comment nous pouvons obtenir quatre noms de lignes à partir du nom de la zone. Nous obtenons aussi une ligne de début au bord de chaque zone avec un <code>-start</code> ajouté au nom de la zone, et une ligne pour l'autre bord avec un <code>-end</code> ajouté.</p><p>Par conséquent, la zone nommée <code>one</code> a des lignes de début appelées <code>one-start</code> et de fin appelées <code>one-end</code>.</p><p>Nous pouvons ensuite utiliser ces noms implicites de lignes pour placer une item sur la grille. Cela peut être utile si on redéfinit la grille à plusieurs points de rupture (<em>breakpoints</em>), si nous voulons toujours que l'tem placé se trouve après un certain nom de ligne.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/QWbbPMQ/">Grid template areas : placer un item avec des noms implicites de lignes</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Utiliser grid template areas dans un design responsif</h2><p>Je construis souvent des composants et je me rends compte que <code>grid-template-areas</code> peut être bien utile pour voir exactement, déjà dans le CSS, à quoi mon composant va ressembler. De plus, la redéfinition du composant pour plusieurs points de rupture est très simple, il suffit de redéfinir les valeurs de <code>grid-template-areas</code>, avec parfois en plus un changement du nombre de pistes de colonnes.</p><p>Dans le CSS qui suit, j'ai défini une mise en page à une seule colonne pour mon composant. Ensuite, à une largeur minimum de 600px, je redéfinis le nombre de colonnes ainsi que la valeur de <code>grid-template-areas</code> afin de créer une mise en page sur deux colonnes. Ce qui est bien avec cette approche, c'est qu'il suffit de regarder le CSS pour voir à quoi ressemble ma mise en page !</p><pre>.wrapper {
  background-color: #fff;
  padding: 1em;
  display: grid;
  gap: 20px;
  grid-template-areas:
    "hd"
    "bd"
    "sd"
    "ft";
}
@media (min-width: 600px) {
  .wrapper {
    grid-template-columns: 3fr 1fr;
    grid-template-areas:
      "hd hd"
      "bd sd"
      "ft ft";
  }
}
header { grid-area: hd; }
article {grid-area: bd; }
aside { grid-area: sd; }
footer { grid-area: ft; }</pre><h2>Accessibilité</h2><p>Il faut être prudent lorsqu'on utilise cette méthode et se rappeler qu'elle peut amener à une réorganisation du contenu qui peut se trouver déconnecté de l'ordre de la source. Un utilisateur naviguant avec la tabulation regarde l'écran tout en écoutant un texte dit par l'ordinateur, et ce dernier lit le contenu dans l'ordre où il figure dans la source HTML. Cela peut entraîner beaucoup de confusion pour l'utilisateur.</p><h2>Résumé</h2><p>Voilà tous les tuyaux à connaître sur les propriétés <code>grid-template-area</code> et <code>grid-area</code> pour créer des mises en page. Si vous ne l'avez pas déjà utilisée, essayez là. Je la trouve très utile notamment pour expérimenter et je m'en sers beaucoup pour mes prototypes — même si, pour une raison ou une autre, je suis amenée plus tard à utiliser une autre méthode pour la production.</p></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-cssgrid-grid-template-areas</link>
      <guid>https://la-cascade.io/articles/comprendre-cssgrid-grid-template-areas</guid>
      <pubDate>Mon, 18 Apr 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre CSS Grid : les lignes Grid]]></title>
      <description><![CDATA[<p><em>Dans cette nouvelle série, Rachel Andrew analyse la spécification CSS Grid Layout. Elle poursuit ici avec les lignes de grille.</em></p><div class="articleContent"><p>Dans le premier article de cette série, nous avons vu comment créer un container grid, et les diverses propriétés utilisables sur l'élément parent qui constitue notre grille. Une fois que nous avons une grille, nous avons un ensemble de lignes. Dans cet article, nous allons voir comment placer des items par rapport à ces lignes, en ajoutant des propriétés aux enfants directs de notre conteneur.</p><p>Ce que nous allons voir :</p><ul><li>Les propriétés de placement grid-column-start, grid-column-end, grid-row-start, grid-row-end et leur raccourci grid-column and grid-row.</li>
<li>Comment utiliser grid-area pour un placement par numéro de ligne</li>
<li>Comment placer des items avec un nom de ligne</li>
<li>La différence entre les grilles implicite et explicite quand on place les items</li>
<li>L'utilisation du mot-clé span (et une sous-grille en bonus)</li>
<li>La vigilance nécessaire lorsqu'on mélange des items placés et auto-placés</li>
</ul><h2>Concepts de base du positionnement par ligne</h2><p>Pour placer un item sur la grille, nous définissons <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridline">la ligne</a> depuis laquelle il part et celle où il s'arrête. Du coup, pour une grille de cinq colonnes et de cinq rangées, si je veux que mon item s'étende de la deuxième à à troisième <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridtrack">piste</a> de colonne, et couvre les première, deuxième et troisième rangées, j'utiliserai le CSS ci-dessous. Gardez à l'esprit que nous visons la ligne, non la piste elle-même.</p><pre>.item {
  grid-column-start: 2;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 4;
}</pre><p>On peut utiliser les raccourcis :</p><pre>.item {
  grid-column: 2 / 4;
  grid-row: 1 / 4;
}</pre><p>Dans Codepen, nous pouvons voir l'exemple et modifier les lignes :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/LYEdOdB/">Grid lines : raccourcis de placement</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Notez que la raison pour laquelle notre arrière-plan de boîte s'étend sur toute la surface est que les valeurs initiales des propriétés d'alignement <code>align-self</code> et <code>justify-self</code> sont <code>stretch</code>.</p><p>Si nous avons seulement besoin de couvrir une piste, nous pouvons omettre la ligne de fin, car le comportement par défaut est que les items s'étendent sur une piste. C'est ce que nous constatons lorsque nous plaçons automatiquement les items comme dans l'article précédent, chaque item va dans une cellule, à la croisée d'une colonne et d'une rangée. Pour indiquer que notre item doit s'étendre de la ligne 2 à la ligne 3, on pourrait écrire :</p><pre>.item {
  grid-column: 2 / 3;
}</pre><p>Il serait tout à fait correct d'omettre la ligne de fin :</p><pre>.item {
  grid-column: 2;
}</pre><h2>Le raccourci grid-area</h2><p>Nous pouvons aussi placer un item avec <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridarea">grid-area</a> (zone de grille). Nous retrouverons cette propriété dans un prochain article, mais disons dès maintenant que lorsqu'on l'utilise avec les numéros de ligne il permet de régler les quatre lignes.</p><pre>.item {
  grid-area: 1 / 2 / 4 / 4;
}</pre><p>L'ordre de ces quatre lignes est <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcs">grid-row-start</a>, <code>grid-column-start</code>, <code>grid-row-end</code>, <code>grid-column-end</code>. Quand on travaille avec un langage écrit horizontalement, de gauche à droite (comme le français), c'est haut, gauche, bas, droite. Vous avez sans doute remarqué que c'est l'inverse de la façon dont on spécifie les raccourcis (pour les marges par exemple) en CSS, qui est haut, droite, bas, gauche.</p><p>La raison en est que Grid fonctionne de la même manière, quel que soit le mode ou la direction d'écriture — nous verrons cela tout à l'heure. Il est donc plus logique de définir d'abord les deux départs, puis les deux fins, plutôt que de se référer aux dimensions physiques de l'écran. Personnellement j'utilise peu ces propriétés pour le placement basé sur les lignes, car je trouve que les deux raccourcis <code>grid-column</code> et <code>grid-row</code> sont plus lisibles quand on lit rapidement une feuille de styles.</p><h2>Les lignes sur la grille explicite</h2><p>J'ai parlé des grilles explicites et implicites dans mon article précédent. Quand on crée une grille avec les propriétés <code>grid-template-columns</code> et <code>grid-template-rows</code>, on crée une grille explicite. En définissant les pistes de colonne et de rangée, on définit aussi les lignes entre ces pistes et les lignes au début et la fin de la grille.</p><p>Ces lignes sont numérotées. La numérotation commence à 1, au bord de la grille, dans la direction block comme inline. Si l'on est dans un mode d'écriture horizontal de gauche à droite, cela signifie que la ligne 1 dans la direction block est au sommet de la grille et la ligne 1 dans la direction inline est à gauche.</p><figure role="group"><img src="https://la-cascade.io/images/grid-lines.webp" alt="visualisation des lignes dans firefox grid layout, et de la position de l'item" /></figure><p>Si vous travaillez dans un langage horizontal de droite à gauche — par exemple dans une langue arabe — alors la ligne 1 dans la direction block est toujours au sommet, mais la ligne 1 dans la direction inline est à droite.</p><figure role="group"><img src="https://la-cascade.io/images/grid-lines-rtl.webp" alt="visualisation des lignes dans firefox grid layout, et de la position de l'item dans un langage de droite à gauche" /></figure><p>Si vous travaillez en mode d'écriture vertical (et dans l'exemple ci-dessous j'ai réglé sur <code>writing-mode: vertical-rl</code>), alors la ligne 1 sera au sommet dans la direction block <em>de ce mode d'écriture</em>, et donc dans ce cas à droite. La ligne 1 dans la direction inline est au sommet.</p><figure role="group"><img src="https://la-cascade.io/images/grid-lines-vertical-rl.webp" alt="visualisation des lignes dans firefox grid layout, et de la position de l'item dans un langage de haut en bas et de droite à gauche" /></figure><p>Les ligne de grille sont donc liées au mode et au sens d'écriture.</p><p>La ligne finale notre grille explicite a poour numéro -1 et les lignes sont numérotées à l'envers à partir de là, la deuxième ligne a donc pour numéro -2. Par conséquent, si vous voulez que votre item s'étende sur toutes les pistes de la grille explicite, vous pouvez écrire :</p><pre>.item {
  grid-column: 1 / -1;
}</pre><h2>Les lignes sur la grille implicite</h2><p>Si nous créons une grille implicite, les pistes sont aussi comptées à partir de 1. Dans l'exemple ci-dessous, j'ai créé une grille explicite pour les colonnes, mais les pistes de rangées ont été créées dans la grille implicite, où j'utilise <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gac">grid-auto-rows</a> pour les dimensionner à 5em.</p><p>L'item ayant une classe de <code>placed</code> a été placé pour s'étendre de la ligne de rangée 1 à la ligne de ragée -1. Si nous travaillions avec une grille explicite pour nos deux rangées, l'item s'étendrait sur deux rangées. Mais du fait que les pistes de rangées ont été créées dans la grille implicite, la ligne -1 est devenue la ligne 2 et non la ligne 3.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/xxbWPJj/">Grid lines : grille explicite vs implicite</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Actuellement il n'est pas possible de cibler la dernière ligne de la grille implicite si l'on ne sait pas combien de lignes on a.</p><h2>Placer les items sur des lignes nommées</h2><p>Dans le dernier article j'ai expliqué qu'en plus des lignes numérotées on a l'option de nommer les lignes sur la grille. On nomme les lignes en ajoutant un ou plusieurs noms entre crochets avant la taille de la piste.</p><pre>.grid {
  display: grid;
  grid-template-columns: [full-start] 1fr [main-start] 2fr 2fr [main-end full-end];
}</pre><p>Une fois qu'on a nommé les lignes, on peut remplacer le numéro de ligne par un nom quand on place les items :</p><pre>.item {
  grid-column: main-start / main-end;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/povLpWa/">Grid lines : nommer les lignes</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si votre ligne a plusieurs noms, vous pouvez prendre celui que vous voulez pour placer votte item, tous les noms se rapporteront à la même ligne.</p><p>Note: il se passe des choses intéressantes quand on nomme les choses, voyez mon article <a href="https://www.smashingmagazine.com/2017/10/naming-things-css-grid-layout/">Naming Things in CSS Grid Layout</a> (en anglais).</p><h2>Que se passe-t-il si nous avons plusieurs lignes avec le même nom ?</h2><p>On observe un comportement intéressant quand on a plusieurs lignes qui ont le même nom. Cette situation pourrait se produire si nous nommons nos lignes dans une notation <code>repeat()</code>. Dans l'exemple qui suit, j'ai défini une grille de 8 colonnes, créée en répétant quatre fois un pattern de <code>1fr</code> <code>2fr</code>. J'ai nommé <code>sm</code> la ligne avant la petite piste et <code>lg</code> la piste après. J'ai donc quatre lignes avec le même nom.</p><p>Dans cette situation, nous pouvons utiliser le nom comme un index. Donc pour placer un item qui commence à la deuxième ligne (appelée <code>sm</code>) et s'étend jusqu'à la troisième ligne (appelée <code>lg</code>), j'utilise <code>grid-colum: sm 2 / lg 3</code>. Si on utilise le nom sans un numéro, on ciblera toujours la première occurrence de cette ligne avec ce nom.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/xxbWppe/">Grid lines : nommer les lignes</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Utiliser le mot-clé span</h2><p>Dans certains cas, vous savez que vous voulez avoir un item qui s'étend sur un certain nombre de pistes, mais vous ne savez pas exactement où dans la grille. Un exemple d'une telle situation serait un cas où vous placez des items avec auto-placement, mais vous voulez qu'ils s'étendent sur plusieurs pistes, plutôt que sur 1fr (qui est le défaut). Dans ce cas, vous pouvez utiliser le mot-clé <code>span</code>. L'exemple ci-dessous montre un item qui commence à la ligne <code>auto</code>, c'est la ligne où l'auto-placement le mettrait, et il couvre ensuite trois pistes.</p><pre>.item {
  grid-column: auto / span 3;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/MWYVrBB/">Grid lines : le mot-clé span</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Cette technique deviendra très utile quand la valeur <code>subgrid</code> sera largement supportée pour <code>grid-template-columns</code> et <code>grid-template-rows</code>. par exemple, dans une mise en page d'encarts, où chaque encart comporte un header et un contenu principal, que vous voulez alignés, vous pouvez avoir chaque encart qui s'étend sur 2 rangées, tout en permettant le comportement habituel d'auto-placement. Les encarts individuels utiliseront <code>subgrid</code> pour leurs rangées (deux rangées pour chacun). On peut le voir dans l'exemple suivant :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/yLyKvJZ/">Grid lines : le mot-clé span et les subgrids</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Le même exemple vu avec Firefox Grid Inspector :</p><figure role="group"><img src="https://la-cascade.io/images/grid-lines-subgrid.webp" alt="vue de l'exemple précédent avec Firefox Grid inspector" /></figure><h2>Placement d'items basé sur les lignes</h2><p>Grid place automatiquement les items dans des cellules vides de la grille, il ne va pas les empiler dans la même cellule. Cependant, en utilisant le placement basé sur les lignes, nous pouvons mettre les items dans la même cellule. Dans l'exemple ci-dessous, j'ai une image qui s'étend sur deux pistes et une légende placée après la deuxième piste et à laquelle j'ai donné un fond semi-transparent.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/QWwmQMz/">Grid lines : encarts et éléments empilés</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Les items s'empilent dans l'ordre dans lequel ils apparaissent dans la source. par conséquent, la légende vient après l'image et s'affiche par-dessus. Si la légende venait en premier, elle serait cachée par l'image. nous pouvons contrôler cet empilement avec <a href="https://la-cascade.io/articles/comment-fonctionne-z-index">la propriété z-index</a>. S'il était important d'avoir la légende avant l'image dans la source, on utiliserait <code>z-index</code> avec une valeur supérieure à celle de l'image, ce qui forcerait la légende à s'afficher par-dessus l'image.</p><h2>Mélanger placement automatique et basé sur les lignes</h2><p>Si l'on souhaite mélanger le placement d'items basé sur les lignes et le placement automatique, il nous faut être bien attentif. Quand les items sont tous auto-placés dans une grille, ils se placeront de manière séquentielle, chacun trouvant l'espace disponible suivant pour se positionner.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/povLaBz/">Grid lines : auto-placement</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Le comportement par défaut est toujours d'avancer, et de laisser un gap si un item ne rentre pas dans la grille. Nous pouvons contrôler ce comportement avec la propriété <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gaf">grid auto flow</a> et une valeur de <code>dense</code>. Dans ce cas, si un item entre dans un espace déjà laissé vide dans la grille, il sera placé en dehors de l'ordre de la source afin de remplir cet espace. Dans l'exemple suivant, qui utilise <code>dense</code>, l'item 3 est maintenant placé avant l'item 2.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/OJPvQKr/">Grid lines : auto-placement et dense</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Notez que ce comportement peut poser des problèmes aux lecteurs qui utilisent la touche tabulation car le contenu visuel sera décalé par rapport à la source.</p><p>Auto-placement fonctionne un peu différemment si vous avez déjà placé quelques items. Les items placés seront positionnés en premier, puis auto-placement cherchera les espaces disponibles pour placer les items. Si vous avez laissé de l'espace blanc en haut de votre mise en page avec une rangée vide, introduisez quelques items qui seront auto-placés, ils se retrouveront dans cette piste.</p><p>Pour le montrer, dans cet exemple final j'ai placé les items 1 et 2, avec la propriété basée sur les lignes, en laissant la première rangée vide. Les derniers items sont maintenant les premiers.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/RwNMMwJ/">Grid lines : auto-placement et items placés</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Il est important de comprendre ce comportement, car on peut se retrouver avec des items placés de manière étrange si on introduit dans la mise en page de nouveaux éléments auxquels on n'aurait pas donné un placement dans la grille.</p><h2>Conclusion</h2><p>C'est à peu près tout ce que vous devez savoir sur les lignes de grille. Rappelez-vous que vous avez toujours les lignes numérotées, et vous pouvez toujours placer un item d'un numéro de ligne à un autre. Les autres méthodes que nous verrons bientôt sont des méthodes alternatives, mais sont basées sur les lignes numérotées.</p></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-cssgrid-lines</link>
      <guid>https://la-cascade.io/articles/comprendre-cssgrid-lines</guid>
      <pubDate>Sun, 17 Apr 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre CSS Grid : créer un container Grid]]></title>
      <description><![CDATA[<p><em>Dans cette nouvelle série, Rachel Andrew analyse la spécification CSS Grid Layout. Elle commence par ce qui se passe quand on crée un conteneur grid.</em></p><div class="articleContent"><p>Nous commençons ici une nouvelle série d'articles consacrés à CSS Grid Layout, publiés dans <a href="https://www.smashingmagazine.com/">Smashing Magazine</a>. Grid est disponible depuis 2017, mais de nombreux développeurs n'ont pas encore eu l'occasion de l'utiliser dans le cadre d'un projet. A première vue, Grid vient avec toute une foule de propriétés et de valeurs, ce qui peut sembler rebutant. Mais en réalité, de nombreux détails de la spécification sont des variantes, ce qui signifie que vous n'avez pas besoin d'apprendre la spécification entière pour commencer. Cette série vise à vous faire passer de débutant à expert de Grid — et vous donnera de nombreux conseils pratiques en cours de route.</p><p>Dans ce premier article nous allons voir ce qui se passe lorsqu'on crée un <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridcontainer">grid container</a> (conteneur de grille) et les diverses propriétés que vous pourrez utiliser sur l'élément parent pour contrôler cette grille. Vous découvrirez qu'il existe plusieurs cas d'utilisation qui ne sont réalisables qu'avec les propriétés de grid container. Dans cet article, nous couvrirons:</p><ul><li>Création d'un grid container avec display: grid ou display: inline-grid,</li>
<li>Configuration des colonnes et des lignes avec grid-template-columns et grid-template-rows,</li>
<li>Contrôle de la taille des pistes (<em>tracks</em>) implicites avec grid-auto-columns et grid-auto-rows.</li>
</ul><p><em>NdT : les termes utilisés ici (pistes,...) sont des termes techniques qu'il faut connaître, nous renverrons à chaque fois que nécessaire vers le</em> <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet">Guide Complet de CSS Grid Layout</a> <em>traduit ici</em>.</p><h2>Créer un container grid</h2><p>Grid, comme Flexbox, est une valeur de la propriété <code>display</code>. Par conséquent, pour indiquer au navigateur qu'on utilise la mise en page grid, on écrit <code>display:grid</code> dans le css de l'élément. Le navigateur nous donne une boîte de niveau <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline">block</a> sur l'élément en question et tout enfant direct sera inclus dans le contexte de formatage grid. Ils se comporteront comme des <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#griditem">items grid</a> et non comme des éléments block ou inline normaux.</p><p>Vous ne verrez sans doute aucune différence immédiate dans votre page à ce stade. Comme vous n'avez encore créé ni ligne ni colonne, vous avez une grille à une colonne. Suffisamment de rangées sont générées pour contenir tous les enfants directs et ils s'affichent l'un après l'autre dans cette colonne unique. Visuellement, ils ont l'air d'éléments block.</p><p>On verrait une différence si l'on avait à la fois une chaîne de caractères, non enveloppée dans un élément, et un enfant direct du container grid, du fait que cette chaîne de caractères serait enveloppée dans un élément anonyme et deviendrait un item grid. Tout élément normalement <em>inline</em>, comme un <code>span</code> par exemple, devient un item grid dès lors que son parent est un container grid.</p><p>L'exemple qui suit montre deux éléments de niveau block et un texte contenant une span au milieu de la chaîne de caractères. On se retrouve avec cinq items grid :</p><ul><li>les deux éléments <code>div</code></li>
<li>la chaîne de caractères qui précède le <code>span</code></li>
<li>le <code>span</code> lui-même</li>
<li>la chaîne de caractères qui suit le <code>span</code></li>
</ul><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/VwYrwBe/">Grid container : enfants directs et chaîne deviennent des items grid</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si l'on inspecte la grille avec <a href="https://firefox-source-docs.mozilla.org/devtools-user/page_inspector/how_to/examine_grid_layouts/index.html">Firefox Grid Inspector</a>, on voit les cinq rangées qui ont été crées pour nos items.</p><figure role="group"><img src="https://la-cascade.io/images/grid-container1.png" width="661" height="303" alt="" /></figure><p>Il est possible de créer une <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#display">grille inline</a> avec <code>display: inline-grid</code> ; dans ce cas, notre container devient une boîte de niveau inline. Les enfants directs sont toujours des items grid et se comportent comme les items grid à l'intérieur d'une boîte de niveau block (c'est seulement le type d'affichage extérieur). C'est pourquoi le container grid se comporte de la même façon que précédemment quand il est avec avec d'autres boîtes dans une page.</p><p>L'exemple suivant montre une grille suivie d'une chaîne de caractères. Comme c'est une grille de niveau inline, le texte peut s'afficher à côté (les éléments de niveau inline ne s'étirent pas pour prendre toute la place dans la dimension inline, contrairement aux éléments de niveau block).</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/Exabxpz/">Grid container : inline-grid</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Note : à l'avenir, on pourra mieux décrire notre layout en utilisant <code>display: block grid</code> pour créer un container de niveau block et <code>display inline grid</code> pour créer un container de niveau inline.</p><h2>Colonnes et rangées</h2><p>Pour obtenir quelque chose qui ressemble à une grille, nous aurons besoin d'ajouter des colonnes et des rangées. Pour cela on utilise les propriétés <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gtc">grid-template-columns</a> et <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gtc">grid-template-rows</a>. Dans la <a href="https://www.w3.org/TR/css-grid-1/">spécification</a> il est dit que ces propriétés acceptent une valeur appelée <code>track-list</code> (une liste de <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridtrack">pistes</a>).</p><blockquote>
<p>Ces propriétés spécifient, sous forme d'une liste de pistes séparées par un espace, les noms des lignes et les fonctions de dimensionnement des pistes de la grille. La propriété <code>grid-template-columns</code> spécifie la liste de pistes pour les colonnes de la grille, tandis que <code>grid-template-rows</code> le fait pour les rangées.</p>
</blockquote><p>A titre d'illustration, voici <strong>quelques valeurs de listes de pistes possibles</strong> :</p><ul><li>
<p><code>grid-template-columns: 100px 100px 200px;</code> crée une grille à trois colonnes: la première fait 100px de large, la deuxième aussi, la troisième fait 200px.</p>
</li>
<li>
<p><code>grid-template-columns: min-content max-content fit-content(10em);</code> crée une grille à trois colonnes, la première à la taille <code>min-content</code>, la deuxième à la taille <code>max-content</code>. La troisième est à la taille <code>max-content</code> <em>sauf si</em> le contenu est plus grand que 10em, auquel cas il est limité à 10em.</p>
</li>
<li>
<p><code>grid-template-columns: 1fr 1fr 1fr;</code> crée une grille à trois colonnes à l'aide de l'unité <code>fr</code>. L'espace disponible dans le container grid est divisé en trois et partagé entre les trois colonnes.</p>
</li>
<li>
<p><code>grid-template-columns: repeat(2, 10em 1fr);</code> crée une grille de quatre colonnes selon un motif répété <code>10em 1 fr 10em 1fr</code>, la liste de pistes étant répétée deux fois.</p>
</li>
<li>
<p><code>grid-template-columns: repeat(autofill 200px);</code> remplit le container d'autant de colonnes de 200px que possible, et laisse un espace à la fin s'il reste de la place.</p>
</li>
<li>
<p><code>grid-template-columns: repeat(autofill minmax(200px, 1fr));</code> remplit le container d'autant de colonnes de 200px que possible, puis distribue l'espace restant de manière égale entre les colonnes.</p>
</li>
<li>
<p><code>grid-template-columns: [full-start] 1fr [content-start] 3fr [content-end] 1fr [full-end];</code> crée une grille de trois colonnes, la première et la troisième occupant une fraction de l'espace disponible et la troisième occupant trois fractions de l'espace disponible. Les lignes sont nommées en mettant leur nom entre crochets.</p>
</li>
</ul><p>Comme vous pouvez le constater, il y a de nombreuses façons de créer une liste de pistes. Voyons maintenant comment tout cela fonctionne, en donnant quelques conseils d'utilisation.</p><h2>Utilisation des unités de longueur</h2><p>On peut utiliser n'importe quelle unité de longueur, ou un pourcentage, pour créer les pistes. Si la dimension des pistes est inférieure à l'espace disponible dans le container, alors par défaut les pistes s'aligneront au début du container et l'espace sera à la fin. Ceci, parce que la valeur par défaut de <code>align-content</code> et de <code>justify-content</code> est <code>start</code>. On peut espacer les pistes, ou les déplacer vers la fin, en utilisant les propriétés d'alignement, comme je l'ai expliqué en détail dans <a href="https://la-cascade.io/articles/alignement-en-css-guide-complet">Alignement en CSS, un guide complet</a></p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/eYmeYbX/">Grid container : unités de longueur</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>On peut aussi utiliser les mots-clés <code>min-content</code>, <code>max-content</code> et <code>fit-content()</code>. Avec <code>min-content</code>, on a une piste qui est aussi étroite que possible sans dépassement. Par conséquent, lorsqu'on l'utilise pour la largeur de la colonne, le contenu reviendra à la ligne à chaque fois que possible. La piste prend donc la dimension du mot le plus long de la colonne, ou du plus large élément de taille fixe.</p><p>Avec <code>max-content</code>, c'est l'inverse, le contenu ne reviendra pas à la ligne du tout. Dans une colonne, cela peut donc avoir pour conséquence un texte qui déborde.</p><p>Le mot-clé <code>fit-content()</code> quant à lui doit prendre une valeur, celle-ci devenant le maximum possible pour cette piste. La piste se comportera donc de la même façon que <code>max-content</code> jusqu'à rencontrer la valeur spécifiée. Arrivé à ce point, le contenu pourra revenir à la ligne sans déborder. Autrement dit, votre piste peut être plus petite que la valeur spécifiée, mais jamais plus grande.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/rNaYNob/">Grid container : min-content, max-content, fit-content()</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Vous trouverez plus d'information sur le dimensionnement dans Grid et d'autres méthodes de mise en page dans mon article <a href="https://la-cascade.io/articles/css-flexbox-et-la-dimension-des-boites">CSS Flexbox et la dimension des boîtes</a>.</p><p>Si vous avez des pistes qui prennent plus d'espace que disponible dans votre container, elles dépasseront. Si vous utilisez des pourcentages, vous devrez veiller à ce que le total ne soit pas supérieur à 100% pour éviter le dépassement.</p><h2>L'unité fr</h2><p>Grid Layout offre une méthode qui vous permettra d'éviter les calculs de pourcentages — le dimensionnement des pistes avec l'unité <code>fr</code>. Cette unité n'est pas une longueur et par conséquent ne peut pas être utilisée en combinaison avec <code>calc()</code>; c'est une unité flex qui représente l'espace disponible dans le container grid.</p><p>Autrement dit, avec une liste de pistes de <code>1fr 1fr 1fr</code> l'espace disponible est divisé en trois et partagé de façon égale entre les pistes. Avec une liste de pistes de <code>2fr 1fr 1fr</code>, l'espace disponible est divisé en quatre, deux parties sont données à la première piste et une partie à chacune des pistes deux et trois.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/QWwOWYx/">Grid container : fr</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Un point auquel il faut être attentif est que ce qui est partagé par défaut, c'est <em>l'espace disponible</em>, qui n'est pas nécessairement l'espace total de notre container. Si une piste contient un élément de taille fixe ou un mot très long sans retour à la ligne, celle-ci sera mise en place avant le partage de l'espace restant.</p><p>Dans l'exemple qui suit, j'ai supprimé les espaces entre les mots de <code>ItemThree</code>, ce qui crée une chaîne de caractères sans retour à la ligne possible. La distribution de l'espace se fait après que les conditions d'affichage de cet item aient été calculées.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/JjoOjzo/">Grid container : fr quand il y a un contenu trop grand</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>On peut mélanger l'unité <code>fr</code> avec des pistes de taille fixe et c'est d'ailleurs là qu'elle devient très utile. Par exemple on peut avoir un composant à deux colonnes fixes et une colonne centrale extensible :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/JjoOjqd/">Grid container : mélanger fr et dimensions fixes</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>On peut aussi avoir un composant avec une piste réglée sur <code>fit-content(300px)</code> et l'autre sur <code>1fr</code>. On a ainsi un composant qui accepte quelque chose d'inférieur à 300px dans la première piste, auquel cas il prend seulement l'espace nécessaire, et l'unité <code>fr</code> s'étend pour prendre le reste de l'espace disponible.</p><p>Si on ajoute quelque chose de plus grand (comme une image ayant une <code>max-width: 100%</code>), la première piste sera limitée à 300px et l'unité <code>fr</code> prendra le reste de l'espace. On crée des composant très flexibles en mélangeant l'unité <code>fr</code> et <code>fit-content()</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/abzVbgb/">Grid container : mélanger fr et fit-content</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>La fonction repeat()</h2><p>La function repeat() peut vous épargner la saisie de valeurs identiques. Les deux lignes ci-dessous sont équivalentes :</p><pre>grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(12, 1fr);</pre><p>La valeur avant la virgule représente le nombre de répétitions, la valeur après la virgule représente la liste de pistes qui doit être répété. On peut avoir un seul pattern (comme ci-dessus) ou des valeurs multiples. Enfin, on peut utiliser <code>repeat()</code> pour une partie d'une liste de pistes. Dans l'exemple ci-dessous, on aurait une piste <code>1fr</code>, trois pistes <code>200px</code> et une piste <code>1fr</code> pour finir.</p><pre>grid-template-columns: 1fr repeat(3, 200px) 1fr;</pre><p>A la place d'un nombre avant la virgule, indiquant un nombre fixe de répétitions d'un pattern, on peut utiliser les mots-clés <code>auto-fill</code> ou <code>auto-fit</code>. Le container grid sera rempli par autant de pistes qu'il peut en contenir.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/oNgoggL/">Grid container : auto-fill</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>L'utilisation d'une unité de mesure fixe a pour effet que si le container ne peut être divisé exactement par cette taille, il restera de l'espace disponible. Dans l'exemple ci-dessus, mon container fait 500px de large, et j'ai deux pistes de 200px et un espace vide à la fin.</p><p>Nous pouvons utiliser une autre fonction Grid pour transformer cette valeur fixe en minimum. La fonction <code>minmax()</code> prend une taille minimum et une taille maximum. Avec un minimum de 200px et un maximum de 1fr, nous avons autant des pistes de 200px que le container peut accepter et comme le maximum est 1fr, ce qui, nous le savons, va répartir l'espace de façon égale, l'espace en trop sera distribué entre les pistes.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/eYmemNw/">Grid container : auto-fill et minmax()</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>J'ai indiqué qu'il y avait deux mots-clés possibles : <code>auto-fill</code> et <code>auto-fit</code>. Si vous avez assez de contenu pour remplir la première rangée de cellules, celles-ci se comporteront exactement de la même manière. Si par contre vous n'avez pas assez de contenu (p.ex. si nous supprimons toutes les cellules sauf une dans le container précédent), alors elles se comporteront différemment.</p><p><code>auto-fill</code> maintiendra le dimensionnement de la piste, même s'il n'y a pas de contenu pour la remplir.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/XWJzJXr/">Grid container : auto-fill et minmax() avec un seul item</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>En revanche, si on utilise <code>auto-fit</code>, les pistes vides seront fondues en une :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/XWJzJdW/">Grid container : auto-fit et minmax() avec un seul item</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Firefox Grid inspector nous permet de voir que les pistes sont toujours là, mais qu'elles ont été fondues. La ligne finale de notre grille est toujours la ligne 3.</p><figure role="group"><img src="https://la-cascade.io/images/grid-container2.webp" alt="" /></figure><h2>Lignes nommées</h2><p>Mon exemple final ci-dessus utilisait l'approche des lignes nommées. Quand on utilise Grid, on a toujours des numéros de ligne, cependant, on peut aussi nommer les lignes. Leur nom apparaît entre crochets. On peut avoir plusieurs noms pour une ligne ; dans ce cas, un espace les sépare. Par exemple, dans la liste de pistes suivante, toutes mes lignes ont deux noms.</p><pre>grid-template-columns: [main-start sidebar-start] 1fr [sidebar-end content-start] 4fr [content-end main-end]</pre><p>On peut nommer nos lignes comme on veut, sauf avec le mot <code>span</code> qui est un mot réservé car il peut être utilisé pour placer des items dans la grille.</p><p>Note : dans les prochains articles de cette série, je parlerai plus en détails du placement basé sur les lignes et de la façon dont on peut se servir des lignes nommées. En attendant, vous pouvez lire mon article <a href="https://www.smashingmagazine.com/2017/10/naming-things-css-grid-layout/">Naming Things in CSS Grid Layout</a> (en anglais) pour en savoir plus sur le sujet.</p><h2>Grille explicite vs grille implicite</h2><p>Lorsqu'on crée une grille avec <code>grid-template-columns</code> et <code>grid-template-rows</code> et une liste de pistes, on crée ce qu'on appelle une <strong>grille explicite</strong>. C'est la grille que vous avez définie, avec le dimensionnement que vous avez choisi pour chaque piste.</p><p>Si vous avez plus d'items qu'elle n'en peut contenir, ou si vous placez un item de telle manière qu'il tombe en dehors des limites de la grille, Grid créera des pistes dans ce qu'on appelle la <strong>grille implicite</strong>. Ces pistes implicites seront autodimensionnées par défaut. Nous avons déjà vu cette grille implicite en action lorsque j'ai déclaré <code>display: grid</code> dans l'élément parent et que grid a créé des rangées, une pour chaque item. Je n'avais pas défini ces rangées, mais puisqu'il y avait des items grid, les pistes de rangées ont été créées pour leur donner un endroit où aller.</p><p>On peut fixer une dimension pour les rangées ou colonnes implicites en utilisant les propriétés <code>grid-auto-rows</code> ou <code>grid-auto-columns</code>. Ces propriétés prennent une liste de pistes et si vous voulez que toutes les colonnes implicites aient ne hauteur d'au moins 200px mais qu'elles puissent s'agrandir s'il y a plus de contenu, vous pouvez écrire :</p><pre>grid-auto-rows: minmax(200px, auto)</pre><p>Si vous souhaitez que la première rangée implicite soit auto-dimensionnée et que la deuxième soit dimensionnée avec <code>min-content</code> etc. (jusqu'à ce que tous les items grid soient en place), vous pouvez passer des valeurs multiples :</p><pre>grid-auto-rows: auto 100px</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/xxbPxyK/">Grid container : grid-auto-rows</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Utiliser une grille avec placement automatique</h2><p>Créer une grille (et permettre au navigateur de placer automatiquement les items) nous emmène loin en termes de patterns utiles. Nous n'avons pas encore abordé la question du placement des items dans la grille, mais de nombreuses mises en page réalisées avec Grid ne font aucun placement. Elle s'appuient simplement sur le placement d'items dans l'ordre de la source — un dans chaque cellule de la grille.</p><p>Si vous débutez avec CSS Grid, une bonne façon de comprendre comment ça marche est de s'amuser avec différentes dimensions de pistes, en regardant comment les items se placent dans les cellules.</p></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-cssgrid-creer-un-container-grid</link>
      <guid>https://la-cascade.io/articles/comprendre-cssgrid-creer-un-container-grid</guid>
      <pubDate>Sat, 16 Apr 2022 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM : comment installer un projet npm existant ?]]></title>
      <description><![CDATA[<p><em>npm nous permet d'installer des projets, par exemple divers 'starter' existent pour créer un blog à partir d'un framework, ce qui nous facilite bien la vie.</em></p><div class="articleContent"><p>À ce stade, nous avons obtenu un bon aperçu du fonctionnement de npm et de la façon de l'utiliser pour installer des paquets et exécuter des commandes. Allons maintenant un peu plus loin et voyons à quoi ressemble le téléchargement et l'installation d'un projet npm existant, plutôt que d'en démarrer un à partir de zéro. Le plus souvent, c'est ce que vous ferez. C'est beaucoup, beaucoup plus facile que d'installer et de configurer toutes les pièces individuelles une par une.</p><p>C'est ce que nous allons couvrir dans ce dernier chapitre du guide de npm, et je m'appuierai sur mon expérience personnelle sur un de mes projets réels.</p><h2>Table des matières <small>(rappel)</small></h2><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a> ← <strong><em>vous êtes ici</em></strong> ???</li>
</ul></div><h2>Voici un projet npm de la vie réelle</h2><p>Le projet que j'ai choisi pour cela est mon propre <a href="https://github.com/josh-collinsworth/sveltekit-blog-starter">starter de blog statique SvelteKit</a>. Je pense que c'est un bon exemple car il est livré avec de nombreux paquets préinstallés qui sont parfaits pour la démonstration.</p><p>Il s'agit d'un projet réel conçu pour vous donner — comme vous l'avez peut-être deviné d'après son nom — une longueur d'avance sur la construction d'un site de blog généré de manière statique. (Le terme "statiquement généré" signifie que notre code sera compilé en fichiers .html, prêts à être déployés partout sur le Web. C'est l'une des quelques approches englobées dans <a href="https://css-tricks.com/what-makes-a-site-jamstack/">la manière "Jamstack" de construire des sites</a>).</p><p>Et ne vous inquiétez pas si vous ne savez rien de <a href="https://kit.svelte.dev/">SvelteKit</a> — il s'agit juste d'une démonstration, et nous n'écrirons rien que vous ne sachiez déjà. Cela dit, il est bon de noter que SvelteKit utilise <a href="https://vitejs.dev/">Vite</a> sous le capot, qui est en fait un <a href="https://www.npmjs.com/package/vite">paquet npm</a> qui nous donne accès à des outils de construction modernes et à un serveur de développement super rapide.</p><h3>Cloner le projet</h3><p>Tout d'abord, nous devons "cloner" le projet, ce qui est un mot fantaisiste pour copier le projet sur notre système afin que nous puissions travailler dessus localement. Il existe deux façons de cloner un projet existant.</p><p>Si vous préférez la méthode visuelle dans le navigateur, rendez-vous sur le <a href="https://github.com/josh-collinsworth/sveltekit-blog-starter">dépôt de démarrage</a> sur GitHub, cliquez sur le menu déroulant "Code" situé directement dans l'interface utilisateur de GitHub, puis sélectionnez l'option "Télécharger le ZIP".</p><figure><img src="https://la-cascade.io/images/download-zip.webp" alt="on peut cliquer sur 'download zip' pour télécharger un fichier du projet" /></figure><p>Sinon, si vous préférez utiliser la ligne de commande à la place, exécutez cette commande (assurez-vous simplement d'être dans un endroit où cela ne vous dérange pas qu'un nouveau dossier de projet soit ajouté à votre ordinateur, par exemple <code>cd /path/to/folder</code>) :</p><pre class="language-bash">npx degit https://github.com/josh-collinsworth/sveltekit-blog-starter.git sveltekit-blog-starter</pre><p>Vous vous souvenez peut-être que <code>npx</code> nous permet d'exécuter des paquets npm sans les installer de façon permanente. degit clone le projet comme le ferait <code>git clone</code>, mais sans son historique Git (littéralement, "de-git").</p><p>Quelle que soit la méthode utilisée, vous obtenez un tout nouveau dossier sveltekit-blog-starter. Ouvrons-le dans un éditeur de code, ouvrons le terminal et exécutons la commande <code>npm install</code> (ou <code>npm i</code>).</p><figure role="group"><img src="https://la-cascade.io/images/audit-on-install.webp" alt="" /><figcaption>npm exécute automatiquement un audit lorsqu'il installe les paquets.</figcaption></figure><p>À ce stade, vous verrez une note sur les vulnérabilités, comme nous l'avons abordé dans la dernière section de ce guide. Elle peut indiquer quelque chose comme "trouvé 0 vulnérabilité" (comme dans la capture d'écran ci-dessus), mais il est fort possible que ce nombre soit supérieur à zéro. Si vous voyez des vulnérabilités, ne vous inquiétez pas. Vous êtes libre de les ignorer pour l'instant puisqu'il ne s'agit pas d'un projet que nous avons l'intention de lancer en production pour que d'autres puissent le voir ou l'utiliser. (Voir la section sur l'audit npm dans un chapitre précédent pour plus d'informations).</p><h3>Démarrer le serveur et effectuer des modifications</h3><p>Si vous jetez un coup d'œil à l'intérieur du fichier package.json du projet cloné, vous verrez la commande permettant de démarrer le serveur de développement :</p><pre class="language-bash">npm run dev</pre><p>Exécutez cette commande dans le terminal et vous devriez voir quelque chose comme ce qui suit presque immédiatement :</p><figure><img src="https://la-cascade.io/images/npm-run-dev.webp" alt="svelte envoie quelques informations (version, adresse du dev local)" /></figure><p>Dans VS Code, vous pouvez appuyer sur CMD tout en cliquant sur l'URL <code>http://localhost:3000</code>, ou vous pouvez la saisir manuellement dans votre navigateur. Dans tous les cas, le site devrait s'afficher dans le navigateur !</p><figure><img src="https://la-cascade.io/images/awesome-blog.webp" alt="image d'une jolie page d'accueil de blog" /></figure><p><strong>Prenons un instant pour apprécier à quel point cela a été relativement rapide et simple !</strong> Oui, nous avons peut-être dû installer d'abord un tas d'échafaudages, mais c'est un coût initial et unique. Nous avons un projet entier fonctionnant sur notre machine avec seulement quelques commandes — et nous pouvons faire la même chose chaque fois que nous voulons installer un autre projet existant !</p><p>Je n'entrerai pas dans les détails de ce projet particulier car il n'est pas important pour l'apprentissage de npm, mais c'est un bon exemple car il a beaucoup de choses sympas préconfigurées, et nous pouvons facilement faire des changements et les voir se mettre à jour immédiatement dans le navigateur. Examinons maintenant quelques-unes de ces commandes.</p><p>SvelteKit nécessite Node 14 ou plus. Si vous avez installé npm dans le cadre de ce guide, cela ne sera pas un problème pour vous. Mais si vous l'aviez déjà installé avant de commencer, et si vous rencontrez des erreurs en essayant de faire fonctionner ce projet, cela vaut la peine de faire un rapide <code>node -v</code> pour être sûr. nvm est votre ami si vous devez faire une mise à jour.</p><h3>Compilation automatique de Sass à la sauvegarde</h3><p>Vous pouvez trouver les fichiers Sass du projet dans le dossier <code>src/lib/assets/scss/</code>. Essayez d'ouvrir directement le fichier <code>global.scss</code>. Apportez une modification, enregistrez-la, et vous devriez voir la mise à jour automatiquement (et presque <em>instantanément</em>) dans votre navigateur.</p><figure><img src="https://la-cascade.io/images/compile-on-save.webp" alt="" /></figure><h3>Apporter des modifications au contenu</h3><p>Le site de démarrage utilise en fait le fichier <code>README.md</code> du repo comme page d'accueil. Si vous ouvrez le fichier <code>README.md</code> et commencez à apporter des modifications (ce n'est pas grave si vous ne connaissez pas le format <a href="https://css-tricks.com/little-stuff-markdown-always-forget-google/">Markdown</a>, n'importe quelle édition fera l'affaire), vous devriez également voir ces modifications s'afficher dès que vous enregistrez, tout comme Sass l'a fait à la dernière étape :</p><figure><img src="https://la-cascade.io/images/make-content-change.webp" alt="" /></figure><p>Si vous le souhaitez, vous pouvez ouvrir une autre page, disons le fichier <code>src/routes/contact.svelte</code>, et mettre à jour le HTML pour le voir s'actualiser en direct dans votre navigateur également dès qu'il est enregistré.</p><p>Vous pouvez même dupliquer l'un des fichiers Markdown à l'intérieur de <code>src/lib/posts/</code> et effectuer des modifications pour qu'il apparaisse automatiquement dans la liste des articles de la page <code>/blog</code>, si vous voulez aller aussi loin. (Veillez simplement à lui donner un titre unique).</p><h3>Comprendre les importations</h3><p>Il y a une chose importante concernant les projets npm que nous avons brièvement mentionnée dans le quatrième chapitre, mais que nous n'avons pas encore couverte : les importations. Ce guide ne serait pas vraiment complet si nous n'en parlions pas. L'idée de base est que nous  comme son nom l'indique — importer un paquet dans notre code, et l'utiliser sur place.</p><p>Comment ? Ouvrez le dossier <code>svelte.config.js</code> à la racine du projet, et vous verrez un bloc de lignes d'importation en haut, quelque chose comme ceci :</p><pre class="language-js">import adapter from '@sveltejs/adapter-static'
import { mdsvex } from 'mdsvex'
import preprocess from 'svelte-preprocess'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeSlug from 'rehype-slug'</pre><p>Chacun de ces imports est un paquet installé utilisé dans ce fichier. Ce que fait réellement chaque paquet n'est pas important pour le moment ; je veux juste attirer votre attention sur la syntaxe d'importation. <em>C'est ainsi que nous utilisons les packages dans nos fichiers de code réels</em> ; nous indiquons à JavaScript *ce qu'*il faut importer et <em>depuis où</em>. Ensuite, nous pouvons l'appeler dans notre code.</p><p>Cette syntaxe est appelée "ES6 imports", qu'il est important de connaître car il s'agit de la norme que JavaScript navigateur et Node JavaScript ont convenu d'utiliser à l'avenir.</p><p>Auparavant, Node JavaScript utilisait (et utilise encore souvent) une syntaxe légèrement différente appelée CommonJS. Si vous voyez une importation qui ressemble à ceci, c'est l'ancien style CommonJS :</p><pre class="language-js">const myPackage = require('package-name')</pre><p>L'autre chose cruciale à comprendre à propos du style d'importation ES6 est la suivante : <strong>la syntaxe est spécifique à npm, ce n'est pas une norme de langage</strong>.</p><p>Pour être clair : <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Statements/import">vous pouvez utiliser <code>import</code> dans du JavaScript normal</a>. Il s'agit d'une fonctionnalité très ordinaire du langage permettant d'exporter une variable, une fonction, un objet, etc. d'un fichier et de l'importer pour l'utiliser dans un autre. Mais pour ce faire, vous devez fournir un chemin relatif ou (dans les navigateurs plus modernes) une URL vers ce que vous importez. La simple utilisation d'une chaîne avec le slug d'un paquet, comme nous le voyons ici, n'est pas valide.</p><p>Alors pourquoi l'utiliser si ce n'est pas un code techniquement valide ? Eh bien parce que la gestion de ce style d'importation est l'une des choses agréables que npm fait pour nous. Lorsque nous demandons à npm <code>import somePackage from 'name'</code> sous la forme d'une chaîne de caractères sans chemin d'accès, npm sait automatiquement qu'il doit rechercher les paquets installés sur le projet pour trouver l'importation que nous avons demandée. Cela nous évite à la fois de taper des chemins relatifs fastidieux et de devoir savoir où se trouvent nos paquets dans le labyrinthe des node_modules.</p><p>Cela va peut-être sans dire, mais : puisque la syntaxe n'est pas valide, vous ne pourrez pas l'utiliser avec succès à moins que votre projet npm ne comprenne un bundler ou un compilateur quelconque, pour traiter les importations et les modules en code de navigateur valide.</p><h3>Construction du site final</h3><p>La plupart des projets npm comme celui-ci ont deux objectifs principaux :</p><ol><li>Vous aider à développer votre site ou votre application</li>
<li>Construire une version de production finalisée</li>
</ol><p>SvelteKit ne fait pas exception. Lorsque nous avons terminé la configuration de notre (génial) serveur de développement et que nous sommes satisfaits de nos modifications, nous pouvons exécuter cette commande :</p><pre class="language-bash">npm run build</pre><blockquote>
<p><em>Si votre serveur de développement est toujours en cours d'exécution, vous pouvez soit l'arrêter avec <code>Ctrl+C</code>, soit ouvrir un nouvel onglet de terminal. Vous ne pourrez pas taper de commandes dans la même fenêtre de terminal où le processus de développement est en cours d'exécution, car il s'agit d'une tâche active et continue.</em></p>
</blockquote><p>Lorsque nous exécutons la commande de construction (<em>build</em>), SvelteKit passe en revue tous les fichiers du projet et produit un ensemble de fichiers HTML, CSS et JavaScript statiques, prêts à être déployés, et ce, assez rapidement. Vous pouvez télécharger cette collection de fichiers partout où vous pouvez héberger un site Web. <strong>Outil moderne ; bon vieux résultat</strong>.</p><p>Lorsque la commande de construction se termine, vous devriez voir un nouveau dossier de construction à la racine (c'est-à-dire au niveau supérieur) de votre dossier de projet. Si vous le parcourez, vous remarquerez qu'il n'y a plus de fichiers <code>.md</code>, <code>.svelte</code> ou tout autre fichier qui ne peut pas être lu par un navigateur. Tout a été compilé en HTML, CSS et JavaScript purs, sans oublier — comme vous le verrez si vous ouvrez un fichier JavaScript ou CSS — qu'ils sont minutieusement minifiés pour être <em>aussi petits</em> que possible et se charger dans le navigateur <em>aussi vite</em> que possible.</p><p>Si vous le souhaitez, vous pouvez exécuter <code>npm run preview</code> une fois la compilation terminée pour voir comment le site compilé se charge dans le navigateur. La différence ici est que le contenu sera chargé à partir du dossier de construction final, plutôt que d'être construit à la volée avec des fichiers précompilés comme ce serait le cas en utilisant la commande dev. Vous ne verrez aucune différence à moins d'ouvrir l'onglet Réseau dans DevTools (ou d'essayer de mettre à jour quelque chose), mais vous regarderez le produit final.</p><p>Il s'agit d'une étape facultative, mais je pense qu'il est assez cool de se faire une idée du peu de fichiers compilés avec lesquels nous nous retrouvons, compte tenu de tous les fichiers divers que nous avons mis dans le projet, et de la petite taille du paquet final, grâce aux incroyables outils de construction intégrés dans ce projet. (Pour mémoire, il s'agit de SvelteKit et Vite).</p><h3>Pratiques de déploiement modernes</h3><p>C'est un sujet pour une autre fois, mais le déploiement moderne ne nécessite souvent pas que vous exécutiez une commande de <em>build</em> et que vous téléchargiez les fichiers vous-même (bien que ce soit toujours une option). Au lieu de cela, un hôte (comme <a href="https://www.netlify.com/">Netlify</a> ou <a href="https://vercel.com/">Vercel</a>) se connecte directement au dépôt GitHub de votre projet et, chaque fois que vous apportez des modifications à la branche principale du dépôt, l'hôte exécute votre commande de construction pour vous et déploie les fichiers compilés automatiquement !</p><p>C'est l'une des nombreuses fonctionnalités extrêmement agréables de cette nouvelle ère du développement frontal. Pas besoin de s'embêter avec le FTP ou de faire glisser manuellement des fichiers n'importe où ; nous sommes sûrs que tout est construit et déployé automatiquement lorsque nous poussons notre code, sans que nous ayons besoin de faire quoi que ce soit !</p><h3>Conclusion de ce guide npm</h3><p>Si vous êtes arrivé jusqu'ici, félicitations ! Et merci à vous. Félicitations, car la lecture de ce guide a été <em>longue, très longue</em>. Et merci, parce que... eh bien, c'était une <em>longue, longue</em> lecture.</p><p>Mais vous avez réussi, et j'espère que vous avez aussi appris des choses importantes. J'ai mentionné au début que mon objectif n'était pas la brièveté, mais l'efficacité. Cela signifie que nous avons couvert <em>beaucoup de choses</em>. Nous avons commencé par un <a href="https://la-cascade.io/articles/npm-guide-1-npm">bref aperçu de npm</a> et de sa place dans le paysage moderne du développement front-end avant de nous <a href="https://la-cascade.io/articles/npm-guide-2-cli">familiariser avec la ligne de commande</a>. À partir de là, nous avons décomposé les termes <a href="https://la-cascade.io/articles/npm-guide-3-node">"Node"</a> et <a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">"gestionnaire de paquets"</a> pour obtenir une compréhension précise de ce qu'est et fait npm. Une fois que nous nous sommes familiarisés avec le rôle que jouent les gestionnaires de paquets dans le développement, nous avons plongé directement dans npm, y compris <a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">comment l'installer</a>, <a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">ajouter des paquets</a> à un projet, <a href="https://la-cascade.io/articles/npm-guide-7-commandes">configurer des commandes</a>, et enfin, comment <a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">sauter dans un projet existant</a> qui utilise npm.</p><p>J'espère que tout ce que nous avons abordé dans ce guide npm vous ouvre au moins suffisamment la porte pour que vous puissiez explorer npm plus avant et passer au niveau supérieur lorsque vous serez prêt. Il faut souvent que je répète quelque chose plusieurs fois et que j'essaie de multiples approches pour que quelque chose s'imprègne vraiment. Donc, si vous êtes assis là à vous sentir presque aussi confus que vous l'étiez avant, prenez un peu plus de temps sur ce sujet. Réfléchissez à ce que vous savez et à ce que vous avez appris, et revenez — ou essayez une nouvelle approche lorsque vous serez prêt !</p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-7-commandes">← Chapitre 8</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-8-installer-projet</link>
      <guid>https://la-cascade.io/articles/npm-guide-8-installer-projet</guid>
      <pubDate>Wed, 02 Feb 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM : comment fonctionnent les commandes npm ?]]></title>
      <description><![CDATA[<p><em>npm nous permet d'exécuter des tâches, sur commande ou en arrière-plan. Un petit exemple avec sass.</em></p><div class="articleContent"><p>npm est, comme vous le savez maintenant, <a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">un gestionnaire de paquets</a>. Mais comme d'autres outils similaires antérieurs qui exécutent des tâches en ligne de commande, tels que <a href="https://gruntjs.com/">Grunt</a> et <a href="https://gulpjs.com/">Gulp</a>, npm peut également exécuter des tâches - ce qui est parfait pour nous car maintenant que nous avons installé le paquet Sass dans le <a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">chapitre précédent</a>, nous pouvons commencer à l'utiliser !</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a> ← <strong><em>vous êtes ici</em></strong></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><h3>Sauter dans les commandes npm</h3><p>Ouvrez le fichier <code>package.json</code> dans votre dossier de test, et vous ne verrez pas grand-chose pour le moment ; juste une propriété dependencies, avec une seule dépendance jusqu'à présent :</p><pre class="language-js">{
  "dependencies" : {
    "sass" : "^1.43.4"
  }
}</pre><p>Le fichier <code>package.json</code> abrite bien plus que des dépendances, cependant. Il contient également de nombreuses méta-informations sur votre projet. L'un des éléments les plus intéressants est une propriété facultative, mais extrêmement utile, appelée scripts.</p><p>Rappelez-vous, toutes les sous-dépendances de Sass sont suivies dans <code>package-lock.json</code>, qui est généré automatiquement, et ne doit pas être modifié à la main. <code>package.json</code> ne contient généralement que les dépendances de premier niveau, et nous pouvons le personnaliser librement.</p><p>L'objet <code>scripts</code> de votre fichier <code>package.json</code> vous permet de créer des commandes que vous pouvez exécuter dans ce projet afin de gérer diverses tâches pour vous, soit en une seule fois, soit en tant que processus fonctionnant en continu. En général, ces "tâches" sont utilisées pour des choses comme le démarrage d'un serveur de développement pour le développement local, la compilation de ressources et/ou l'exécution de tests. En fait, il y a souvent une seule commande <code>start</code> ou <code>dev</code> intégrée aux projets pour gérer <em>toutes</em> les tâches que vous pourriez avoir besoin d'exécuter simultanément, comme la compilation de Sass et JavaScript dans la même séquence.</p><p>Nous n'avons pas encore de scripts à exécuter, mais réparons cela !</p><h3>Exemple : Compilation de Sass en CSS</h3><p>À l'intérieur de la section <code>scripts</code> du fichier <code>package.json</code>, nous avons accès à tous nos paquets installés. Même si nous ne pouvons pas simplement taper des commandes <code>sass</code> dans le terminal pour le moment, nous pouvons exécuter des commandes <code>sass</code> dans le cadre d'un script npm.</p><p>Note : <em>Nous pourrions exécuter des commandes sass dans le terminal si Sass était installé globalement, c'est-à-dire à l'échelle du système, plutôt que dans un dossier de projet spécifique. Jusqu'à présent, nous n'avons installé Sass que dans ce dossier (c'est ce qui se passe par défaut lorsque vous installez un paquet). Mais une installation globale rendrait les commandes sass disponibles partout sur le système</em>.</p><p>Commencez par coller ce bloc de code dans votre fichier package.json, juste après l'accolade <code>{</code> ouvrante :</p><pre class="language-js">"scripts" : {
  "sass:build" : "sass style.scss style.css"
},</pre><p>La syntaxe JSON est très stricte. Essayez de faire passer le contenu du fichier par un <a href="https://jsonlint.com/">validateur JSON</a> si vous êtes bloqué.</p><p>Cela nous donne accès à un script <code>npm run sass:build</code>, qui compilera Sass en CSS pour nous !</p><p>Le nom de la commande n'a pas d'importance, tant qu'il s'agit d'une chaîne continue. Il convient également de noter que les deux points ( : ) ne font rien de spécial ici ; c'est juste une convention, puisque build ou sass seul serait probablement trop générique.</p><p>Si vous avez déjà travaillé avec des commandes Sass, vous savez probablement que cela signifie que nous devons également créer un fichier <code>style.scss</code> à la racine de notre dossier de projet. Faisons-le et insérons-y un peu de code Sass arbitraire.</p><figure role="group"><img src="https://la-cascade.io/images/sass-example.webp" alt="" /><figcaption>Le fichier `style.scss` file est à côté des fichiers JSON et le dossier node_modules est le premier dans le projet.</figcaption></figure><p>Voici le code Sass que j'ai utilisé, si vous souhaitez le copier et le coller :</p><pre class="language-scss">$myColor: #ffd100;
.a {
  .nested {
    .selector {
      color: $myColor;
    }
  }
}</pre><p>Super ! Enregistrez ce fichier en tant que <code>style.scss</code> à la racine de votre projet, et essayons d'exécuter notre nouvelle commande :</p><pre class="language-bash">npm run sass:build</pre><p>Une fois cette tâche accomplie, vous devriez voir deux nouveaux fichiers apparaître presque instantanément dans votre dossier de projet : <code>style.css</code> et <code>style.css.map</code>.</p><figure role="group"><img src="https://la-cascade.io/images/sass-example2.webp" alt="" /><figcaption>Après avoir lancé `npm run sass:build`, vous devriez voir les fichiers style.css and style.css.map apparaître tout en haut du dossier projet.</figcaption></figure><p>Si vous le souhaitez, vous pouvez ouvrir le fichier style.css — qui contient le code CSS compilé — pour vérifier qu'il correspond bien à nos attentes :</p><figure role="group"><img src="https://la-cascade.io/images/sass-example3.webp" alt="" /><figcaption>Regardez-moi ça, du pur CSS !</figcaption></figure><p>Le paquet sass va même jusqu'à compiler une <em><a href="https://css-tricks.com/should-i-use-source-maps-in-production/">source map</a></em> pour nous, ce qui nous permet de voir quels styles proviennent de quels fichiers <code>.scss</code> lorsque nous les inspectons dans les DevTools d'un navigateur. Comme c'est agréable !</p><p><strong>Si vous rencontrez une erreur</strong> : vérifiez la syntaxe du <code>package.json</code> pour vous assurer qu'il s'agit d'un JSON valide (voici un <a href="https://jsonlint.com/">validateur JSON en ligne</a> que vous pouvez utiliser), et que votre fichier .scss contient du Sass valide (voici un <a href="https://jsonformatter.org/sass-to-css">convertisseur Sass en ligne</a>). Une autre chose à vérifier est que le nom du fichier correspond au nom dans la commande.</p><h3>Création d'une commande réservée au développement</h3><p>C'est assez génial, mais nous en aurons probablement assez d'exécuter cette commande à plusieurs reprises pendant le développement. Alors, créons une deuxième commande qui demande à Sass de surveiller le fichier pour nous et de le recompiler automatiquement chaque fois que nous enregistrons des modifications !</p><p>Ajoutez ceci à l'intérieur de l'objet <code>scripts</code> dans <code>package.json</code> :</p><pre class="language-js">"sass:watch" : "sass style.scss style.css --watch" : "sass:watch"</pre><p>Remarque importante : assurez-vous qu'il y a une virgule (,) entre les deux scripts. L'ordre n'a pas d'importance, mais la virgule entre eux en a. Encore une fois, <strong>JSON est strict</strong>, alors appuyez-vous sur le validateur JSON si nécessaire.</p><p>Maintenant, si nous exécutons <code>sass:watch</code>, vous verrez un message dans votre terminal disant : “Sass is watching for changes. Press Ctrl-C to stop.” ("Sass surveille les changements. Appuyez sur Ctrl-C pour arrêter".)</p><p>Si vous ouvrez maintenant votre fichier style.scss, que vous y apportez une modification et que vous l'enregistrez, vous devriez voir apparaître automatiquement dans le terminal un message confirmant que Sass a été recompilé en CSS :</p><figure><img src="https://la-cascade.io/images/sass-message.webp" alt="Une capture d'écran du texte du terminal indiquant que Sass surveille les modifications. Appuyez sur control plus c pour arrêter. En dessous, il est indiqué que le fichier style.scss a été compilé en un fichier style.css." /></figure><p><em>Ah, voilà qui est utile !</em> Non seulement cela, mais une fois que nous aurons livré ces fichiers à notre dépôt, nous aurons les instructions exactes pour installer et faire fonctionner Sass, avec une simple commande - et tous les autres qui travaillent sur ce projet aussi !</p><p>Nous allons laisser les choses en l'état pour ce projet de test. Il était utile de voir comment démarrer, mais le plus souvent, vous vous tournerez vers un projet préconfiguré, plutôt que de créer des commandes npm à partir de zéro, ce qui est exactement ce que nous ferons ensuite, dans le <a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">dernier chapitre de ce guide npm</a>.</p><h3>Dernières notes sur l'installation des paquets npm</h3><p>Vous devez savoir qu'il existe en fait deux façons d'installer des paquets npm, à choisir selon que le paquet est censé faire partie du <em>build</em> (la construction) de <strong>production</strong>, ou qu'il est purement destiné au <strong>développement</strong>.</p><ul><li><code>npm install</code> (ou <code>npm i</code>) est la manière standard (et par défaut) d'ajouter un paquet à un projet.</li>
<li><code>npm install --save-dev</code> (ou <code>npm i -D</code>) ajoute uniquement le paquet à vos "dépendances de développement", ce qui signifie qu'il ne sera installé que lors du développement du projet, et non lors de la construction de la version de production finalisée du projet.</li>
</ul><p>Les paquets installés comme dépendances de développement peuvent inclure des bibliothèques de test, des linters, des serveurs de prévisualisation et d'autres outils qui vous aident uniquement pendant le processus de développement. Ils ne sont généralement pas utilisés pour compiler ou exécuter le site Web lui-même.</p><p>Il existe un dernier drapeau qui mérite d'être connu : <code>npm install --global</code> (ou <code>npm i -g</code>). Il s'agit de l'installation globale d'un paquet, comme nous l'avons évoqué un peu plus tôt lors de l'installation de Sass. Vous pouvez l'utiliser si, par exemple, vous voulez pouvoir exécuter sass n'importe où sur votre machine. D'autres cas d'utilisation courants pour une installation globale pourraient inclure des outils CLI que vous voudriez utiliser partout, ou même un autre gestionnaire de paquets, comme <a href="https://yarnpkg.com/">Yarn</a>.</p><h3>Prochaines étapes</h3><p>Nous approchons de la fin de notre voyage ! Il y a une dernière chose que vous devez savoir, et comment utiliser npm pour faire tourner rapidement tout ce dont vous avez besoin sur un projet existant. Disons que vous héritez d'un projet qui utilise npm. Par où commencez-vous ? Comment vous assurer que vous collaborez avec les autres de manière cohérente ? C'est l'objet de la dernière section de ce guide npm.</p><div class="button-container button-block"><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">← Chapitre 7</a></p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Chapitre 9 →</a></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-7-commandes</link>
      <guid>https://la-cascade.io/articles/npm-guide-7-commandes</guid>
      <pubDate>Tue, 01 Feb 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM : comment installer les paquets npm ?]]></title>
      <description><![CDATA[<p><em>Créons maintenant un petit projet pour nous avoir une expérience pratique de travail avec les bases de npm et comprendre comment npm nous aide dans notre workflow de développement front.</em></p><div class="articleContent"><p>À présent, vous commencez à bien connaître npm ! Jusqu'à présent, nous avons décomposé les trois lettres de "npm" pour mieux comprendre Node et les gestionnaires de paquets. Dans <a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">le chapitre précédent</a>, nous avons même installé Node et npm tout en nous familiarisant avec le gestionnaire de version de Node, ou nvm. La prochaine étape de ce guide du débutant pour npm est probablement la raison pour laquelle vous êtes ici en premier lieu : l'installation des paquets npm.</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a> ← <strong><em>vous êtes ici</em></strong></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><h3>Un exemple rapide</h3><p>Nous pouvons installer notre tout premier paquet avec la commande <code>npm install</code> (ou <code>npm i</code> pour faire court), suivie du nom des paquets que nous voulons ajouter à notre projet. Par exemple, <a href="https://www.npmjs.com/package/sass">le paquet Node pour Sass</a> est simplement appelé "sass", ce qui signifie que nous pouvons l'ajouter à un projet comme ceci (assurez-vous simplement d'être d'abord dans un nouveau dossier que vous avez créé pour ce petit projet) :</p><pre class="language-bash">npm install sass</pre><p>C'est tout ce dont vous avez besoin ! Tapez cela et npm se met directement au travail :</p><figure><img src="https://la-cascade.io/images/npm-install.webp" alt="lancement de la commande 'npm install sass' pour installer Sass sur notre ordi" /></figure><p>Ce qui se passe en coulisses, c'est que npm essaie de trouver un paquet nommé sass dans le registre des paquets npm. S'il trouve ce paquet (ce qui est le cas), npm l'installe dans le projet dans un dossier node_modules généré automatiquement (nous y reviendrons plus tard) situé dans le dossier racine du projet, y compris tout ce dont le paquet a besoin pour fonctionner. (C'est pourquoi vous voyez que npm a ajouté 16 paquets et vérifié un total de 17 paquets npm, au lieu du seul paquet Sass - lui aussi a des dépendances).</p><p>Une fois que nous avons exécuté la commande <code>install</code>, vous pouvez remarquer que vous ne voyez rien nommé "sass" dans le dossier du projet, comme vous pourriez vous y attendre. Curieusement, cependant, nous voyons trois nouveaux éléments dans le dossier du projet : deux fichiers JSON nommés <code>package.json</code> et <code>package-lock.json</code>, plus un dossier <code>node_modules</code> entièrement nouveau.</p><figure><img src="https://la-cascade.io/images/package-json.webp" alt="" /></figure><p>Qu'est-ce que c'est que ça ? Nous avons demandé à npm d'installer Sass, pas tous ces trucs. Cela ne fait pas partie de Sass... n'est-ce pas ? Eh bien, c'est exact, mais il y a une très bonne raison pour laquelle ces nouveaux éléments ont été générés dans le dossier du projet. Voyons ce qui vient de se passer.</p><h3>Ce qui se passe lorsque vous installez un paquet</h3><p>Lorsque vous installez (ou désinstallez, ou mettez à jour) un paquet, npm fait la plupart, sinon la totalité, des quatre choses suivantes :</p><ul><li>met à jour le fichier <code>package.json</code> dans votre projet, si nécessaire ;</li>
<li>met à jour le fichier <code>package-lock.json</code> (appelé "lockfile") qui contient toutes les spécificités techniques ;</li>
<li>installe les fichiers du paquet réel - et tout autre paquet dont le paquet original pourrait dépendre (à l'intérieur du dossier <code>node_modules</code>) ; et</li>
<li>exécute un audit des paquets installés.</li>
</ul><p>Passons en revue ces éléments un par un.</p><h4>package.json et package-lock.json</h4><p>Ces deux fichiers JSON fonctionnent ensemble pour assurer un enregistrement précis de toutes les dépendances de votre projet (et de toutes <em>leurs</em> dépendances, et de toutes les dépendances de leurs dépendances, et ainsi de suite). La différence est un peu technique, mais expliquée en gros : le fichier lockfile est l'instantané précis et approfondi de l'arbre des dépendances du projet, et <code>package.json</code> est une vue d'ensemble de haut niveau, qui peut aussi contenir d'autres choses. <strong>Les principaux paquets que vous installez peuvent être répertoriés dans package.json, mais package-lock.json est l'endroit où l'arbre de dépendance entier est suivi</strong>.</p><p>Le fichier lockfile n'est également jamais censé être mis à jour à la main ; uniquement par npm. Veillez donc à ne pas confondre le fichier lockfile avec le fichier <code>package.json</code>.</p><p>Lorsque vous partagez ou collaborez avec d'autres personnes sur un projet, npm sait d'où vient le projet et ce que vous avez exactement installé dans le projet par ces deux fichiers. Il peut répliquer cet environnement avec précision sur la machine de n'importe qui d'autre, grâce à leurs informations. Les deux fichiers sont destinés à être commis à votre repo Git, et servent de schéma directeur des dépendances de votre projet. Ainsi, lorsqu'un autre développeur de votre équipe clone le repo et exécute la commande npm install, npm sait exactement quels paquets installer, ce qui vous permet de rester synchronisé avec votre collègue.</p><p>Si vous ouvrez <code>package.json</code>, vous ne verrez pas grand-chose, mais cela vaut la peine de jeter un coup d'œil juste pour voir ce qui se passe :</p><pre class="language-js">{
  "dependencies" : {
    "sass" : "^1.43.4"
  }
}</pre><p>Vous ne verrez probablement pas ce numéro de version exact (puisque le paquet a été mis à jour depuis le moment de l'écriture), mais vous <em>devriez</em> voir <code>sass</code> listé dans un objet JSON dependencies. Le numéro lui-même (1.43.4 dans ce cas) indique la version spécifique de Sass qui est installée.</p><p><strong>Note</strong> : <em>Petite parenthèse importante : le caractère "accent circonflexe" (^) au début du numéro de version indique à npm qu'il est autorisé à installer des mises à jour mineures du paquet. En d'autres termes, il indique à npm que le paquet Sass installé doit être au moins la version 1.43.4, mais qu'il peut s'agir de n'importe quelle version 1.x.x supérieure, tant qu'elle est inférieure à 2.0.0. npm choisit généralement la dernière version stable lorsqu'un paquet est installé, mais ajoute ce caractère pour permettre des mises à jour non cassantes. Cette partie est appelée "versionnement sémantique" et fait l'objet d'un article de blog en soi, mais n'est pas propre à npm.</em></p><p>Quoi qu'il en soit, cela couvre les deux fichiers JSON. Parlons maintenant du dossier <code>node_modules</code>.</p><h4>node_modules</h4><p>node_modules est <strong>l'endroit où se trouve tout le code de paquetage réel</strong> ; c'est l'endroit où vos paquets Node installés et toutes les choses qui les font fonctionner sont réellement installés. Si vous ouvrez le dossier en ce moment même, vous trouverez un dossier <code>sass</code>, mais aussi plusieurs autres dossiers.</p><p>La raison de ces dossiers supplémentaires est que lorsque vous installez un paquet, il peut avoir besoin <em>d'autres</em> paquets pour fonctionner correctement (comme c'est clairement le cas pour Sass). Ainsi, npm fait automatiquement le travail difficile de trouver et d'installer toutes ces dépendances. Comme vous l'avez peut-être deviné, ces dépendances peuvent également avoir <em>d'autres</em> dépendances, et le processus se répète, ainsi de suite, jusqu'à ce que nous ayons fini de parcourir l'arbre des dépendances jusqu'à ses branches les plus éloignées et qu'absolument tout ce dont nous avons besoin soit installé (ou jusqu'à ce que nous ayons rencontré une erreur quelconque, bien que nous espérions que ce ne soit pas le cas).</p><p>Pour cette raison, il est courant qu'un projet ait des sous-dossiers node_modules par centaines ou plus, qui s'additionnent rapidement en termes d'espace disque. <code>node_modules</code> peut souvent devenir assez lourd.</p><p>Si vous vous demandez comment commettre un dossier super volumineux comme node_modules dans le dépôt d'un projet, voici une remarque importante : contrairement aux fichiers JSON, <strong>le dossier node_modules n'est pas destiné à être committé dans Git</strong>, ni même partagé. En fait, presque tous les exemples de fichiers <code>.gitignore</code> (le fichier qui indique les fichiers que Git doit ignorer lorsqu'il suit des fichiers) incluent <code>node_modules</code> pour s'assurer que Git ne le touche jamais ou ne le suit pas.</p><p>Alors, comment les autres membres de votre équipe obtiennent-ils ces paquets ? Eh bien ils exécutent <code>npm install</code> (ou <code>npm i</code> en abrégé) depuis la ligne de commande pour télécharger les dépendances directement depuis la source. De cette façon, il n'est pas nécessaire de pousser (ou de tirer) des quantités massives de données depuis et vers le dépôt d'origine.</p><h3>Faire preuve de prudence lors de l'installation des dépendances</h3><p>Cette toile massive de dépendances et de leurs arrière-arrière-arrière-dépendances peut conduire à des situations où une petite bibliothèque utilitaire qui fournit un service utile peut être adoptée par de nombreux autres paquets, qui sont à leur tour utilisés par de nombreux <em>autres</em> paquets, jusqu'à ce que le code original finisse par être installé discrètement sur un pourcentage significatif de sites et d'applications.</p><p>Il peut sembler étrange (voire effrayant) que, dans le processus d'installation de votre paquet, vous puissiez <em>laisser passer tout un tas d'autres choses</em>. Cela peut ressembler à inviter un nouvel ami à votre fête chez vous, qui se présente ensuite avec 20 étrangers non invités. Mais ce n'est pas aussi bizarre ou effrayant que cela peut paraître, pour quelques raisons :</p><ol><li><strong>La plupart des paquets npm sont open source</strong>. Vous et n'importe qui d'autre pouvez facilement jeter un coup d'œil sous le capot et voir exactement ce que fait le paquet. Vous pouvez également consulter le paquet sur le registre (<a href="https://www.npmjs.com/">npmjs.com</a>) pour voir combien de fois il a été installé, quand il a été mis à jour pour la dernière fois et d'autres informations pertinentes. Si un paquet est assez populaire, vous pouvez être raisonnablement certain qu'il est sûr.</li>
<li><strong>Il existe un vaste monde de fonctionnalités dont de <em>nombreux</em> projets auront besoin</strong>. Pensez au formatage de la date, à la gestion des demandes et des réponses HTTP, à l'étranglement, au débruitage ou aux animations, pour ne citer que quelques exemples rapides. Cela n'a aucun sens de réinventer la roue et de coder manuellement ces éléments chaque fois qu'ils sont utilisés dans un nouveau projet.</li>
<li><strong>L'installation d'un paquet n'est pas vraiment très différente de l'installation d'une application sur votre téléphone ou d'un plugin sur un site WordPress</strong>. La différence est que nous n'avons pas le même aperçu du fonctionnement interne de ces applications et plugins qu'avec les paquets, ni des autres éléments sur lesquels ces applications et plugins peuvent s'appuyer. Il y a de fortes chances qu'ils s'appuient également sur de nombreux petits paquets, d'une manière ou d'une autre.</li>
</ol><p>Un certain degré de prudence est une bonne idée dans tout environnement dans lequel on peut installer et exécuter du code arbitraire, bien sûr. Ne vous méprenez pas. Je mentirais si je disais que de mauvais acteurs n'ont jamais réussi à tirer parti de ce système. Mais sachez qu'il existe de nombreux processus en place pour éviter que les choses ne dérapent. En cas de doute, contentez-vous des paquets les plus populaires et tout ira bien.</p><p>Sachez également que npm exécute des audits de sécurité automatiques pour vous, ce qui nous amène au dernier point de cette section.</p><h3>Qu'est-ce que npm audit ?</h3><p>Lorsque nous avons installé sass plus tôt, nous avons vu le message suivant dans le terminal une fois l'installation terminée :</p><pre class="language-bash">found 0 vulnerabilities</pre><p>Cependant, vous pouvez voir quelques avertissements à la place, comme ce vieux projet à moi dans l'image suivante. J'ai décidé de le démarrer et d'exécuter <code>npm install</code> (<code>npm i</code>) après qu'il soit resté inutilisé pendant au moins deux ans. Voyons comment cela se passe :</p><figure><img src="https://la-cascade.io/images/npm-audit.webp" alt="" /></figure><p><strong>Les paquets présentant des vulnérabilités connues sont signalés par <code>npm audit</code></strong>, qui s'exécute automatiquement chaque fois que vous installez un paquet. Si vous voyez un message comme celui-ci, ne soyez pas <em>trop</em> alarmé ; de nombreuses vulnérabilités, en particulier dans la catégorie "modérée", comportent un risque très faible dans le monde réel, et peuvent n'être pertinentes que dans des situations très spécifiques. (Par exemple, il se peut qu'une seule méthode d'un paquet, lorsqu'elle est utilisée d'une manière particulière, le rende vulnérable).</p><p>Néanmoins, il est préférable de traiter ce que nous pouvons, ce à quoi sert la commande <code>npm audit fix</code>. L'ajout de <code>fix</code> à la fin de la commande indique à npm de procéder à la mise à jour vers une nouvelle <em>version mineure</em> de tout paquet présentant une vulnérabilité connue. La partie "version mineure" est importante ; les versions mineures ne sont pas censées contenir des changements de rupture, seulement des mises à jour. Cela signifie qu'il devrait être possible d'exécuter une mise à jour de cette manière sans risquer de casser votre projet.</p><p>Si l'augmentation du paquet d'un numéro de version mineure ne suffit pas, vous pouvez ajouter le drapeau <code>--force</code> à la commande originale :</p><pre class="language-bash">npm audit fix --force</pre><p>Il s'agit toutefois d'une manœuvre risquée. Donner à npm la permission d'"utiliser la force" signifie qu'il peut maintenant installer des mises à jour de versions majeures pour corriger les vulnérabilités — ce qui signifie qu'il peut effectuer des changements cassants ou introduire des incompatibilités. Je ne recommanderais pas de faire cela à moins qu'il n'y ait des vulnérabilités critiques que le correctif d'audit de npm est incapable de traiter et que vous soyez prêt et capable de passer beaucoup de temps par la suite à dépanner, si nécessaire.</p><p>Une dernière remarque à ce sujet : il est utile de savoir que vous pouvez parfois résoudre certains problèmes inattendus avec les projets npm en supprimant les node_modules, et en relançant <code>npm install</code>. C'est la façon dont npm " désactive et réactive les choses ", ce que j'ai moi-même fait de nombreuses fois.</p><h3>La suite</h3><p>Maintenant que nous avons exploré en profondeur le terrier du lapin qui explique comment npm fonctionne sous le capot, <em>revenons à la pratique</em>, d'accord ?</p><div class="button-container button-block"><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-5-installer-npm">← Chapitre 6</a></p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-7-commandes">Chapitre 8 →</a></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-6-package-installer-paquets</link>
      <guid>https://la-cascade.io/articles/npm-guide-6-package-installer-paquets</guid>
      <pubDate>Mon, 31 Jan 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM : comment installer npm ?]]></title>
      <description><![CDATA[<p><em>Installons Node et npm tout en nous familiarisant avec le gestionnaire de version de Node, ou nvm.</em></p><div class="articleContent"><p>Vous avez l'impression d'avoir une assez bonne idée de ce qu'est un gestionnaire de paquets ? Nous avons certainement couvert beaucoup de terrain en nous familiarisant avec tous les termes et concepts des gestionnaires de paquets, mais je dirais qu'il est grand temps de faire quelque chose de nos nouvelles connaissances. Et d'abord, nous devons installer npm.</p><p>À cette fin, nous allons nous assurer que nous avons installé Node et npm, puis créer un petit projet d'exemple pour vous donner une véritable expérience pratique de travail avec les bases de npm et ce à quoi ressemble l'utilisation de npm dans votre flux de travail de développement front.</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a> ← <strong><em>vous êtes ici</em></strong></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><h3>Vérifiez si npm est déjà installé</h3><p>Avant d'installer npm, nous devons vérifer s'il est déjà installé ! Si vous n'êtes pas sûr que npm soit déjà installé sur votre système, ouvrez le terminal de votre choix, qu'il s'agisse de l'application Terminal sous MacOS, du terminal intégré dans un éditeur de code comme VS Code, ou d'un autre terminal où vous avez accès à la ligne de commande.</p><p>Vous êtes prêt ? Commencez par cette commande (remarquez que nous n'incluons pas le caractère <code>$</code> dans ces exemples) :</p><pre class="language-js">node - v</pre><p>Cette commande affiche la version actuelle de Node, si elle est installée. Si Node est installé, la ligne de commande répondra avec le numéro de version de Node qui est actuellement installé :</p><pre class="language-js">v16.9.1</pre><p>Votre version peut être différente, bien sûr. Quoi qu'il en soit, le fait que vous voyiez un numéro de version confirme que npm est installé sur votre système ! Permettez-moi d'insister sur le fait que <strong>les numéros eux-mêmes sont sans importance</strong>, du moment que nous obtenons un numéro de version.</p><p>Si npm ou Node n'est pas actuellement installé, vous verrez un message du type "Commande non trouvée" à la place. Dans le cas improbable où npm serait installé mais pas Node (ou vice versa), il est probablement utile de le désinstaller avant de continuer.</p><p>En supposant que vous ayez besoin d'installer npm et Node (et si ce n'est pas le cas, vous pouvez passer directement à la section suivante), nous allons suivre les conseils des <a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">instructions officielles de NPM</a> et le faire via un programme appelé <a href="https://github.com/nvm-sh/nvm">nvm</a>.</p><h3>Installation du gestionnaire de version de Node</h3><p>Node Version Manager, ou nvm, vous permet d'installer, de mettre à jour et de désinstaller Node sur votre système, et aussi de gérer plusieurs versions de Node entre lesquelles vous pouvez passer.</p><figure role="group"><img src="https://la-cascade.io/images/nvm-github.webp" alt="" /><figcaption>Le dépôt du gestionnaire de version de Node (Node Version Manager) sur GitHub</figcaption></figure><blockquote>
<p>Note : <em>Comme vous le savez peut-être, les langages côté serveur ont leurs propres versions, par exemple Node 17.1.0, plutôt que d'être liés aux versions des navigateurs, comme Chrome 96. Nous n'aurons besoin d'aucune autre version de Node que la dernière, donc cela ne sera pas nécessaire pour nous dans l'immédiat, bien que cela puisse être avantageux pour vous plus tard</em>.</p>
</blockquote><p>Je sais, cela peut sembler beaucoup de travail supplémentaire d'installer un programme juste pour en installer un autre, mais encore une fois, c'est le chemin recommandé, et faire les choses de la bonne manière dès le début les rend beaucoup plus faciles à long terme. Je préfère vous mettre sur la voie du succès plutôt que de rendre les choses brièvement plus faciles au prix d'une plus grande complexité par la suite.</p><h3>Installation de nvm sur Windows</h3><p>Si vous êtes sous Windows, vous aurez en fait plus de facilité ici. Vous aurez besoin de nvm pour Windows spécifiquement, mais heureusement, Windows a déjà un installateur qu'il suffit de télécharger et d'exécuter. <a href="https://github.com/coreybutler/nvm-windows">Les instructions se trouvent dans le repo NVM pour Windows</a> sur GitHub.</p><ul><li>Téléchargez <a href="https://github.com/coreybutler/nvm-windows/releases">la dernière version de NVM pour Windows</a>. Vous pouvez <a href="https://github.com/coreybutler/nvm-windows/wiki#manual-installation">l'installer manuellement</a>, si vous préférez.</li>
<li>Ouvrez le terminal et exécutez la commande <code>nvm list available</code> pour voir une liste des versions de Node qui sont disponibles pour le téléchargement et l'installation.</li>
<li>Exécutez la commande <code>nvm use</code>, suivie du numéro de version de Node que vous souhaitez utiliser (par exemple, <code>nvm use 16.9.1</code>) pour utiliser une version spécifique. Vous pouvez également utiliser <code>use latest</code>, <code>lts</code>, ou <code>newest</code> au lieu d'un numéro de version spécifique, où <code>newest</code> est la dernière version installée.</li>
</ul><p>Une fois installé, nvm fonctionnera de la même manière sur votre machine Windows que sur tout autre système.</p><h3>Installation de nvm sur MacOS</h3><p>Pour installer nvm sur MacOS, la première étape consiste à le télécharger avec cette commande :</p><pre class="language-bash">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash</pre><blockquote>
<p>Note : <em>0.39.0 est la dernière version publiée, mais il peut être utile de vérifier le readme d'installation de nvm et d'obtenir la dernière version, si elle est différente.</em></p>
</blockquote><p>Une fois que vous avez collé cette commande dans le terminal et appuyé sur Entrée, vous verrez votre terminal afficher un tas de choses qui n'ont pas vraiment d'importance. En fait, je vais vous confier un petit secret : la plupart du temps, personne ne lit ce que contient son terminal. Tout ce qui nous intéresse, c'est que...</p><ol><li>la commande se termine finalement ; et</li>
<li>qu'elle ne se termine pas par un message d'erreur.</li>
</ol><blockquote>
<p>Note : <em>Si vous êtes invité à entrer une commande au milieu de l'installation, appuyez sur la touche q pour quitter et continuer.</em></p>
</blockquote><p>Vous saurez que l'exécution de la commande est terminée lorsque le curseur de saisie recommence à clignoter, indiquant que le terminal attend votre saisie. Vous pouvez même voir ceci juste après la fin de l'installation de nvm :</p><pre class="language-bash">=&gt; Close and reopen your terminal to start using nvm or run the following to use it now:
</pre><p>C'est à dire : <em>Fermez et rouvrez votre terminal pour commencer à utiliser nvm ou exécutez ce qui suit pour l'utiliser maintenant</em>.</p><p>En supposant que vous ne voyiez pas d'erreurs à ce stade, je recommanderais l'option plus simple consistant à quitter et à redémarrer l'application de terminal que vous utilisez avant de continuer. C'est une bonne façon de s'assurer que vous travaillez avec une ardoise propre.</p><h3>Comment installer npm via Node</h3><p>Maintenant que nvm est installé, nous sommes prêts à faire ce que nous voulions <em>vraiment</em> faire en premier lieu : installer npm et Node sur notre système.</p><p>Ce n'est pas une mauvaise idée de confirmer que nvm est installé correctement, en exécutant <code>nvm -v</code>. Si le terminal vous montre le numéro de la version installée, vous êtes prêt à partir ! Si ce n'est pas le cas, rappelez-vous que vous devrez peut-être redémarrer votre application de terminal avant que l'installation ne soit complètement terminée.</p><p>Maintenant que nous avons nvm, l'installation de Node est une commande super courte :</p><pre class="language-bash">nvm install node</pre><p>Assez simple, hein ?</p><p>Vous devriez voir un message du type <code>Downloading and installing node v17.1.0</code>, bien que le numéro de version puisse ne pas correspondre, ce qui est bien. Vous obtiendrez la dernière version stable au moment de l'exécution. Attendez jusqu'à ce que la commande ait fini de s'exécuter — encore une fois, vous saurez qu'elle est terminée lorsque vous serez de retour à l'invite par défaut et que vous pourrez taper d'autres commandes.</p><p>Après cela, vous avez terminé ! Cette simple commande n'installe pas seulement Node, mais elle installe également npm. Encore une fois, vous pouvez vérifier que tout est installé et à jour avec <code>npm -v</code> et <code>node -v</code>. Si tout est bon, vous obtiendrez un numéro de version.</p><h3>Prochaine étape</h3><p>Très bien, à ce stade, nous avons nvm pour installer et gérer Node, Node lui-même, et npm pour gérer les paquets Node. Dans la suite de ce guide npm, nous allons installer quelques paquets dans un projet !</p><div class="button-container button-block"><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">← Chapitre 5</a></p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Chapitre 7 →</a></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-5-installer-npm</link>
      <guid>https://la-cascade.io/articles/npm-guide-5-installer-npm</guid>
      <pubDate>Sun, 30 Jan 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM, qu'est-ce qu'un gestionnaire de paquets ?]]></title>
      <description><![CDATA[<p><em>Le 'pm' de npm est 'package manager', ou gestionnaire de paquets. Qu'est-ce que cela signifie ? Et qu'est-ce que cela fait ?</em></p><div class="articleContent"><p>Si vous êtes toujours avec moi, jusqu'à présent dans ce guide npm, nous avons développé une compréhension générale de <strong>ce qu'est npm</strong>, notamment qu'il s'agit de Node Package Manager. Dans le processus, nous avons discuté de l'importance de la <strong>ligne de commande</strong> et de la façon dont elle est utilisée avec npm.</p><p>Nous nous sommes également penchés sur le "n" de npm-Node et avons appris que Node ressemble beaucoup au code JavaScript que nous écrivons pour exécuter des sites Web dans un navigateur. En fait, Node est du JavaScript ; il s'exécute simplement <em>en dehors du navigateur</em> et est capable de faire des choses différentes de son homologue basé sur le navigateur.</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a> ← <strong><em>vous êtes ici</em></strong></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><h3>Ce que nous entendons par "paquet"</h3><p>Tournons maintenant notre attention vers les deux dernières lettres de npm, à savoir la partie "gestionnaire de paquets". Afin de bien comprendre ce qu'est npm, nous devons savoir ce qu'est un gestionnaire de paquets. Il s'ensuit donc naturellement que pour comprendre cela, nous devons comprendre ce qu'est un "paquet".</p><p>Un "package" est un terme fourre-tout pour tout fichier de code externe que vous intégrez dans un projet et que vous utilisez d'une manière ou d'une autre. Vous avez peut-être déjà utilisé <a href="https://jquery.com/">jQuery</a>, <a href="https://getbootstrap.com/">Bootstrap</a> ou <a href="https://axios-http.com/">Axios</a> dans un projet. Ce sont des exemples courants de packages.</p><p>Nous les appelons "paquets" car ils sont "emballés" et prêts à être utilisés. Certains langages les appellent par d'autres noms (Ruby les appelle "gems" par exemple), mais le concept est le même. Au risque de simplifier à l'extrême, <strong>un paquet est du code que vous n'avez pas écrit mais que vous avez obtenu d'une source publique pour l'utiliser dans votre projet</strong>. Vous savez, du code tiers.</p><p>Ou, si vous préférez les parodies musicales pour vos moyens mnémotechniques :</p><p>? <em>Quand il y a du code que vous choisissez</em>? <em>Qui n'est pas le vôtre, mais que vous utilisez</em>? <em>C'est un paquet</em>? <em>Quand c'est du matériel que vous installez</em>? <em>Que vous importez et appelez</em>,? <em>C'est un package</em></p><p>Les paquets sont également souvent appelés "dépendances", car le code que vous écrivez <em>dépend</em> de leur présence. Le code écrit à l'aide du $ de jQuery ne fonctionnera pas correctement si jQuery lui-même n'est pas déjà chargé, par exemple. (Pour cette raison, les gestionnaires de paquets sont aussi parfois appelés "gestionnaires de dépendances").</p><p>Les paquets peuvent être grands ou petits en termes de quantité de code qu'ils contiennent. Un paquet peut faire quelque chose d'énorme qui change la façon dont vous écrivez votre projet entier (comme un framework entier), ou il peut faire quelque chose de très petit et ciblé que vous saupoudrez seulement là où c'est nécessaire (comme un widget, ou une aide pour une tâche spécifique).</p><h3>Utilisation de paquets sans gestionnaire de paquets</h3><p>Si vous avez déjà utilisé un paquet dans le passé, vous l'avez très probablement appliqué avec une balise <code>&lt;script&gt;</code> dans votre HTML, qui va le chercher via une URL externe (idéalement <a href="https://css-tricks.com/adding-a-cdn-to-your-website/">d'un CDN</a>). Voici comment vous pourriez inclure jQuery dans le HTML de votre site :</p><pre class="language-js">&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"&gt;&lt;/script&gt;</pre><p>Une autre approche consiste à télécharger une copie du paquet, à l'ajouter aux fichiers de votre projet et à créer un lien vers celui-ci localement, comme ceci :</p><pre class="language-js">&lt;script src="/jquery.min.js"&gt;&lt;/script&gt;</pre><h3>Ce que les gestionnaires de paquets résolvent</h3><p>Ces deux approches ont bien fonctionné pendant des années. C'est simple. C'est propre. Elle vous permet généralement de "définir et d'oublier" le paquet. Alors pourquoi auriez-vous besoin d'autre chose ?</p><p>Vous pouvez probablement imaginer comment le fait de posséder une voiture peut sembler peu attrayant pour quelqu'un qui a un accès facile aux transports en commun ou qui n'a pas besoin de se déplacer sur de longues distances. (Cela va nous ramener à la discussion sur le gestionnaire de forfaits, je vous le promets. Restez avec moi).</p><p>Si vous avez un accès facile à des transports en commun pratiques et efficaces, alors payer un prix élevé pour une machine massive que vous devez stocker quelque part, nettoyer régulièrement, entretenir et remplir de carburant coûteux n'aura probablement pas beaucoup d'avantages de votre point de vue. Dans ce cas précis, les avantages sont négligeables ; les coûts sont comparativement écrasants. Une personne dans cette position hypothétique pourrait même se demander pourquoi quelqu'un veut une voiture tout court !</p><p>J'évoque cette analogie parce que l'apprentissage d'une nouvelle technologie peut être très difficile lorsqu'elle <em>résout un problème que vous n'avez pas</em>, de la même manière que l'achat d'une voiture peut ne pas résoudre un transport que vous avez déjà. Cela peut sembler être une dépense massive et inutile.</p><p>Ce qu'un gestionnaire de paquets résout, alors, est plus une question de mise à l'échelle et de problèmes de manipulation. La simple liaison à un paquet dans une balise de script fonctionne bien, tant que :</p><ul><li>le nombre de projets que vous avez est gérable ;</li>
<li>le nombre de personnes travaillant sur les projets est gérable ;</li>
<li>le nombre de mises à jour qui doivent être apportées aux paquets est gérable ; et, plus important encore</li>
<li>chaque paquet utilisé dans vos projets est du côté client (navigateur) JavaScript ou CSS.</li>
</ul><p>Ce dernier point est le plus important, car il existe une pléthore d'outils que vous ne pourrez jamais utiliser si vous n'exécutez les choses <em>que</em> dans le navigateur (nous y reviendrons dans un instant).</p><p>Si vous cochez toutes ces cases, il se peut que vous ne dépassiez jamais cette approche. Votre approche du développement pourrait bien ressembler à ceci :</p><figure><img src="https://la-cascade.io/images/packages.webp" alt="Une illustration en noir et blanc montrant le diagrame de paquets et de gestionnaire de paquets. Un paquet labellisé 'Cloud' (nuage) est suivi de trois fichiers, HTML, CSS, et JavaScript, qui sont suivis par le navigateur." /></figure><p>Mais même dans ce cas, lorsque vous avez plusieurs balises <code>&lt;script&gt;</code>, dont chacune renvoie à une version spécifique d'un script ou d'une bibliothèque, la <em>seule</em> façon de savoir quels paquets vous utilisez — et s'ils sont à jour — est d'ouvrir manuellement le HTML et de regarder le code.</p><p>Ce n'est pas un problème en soi, mais il croît de façon exponentielle à mesure que la taille et la portée d'un projet augmentent. Vous pouvez peut-être assurer le suivi de quelques paquets manuellement, mais comment le faire quand il s'agit de centaines, voire de milliers de paquets ? Et même si vous pouviez les suivre manuellement, le risque d'erreur humaine reste élevé.</p><p><strong>Ce n'est pas le rôle de HTML d'être la source de vérité pour tous les paquets utilisés sur un projet</strong>. En plus de mélanger les points d'attention, cela introduit aussi potentiellement des conflits lorsqu'on essaie de fusionner des travaux sans rapport entre coéquipiers.</p><p>Tout cela est important, mais ce n'est que la plus petite partie d'un problème plus vaste. Comprenez que JavaScript côté client n'est probablement pas le <em>seul</em> type de package que vous voudrez inclure dans vos projets pour toujours, même si c'est le cas en ce moment — et c'est là que les choses commencent <em>vraiment</em> à se gâter.</p><p>De nombreuses applications de production utilisent une combinaison des outils et paquets suivants, voire tous :</p><ul><li>Sass (facilite l'écriture des CSS)</li>
<li>PostCSS (améliore les CSS pour une efficacité et une compatibilité maximales)</li>
<li>Babel (transpose les nouveaux JavaScript pour qu'ils fonctionnent dans les anciens navigateurs)</li>
<li>TypeScript (ajoute la vérification de type à JavaScript)</li>
<li>Rechargement des modules par un serveur de développement qui rafraîchit automatiquement le navigateur pour afficher vos modifications.</li>
<li>Utilitaires supplémentaires pour le regroupement, la minification et/ou la concaténation de code</li>
<li>Compression automatique des images</li>
<li>Bibliothèques de test</li>
<li>Linters</li>
</ul><p>Mais remarquez que vous avez maintenant plusieurs dépendances qui non seulement ne sont <em>pas</em> présentes dans vos balises de script, mais qui ne sont <em>pas non plus prises en compte dans votre projet</em> ! Il n'y a aucun moyen pour quiconque — y compris pour vous-même dans le futur — d'avoir une idée des outils qui ont été utilisés ou qui sont nécessaires pour faire fonctionner ce projet.</p><p>Et même si vous pouviez savoir exactement ce dont le projet a besoin de cette façon, vous auriez toujours besoin d'aller localiser, télécharger et installer tous ces paquets vous-même... manuellement. En fonction du projet, cette tâche pourrait facilement prendre une journée, voire plus.</p><p>Tout cela signifie que votre flux de travail ressemble maintenant un peu plus à ceci :</p><figure role="group"><img src="https://la-cascade.io/images/workflow.webp" alt="" /><figcaption>Encore une fois, tout cela est bien. Cette chaîne d'outils signifie que ce qui est expédié au navigateur est hautement optimisé, mais cela représente également des frais généraux et une complexité supplémentaires.</figcaption></figure><p><strong>Aussi pratiques que soient tous les outils ci-dessus, vous devez quand même les gérer</strong>. Les dépendances sont aussi des projets, et elles envoient des mises à jour pour corriger les bogues et introduire de nouvelles fonctionnalités. En tant que tel, il n'est pas réaliste de simplement coller une balise de script dans le HTML avec un lien qui pointe vers un paquet sur un CDN et d'appeler cela bon. Vous devez vous assurer que chaque chose est installée et fonctionne correctement non seulement sur votre machine, mais aussi sur celle de chaque collaborateur.</p><p>Les gestionnaires de paquets existent pour rendre les paquets — ou dépendances — d'un projet gérables en sachant ce qui est installé, ce qui est disponible pour la mise à jour et si un paquet peut créer des conflits avec un autre. Et la beauté d'un gestionnaire de paquets est qu'il accomplit tout cela directement à partir de la ligne de commande, avec un minimum d'effort.</p><p>De nombreux gestionnaires de paquets, notamment npm, proposent également des fonctionnalités supplémentaires qui ouvrent encore plus de possibilités pour rendre le développement plus efficace. Mais la gestion de paquets est l'attraction principale.</p><h3>Il existe des gestionnaires de paquets qui ne sont pas npm</h3><p>Cette partie n'est pas super pertinente pour npm lui-même, mais par souci d'exhaustivité, je devrais également mentionner que npm n'est pas le seul gestionnaire de paquets JavaScript. Par exemple, vous pouvez voir <a href="https://yarnpkg.com/">Yarn</a> référencé dans les exemples de code. Yarn et npm fonctionnent à peu près de la même manière, à tel point qu'une grande partie de l'interopérabilité entre les deux est volontairement intégrée.</p><p>Certaines personnes préfèrent un gestionnaire de paquets plutôt qu'un autre. Personnellement, je pense que les différences entre npm et Yarn étaient plus prononcées au début, mais les deux sont maintenant plus similaires.</p><p>Vous verrez peut-être des exemples de code (dont certains dans les articles de CSS-Tricks) qui font référence à la fois à Yarn et à npm. C'est pour faire savoir au lecteur que l'une ou l'autre approche est bonne, plutôt que la nécessité d'utiliser les deux ensemble.</p><p>La syntaxe de Yarn et de npm diffère parfois, mais lorsqu'un seul est présent, il est généralement trivial de convertir une commande ou un projet de l'un à l'autre. D'un point de vue fonctionnel, il est rare (voire jamais) que vous utilisiez l'un ou l'autre, sauf, bien sûr, que tous ceux qui travaillent ensemble sur le même projet voudront utiliser le même pour assurer la compatibilité et la cohérence.</p><p>Alors que npm et Yarn constituent la grande majorité des gestionnaires de paquets utilisés par les développeurs, il existe <a href="https://pnpm.io/">un autre gestionnaire de paquets appelé PnPm</a> qui est npm dans les faits, mais plus performant et efficace. La contrepartie est que PnPm nécessite un peu plus de connaissances techniques dans certains cas, c'est donc une option un peu plus avancée.</p><figure role="group"><img src="https://la-cascade.io/images/p-managers.png" alt="" /><figcaption>Les différences de syntaxe entre les différents gestionnaires de paquets sont généralement minimes. (Source: <a href="https://vitejs.dev/">Vite</a>)</figcaption></figure><h3>Qu'est-ce qui fait de npm le gestionnaire de paquets "standard" ?</h3><p>Encore une fois, je n'évoque d'autres gestionnaires de paquets que pour illustrer le fait que npm n'est pas le seul gestionnaire de paquets existant, mais qu'il est généralement la norme.</p><p>Qu'est-ce qui en fait le "standard" parmi les gestionnaires de paquets ? D'autres langages, dont Ruby et PHP, disposent de gestionnaires de paquets depuis de nombreuses années ; JavaScript n'en avait pas vraiment de bons avant npm.</p><p>npm a commencé comme un projet indépendant et open-source, mais a été racheté par Microsoft en 2020. Il se compose techniquement de deux parties : le gestionnaire de paquets proprement dit et le registre de paquets, qui est une liste toujours croissante de près de deux millions de paquets disponibles pour l'installation.</p><p>Vous pouvez considérer npm comme le magasin d'applications pour tout ce que vous pourriez vouloir utiliser sur un front-end ou un projet basé sur Node. Trouvez ce que vous voulez et installez-le sur votre système via la ligne de commande. Vous pouvez mettre à jour ce paquet lorsqu'une nouvelle version est publiée, ou le supprimer complètement si le projet n'en dépend plus.</p><h3>Une note sur npx</h3><p>Vous pouvez également voir passer des commandes npx. <a href="https://docs.npmjs.com/cli/v7/commands/npx">npx</a> est en fait une partie de npm, mais en utilisant <code>npx</code> dans une commande au lieu de <code>npm</code> , vous pouvez exécuter le code d'un paquet sans l'installer définitivement. NPX installe simplement ce dont il a besoin, l'exécute et le décharge.</p><p>C'est utile si, par exemple, vous voulez exécuter un script d'installation. Plutôt que de télécharger le programme d'installation, <em>puis</em> de l'exécuter, NPX vous permet simplement d'exécuter le programme d'installation directement, sans rien laisser sur votre machine par la suite. C'est comme l'invité de la maison qui nettoie après lui.</p><p>Un autre exemple cool : vous pouvez exécuter <code>npx sass</code> (avec les arguments d'entrée et de sortie nécessaires) si vous voulez compiler les fichiers Sass de votre projet juste une fois sans vous donner la peine d'installer complètement Sass. Ce n'est probablement pas pratique dans la plupart des cas, mais si vous avez juste besoin d'une compilation rapide et ponctuelle ici et là, npx serait un moyen pratique de le faire, car cela signifie moins de paquets installés qui doivent être mis à jour et maintenus.</p><h3>La suite</h3><p>Très bien, c'était une plongée profonde dans ce que nous voulons dire lorsque nous appelons quelque chose un gestionnaire de paquets. Dans le cas de npm, il est utilisé spécifiquement pour installer et gérer les paquets Node, des outils qui aident à ajouter des fonctionnalités à un projet, à ajouter des commodités pratiques pour les développeurs... ou tout cela à la fois !</p><p>Nous allons poursuivre en faisant maintenant nos premiers pas dans l'utilisation de npm. Et pour ce faire, nous devons l'installer sur notre système. C'est la prochaine étape de ce guide complet de npm.</p><div class="button-container button-block"><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-3-node">← Chapitre 4</a></p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Chapitre 6 →</a></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets</link>
      <guid>https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets</guid>
      <pubDate>Sat, 29 Jan 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM, qu'est-ce que Node ?]]></title>
      <description><![CDATA[<p><em>Le 'n' de npm est Node. Node a commencé comme un moyen d'exécuter JavaScript en dehors du navigateur.</em></p><div class="articleContent"><p>Voici ce que vous devez savoir sur Node.js (ou simplement Node) et sur son rapport avec npm dès le départ :</p><ul><li>Node est du JavaScript, mais en tant que langage côté serveur.</li>
<li>Cela est possible grâce à V8, le moteur JavaScript de Chromium, qui peut fonctionner seul, en dehors des limites du navigateur.</li>
<li>Node et le JavaScript basé sur le navigateur peuvent être très différents, et avoir des capacités différentes, bien que tous deux soient JavaScript à leur base.</li>
<li>Vous n'avez pas besoin de connaître Node pour utiliser npm.</li>
</ul><p>Comme vous le savez peut-être maintenant, npm est l'abréviation de Node Package Manager (même si le <a href="https://www.npmjs.com/">site officiel de npm</a> affiche des noms alternatifs amusants dans son en-tête à chaque chargement de page, comme "Ninja Pumpkin Mutants").</p><p>La chose essentielle à comprendre tout de suite est la suivante : "Node" et "Package Manager" sont les deux grandes pièces distinctes qui se combinent pour former npm.</p><p>Nous couvrirons ce qu'est un gestionnaire de paquets et pourquoi vous pourriez envisager d'en utiliser un lorsque nous aborderons le prochain chapitre de ce guide npm. Pour l'instant, concentrons-nous sur la compréhension de ce qu'est Node, car il s'agit d'un élément clé pour comprendre le développement Web moderne.</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a> ← <strong><em>vous êtes ici</em></strong></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><h3>Node, c'est JavaScript, mais sans le navigateur</h3><p>Vous connaissez probablement JavaScript principalement comme un langage qui s'exécute dans le navigateur, similaire à HTML et CSS. Oui, chacun de ces langages possède des abstractions et des supersets (comme <a href="https://haml.info/">HAML</a> pour HTML, Sass pour CSS, et TypeScript pour JavaScript, par exemple), ainsi que des compilateurs et des transpilateurs et toutes sortes de choses qui les transforment en telle ou telle forme. Mais en fin de compte, ce que ces outils génèrent, c'est du code vanille (c'est-à-dire pur) dans la syntaxe correcte, comme si les abstractions n'avaient jamais été utilisées, à exécuter dans le navigateur et dans le navigateur seul.</p><p>C'est la chose qui m'a pris le plus de temps à comprendre, et qui, honnêtement, pourrait être un mémo manqué encore plus grand que toute l'histoire de npm. JavaScript n'a plus besoin d'un navigateur pour fonctionner. Ainsi, vous me verrez parfois faire référence à Node JavaScript lorsque je ferai la distinction entre ce dernier et le JavaScript "basé sur un navigateur".</p><h3>Langages côté serveur ou côté client</h3><p>À ce stade, je pense qu'il est utile de prendre un moment pour explorer la distinction entre les langages côté client (HTML, CSS, JavaScript) et les langages côté serveur (essentiellement tous les autres). Je ne suppose pas que vous ayez une quelconque expérience des langages côté serveur, comme PHP, Ruby ou Python, mais si le concept des langages côté serveur est entièrement nouveau pour vous, il peut être utile de <a href="https://developer.mozilla.org/fr/docs/Learn/Server-side/First_steps/Introduction">lire ce qu'ils sont</a> (NdT: dans MDN en français). (Pour résumer : ce sont des langages de code qui s'exécutent purement sur un serveur au lieu du navigateur, et qui ont généralement des capacités beaucoup plus larges et plus puissantes).</p><p>Ceci est pertinent parce qu'il y a plusieurs années, vers 2009, il y avait des gens très intelligents qui aimaient vraiment JavaScript. En particulier, ils aimaient la <em>rapidité</em> de JavaScript (surtout par rapport aux langages côté serveur dominants à l'époque, notamment PHP et Ruby), et ils voulaient que JavaScript soit présent <em>partout</em>, pas seulement dans un navigateur.</p><p><a href="https://en.wikipedia.org/wiki/Ryan_Dahl">Ryan Dahl</a> est la figure la plus marquante parmi eux, et on lui attribue l'invention de Node (et plus récemment, <a href="https://deno.land/">Deno</a>, qui est une anagramme de Node). C'est une chose amusante à savoir, mais autrement pas strictement pertinente à ce sujet.</p><h3>Comment fonctionne Node</h3><p>Ce qui est pertinent, cependant, c'est que <strong>Node est essentiellement JavaScript en tant que langage côté serveur qui fonctionne <em>en dehors</em> du navigateur</strong>.</p><p>Comment est-ce possible ? Sous le capot, chaque navigateur possède son propre moteur JavaScript individuel. Il s'agit de la partie du navigateur qui exécute réellement JavaScript. Oui, il s'agit apparemment d'une partie distincte du navigateur, qui ne fait pas partie des mêmes éléments que le HTML et le CSS, ce qui est logique si l'on considère que nous avons des API littérales entre le document et JavaScript. D'ailleurs, même <a href="https://la-cascade.io/articles/le-dom-cest-quoi-exactement">le concept de DOM</a> est plus logique si l'on considère que le département qui gère JavaScript est un bureau improvisé au bout du couloir du département HTML.</p><p>Le moteur JavaScript des navigateurs basés sur Chromium s'appelle V8, vraisemblablement d'après un type spécifique de moteur de voiture (et non la "boisson végétale" faite principalement de jus de tomate). V8 est de loin le moteur JavaScript le plus populaire. Grâce aux efforts de normalisation de l'<a href="https://en.wikipedia.org/wiki/ECMAScript">ECMAScript</a> au cours des 15 dernières années environ, il n'y a plus vraiment de différences majeures entre les moteurs JavaScript en ce qui concerne les navigateurs. Le moteur utilisé dans Chrome ressemble beaucoup à celui de Firefox, qui ressemble beaucoup à Safari, et ainsi de suite. La popularité de V8 de nos jours a moins à voir avec ses distinctions, et plus à voir avec l'omniprésence auto-entretenue de Chrome.</p><p>(Note annexe : le moteur JavaScript de Firefox s'appelle SpiderMonkey. Ce n'est pas particulièrement pertinent, mais c'est une preuve supplémentaire que Firefox est le plus cool).</p><p>Pourquoi cela est-il important ? Eh bien, il s'avère que vous pouvez retirer le moteur JavaScript d'un navigateur et, avec quelques modifications, le faire fonctionner seul - un peu comme si vous décidiez de retirer la stéréo d'une voiture, de la bricoler un peu et d'en faire une chaîne stéréo pour votre maison. V8 (et, vraisemblablement, la stéréo d'une voiture) peut parfaitement fonctionner en tant qu'unité autonome dans n'importe quel environnement.</p><p>En d'autres termes : V8 permet d'exécuter JavaScript n'importe où. C'est pourquoi nous avons le JavaScript "Node" et le JavaScript "basé sur le navigateur".</p><h3>Node est presque (mais pas exactement) JavaScript</h3><p>Pour récapituler : JavaScript est maintenant un langage côté serveur ! Il s'appelle Node, et cela pourrait signifier que vous n'avez même pas besoin d'apprendre quoi que ce soit sur les autres langages côté serveur. Nous sommes des développeurs frontaux, et nous avons des super-pouvoirs maintenant.</p><p>Cela dit, <strong>Node et le JavaScript que vous avez l'habitude d'exécuter dans le navigateur sont à la fois similaires et très différents l'un de l'autre</strong>.</p><p>Au risque de nous perdre dans les méandres de l'histoire : bien que tous deux soient JavaScript à la base, et que le langage et la syntaxe soient les mêmes, de nombreux éléments de base de JavaScript dans le navigateur (comme la fenêtre ou le document, et même l'<code>alerte</code>) ne sont pas présents dans un environnement Node purement côté serveur. Il n'y a pas de <code>window</code>, bien sûr, lorsque le langage s'exécute tout seul, et non dans un navigateur. Les nouveaux développeurs JavaScript Node sont souvent surpris d'apprendre que même <code>fetch</code> est en fait une API de navigateur, et non du JavaScript "pur".</p><p>N'ayez crainte, cependant. console.log est toujours votre meilleur ami, et il y a beaucoup de nouvelles caractéristiques spécifiques à l'environnement de Node JavaScript qui diffèrent de la mise en œuvre de JavaScript par le navigateur, comme l'objet processus, qui contient tous les détails sur les processus en cours d'exécution.</p><p>Au fil des ans, Node et son écosystème ont souvent, par nécessité, évolué dans une direction très différente de celle du JavaScript basé sur le navigateur. (Un exemple évident : la syntaxe des importations entre les deux a été différente pendant des années, et ne commence que maintenant à fusionner à nouveau. Nous en parlerons un peu plus dans <a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">le dernier chapitre</a>).</p><p>Node a longtemps eu le privilège de pouvoir évoluer beaucoup plus rapidement que les navigateurs lorsqu'il s'agit d'acquérir de nouvelles fonctionnalités, et a également dû faire face à ses propres problèmes. Il a commencé à alimenter les applications côté serveur de la même manière que Ruby et PHP l'ont fait pendant des années, même si les navigateurs essayaient encore de se mettre d'accord sur les normes. Par conséquent, Node JavaScript et JavaScript basé sur le navigateur ressemblent plus à des cousins qu'à des clones.</p><p>Voici ce que je pense être une analogie juste pour expliquer les différences entre les deux cousins JavaScript : considérez deux instruments de musique similaires, disons une basse droite et une guitare basse électrique moderne. Les deux instruments sont accordés de la même manière et <em>jouent</em> les mêmes notes ; si vous connaissez l'un, à bien des égards, vous connaissez en quelque sorte l'autre. Mais si vous trouverez qu'il est beaucoup plus facile d'apprendre l'un après avoir appris l'autre, jouer du nouvel instrument sera très différent de ce à quoi vous êtes habitué.</p><figure role="group"><img src="https://la-cascade.io/images/basses.webp" alt="un violoncelle à côté d'une basse électrique" /><figcaption>La même chose, mais différent (Photos: <a href="https://commons.wikimedia.org/wiki/Main_Page">Wikimedia Commons</a>, <a href="https://unsplash.com/">Unplash</a>).</figcaption></figure><p>De même, alors qu'un développeur peut écrire un type de JavaScript et qu'un second développeur écrit dans un autre type de JavaScript, il est peu probable que leurs tâches se ressemblent.</p><p>Node est JavaScript, avec les capacités des autres langages côté serveur mentionnés précédemment - des choses comme la lecture et l'écriture du système de fichiers, l'accès aux API de niveau système, la messagerie, la capacité d'écouter et de répondre aux demandes, les tâches planifiées... la liste est longue.</p><p>Je n'en dirai pas plus ici, mais sachez simplement que si les deux sont des JavaScript en fin de compte, ils fonctionnent dans des environnements différents et sont chacun capable de faire certaines choses que l'autre ne peut pas faire. Même si vous avez déjà écrit du JavaScript par navigateur, Node vous semblera probablement un peu étranger au-delà de la syntaxe de base, et sera souvent utilisé de manière très différente.</p><h3>Exécuter Node localement</h3><p>Comme c'est généralement le cas avec les langages côté serveur, vous devez installer Node avant de pouvoir l'utiliser.</p><p>Node est généralement installé aux côtés de npm, ensemble, puisque la partie gestionnaire de paquets a besoin de Node, et que la partie Node est plus utile avec un gestionnaire de paquets. (On pourrait dire qu'ils sont un ensemble de paquets. Non, je ne m'excuserai pas pour cette blague. Je suis un père, après tout).</p><p>Je tiens à souligner à ce stade que <strong>vous n'avez pas besoin de connaître quoi que ce soit à propos de Node pour utiliser npm</strong>. Donc, même si je suis sur le point de couvrir quelques exemples de Node ici, veuillez considérer toute cette section comme quelque chose d'agréable à savoir, mais non essentiel à cette fin. Je pense qu'il est toujours utile d'avoir une idée un peu plus précise de la façon dont Node fonctionne, juste dans le but de brosser un tableau plus complet.</p><blockquote>
<p><em>Nous couvrirons l'<a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">installation de Node et de npm</a> dans un prochain chapitre de ce guide. Donc, si vous ne les avez pas encore installés, vous pouvez soit jeter un coup d'œil sur cette partie, soit revenir ici lorsque vous les aurez prêts. Dans tous les cas, cela ne sera pas crucial pour suivre ce guide npm.</em></p>
</blockquote><p>Si vous souhaitez l'essayer, vous pouvez créer un nouveau fichier test.js et y placer du JavaScript générique. Quelque chose d'artificiel comme le code suivant qui enregistre un certain contenu dans la console devrait faire l'affaire :</p><pre class="language-js">console.log('Regarde, ma, des mains Node!')
const oneThroughFive = [1, 2, 3, 4, 5]
oneThroughFive.forEach((nombre) =&gt; {
  console.log(nombre)
})</pre><p>Disons que vous enregistrez ce code, puis ouvrez la ligne de commande dans une fenêtre de terminal, naviguez jusqu'à l'endroit où se trouve le fichier (en utilisant <code>cd</code>, qui signifie "changer de répertoire"), et exécutez node test.js pour obtenir la sortie suivante :</p><pre class="language-bash">Look, ma, Node hands!
1
2
3
4
5</pre><p>Vous pouvez également entrer node tout seul (sans nom de fichier ensuite) pour ouvrir un terminal interactif où vous pouvez exécuter du JavaScript Node arbitraire. Si vous avez déjà ouvert la console dans les DevTools de votre navigateur pour taper du code, c'est <em>exactement</em> la même chose, mais en ligne de commande avec Node à la place.</p><p>Essayez-le si vous le souhaitez, en supposant que vous avez installé Node. Mais encore une fois, tout ceci n'est qu'une illustration et n'est pas nécessaire pour utiliser npm.</p><figure><img src="https://la-cascade.io/images/node.webp" alt="commandes JavaScript dans la console" /></figure><h3>La suite</h3><p>Tout ce que nous avons couvert dans ce chapitre est ingénieux et permet, nous l'espérons, de vous montrer (aussi simplement que cela puisse paraître) la façon dont Node fonctionne. Rappelez-vous, bien que nous n'ayons pas couvert d'exemple spécifique, Node est capable de faire tout ce qu'un langage côté serveur peut faire. Il n'est, je l'espère, pas trop difficile d'imaginer comment l'exécution de JavaScript pour faire pratiquement tout ce à quoi vous pouvez penser au niveau du système ou même sur un serveur distant est très attrayant et avantageux.</p><p>Le concept de Node a commencé comme un moyen d'exécuter JavaScript en dehors du navigateur. En tant que tel, nous avons des paquets de scripts basés sur Node qui sont utilisés pour nous aider avec le développement front-end. Alors comment installer ces paquets et s'assurer qu'ils ne sont pas seulement mis à jour mais qu'ils peuvent être désinstallés ? Cette question est contenue dans les deux dernières lettres de l'abréviation npm : <em>gestionnaire de paquets</em> (package manager).</p><p>En d'autres termes, npm est un outil qui gère les paquets écrits en JavaScript Node. Qu'est-ce qu'un gestionnaire de paquets exactement et comment npm peut-il être considéré comme tel ? C'est ce que nous allons voir dans notre guide npm.</p><div class="button-container button-block"><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-2-cli">← Chapitre 3</a></p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Chapitre 5 →</a></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-3-node</link>
      <guid>https://la-cascade.io/articles/npm-guide-3-node</guid>
      <pubDate>Fri, 28 Jan 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM et ligne de commande]]></title>
      <description><![CDATA[<p><em>Passons un peu de temps à nous familiariser avec la ligne de commande. Même si la ligne de commande n'est pas spécifique à npm, elle est essentielle pour travailler avec npm.</em></p><div class="articleContent"><p>Maintenant que nous savons <a href="https://la-cascade.io/articles/npm-guide-1-npm">ce que signifie npm</a> et que nous avons une idée très générale de ce qu'il fait et de sa place dans le développement Web, nous devons passer un peu de temps à examiner la ligne de commande, car c'est ainsi que nous interagissons avec npm.</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a> ← <strong><em>vous êtes ici</em></strong></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><h3>Un aperçu de l'interface en ligne de commande</h3><p>L'<a href="https://fr.wikipedia.org/wiki/Interface_en_ligne_de_commande">interface en ligne de commande</a> (CLI) est un endroit où nous pouvons taper des <em>commandes</em>, qui seront exécutées directement par notre ordinateur. Elle est extrêmement rapide et permet des autorisations d'administration plus importantes que la plupart des applications qui tentent de gérer la ligne de commande pour vous. Vous avez besoin d'installer quelque chose sur votre système, ou de le mettre à jour ? elle peut le faire, sans oublier de les désinstaller également. Même les langages côté serveur peuvent s'exécuter sur la ligne de commande, ce qui ouvre un large éventail d'outils et de techniques de développement.</p><p>C'est pour ces raisons que l'interface en ligne de commande est considérée comme un outil indispensable pour de nombreux développeurs. Même si vous n'êtes pas un développeur, il y a de fortes chances que vous ayez rencontré la ligne de commande à un moment ou à un autre. Vous y avez peut-être accédé en ouvrant l'application Terminal sous MacOS. Vous en avez peut-être utilisé une directement intégrée à votre éditeur de code — <a href="https://code.visualstudio.com/">VS Code</a> et de nombreux autres éditeurs de code sont dotés d'un terminal intégré. Vous avez peut-être même rencontré des applications de terminal tierces comme <a href="https://iterm2.com/">iTerm</a> ou <a href="https://hyper.is/">Hyper</a>.</p><figure><img src="https://la-cascade.io/images/terminal.webp" alt="images de divers terminaux" /></figure><p>Si vous avez utilisé le terminal, il est possible qu'une grande partie de votre utilisation de la ligne de commande ait consisté à taper (ou coller) des commandes que quelqu'un d'autre vous a données. C'est très bien ; c'est souvent de cette façon que nous parvenons à faire les choses.</p><p>Mais prenons un moment pour comprendre ce qu'<em>est</em> exactement la ligne de commande, et pourquoi elle est si largement utilisée.</p><h3>Ligne de commande et terminal</h3><p>La "ligne de commande" et le "terminal" sont techniquement deux choses différentes et distinctes, mais sont souvent utilisés de manière interchangeable. Vous pouvez également entendre la ligne de commande appelée "shell" ou la voir abrégée en "CLI", abréviation de "command line interface".</p><p>Distinctions pédantes mises à part, ces termes sont souvent utilisés pour signifier à peu près la même chose. Aussi, pour simplifier au maximum les choses, je les utiliserai indifféremment à partir de maintenant.</p><h3>Ouverture de la ligne de commande</h3><p>Quel que soit le nom que vous lui donnez, vous connaissez probablement la ligne de commande comme cette fenêtre à l'aspect intimidant, où vous tapez des commandes que votre ordinateur semble comprendre, même si vous ne le faites pas.</p><figure role="group"><img src="https://la-cascade.io/images/open-cli.webp" alt="" /><figcaption>Par défaut, une fenêtre de terminal devrait ressemble à ceci, mais les apparences peuvent varier.</figcaption></figure><p>Selon l'endroit et la manière dont vous travaillez sur la ligne de commande, l'une des premières choses que vous pouvez remarquer est un signe dollar discret, <code>$</code>, qui s'affiche sur la première ligne où vous pouvez commencer à taper. Vous l'avez peut-être même vu dans d'autres articles ou documentations.</p><figure><img src="https://la-cascade.io/images/command.webp" alt="n'entrez pas le caractère $" /></figure><p>C'est une convention courante que de préfixer les commandes par le caractère $ — mais c'est une convention qui prête à confusion, parce qu'en fait il n'y a pas besoin de taper ce caractère. Il ne fait littéralement <em>pas</em> partie de la commande. Le caractère <code>$</code> signifie simplement que la commande doit être exécutée dans un terminal.</p><p>Voici donc la première règle à connaître pour travailler avec la ligne de commande : si vous vous retrouvez à taper ou à copier une instruction qui inclut le caractère <code>$</code>, sachez qu'il n'est pas nécessaire de l'inclure dans votre travail ; le terminal s'en charge.</p><pre class="language-bash">Pas besoin de copier le caractère $
$ npm run build</pre><p>Vous verrez peut-être quelque chose d'autre commencer une ligne à la place de $, comme &gt;, _ , ou même une flèche. Encore une fois, quoi que ce soit, il est presque certain que ce n'est pas destiné à être tapé ou collé directement dans la ligne de commande. La question de savoir si la documentation ou d'autres didacticiels doivent ou non inclure le caractère de début de ligne est une toute autre conversation (<a href="https://css-tricks.com/to-or-not-to-displaying-terminal-code-snippets/">dont Chris a longuement discuté</a>). Quoi qu'il en soit, cela peut prêter à confusion, c'est pourquoi je veux m'assurer que cela est mentionné.</p><h3>Que fait la ligne de commande ?</h3><p>La ligne de commande n'est pas exactement faite pour écrire du code. Comme le nom "ligne de commande" l'indique, elle sert à écrire des commandes. Je suppose que l'on pourrait dire que <em>tout</em> le codage est constitué de commandes dans une certaine mesure, donc il est vrai que la séparation est un peu floue. Mais de manière générale, le code dans un terminal est écrit différemment de ce qu'il est dans un éditeur de code. On utilise le terminal pour diriger notre ordinateur avec des commandes que nous voulons qu'il exécute <em>immédiatement</em>.</p><h3>Les avantages de la ligne de commande</h3><p>Pour commencer, vous vous demandez peut-être pourquoi les développeurs aiment travailler avec la ligne de commande. Vous préférez peut-être une belle application, ou une interface utilisateur graphique (GUI en abrégé, parfois prononcé "gooey") où vous pouvez voir toutes vos options et trouver la meilleure visuellement. C'est tout à fait normal, et nous parlerons un peu des GUI dans ce chapitre et en fournirons des exemples.</p><p>De nombreux développeurs pensent ainsi, mais travailler en ligne de commande apporte certains avantages qui ne sont pas toujours faciles à reproduire dans une application visuelle.</p><h4>Elle vous accorde des privilèges système dignes d'un dieu</h4><p>La ligne de commande est ce que les informaticiens appellent un "environnement privilégié". Cela peut sembler faire référence à une maison de fraternité de Yale, mais cela signifie simplement qu'il s'agit d'un endroit où il y a très peu de restrictions sur ce que vous êtes autorisé à faire ; un endroit sans garde-fous.</p><p>C'est de là que vient la réputation déconcertante de la ligne de commande : quelle que soit la commande que vous tapez, pour autant qu'elle soit valide, elle est exécutée immédiatement et, souvent, de manière irréversible. Elle est capable d'interagir avec les fichiers cachés que votre système d'exploitation tente de vous empêcher de modifier. Vous avez le pouvoir d'accéder à tout ce qui se trouve dans le système. Vous avez même le pouvoir d'interagir avec des fichiers centraux similaires sur un serveur distant — et nous connaissons tous l'adage selon lequel une grande responsabilité accompagne ce genre de pouvoir.</p><p>Il peut être utile de considérer la ligne de commande comme un gardien de sécurité paresseux. Elle suppose que vous savez <em>toujours</em> ce que vous faites et vous laisse passer l'entrée. Cela la rend un peu risquée, oui, mais cela la rend aussi très puissante, et le choix parfait pour certaines tâches et projets.</p><h4>Elle est super rapide</h4><p>Un autre avantage de la ligne de commande par rapport aux applications classiques est qu'elle est rapide.</p><p>Ce n'est pas toujours le cas ; la vitesse de la ligne de commande a tendance à être surestimée et dépend largement de la tâche en question. Mais lorsqu'elle est rapide, elle peut souvent être <em>plusieurs fois</em> plus rapide. De plus, l'endroit où la ligne de commande brille vraiment a tendance à être exactement l'endroit où les projets de code ont le plus besoin de vitesse, à savoir le téléchargement et la création de fichiers.</p><p>Comme nous le verrons dans d'autres chapitres de ce guide, une partie essentielle de ce que fait npm consiste à installer des choses sur votre machine (généralement dans un dossier désigné pour le projet sur lequel vous travaillez). C'est ce qui rend la ligne de commande idéale pour travailler avec un gestionnaire de paquets (nous verrons ce que cela signifie également) comme npm — elle télécharge et transmet les fichiers entre les ordinateurs — généralement beaucoup, <em>beaucoup</em> plus rapidement que, disons, en utilisant un navigateur pour le faire.</p><p>La ligne de commande permet à npm de générer des tonnes de fichiers à une vitesse incroyable. La possibilité d'exécuter une seule commande qui installe, met à jour ou supprime ces fichiers d'un seul coup et à grande vitesse fait du terminal l'outil le plus rapide et le plus efficace pour de nombreuses tâches.</p><h4>Elle fait ce que les autres langages ne peuvent pas faire</h4><p>Une autre raison pour laquelle le travail dans le terminal est si avantageux est que c'est l'endroit où de nombreux outils que vous pourriez vouloir utiliser dans votre projet sont déjà disponibles pour vous sans aucune configuration supplémentaire.</p><p>Mais revenons un peu en arrière.</p><p>Lorsque vous entendez l'expression "langage côté serveur", vous pensez peut-être à PHP, Ruby ou Java. Peut-être même à des langages plus récents comme Rust ou Go. Vous savez peut-être déjà que Node fait partie de cette liste, mais si ce n'est pas le cas, pardonnez-moi de prendre un peu d'avance.</p><p>Quoi qu'il en soit, lorsque la plupart des gens pensent à des langages côté serveur comme ceux-ci, ils ont tendance à penser à un serveur Web qui attend des requêtes et y répond. WordPress, par exemple, reste inactif jusqu'à ce qu'il reçoive une requête qui déclenche PHP. Lorsque vous envoyez un nouveau tweet, il s'agit d'une requête sur les serveurs de Twitter qui finit par atteindre une méthode Ruby dans Rails.</p><p>Les langages côté serveur sont à juste titre considérés comme plus puissants, pour ainsi dire, que les langages Web. HTML, CSS et JavaScript sont merveilleux, mais ils ne peuvent pas travailler avec un système de fichiers, envoyer des e-mails, traiter des images, émettre des commandes système, interagir avec le système d'exploitation ou exécuter des tâches planifiées, parmi tant d'autres choses qu'une application ou un site Web peut avoir à faire. Par défaut, le JavaScript du navigateur ne peut même pas s'exécuter si quelqu'un ne regarde pas activement la page Web dans son navigateur.</p><p>Il est normal de penser que les langages côté serveur sont le puissant moteur derrière des applications et des logiciels plus robustes. Et, dans de nombreux cas, c'est exact. Mais prenons un moment pour reconnaître que, dans le but d'exécuter du code, votre machine est un serveur. Pas un serveur web bien sûr (il <em>pourrait</em> en être un, mais ce serait bizarre et probablement peu judicieux). Mais un serveur, néanmoins.</p><figure role="group"><img src="https://la-cascade.io/images/server.webp" alt="un ordinateur portable avec un message écrit à la main : ceci est un serveur, ne le fermez pas !" /><figcaption>Vous ne voyez sans doute pas votre machine comme un serveur, mais elle peut exécuter des langages côté serveur...</figcaption></figure><p>Vous pouvez installer et exécuter n'importe lequel des langages côté serveur que nous avons mentionnés, et peut-être l'avez-vous déjà fait à un moment donné (ou du moins essayé). Vous avez peut-être installé PHP pour pouvoir exécuter WordPress (bien que de nos jours, il existe <a href="https://css-tricks.com/using-local-with-flywheel/">des moyens bien plus agréables de le faire</a>), ou vous avez peut-être installé Ruby pour pouvoir suivre des tutoriels sur Rails, à titre d'exemple.</p><p>Ou, peut-être pas. Vous n'avez peut-être jamais installé un langage de programmation complet. Quoi qu'il en soit, sachez simplement que ces langages s'exécutent sur un serveur plutôt que sur un navigateur Web - et à cet effet, <em>votre machine est un serveur</em>.</p><p>En outre, la plupart des outils que vous souhaitez utiliser dans votre flux de travail de développement, comme Sass pour compiler les CSS, fonctionnent en fait sur des langages côté serveur. L'utilisation de la ligne de commande vous place donc à l'endroit où tous les outils les plus puissants sont facilement disponibles.</p><h3>Utiliser une application au lieu de la ligne de commande</h3><p>Nous avons brièvement abordé les interfaces graphiques plus tôt dans cet article. Il est intéressant de noter que certaines tâches de la ligne de commande ont des interfaces graphiques correspondantes qui rendent le travail avec la ligne de commande plus visuel et programmatique.</p><p>Parmi les bons exemples, citons <a href="https://desktop.github.com/">GitHub Desktop</a> (pour la gestion des dépôts de code), <a href="https://codekitapp.com/">CodeKit</a> (pour le traitement, le regroupement et la compilation des ressources), et l'onglet Source Control de VS Code. Même si les interfaces graphiques de ce type sont généralement axées sur des tâches spécifiques, elles vous permettent d'effectuer des tâches par le biais d'une interface utilisateur visuelle agréable, dans une fenêtre d'application réelle qui se trouve en dehors de la fenêtre du terminal.</p><figure role="group"><img src="https://la-cascade.io/images/codekit.webp" alt="" /><figcaption>CodeKit peut exécuter une commande pour vérifier le formatage du code avec des outils comme ESLint, sans utiliser directement la ligne de commande.</figcaption></figure><p>Il est agréable d'avoir une interface graphique en option, et même si je me suis habitué à travailler en ligne de commande au fil des ans, j'aimerais qu'il y ait plus d'interfaces graphiques pour faire les choses que la ligne de commande rend possibles, à la fois pour mon propre confort et pour abaisser la barrière d'entrée pour les nouveaux développeurs.</p><p>Je pense néanmoions que la raison pour laquelle il n'y a pas plus d'applications de ce type est la vitesse. Il est beaucoup plus rapide et facile de créer une interface de ligne de commande (CLI) que de mettre au point une application à part entière. Donc, si nous voulons des choses agréables <em>aujourd'hui</em>, la ligne de commande est souvent l'endroit où nous devons aller pour les obtenir.</p><h3>La suite</h3><p>Nous venons de passer un peu de temps à nous familiariser avec la ligne de commande. Même si elle n'est pas <em>spécifique</em> à npm, elle est essentielle pour travailler avec npm. Il s'agit de l'interface à partir de laquelle nous indiquons au système ce qu'il doit faire, ce qui nous confère des pouvoirs incroyables au niveau du système ou du serveur pour accomplir des tâches en grande quantité à une vitesse fulgurante. En tant que gestionnaire de paquets, npm s'occupe d'installer, de mettre à jour et de supprimer des fichiers (entre autres choses) pour un projet Web. La ligne de commande est la façon dont nous communiquons avec npm pour faire tout cela.</p><p>Ensuite, nous allons décomposer un peu plus ce qu'est npm en nous concentrant sur la première lettre de l'abréviation : "n" pour Node. Qu'est-ce que c'est et pourquoi est-elle dans le nom ? C'est ce point que nous allons voir maintenant.</p><div class="button-container button-block"><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-1-npm">← Chapitre 2</a></p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-3-node">Chapitre 4 →</a></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-2-cli</link>
      <guid>https://la-cascade.io/articles/npm-guide-2-cli</guid>
      <pubDate>Thu, 27 Jan 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Qu'est-ce que npm ?]]></title>
      <description><![CDATA[<p><em>Ce que nous appelons 'npm' n'est pas vraiment une chose, mais un ensemble de choses qui fonctionnent ensemble pour nous faciliter le développement.</em></p><div class="articleContent"><p>L'une des raisons pour lesquelles cette nouvelle ère de développement front-end, riche en outils, est si difficile à comprendre au début, c'est que nous <em>appelons</em> souvent les choses par un nom unique, alors qu'elles sont composées de plusieurs éléments interconnectés. Il en va ainsi pour npm et l'écosystème qui l'entoure.</p><p>Pensons par exemple à la façon dont nous nous référons avec désinvolture à "l'Internet", même si le Web lui-même n'est pas une chose unique et unifiée, mais une collection de protocoles, de DNS, de serveurs, de navigateurs, de réseaux, de demandes et de réponses... et bien d'autres choses assemblées au cours d'années d'itérations. Le navigateur lui-même est une machine composée de nombreuses pièces.</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a> ← <strong><em>vous êtes ici</em></strong></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><h3>npm est un ensemble de technologies</h3><p>De même, ce que nous appelons généralement "npm" (oui, tout en minuscules) et "back-of-the-front-end" en particulier est un nom unique pour une collection de nombreuses technologies et systèmes individuels différents ! une sorte de <a href="https://en.wikipedia.org/wiki/Rube_Goldberg_machine">machine de Rube Goldberg</a> pour générer du code convivial pour le navigateur.</p><p>J'ai déjà mentionné la ligne de commande ! c'est une partie importante de l'écosystème car c'est la façon dont nous interagissons avec lui. Mais nous en reparlerons dans le prochain chapitre.</p><p>Et puis il y a npm, qui fait partie d'une catégorie connue sous le nom de logiciel de "gestion de paquets". Nous en parlerons également. En fait, vous me verrez probablement faire référence à npm en tant que gestionnaire de paquets tout au long de ce guide.</p><p>Et enfin, il y a <a href="https://nodejs.org/en/">Node</a> lui-même, qui est si difficile à expliquer succinctement que je le décris souvent en paraphrasant Douglas Adams : c'est un langage de programmation qui ressemble presque — mais pas tout à fait — à JavaScript.</p><h3>npm gère les outils de projet</h3><p>Pour brouiller encore un peu les pistes, de nombreux projets pour lesquels vous tapez <code>npm install</code> dans la ligne de commande peuvent être livrés avec des outils préinstallés pour vous aider à faire une grande variété de choses dans votre projet, comme retraiter votre code (par exemple, transformer le code Sass en CSS). Il existe de nombreux projets tout-en-un, préconfigurés, qui n'attendent que votre installation et votre démarrage (<a href="https://create-react-app.dev/">Create React App</a>, <a href="https://nextjs.org/">Next</a>, <a href="https://nuxtjs.org/fr/">Nuxt</a> et <a href="https://kit.svelte.dev/">SvelteKit</a>, pour n'en citer que quelques-uns). C'est pratique quand c'est bien fait, bien sûr, mais cela a aussi ajouté de la complexité — ce qui signifie ajouter encore d'autres noms à notre liste de choses de l'<em>arrière du front</em>.</p><p>Cette liste comprend souvent des outils tels que <a href="https://babeljs.io/">Babel</a> (pour la compilation de JavaScript), <a href="https://sass-lang.com/">Sass</a> (pour la compilation de CSS), <a href="https://webpack.js.org/">webpack</a> (pour le regroupement des ressources), <a href="https://vitejs.dev/">Vite</a> (pour les serveurs de développement et autres outils), <a href="https://postcss.org/">PostCSS</a> (pour transformer une syntaxe en une autre) ! <a href="https://autoprefixer.github.io/">Autoprefixer</a> (qui peut être un plugin PostCSS pour les préfixes des fournisseurs de CSS) ! <a href="https://www.typescriptlang.org/">TypeScript</a> (pour une syntaxe JavaScript supplémentaire) ! <a href="https://eslint.org/">ESlint</a> (pour vérifier la qualité du code) ! <a href="https://prettier.io/">Prettier</a> (pour le formatage du code), et des bibliothèques de test comme <a href="https://jestjs.io/">Jest</a> ou <a href="https://www.cypress.io/">Cypress</a>.</p><figure role="group"><img src="https://la-cascade.io/images/library-building.webp" alt="" /><figcaption>npm ressemble à une bibliothèque, avec des étages de livres bien organisés pour les retrouver et les gérer. (Photo: <a href="https://unsplash.com/@leonardo_64?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Johannes Mändle</a> on <a href="https://unsplash.com/">Unsplash)</a></figcaption></figure><p>Toutes ces choses (et bien d'autres) entrent dans cette vaste catégorie générale d'outils qui sont souvent fournis <em>avec</em> les projets installés par npm — ou qui peuvent être installés et utilisés via npm — mais qui ne font pas réellement partie de npm lui-même. Ce ne sont que des exemples d'outils modernes qui nous aident à faire de belles choses avec notre code, et je les mentionne ici uniquement parce que cela vaut la peine de noter la distinction, pour avoir une idée de l'endroit où se trouvent les limites dans ce vaste et nouveau monde.</p><p>Et d'ailleurs, si vous ne savez pas ce que sont la plupart (ou <em>aucun</em>) des outils mentionnés ci-dessus, ce n'est pas grave. Peut-être ne les avez-vous pas encore rencontrés, ou peut-être avez-vous travaillé, sans en connaître le nom, sur un projet où ils étaient installés. Quoi qu'il en soit, tout ceci n'est qu'un contexte supplémentaire.</p><h3>Faisons une pause ici</h3><p>Si vous vous sentez déjà un peu dépassé à ce stade, ne vous inquiétez pas. Ce que je veux que vous reteniez de la lecture de ce chapitre d'intro, c'est que ce que nous appelons "npm" (ou peut-être plus simplement "tous ces trucs en ligne de commande et en arrière-plan") n'est pas vraiment une chose, mais <em>un ensemble de choses qui fonctionnent ensemble pour nous faciliter le développement</em>.</p><p>Ah, et oui : toute cette complexité peut sembler intimidante au départ, mais elle améliore <em>réellement</em> les choses. Je vous le promets.</p><p>Alors que le front-end <em>semble</em> évoluer très rapidement, non, <strong>vous n'avez pas été laissé derrière</strong>. Vous avez peut-être juste un peu de formation continue à rattraper.</p><div class="button-container button-block"><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">← Chapitre 1</a></p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-2-cli">Chapitre 3 →</a></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-1-npm</link>
      <guid>https://la-cascade.io/articles/npm-guide-1-npm</guid>
      <pubDate>Wed, 26 Jan 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[NPM, un guide complet pour le débutant]]></title>
      <description><![CDATA[<p><em>Commençons par une introduction générale à la série d'articles sur npm et son écosystème...</em></p><div class="articleContent"><p>Je me souviens parfaitement du moment, au début de ma carrière de développeur, où j'ai commencé à percevoir que les choses s'éloignaient de ce que je connaissais, pour se diriger vers un ensemble plus complexe d'outils et de pratiques, ancrés dans la ligne de commande et quelque chose appelé <a href="https://www.npmjs.com/">npm</a>.</p><p>Voici la première partie d'un <strong>guide du débutant</strong> où nous couvrons le vaste sujet de <strong>Node Package Manager</strong>, ou npm. Nous prenons souvent pour acquis ces trois petites lettres — npm — lorsque nous les tapons dans la ligne de commande, mais npm fait partie d'un écosystème beaucoup plus vaste qui pourrait sembler intimidant ou déroutant pour quiconque s'y lance pour la première fois. Ce guide contribuera à démystifier cet écosystème et vous aidera non seulement à comprendre ce qu'est npm et ce qu'il fait, mais aussi à vous sentir à l'aise pour travailler avec lui.</p><div class="toc"><ul><li><a href="https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant">À qui s'adresse ce guide ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-1-npm">Que signifie le mot "npm" ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-2-cli">Qu'est-ce que la ligne de commande ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-3-node">Qu'est-ce que Node ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-4-gestionnaire-de-paquets">Qu'est-ce qu'un gestionnaire de paquets ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-5-installer-npm">Comment installer npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-6-package-installer-paquets">Comment installer les paquets npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-7-commandes">Que sont les commandes npm ?</a></li>
<li><a href="https://la-cascade.io/articles/npm-guide-8-installer-projet">Comment installer un projet npm existant ?</a></li>
</ul></div><p>Le développement moderne "<a href="https://css-tricks.com/front-of-the-front-back-of-the-front/">back-of-the-front-end</a>" — dont npm fait partie — semble complexe car il s'appuie sur de nombreux outils interconnectés. Si vous ajoutez à cela le fait que le monde du front-end <em>semble</em> évoluer beaucoup plus vite qu'il ne le fait en réalité, on a l'impression qu'on sera bientôt largué si l'on ne saute pas tout de suite sur la dernière nouveauté.</p><p>C'est pourquoi nous avons créé ce guide — pour rendre la technologie plus accessible et vous permettre de l'utiliser dans votre propre travail.</p><h3>À qui s'adresse ce guide ?</h3><p>Dans mon propre parcours d'apprentissage du dev, je lisais des guides sur des technologies qui me passionnaient, puis j'arrivais à une partie qui disait "il suffit d'installer npm" ceci ou cela, et je poussais un soupir et j'abandonnais l'idée d'utiliser cet outil qui avait l'air si cool. Ou, lors de journées plus aventureuses, je copiais la commande, mais je me retrouvais inévitablement à une autre étape que je n'avais pas comprise ("il suffit", disaient-ils toujours, "de faire [une chose dont je n'avais aucune idée]"), ou je recevais un message d'erreur que le guide n'expliquait pas et qui m'arrêtait net.</p><p><strong>Peu importe ce qu'était npm, ce que faisaient ces commandes et où vous étiez censé les taper, personne n'avait jamais pris le temps de me l'expliquer</strong>. Et plus je lisais des guides écrits par des personnes qui considéraient ces connaissances comme acquises, plus je me sentais isolé.</p><p><strong><em>Si tout cela vous semble familier : cette série est pour vous</em></strong>.</p><p>Vous faites très probablement partie du groupe que l'on a décrit ces dernières années comme le "<a href="https://bradfrost.com/blog/post/front-of-the-front-end-and-back-of-the-front-end-web-development/">front du front-end</a>". Comme moi, vous connaissez probablement bien votre affaire en matière de HTML et de CSS. Vous connaissez peut-être aussi un peu de JavaScript, soit le JavaScript "classique", soit jQuery. L'un ou l'autre est parfait, à la fois pour les besoins de cet article et en général.</p><p>Vous avez peut-être même essayé un framework comme React ou Vue, mais vous vous êtes surtout contenté de copier et coller des éléments pour lancer votre projet, sans savoir exactement ce qu'ils faisaient.</p><p><strong>Ce billet est pour vous</strong> si vous sentez <a href="https://css-tricks.com/the-great-divide/">le grand fossé</a> entre les définitions plus traditionnelles et "modernes" du développement front — et si vous craignez de nuire à votre carrière si vous ne comblez pas ce gouffre.<strong>Ce billet est pour vous</strong> si vous n'êtes pas vraiment sûr de savoir à quoi rime toute cette agitation autour des terminaux et des lignes de commande, et que vous préféreriez de loin ne jamais en toucher un du tout.<strong>Ce billet est pour vous</strong> si vous vous demandez pourquoi les autres développeurs semblent aimer <em>rendre les choses si compliquées</em>, et quel est l'intérêt de toutes ces lignes de commande, alors que vous pourriez simplement écrire du HTML, du CSS et du JavaScript à la place.<strong>Ce billet est pour vous</strong> si vous vous sentez exclu. Si vous avez l'impression qu'il y a une chose, <em>une chose vraiment importante</em>, que personne n'a jamais pris la peine de vous expliquer, et que vous avez peur d'être le seul à ne pas comprendre.Sachez ceci, ami développeur front : <strong>vous n'êtes pas seul</strong>. Vous êtes loin de l'être. Vous êtes exactement là où j'étais il n'y a pas si longtemps, et le souvenir troublant de cet endroit est encore frais dans mon esprit.</p><p>Laissez-moi essayer de répondre aux questions que vous vous posez probablement — les mêmes que j'avais — de la manière dont j'aurais aimé que quelqu'un le fasse pour moi, avant même que je sache comment les poser.</p><h3>Ce qui est couvert dans ce guide</h3><p>Ce guide est une série d'articles. Non que ce sujet soit difficile à comprendre, mais parce qu'il comporte de nombreuses parties, et que chacune mérite une explication à part entière. C'est un vaste territoire avec de nombreux trous de lapin à explorer. En nous concentrant sur une étape à la fois, nous pouvons consacrer du temps à rendre les choses claires et compréhensibles. L'objectif n'est pas de tout couvrir, mais je veux être plus complet que rapide.</p><p>Nous commencerons par parler de la situation actuelle, de ce qu'est npm, d'où il vient et comment nous en sommes arrivés là. À partir de là, nous couvrirons ce qu'est Node, puis ce que sont les gestionnaires de paquets en général, avant de travailler réellement avec npm. Nous terminerons par l'installation de Node et de npm, l'initialisation d'un projet pour avoir une idée de son fonctionnement, et enfin, l'installation d'un projet npm réel depuis GitHub avec tous ses paquets et commandes.</p><p>Une partie (ou la totalité) de tout cela peut sembler très intimidant pour le moment, mais ne vous inquiétez pas. C'est pourquoi nous consacrons ensemble la durée d'un guide entier.</p><h3>Ce qu'il faut savoir avant de commencer</h3><p>Je vais faire de mon mieux pour supposer le moins possible à votre sujet, au-delà du fait que vous êtes un développeur Web qui sait généralement comment construire un site Web avec HTML et CSS. Vous n'aurez pas besoin d'en savoir beaucoup sur JavaScript ou d'en écrire pour suivre ce guide, mais il sera certainement utile que vous ayez au moins une compréhension de base de ce qu'est JavaScript et de son fonctionnement.</p><p>JSON est le seul autre élément qu'il pourrait être utile de connaître avant de commencer. Si vous n'êtes pas familier avec JSON, il peut être utile de jeter un coup d'œil à <a href="https://www.w3schools.com/whatis/whatis_json.asp">ce guide sur JSON</a>, (NdT : et/ou à <a href="https://la-cascade.io/articles/json-pour-les-debutants">celui-ci en français</a>) ou du moins de le préparer pour le moment où nous arriverons à cette partie.</p><p>En outre, il se peut que je fasse référence à des outils, projets et frameworks spécifiques tels que <a href="https://getbootstrap.com/">Bootstrap</a>, <a href="https://reactjs.org/">React</a>, <a href="https://vuejs.org/">Vue</a> et <a href="https://kit.svelte.dev/">SvelteKit</a>, mais je ne supposerai pas que vous ayez une quelconque expérience pratique de ces outils, ni que vous ayez déjà utilisé npm ou la ligne de commande.</p><p>Prêt à commencer ? Commençons par clarifier ce que nous entendons par "npm", c'est-à-dire ce qu'il représente et comment il s'intègre au développement Web moderne.</p><p><a class="button-block_link" href="https://la-cascade.io/articles/npm-guide-1-npm">Chapitre 2 →</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant</link>
      <guid>https://la-cascade.io/articles/npm-guide-complet-pour-le-debutant</guid>
      <pubDate>Tue, 25 Jan 2022 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[flex-grow]]></title>
      <description><![CDATA[<p>La propriété <code>flex-grow</code> est une sous-propriété du module Flexible Box Layout.</p><p>Elle définit la capacité d'un élément flex à croître si nécessaire. Elle accepte une valeur sans unité qui sert de proportion. Elle dicte la quantité d'espace disponible à l'intérieur du conteneur flexible que l'élément doit occuper.</p><pre class="language-css">.element {
  flex-grow: 2;
}</pre><p>Par exemple, si tous les éléments ont la valeur <code>flex-grow</code> définie sur 1, chaque enfant aura une taille égale à l'intérieur du conteneur. Si vous donnez à l'un des enfants une valeur de 2, cet enfant occupera deux fois plus d'espace que les autres.</p><pre class="language-css">flex-grow: &lt;number&gt;;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/KittyGiraudel/pen/krMwzK/9a9ad8fb040f5efaf4e749b49cae7281">Flex-grow: demo</a>de Kitty Giraudel dans<a href="https://codepen.io">CodePen</a></div><p>Tous les éléments ont une valeur <code>flex-grow</code> de 1, sauf le 3e qui a une valeur <code>flex-grow</code> de 2. Cela signifie que lorsque l'espace disponible est distribué, le 3e élément flex aura deux fois plus d'espace que les autres.</p>]]></description>
      <link>https://la-cascade.io/articles/flex-grow</link>
      <guid>https://la-cascade.io/articles/flex-grow</guid>
      <pubDate>Tue, 24 Aug 2021 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Grid : la différence entre grilles explicite et implicite]]></title>
      <description><![CDATA[<p><em>Ne pas avoir à placer chaque élément manuellement rend Grid encore meilleur. Les grilles sont suffisamment flexibles pour s'adapter à leurs éléments.</em></p><div class="articleContent"><p><a href="https://www.w3.org/TR/css-grid-1/">Grid Layout</a> nous donne enfin la possibilité de définir des grilles en CSS et de placer des éléments dans des cellules de grille. En soi, c'est génial, mais le fait de <em>ne pas avoir à spécifier chaque <a href="https://www.w3.org/TR/css-grid-1/#grid-track-concept">piste</a> et de ne pas avoir à placer chaque élément manuellement</em> rend le nouveau module encore meilleur. Les grilles sont suffisamment flexibles pour s'adapter à leurs éléments.</p><p>Tout ceci est géré par <em>les grilles dites explicites et implicites</em>.</p><p>Note : Tous les exemples de code de cet article sont accompagnés d'images afin d'afficher les lignes et les pistes de la grille. Si vous voulez bricoler le code vous-même, je vous recommande d'utiliser Firefox pour déboguer les grilles.</p><h2>Grilles explicites</h2><p>Nous pouvons définir un nombre fixe de <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridline">lignes</a> et de <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gridtrack">pistes</a> qui forment une grille en utilisant les propriétés <code>grid-template-rows</code>, <code>grid-template-columns</code> et <code>grid-template-areas</code>. Cette grille définie manuellement s'appelle la <strong>grille explicite</strong>.</p><figure role="group"><img src="https://la-cascade.io/images/grid1.webp" alt="" /><figcaption>Une grille explicite comportant 4 pistes verticales (colonnes) et 2 pistes horizontales (rangées) (<a href="https://codepen.io/matuzo/pen/OjMGMY">Voir Codepen</a>).</figcaption></figure><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 100px 100px;
  grid-gap: 20px;
}</pre><h3>Répétition des pistes</h3><p>Lorsque nous définissons <code>grid-template-columns : 1fr 1fr 1fr 1fr</code> nous obtenons quatre pistes verticales, chacune ayant une largeur de <code>1fr</code>. Nous pouvons automatiser cela en utilisant la notation <code>repeat()</code> comme suit <code>grid-template-columns : repeat(4, 1fr)</code>. Le premier argument spécifie le nombre de répétitions, le second une liste de pistes, qui est répétée ce nombre de fois.</p><p><em>Une liste de pistes</em> ? Oui, vous pouvez effectivement répéter plusieurs pistes.</p><figure class="break-out">
</figure><h3>Répétition automatique des pistes</h3><figure role="group"><img src="https://la-cascade.io/images/grid6_.webp" alt="" /><figcaption>Une grille explicite avec 4 pistes verticales de 100px de large chacune, générée par la notation repeat. (<a href="https://codepen.io/matuzo/pen/VzeNpE">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><p>La notation <code>repeat</code> est très utile, mais elle peut être automatisée encore davantage. Au lieu de définir un nombre fixe de répétitions, nous pouvons utiliser les mots-clés <code>auto-fill</code> et <code>auto-fit</code>.</p><h3>Remplissage automatique des pistes</h3><p>Le mot-clé <code>auto-fill</code> crée autant de pistes que le conteneur de la grille peut en contenir sans que la grille ne déborde.</p><figure role="group"><img src="https://la-cascade.io/images/grid7_.webp" alt="" /><figcaption>Répétition d'autant de pistes verticales d'une largeur de 100px que possible dans le conteneur de la grille. (<a href="https://codepen.io/matuzo/pen/PKZgmr">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  grid-gap: 20px;
}</pre><p>Notez que <code>repeat(auto-fill, 1fr)</code> <del>ne créera qu'une seule piste car une seule piste avec une largeur de 1fr remplit déjà tout le conteneur de la grille, c'</del> est une déclaration invalide (<em>peut-être qu'elle a changé ? je ne sais pas</em>).</p><h3>Ajustement automatique des pistes</h3><p>Le mot-clé <code>auto-fit</code> se comporte de la même manière que <code>auto-fill</code>, sauf qu'après le placement des éléments de la grille, il ne créera qu'autant de pistes que nécessaire et toute piste vide répétée disparaît.</p><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, 100px);
  grid-gap: 20px;
}</pre><p>Dans l'exemple utilisé dans cette section, la grille aura le même aspect avec <code>repeat(auto-fit, 100px)</code> et <code>repeat(4, 100px)</code>. La différence est visible lorsqu'il y a plus de 4 éléments de grille.</p><p>S'il y a plus d'éléments, <code>auto-fit</code> crée plus de colonnes.</p><figure role="group"><img src="https://la-cascade.io/images/grid8.webp" alt="" /><figcaption>La notation repeat avec le mot-clé auto-fit crée autant de pistes que nécessaire pour tenir dans le conteneur de la grille. (<a href="https://codepen.io/matuzo/pen/RZrOXw">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><p>En revanche, si un nombre fixe de pistes verticales est utilisé dans la notation <code>repeat</code> et que le nombre d'éléments dépasse cette valeur, davantage de lignes sont ajoutées. Vous pouvez en savoir plus à ce sujet dans la section suivante : <a href="https://la-cascade.io/articles/css-grid-difference-entre-grilles-explicite-et-implicite#implicitgrids">les grilles implicites</a>.</p><figure role="group"><img src="https://la-cascade.io/images/grid9.webp" alt="" /><figcaption>S'il y a plus d'éléments que de pistes verticales, plus de rangées sont ajoutées. (<a href="https://codepen.io/matuzo/pen/ZJQZgr">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><p>J'ai utilisé <code>grid-template-columns</code> dans les exemples ci-dessus par commodité, mais toutes les règles s'appliquent également à <code>grid-template-rows</code>.</p><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
  grid-template-rows: repeat(auto-fill, 100px);
  grid-gap: 20px;
  height: 100%;
}
html,
body {
  hauteur: 100%;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid10.webp" alt="" /><figcaption>La notation de répétition avec le mot-clé auto-fill sur les deux axes. (<a href="https://codepen.io/matuzo/pen/prgVmW">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><h2 id="implicitgrids">Grilles implicites</h2><p>S'il y a plus d'éléments de grille que de cellules dans la grille ou lorsqu'un élément de grille est placé en dehors de la grille explicite, le conteneur de grille génère automatiquement des pistes de grille en ajoutant des lignes de grille à la grille. La grille explicite ainsi que ces pistes et lignes implicites supplémentaires forment ensemble ce qu'on appelle la grille implicite.</p><figure role="group"><img src="https://la-cascade.io/images/grid2.webp" alt="" /><figcaption>Deux éléments placés en dehors de la grille explicite entraînant la création de lignes et de pistes implicites. (<a href="https://codepen.io/matuzo/pen/vJLwNY">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><pre class="language-css">.item:first-child {
  grid-column-start: -1;
}
.item:nth-child(2) {
  grid-row-start: 4;
}</pre><p>Les largeurs et hauteurs des pistes implicites sont définies automatiquement. Elles sont juste assez grandes pour s'adapter aux <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#griditem">éléments de grille</a> (<em>items</em>) placés, mais il est possible de modifier ce comportement par défaut.</p><h3>Dimensionnement des pistes implicites</h3><p>Les propriétés <code>grid-auto-rows</code> et <code>grid-auto-columns</code> nous permettent de contrôler la taille des pistes implicites.</p><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: 100px 100px;
  grid-gap: 20px;
  grid-auto-columns: 200px;
  grid-autorows: 60px;
}</pre><p>Les pistes implicites auront désormais toujours une largeur de 200px et une hauteur de 60px, peu importe si l'élément de la grille s'adapte ou non.</p><figure role="group"><img src="https://la-cascade.io/images/grid3.webp" alt="" /><figcaption>Largeurs et hauteurs fixes pour les pistes implicites. (<a href="https://codepen.io/matuzo/pen/vJLwNY">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><p>Vous pouvez rendre les pistes implicites de taille plus flexible en spécifiant une plage à l'aide de la notation minmax().</p><pre class="language-css">.grid {
  grid-auto-columns: minmax(200px, auto);
  grid-auto-rows: minmax(60px, auto);
}</pre><p>Les pistes implicites font maintenant au moins 200px de large et 60px de haut, mais s'étendront si le contenu l'exige.</p><h2>Extension de la grille au début</h2><p>Il ne faut pas croire que les pistes implicites ne peuvent être ajoutées qu'à la fin de la grille explicite. Il peut également arriver que la grille explicite doive être étendue au début.</p><figure role="group"><img src="https://la-cascade.io/images/grid4_.webp" alt="" /><figcaption>Une grille implicite étendue d'une ligne et d'une colonne au début. (<a href="https://codepen.io/matuzo/pen/BdyJWR">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><pre class="language-css">.item:first-child {
  grid-row-end: 2;
  grid-row-start: span 2;
}
.item:nth-child(2) {
  grid-column-end: 2;
  grid-column-start: span 2;
}</pre><p>Chaque élément se termine sur la deuxième ligne et s'étend sur 2 cellules (une verticalement, l'autre horizontalement). Comme il n'y a qu'une seule cellule avant la deuxième ligne, une autre piste implicite est ajoutée à la grille au début de chaque côté.</p><h2>Placement automatique</h2><p>Comme déjà mentionné, des pistes implicites sont également ajoutées si le nombre d'éléments dépasse le nombre de cellules. Par défaut, l'algorithme de placement automatique place les éléments en remplissant chaque ligne consécutivement, en ajoutant de nouvelles rangées si nécessaire. Nous pouvons spécifier comment les éléments placés automatiquement s'écoulent dans la grille en utilisant la propriété <code>grid-auto-flow</code>.</p><figure role="group"><img src="https://la-cascade.io/images/grid11.webp" alt="" /><figcaption>Au lieu de rangées, de nouvelles colonnes sont ajoutées si le nombre d'éléments dépasse le nombre de cellules. (<a href="https://codepen.io/matuzo/pen/JyGqBP">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><pre class="language-css">.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: 100px 100px;
  grid-gap: 20px;
  grid-auto-flow: column;
}</pre><p>Au lieu de rangées, les colonnes sont remplies d'éléments et des colonnes implicites supplémentaires sont créées.</p><h2>Ne pas définir une grille explicite</h2><p>Étant donné qu'il est possible de dimensionner automatiquement les cellules à l'aide de <code>grid-auto-rows</code> et <code>grid-auto-columns</code>, il n'est pas obligatoire de définir une grille explicite.</p><figure role="group"><img src="https://la-cascade.io/images/grid5.webp" alt="" /><figcaption>Une grille implicite sans lignes et pistes explicites. (<a href="https://codepen.io/matuzo/pen/gxPzeY">Voir Codepen</a>).</figcaption></figure><figure class="break-out">
</figure><pre class="language-css">.grid {
  display: grid;
  grid-auto-columns: minmax(60px, 200px);
  grid-autorows: 60px;
  grid-gap: 20px;
}
.item:first-child {
  grid-row: span 2;
}
.item:nth-child(2) {
  grid-column: 1 / span 2;
}
.item:nth-child(5) {
  grid-column: 3;
}</pre><p>S'appuyer uniquement sur la grille implicite peut être source de confusion et difficile à comprendre en combinaison avec le placement explicite. Dans cet exemple, le premier élément est placé automatiquement et s'étend sur 2 rangées, le deuxième élément est placé explicitement dans la première colonne et s'étend sur 2 colonnes, créant ainsi une deuxième piste verticale. Les troisième et quatrième éléments seraient en fait tous deux placés automatiquement dans la quatrième rangée, mais le cinquième élément est placé explicitement dans la troisième colonne, qui n'existait pas auparavant. Cela crée une troisième piste verticale et, grâce au placement automatique de Grids, le troisième élément remonte d'une rangée pour remplir l'espace.</p><h2>Conclusion</h2><p>Cet article ne couvre pas tout ce qu'il y a à savoir sur la grille explicite et implicite, mais il devrait vous donner plus qu'une solide compréhension du concept. Savoir pourquoi et comment les lignes et les pistes implicites ont été créées est essentiel pour travailler avec la mise en page de la grille.</p><p>Vous pouvez trouver tous les exemples utilisés dans cet article dans une <a href="https://codepen.io/collection/XkLzYO/">collection sur CodePen</a>.</p><p>Si vous souhaitez en savoir plus sur les grilles, consultez <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet">Grid Layout, guide complet</a>, <a href="https://css-tricks.com/getting-started-css-grid/">Getting Started with CSS Grid</a>, <a href="https://gridbyexample.com/">Grid By Example</a> et <a href="https://css-tricks.com/collection-interesting-facts-css-grid-layout/">A Collection of Interesting Facts about CSS Grid Layout</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-grid-difference-entre-grilles-explicite-et-implicite</link>
      <guid>https://la-cascade.io/articles/css-grid-difference-entre-grilles-explicite-et-implicite</guid>
      <pubDate>Fri, 05 Mar 2021 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[La propriété CSS Clip Path]]></title>
      <description><![CDATA[<p>La propriété <code>clip-path</code> en CSS nous permet de détourer une région spécifique d'un élément à afficher, le reste étant masqué (ou "clippé").</p><pre class="language-css">.clip-me {
  /* Exemple : détourer l'élément suivant les bords supérieur, droit, inférieur et gauche */
  clip-path: inset(10px 20px 30px 40px); /* ou "none" */
  /* Exemple : clipper l'élément dans un Heptagone */
  clip-path: polygone(
    50% 0%,
    90% 20%,
    100% 60%,
    75% 100%,
    25% 100%,
    0% 60%,
    10% 20%
  );
  /* Version obsolète */
  position: absolute; /* Positionnement absolu ou fixe requis */
  clip: rect(110px, 160px, 170px, 60px); /* ou "auto" */
  /* les valeurs décrivent un point haut/gauche et un point bas/droit */
}</pre><p>?? <em>Il existait auparavant une propriété <code>clip</code>, mais notez qu'elle est obsolète</em>.</p><p>Le cas d'utilisation le plus courant serait une image, mais nous ne sommes pas limités à cela. Nous pourrions tout aussi bien appliquer <code>clip-path</code> à une balise de paragraphe et seulement à une partie du texte.</p><pre class="language-html">&lt;img
  class="clip-me"
  src="/images/image-a-clipper.png"
  alt="Description de l'image"
/&gt;
&lt;p class="clip-me"&gt;Je vais être clippé.&lt;/p&gt;</pre><p>Ces quatre valeurs dans <code>inset()</code> (dans le CSS ci-dessus) représentent le point <strong>haut/gauche</strong> et le point <strong>bas/droit</strong>, ce qui forme le rectangle visible. Tout ce qui se trouve en dehors de ce rectangle est caché.</p><figure role="group"><img src="https://la-cascade.io/images/clip-visual.webp" alt="" /><figcaption>Cette image de Louis Lazaris explique très bien les quatre points de l'ancienne syntaxe clip : rect();</figcaption></figure><p>Autres valeurs possibles :</p><pre class="language-css">.clip-me {
  /* référencement du chemin d'accès à partir d'un SVG en ligne */
  clip-path: url(#c1);
  /* chemin de référence d'un SVG externe */
  clip-path: url(path.svg#c1);
  /* polygone */
  clip-path: polygon(
    5% 5%,
    100% 0%,
    100% 75%,
    75% 75%,
    75% 100%,
    50% 75%,
    0% 75%
  );
  /* cercle */
  clip-path: circle(30px at 35px 35px);
  /* ellipse */
  clip-path: ellipse(65px 30px at 125px 40px);
  /* inset-rectangle() pourrait remplacer inset() ? */
  /* rectangle() arrive dans SVG 2 */
  /* coins arrondis... pas sûr que ce soit encore une chose */
  clip-path: inset(10% 10% 10% 10% round 20%, 20%);
}</pre><p>Exemple de chemin de clip SVG :</p><pre class="language-xml">&lt;clipPath id="clipping"&gt;
  &lt;circle cx="150" cy="150" r="50" /&gt;
  &lt;rect x="150" y="150" width="100" height="100" /&gt;
&lt;/clipPath&gt;</pre><p>Il est étrange que <code>clip-path</code> n'ait pas pris en charge la fonction <code>path()</code> dès le départ, puisque <code>path()</code> est déjà une chose pour des <a href="https://css-tricks.com/almanac/properties/o/offset-path/">propriétés comme <code>motion-path</code></a>. Firefox la prend maintenant en charge, et nous attendons le reste des navigateurs. Voir <a href="https://css-tricks.com/an-initial-implementation-of-clip-path-path/">An Initial Implementation of clip-path: path();</a></p><h2>Créer notre propre modèle</h2><p>En attendant que nous puissions utiliser <code>path()</code> de manière fiable, le clip le plus utile pour les formes personnalisées fantaisistes est <code>polygon()</code>. Voici un éditeur très soigné de Mads Stoumann (qui fonctionne aussi pour les cercles et les ellipses)</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/stoumann/pen/abZxoOM">CSS clip-path Editor</a>de Mads Stoumann dans<a href="https://codepen.io">CodePen</a></div><h2>Plus d'information</h2><ul><li><a href="https://css-tricks.com/clipping-masking-css/">Clipping and Masking in CSS</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/clip-path">clip-path dans MDN</a></li>
<li><a href="https://bennettfeely.com/clippy/">Clippy: Bennett Feely’s clip-path maker</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/SVG/Tutorial/Clipping_and_masking">Découpage et Masquage dans MDN</a></li>
<li><a href="https://www.sarasoueidan.com/blog/css-svg-clipping/">Clipping in CSS and SVG – The clip-path Property and Element by Sara Soueidan</a></li>
<li><a href="https://codepen.io/tag/clip-path/">Pens tagged clip-path on CodePen</a></li>
<li><a href="https://codepen.io/yoksel/full/GRodvp">Demos and browser support demo Pen by Yoksel</a></li>
<li><a href="https://jenkov.com/tutorials/svg/mask.html">SVG Masks by Jakob Jenkov</a></li>
</ul><p><a href="https://caniuse.com/css-clip-path">Compatibilité navigateurs</a> à ce jour.</p>]]></description>
      <link>https://la-cascade.io/articles/la-propriete-css-clip-path</link>
      <guid>https://la-cascade.io/articles/la-propriete-css-clip-path</guid>
      <pubDate>Sun, 27 Dec 2020 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Quand utiliser inline-block ?]]></title>
      <description><![CDATA[<p><em>La valeur inline-block pour l'affichage est un classique, mais à quoi sert-elle réellement et quand la choisirons-nous parmi d'autres options ?</em></p><div class="articleContent"><p>La valeur <code>inline-block</code> pour l'affichage est un classique ! Elle n'est pas nouvelle et la prise en charge par les navigateurs n'est certainement pas un sujet d'inquiétude. Je suis sûr que beaucoup d'entre nous l'utilisent intuitivement. Mais essayons de creuser un peu. À quoi sert-elle réellement ? Quand la choisirez-vous plutôt que d'autres options, peut-être similaires ?</p><h2>Boutons</h2><p>La réponse la plus fréquente que j'ai reçue c'est : <em>Je l'utilise toujours pour aligner les boutons</em>.</p><p>Au fond, ça fait sens, mais ça contribue à entretenir ce que je perçois comme une légère incompréhension. L'idée est qu'on veut aligner horizontalement des éléments qui ressemblent à des boutons (qui pourraient être des ancres, des boutons, des inputs) — comme ils le font naturellement — mais avec la possibilité d'avoir des marges et du padding. C'est là que réside la petite incompréhension : les éléments <code>display: inline</code> peuvent <em>toujours</em> avoir des <code>margin</code> et <code>padding</code>, et se comportent probablement comme vous l'attendez.</p><p>La partie compliquée est que :</p><ul><li>la marge dans la direction block sur les éléments inline est entièrement ignorée</li>
<li>le padding sur les éléments inline n'affecte pas la hauteur de la ligne de texte</li>
</ul><p>Donc, même si les boutons eux-mêmes sont stylés comme il faut, l'élément parent et le le texte qui l'entoure ne le sont sans doute pas. Voici <a href="https://codepen.io/chriscoyier/pen/mdVpwYR">une démo</a> pour l'illustrer :</p><figure class="wp-block-image size-large is-resized"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-08-at-5.51.20-AM.png?resize=681%2C188&amp;ssl=1" alt="" class="wp-image-316791" width="681" height="188" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-08-at-5.51.20-AM.png?w=748&amp;ssl=1 748w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-08-at-5.51.20-AM.png?resize=300%2C83&amp;ssl=1 300w" /><figcaption>Le padding des boutons inline les fait sortir du container, ce qui est un peu bizarre.</figcaption></figure><p>Les choses se compliquent quand la largeur de page se réduit :</p><figure class="wp-block-image size-large is-resized"><img src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-08-at-5.51.58-AM.png?resize=384%2C309&amp;ssl=1" alt="" class="wp-image-316792" width="384" height="309" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-08-at-5.51.58-AM.png?w=405&amp;ssl=1 405w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-08-at-5.51.58-AM.png?resize=300%2C241&amp;ssl=1 300w" /></figure><p>Donc, oui, <code>inline-block</code> fait sens pour aligner les boutons, mais...</p><h2>N'oubliez pas inline-flex et inline-grid</h2><p>Avec les valeurs d'affichage <code>inline-flex</code> et <code>inline-grid</code>, vous aurez le même (bon) comportement que vous attendez d'<code>inline-block</code>, mais les éléments (souvent des boutons) bénéficient d'un système de mise en page plus solide.</p><p>Prenez l'exemple de boutons avec des icônes :</p><pre class="language-html">&lt;a href="#" class="button&gt;
  &lt;svg&gt; ... &lt;/svg&gt;
  Text
&lt;/a&gt;</pre><p>Pour que le texte et l'icone s'aligent parfaitement au centre, il est tentant de faire :</p><pre class="language-css">.button svg {
  vertical-align: middle;
}</pre><p>qui ne réussit jamais exactement...</p><figure class="wp-block-image size-large"><img width="695" height="125" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-09-at-6.30.32-AM.png?resize=715%2C129&amp;ssl=1" alt="" class="wp-image-316842" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-09-at-6.30.32-AM.png?w=715&amp;ssl=1 715w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-09-at-6.30.32-AM.png?resize=300%2C54&amp;ssl=1 300w" /><figcaption>Ces icônes sont un pixel ou deux trop bas par rapport au centre.</figcaption></figure><p>Mais on peut réparer ça facilement avec <code>inline-flex</code> :</p><pre class="language-css">.button {
  display: inline-flex;
  align-items: center;
}</pre><figure class="wp-block-image size-large"><img width="728" height="140" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-09-at-6.31.17-AM.png?resize=728%2C140&amp;ssl=1" alt="" class="wp-image-316843" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-09-at-6.31.17-AM.png?w=728&amp;ssl=1 728w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-09-at-6.31.17-AM.png?resize=300%2C58&amp;ssl=1 300w" data-recalc-dims="1" /><figcaption>Des icônes parfaitement alignées (et bientôt nous pourrons <a href="https://css-tricks.com/lh-and-rlh-units/">utiliser l'unité <code>lh</code></a> !)</figcaption></figure><p>Avec <code>inline-flex</code> ou <code>inline-grid</code> on a toute la puissance de flexbox ou de grid à l'intérieur d'un bloc qui se met en page dans la direction inline.</p><h2>Les blocks peuvent toujours revenir à la ligne</h2><p><em>Un élément inline-block respecte une largeur</em>. C'est une différence supplémentaire avec les éléments inline. On s'est habitué à construire des systèmes de mise en page par colonnes avec des éléments inline-block, parce qu'ils peuvent faire ce que que les éléments flottés pouvaient faire ici, mais sans avoir à s'inquiéter de faire un <em>clear</em> du <code>float</code> (est-ce que les jeunes générations comprennent ce que je veux dire ?), ce qui permettait un retour à la ligne plus élégant que le <code>float</code>.</p><p>L'idée d'avoir des inline-blocks se comportant comme des colonnes avec retour à la ligne (même avec une seule colonne) est toujours vivante aujourd'hui parce que c'est une astuce qu'on peut utiliser dans les emails html pour permettre des mises en page à plusieurs colonnes qui se résolvent en une seule colonne sur des écrans réduits <em>sans avoir à utiliser les media queries</em> (que certains clients email ne permettent pas.)</p><h2>transform sur un élément inline</h2><p>Les éléments inline ne peuvent pas prendre un <code>transform</code>. Si vous en avez besoin, il faudra que ce soit un inline-block.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/chriscoyier/pen/YzwLRYJ">Transformed inline elements need to be inline-block</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h2>Des enfants de colonnes qui ne se cassent pas au milieu</h2><p>Les colonnes CSS peuvent être utilisées avec des paragraphes de textes lorsque vous ne vous souciez pas qu'elles se cassent entre les colonnes. Mais parfois les colonnes CSS sont utilisées pour des blocs pour lesquels ce serait bizarre. Supposons que nos blocs aient leur propre background et padding. Les ruptures sont vraiment bizarres visuellement</p><figure class="wp-block-image size-full"><img width="744" height="659" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/awkward-columns.png?resize=1488%2C1318&amp;ssl=1" alt="Screenshot. Three columns of paragraphs with a tan background and padding. The last paragraph of the first column breaks into the second column, leaving no bottom or top padding on it in the columns." class="wp-image-316950" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/awkward-columns.png?w=1488&amp;ssl=1 1488w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/awkward-columns.png?resize=300%2C266&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/awkward-columns.png?resize=1024%2C907&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/awkward-columns.png?resize=768%2C680&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/awkward-columns.png?resize=1000%2C886&amp;ssl=1 1000w" data-recalc-dims="1" /></figure><p>C'est une astuce étrange, dont je ne peux pas dire que je la comprends à 100%, mais si vous mettez <code>display:inline-block</code> sur ces boîtes (et probablement <code>width: 100%</code> pour être sûr) eh bien elles ne se casseront pas et la colonne sera préservée.</p><figure class="wp-block-image size-large"><img width="512" height="377" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-12-at-1.52.23-PM.png?resize=1024%2C755&amp;ssl=1" alt="" class="wp-image-316951" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-12-at-1.52.23-PM.png?resize=1024%2C755&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-12-at-1.52.23-PM.png?resize=300%2C221&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-12-at-1.52.23-PM.png?resize=768%2C567&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-12-at-1.52.23-PM.png?resize=1536%2C1133&amp;ssl=1 1536w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-12-at-1.52.23-PM.png?resize=1000%2C738&amp;ssl=1 1000w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/Screen-Shot-2020-07-12-at-1.52.23-PM.png?w=1670&amp;ssl=1 1670w" data-recalc-dims="1" /><figcaption><a href="https://codepen.io/chriscoyier/pen/NWxBRar" rel="noopener">Demo</a></figcaption></figure><h2>Une façon rapide de rendre une liste horizontale</h2><p>Ça aussi, c'est assez populaire : les listes empilent les éléments verticalement, comme des éléments blocs. Mais ce ne sont pas des blocs. Ce sont des <code>display: list-item</code> , ce qui est important comme nous l'allons voir. Le cas d'usage populaire est <em>quand je veux aligner une liste horizontalement</em>.</p><p>Donc, vous avez une liste...</p><pre class="language-html">&lt;ul&gt;
  &lt;li&gt;Three&lt;/li&gt;
  &lt;li&gt;Little&lt;/li&gt;
  &lt;li&gt;Piggies&lt;/li&gt;
&lt;/ul&gt;</pre><p>...vous voulez l'afficher horizontalement, vous pouvez...</p><pre class="language-css">li {
  display: inline-block;
}</pre><p>Et voilà.</p><p>J'ai écouté ce que disait VoiceOver (<em>NdT: l'outil d'accessibilité</em>) et la liste <code>inline-block</code> est toujours annoncée comme une liste, mais elle n'annonce pas les puces (<em>bullet points</em>) ce qui fait sens puisqu'elles n'y sont pas. C'est le souci lorsqu'on change l'affichage des éléments de listes en n'utilisant pas <code>display: list-item</code>, elles perdent en list-item-ité...</p><p>Une alternative pourrait être de faire du parent un container flex :</p><pre class="language-css">ul {
  display: flex;
}</pre><p>ce qui permet l'alignement horizontal (la valeur par défaut de flexbox) mais conserve les puces puisqu'on n'a pas modifié le display des élements de liste. Vous pouvez toujours les retirer manuellement si vous le souhaitez.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/chriscoyier/pen/dyGjpZa">Horz List Demo</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h2>Listes centrées</h2><p>À propos de liste, Jeff Starr a écrit un article sur l'idée de <a href="https://perishablepress.com/css-center-align-list-left-align-text/">listes à l'intérieur d'un texte centré</a>, qui peut sembler bizarre elle aussi. Ce qui est bizarre dans cette idée, c'est que le texte des eéléments de la liste est centré, mais la liste elle-même est affichée en pleine largeur, ce qui crée cette situation où les puces sont alignées à gauche :</p><figure class="wp-block-image size-full"><img width="738" height="384" src="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/center-left-list-01.png?resize=1236%2C644&amp;ssl=1" alt="Screenshot. Shows an unordered list with centered list items. The text of the list items is centered, but the bulletpoints are still aligned to the left." class="wp-image-316954" srcset="https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/center-left-list-01.png?w=1236&amp;ssl=1 1236w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/center-left-list-01.png?resize=300%2C156&amp;ssl=1 300w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/center-left-list-01.png?resize=1024%2C534&amp;ssl=1 1024w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/center-left-list-01.png?resize=768%2C400&amp;ssl=1 768w, https://i0.wp.com/css-tricks.com/wp-content/uploads/2020/07/center-left-list-01.png?resize=1000%2C521&amp;ssl=1 1000w" /></figure><p>La solution de Jeff a été de mettre <code>inline-block</code> la liste entière. Ça permet à la liste d'être aussi large que son contenu et permet aux puces de ne plus être accrochées au bord gauche et de voyager avec le contenu centré. Tant qu'il y a des éléments de niveau block avant et après, c'est une bonne solution.</p><p>Une alternative, si le but est de réduire la largeur de la liste à celle du contenant, pourrait être <a href="https://codepen.io/chriscoyier/pen/rNxrMQv">la suivante</a> qui n'empêche pas la liste d'être de niveau bloc :</p><pre class="language-css">ul {
  width: max-content;
  margin: 0 auto;
  text-align: left;
}</pre></div>]]></description>
      <link>https://la-cascade.io/articles/quand-utiliser-inline-block</link>
      <guid>https://la-cascade.io/articles/quand-utiliser-inline-block</guid>
      <pubDate>Thu, 17 Sep 2020 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[:first-of-type]]></title>
      <description><![CDATA[<p><em>La pseudo-classe first-of-type cible un élément qui est le premier enfant d'un type donné dans la liste des enfants de l'élément parent.</em></p><div class="articleContent"><p>Le sélecteur <code>:first-of-type</code> en CSS vous permet de cibler la première occurrence d'un élément dans son conteneur. Il est défini dans la spécification CSS Selectors Level 3 comme une "pseudo-classe structurelle", ce qui signifie qu'il est utilisé pour styliser le contenu en fonction de sa relation avec le contenu parent et frère.</p><p>Supposons que nous ayons un article avec un titre et plusieurs paragraphes :</p><pre class="language-html">&lt;article&gt;
  &lt;h1&gt;A Title&lt;/h1&gt;
  &lt;p&gt;Paragraph 1.&lt;/p&gt;
  &lt;p&gt;Paragraph 2.&lt;/p&gt;
  &lt;p&gt;Paragraph 3.&lt;/p&gt;
&lt;/article&gt;</pre><p>Nous voulons agrandir le premier paragraphe, comme une sorte de paragraphe d'introduction. Au lieu de lui donner une classe, nous pouvons utiliser <code>:first-of-type</code> pour le sélectionner :</p><pre class="language-css">p:first-of-type {
  font-size: 1.25em;
}</pre><p>L'utilisation de <code>:first-of-type</code> est très similaire à <code>:nth-child</code> mais avec une différence essentielle : <strong>elle est moins spécifique</strong>. Dans l'exemple ci-dessus, si nous avions utilisé <code>p:nth-child(1)</code>, rien ne se serait produit car le paragraphe n'est pas le premier enfant de son parent (l'<code>&lt;article&gt;</code>). Cela révèle la puissance de <code>:first-of-type</code> : il cible un type d'élément particulier dans une disposition particulière par rapport aux frères et sœurs similaires, et non pas tous les frères et sœurs.</p><p>L'exemple plus complet ci-dessous démontre l'utilisation de <code>:first-of-type</code> et d'un sélecteur de pseudo-classe connexe, <code>:last-of-type</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/zakkain/pen/DwGXKv">CSS-Tricks: :first-of-type and :last-of-type</a>de zakkain dans<a href="https://codepen.io">CodePen</a></div></div>]]></description>
      <link>https://la-cascade.io/articles/first-of-type</link>
      <guid>https://la-cascade.io/articles/first-of-type</guid>
      <pubDate>Fri, 24 Jul 2020 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Attributs]]></title>
      <description><![CDATA[<p>Il existe bien des façons de sélectionner des éléments en CSS. La plus basique est la sélection par nom de balise, comme <code>p { }</code>. Presque tout ce qui est plus spécifique qu'un sélecteur de balise utilise des <a href="https://developer.mozilla.org/fr/docs/Web/HTML/Attributes">attributs</a> — <code>class</code> et <code>id</code> permettent tous deux de sélectionner ces attributs sur les éléments HTML. Mais la classe et l'ID ne sont pas les seuls attributs que les développeurs peuvent choisir. Nous pouvons utiliser n'importe quel <strong>attribut</strong> d'un élément comme sélecteur.</p><p>La sélection d'attributs a une syntaxe spéciale. En voici un exemple :</p><pre class="language-css">a[href="https://css-tricks.com"]
{
  color: #e18728;
}</pre><p>Il s'agit d'un <strong>sélecteur à correspondance exacte</strong> qui ne sélectionnera que les liens dont la valeur exacte de l'attribut <code>href</code> est "https://css-tricks.com".</p><h2>Les sept différents types</h2><p>Les sélecteurs d'attributs sont sensibles à la casse par défaut (voir <a href="https://la-cascade.io/articles/les-attributs-html#caseinsensitive">correspondance insensible à la casse ci-dessous</a>), et sont écrits entre crochets <code>[]</code>.</p><p>Il existe sept types différents de correspondances avec un sélecteur d'attribut, et la syntaxe est différente pour chacun. Les sélecteurs d'attributs les plus complexes reposent sur la syntaxe du sélecteur de correspondance exacte : ils commencent tous par le nom de l'attribut et se terminent par un signe égal suivi de la ou des valeurs de l'attribut, généralement entre guillemets. Ce qui se trouve entre le nom de l'attribut et le signe égal est ce qui fait la différence entre les sélecteurs.</p><pre class="language-css">[data-value] {
  /* L'attribut existe */
}
[data-value='foo'] {
  /* L'attribut a cette valeur exacte */
}
[data-value*='foo'] {
  /* La valeur de l'attribut contient cette valeur quelque part */
}
[data-value~='foo'] {
  /* L'attribut contient cette valeur quelque part dans une liste séparée par un espace */
}
[data-value^='foo'] {
  /* La valeur de l'attribut commence par ceci */
}
[data-value|='foo'] {
  /* La valeur de l'attribut commence par ceci dans une liste séparée par un tiret */
}
[data-value$='foo'] {
  /* La valeur de l'attribut se termine par ceci */
}</pre><p><strong>La valeur contient</strong> : la valeur de l'attribut contient un terme comme seule valeur, une valeur dans une liste de valeurs ou comme partie d'une autre valeur. Pour utiliser ce sélecteur, ajoutez un astérisque (_) avant le signe égal. Par exemple, <code>img[alt_="art"]</code> sélectionnera les images dont le texte alt est "art abstrait" et "Le départ de Nimrod", car la valeur "art" se trouve dans le mot "départ".</p><p><strong>La valeur est dans une liste séparée par un espace</strong> : la valeur est soit la seule valeur de l'attribut, soit une valeur entière dans un ensemble de valeurs séparées par un espace. Contrairement au sélecteur "contains", ce sélecteur ne recherchera pas la valeur sous forme de fragment de mot. Pour utiliser ce sélecteur, ajoutez un tilde (<code>~</code>) avant le signe égal. Par exemple, <code>img[alt~="art"]</code> sélectionnera les images avec le texte alt "art abstrait" et "exposition d'art", mais pas "Le départ de Nimrod" (que le sélecteur "contains" sélectionnerait).</p><p><strong>Valeur commence par</strong> : la valeur de l'attribut commence par le terme sélectionné. Pour utiliser ce sélecteur, ajoutez un caret (<code>^</code>) avant le signe égal. N'oubliez pas que la sensibilité à la casse compte. Par exemple, <code>img[alt^="art"]</code> sélectionnera les images avec le texte alt "exposition d'art" et "motif artistique", mais pas une image avec le texte alt "Arthur Miller" car "Arthur" commence par une majuscule.</p><p><strong>La valeur est la première dans une liste séparée par des tirets</strong> : Ce sélecteur est très similaire au sélecteur "commence par". Ici, le sélecteur correspond à une valeur qui est soit la seule valeur, soit la première d'une liste de valeurs séparées par un tiret. Pour utiliser ce sélecteur, ajoutez un caractère pipe (<code>|</code>) (<em>tuyau</em>)avant le signe égal. Par exemple, <code>li[data-years|="1900"]</code> sélectionnera les éléments de liste dont la valeur de data-years est "1900-2000", mais pas l'élément de liste dont la valeur de data-years est "1800-1900".</p><p><strong>Valeur se terminant par</strong> : la valeur de l'attribut se termine par le terme sélectionné. Pour utiliser ce sélecteur, ajoutez un signe dollar (<code>$</code>) avant le signe égal. Par exemple, <code>a[href$="pdf"]</code> sélectionne tous les liens qui se terminent par .pdf.</p><p class="is-style-explanation">Une remarque sur les guillemets : Dans certaines circonstances, vous pouvez ne pas utiliser de guillemets autour de la valeur, mais les règles de sélection sans guillemets sont incohérentes d'un navigateur à l'autre. Les guillemets fonctionnent toujours, donc si vous vous en tenez à leur utilisation, vous pouvez être sûr que votre sélecteur fonctionnera.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/OPobRY">Attribute Selectors</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><p>Fait amusant : les valeurs sont traitées comme des chaînes de caractères, vous n'avez donc pas besoin d'effectuer un échappement fantaisiste des caractères pour les faire correspondre, comme vous le feriez si vous utilisiez des caractères inhabituels dans un sélecteur de classe ou d'ID.</p><pre class="language-css">[class='(╯°□°）╯︵ ┻━┻'] {
  couleur: rouge;
  font-weight: bold;
}</pre><h2 id="caseinsensitive">Correspondance insensible à la casse</h2><p>Les sélecteurs d'attributs insensibles à la casse font partie de la spécification <a href="https://www.w3.org/TR/selectors-4/#attribute-case">Selectors Level 4</a> du groupe de travail CSS. Comme mentionné ci-dessus, les chaînes de valeur d'attribut sont par défaut sensibles à la casse, mais peuvent être modifiées en insensibles à la casse en ajoutant <code>i</code> juste avant le crochet fermant :</p><pre class="language-css">[attribute='value' i] {
  /* Les styles ici s'appliqueront aux éléments avec :
    attribut="valeur"
    attribut="VaLuE"
    attribut="VALUE"
    ...etc
  */
}</pre><p>La correspondance insensible à la casse pourrait être vraiment pratique pour cibler les attributs contenant du texte imprévisible, écrit par les humains. Par exemple, supposons que vous conceviez une bulle de dialogue sur une application de chat et que vous souhaitiez ajouter une "main agitée" à tous les messages contenant le texte "hello" sous une forme ou une autre. Vous pourriez le faire rien qu'avec CSS, en utilisant une correspondance insensible à la casse pour attraper toutes les variations possibles :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/andyadams/pen/ydpvGQ">Case-insensitive CSS attribute matching</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><h2>Combiner tout cela</h2><p>Vous pouvez combiner un sélecteur d'attribut avec d'autres sélecteurs, tels que tag, class ou ID.</p><pre class="language-css">div[attribute='value'] {
  /* règles de style ici */
}
.module[attribute='value'] {
  /* règles de style ici */
}
#header[attribute='value'] {
  /* règles de style ici */
}</pre><p>Vous pouvez même combiner plusieurs sélecteurs d'attributs. Cet exemple sélectionne les images dont le texte alternatif comprend le mot "personne" comme seule valeur ou une valeur dans une liste séparée par un espace, et une valeur src qui comprend la valeur "lorem" :</p><pre class="language-css">img[alt~='person'][src*='lorem'] {
  /* règles de style ici */
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/jEvVVb">Combined Attributes and Attribute-Only Selection</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div><h2>Sélecteurs d'attributs en JavaScript et jQuery</h2><p>Les sélecteurs d'attributs peuvent être utilisés dans jQuery comme tout autre sélecteur CSS. En JavaScript, vous pouvez utiliser les sélecteurs d'attributs avec <code>document.querySelector()</code> et <code>document.querySelectorAll()</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/team/css-tricks/pen/XJPNNg">Attribute Selectors in JS and jQuery</a>de css-tricks dans<a href="https://codepen.io">CodePen</a></div>]]></description>
      <link>https://la-cascade.io/articles/les-attributs-html</link>
      <guid>https://la-cascade.io/articles/les-attributs-html</guid>
      <pubDate>Thu, 23 Jul 2020 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Approfondir la propriété display : la génération de boîtes]]></title>
      <description><![CDATA[<p><em>Rachel Andrew examine les valeurs qui contrôlent la génération des boîtes, au cas où vous ne voudriez pas générer de boîte du tout.</em></p><div class="articleContent"><p>Cet article est le second d'une courte série d'articles sur la propriété <code>display</code> en CSS, le premier parle des <a href="https://la-cascade.io/articles/approfondir-la-propriete-display-les-deux-valeurs-de-display">deux valeurs de display</a>. La spécification de <code>display</code> est très importante à comprendre car elle sous-tend toutes les différentes méthodes de mise en page dont nous disposons.</p><p>Même si de nombreuses valeurs de <code>display</code> ont leur propre spécification, beaucoup de termes et idées sont détaillés dans <code>display</code>. Par conséquent, la compréhension de cette spécification vous aide à comprendre les spécifications détaillant essentiellement <em>les valeurs</em> de <code>display</code>. Dans cet article, je vais examiner les valeurs de génération de boîtes de <code>display</code> — <code>none</code> et <code>contents</code>.</p><h2>Tout est une boîte</h2><p><strong>En CSS, tout génère des boîtes</strong>. Fondamentalement, une page Web est un ensemble de boîtes, block et inline. On le voit très bien si on ouvre DevTools dans notre navigateur préféré et qu'on commence à sélectionner des éléments sur la page. On voit les boîtes qui composent la page, et comment leurs marges, paddings et bordures sont appliqués.</p><figure class="break-out article__image"><a href="https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png"><img srcset="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png 400w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_800/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png 800w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1200/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png 1200w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_1600/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png 1600w, https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_2000/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png 2000w" src="https://res.cloudinary.com/indysigner/image/fetch/f_auto,q_80/w_400/https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png" alt="An image of a simple layout with an unordered list highlighted in browser DevTools" /></a>
<figcaption class="op-vertical-bottom">J'ai mis en évidence l'élément 'ul' à l'aide de Firefox DevTools afin de pouvoir inspecter les différentes parties de la boîte. (<a href="https://archive.smashing.media/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/302b6b8a-7aae-4196-a118-cd2c5fd357de/css-inspecting-box.png">Grand aperçu</a>)</figcaption></figure><h2>Contrôler la génération de boîtes</h2><p>Les valeurs <code>none</code> et <code>contents</code> de <code>display</code> déterminent si les boîtes doivent apparaître ou pas. Si vous avez des éléments dans votre balisage dont vous ne voulez pas qu'ils génèrent une boîte en CSS, vous devez d'une manière ou d'une autre supprimer la génération de la boîte. Vous pouvez faire deux choses :</p><ul><li>Empêcher la génération d'une boîte et de tous ses enfants.</li>
<li>Empêcher la génération d'une boîte <em>mais</em> afficher quand même les enfants.</li>
</ul><p>Nous allons examiner chacun de ces scénarios à tour de rôle.</p><h2>display: none</h2><p>La valeur <code>none</code> de <code>display</code> est la façon dont nous empêchons la génération d'une boîte et de tous les enfants de cette boîte. Elle agit comme si l'élément n'existait pas du tout. Elle est donc utile dans les situations où vous avez l'intention de cacher complètement ce contenu, peut-être parce qu'il sera révélé plus tard après l'activation d'un lien.</p><p>Voici un exemple avec un paragraphe, une liste non ordonnée et un autre paragraphe, vous pouvez voir que les éléments s'affichent dans un flux normal. L'<code>ul</code> a un background et une bordure appliqués, ainsi qu'un peu de padding.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/XQGagV">Smashing Box Generation: example</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si j'ajoute <code>display: none</code> à l'<code>ul</code>, il disparaît de l'affichage visuel, emportant avec lui ses enfants ainsi que le background et la bordure.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/VNRzzg">Smashing Box Generation: example display: none</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si vous utilisez <code>display: none</code>, le contenu est caché à tous les utilisateurs du site Web. <em>Y compris les utilisateurs de lecteurs d'écran</em>. Par conséquent, vous ne devez l'utiliser que si votre intention est que la boîte et tout ce qu'elle contient soit <em>complètement</em> caché à <em>tous</em>.</p><p>Il existe des situations où vous souhaitez ajouter des informations supplémentaires pour les utilisateurs de technologies d'assistance, comme les lecteurs d'écran, mais les cacher pour les autres utilisateurs ; dans ce cas, vous devez utiliser une technique différente. D'excellentes suggestions sont faites par Scott O 'Hara dans son article "<a href="https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html">Inclusivement caché</a>".</p><p>L'utilisation de <code>display: none</code> est donc assez simple. Utilisez-la dans une situation où vous voulez qu'une boîte et son contenu disparaissent de l'affichage, de l'arbre des boîtes et de l'arbre d'accessibilité (comme si elle n'avait jamais été là).</p><h2>display: contents</h2><p>Pour le deuxième scénario, nous devons examiner une valeur beaucoup plus récente de display. La valeur <code>display: contents</code> supprime la boîte à laquelle elle est appliquée de l'arbre des boîtes, de la même manière que <code>display: none</code>, <em>mais laisse les enfants en place</em>. Ça entraîne un comportement bien utile pour ce que nous pouvons faire ensuite dans notre mise en page. Prenons un exemple simple et explorons-le plus avant.</p><p>J'utilise le même exemple que précédemment, mais cette fois, j'ai utilisé <code>display: contents</code> sur le <code>ul</code>. Les éléments de la liste sont maintenant visibles, mais ils n'ont pas d'arrière-plan ni de bordures et se comportent comme si l'on avait ajouté des éléments <code>li</code> à la page sans aucun <code>ul</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/JVzyra">Smashing Box Generation: example display: contents</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>La raison pour laquelle il peut être utile de supprimer une boîte tout en gardant les enfants tient à la façon dont les autres valeurs d'affichage se comportent. Lorsque nous modifions la valeur de <code>display</code>, nous le faisons sur une boîte et les enfants directs de cette boîte, comme je l'ai décrit dans le dernier article. Si j'ajoute <code>display: flex</code> aux règles CSS d'un élément, cet élément devient une boîte de niveau bloc, et les enfants directs deviennent des éléments flex. Les enfants de ces éléments flex reviennent au flux normal (ils ne font pas partie de la mise en page flex).</p><p>Vous pouvez voir ce comportement dans l'exemple suivant. Ici, j'ai un élément conteneur, configuré comme <code>display: flex</code>, il a quatre enfants directs, trois éléments <code>div</code> et un <code>ul</code>. L'<code>ul</code> comporte deux éléments liste. Les enfants directs participent tous à la mise en page flex et s'affichent comme des éléments flex. Les éléments de liste ne sont pas des enfants directs et s'affichent donc comme des éléments de liste à l'intérieur de la boîte de l'<code>ul</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/yrwovX">Smashing Box Generation: display: contents and flexbox 1</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si nous reprenons cet exemple et ajoutons <code>display: contents</code> à l'<code>ul</code>, la boîte est retirée de l'affichage visuel et les enfants participent maintenant à la mise en page flex. Vous pouvez voir qu'ils ne deviennent pas des enfants directs. Ils ne sont pas sélectionnés par le sélecteur universel d'enfant direct (<code>.wrapper &gt; *</code>) comme le sont les éléments <code>div</code> et <code>ul</code>, et ils conservent l'arrière-plan qui leur a été donné. Tout ce qui s'est passé, c'est que la boîte de l'élément <code>ul</code> qui le contient a été supprimée, tout le reste continue normalement.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/JVzypm">Smashing Box Generation: display: contents and flexbox 2</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Ça a des implications potentiellement très utiles si nous considérons les éléments du HTML qui sont importants pour l'accessibilité et les données sémantiques, mais qui génèrent une boîte supplémentaire pouvant nous empêcher de mettre en page le contenu avec flex ou grid.</p><h2>Ceci n'est pas un reset CSS</h2><p>Vous avez peut-être remarqué que l'un des effets secondaires de l'utilisation de <code>display: contents</code> est la suppression de la marge et du padding de l'élément. C'est dû au fait qu'elles sont liées à la boîte, qui fait partie du modèle de boîte CSS. Ça pourrait vous amener à penser que <code>display: contents</code> est un bon moyen de se débarrasser rapidement du padding et de la marge d'un élément.</p><p>C'est une utilisation qu'Adrian Roselli a repérée dans la nature ; il s'est suffisamment inquiété pour rédiger un billet détaillé expliquant les problèmes que cela pose — "<a href="https://adrianroselli.com/2018/05/display-contents-is-not-a-css-reset.html">display : contents is not a CSS reset</a>". Certains des problèmes qu'il soulève sont dus à un malheureux problème d'accessibilité dans les navigateurs actuellement dotés de <code>display: contents</code>, dont nous parlerons plus loin. Cependant, même une fois ces problèmes résolus, supprimer un élément de l'arbre des boîtes juste pour se débarrasser de la marge et du padding est quelque peu... extrême.</p><p>Entre autres choses, ça serait problématique pour la maintenance future du site, un futur développeur pourrait se demander pourquoi il ne peut apparemment pas appliquer quoi que ce soit à cette mystérieuse boîte — oubliant le fait qu'elle a été supprimée ! Si vous avez besoin que <code>margin</code> et <code>padding</code> soient à 0, faites une faveur à votre moi futur et réglez-les à <code>0</code> de la manière traditionnelle. Réservez l'utilisation de <code>display: contents</code> pour les cas particuliers où vous voulez vraiment supprimer la boîte.</p><p>Il convient également de noter la différence entre <code>display: contents</code> et CSS Grid Layout subgrid. Alors que <code>display: contents</code> supprime complètement la boîte, le background et la bordure de l'affichage, faire d'un élément de grille une sous-grille maintiendrait le style de la boîte sur cet élément et transmettrait simplement le dimensionnement de la piste de façon à ce que les éléments imbriqués puissent utiliser la même grille. Pour en savoir plus, consultez mon article "<a href="https://www.smashingmagazine.com/2018/07/css-grid-2/">Grille CSS niveau 2 : voici la sous-grille</a>".</p><h2>Problèmes d'accessibilité et display: contents</h2><p>Un problème sérieux rend actuellement <code>display: contents</code> inutile pour la chose-même pour laquelle il serait le plus utile. Les cas évidents d'utilisation de <code>display: contents</code> sont ceux où des boîtes supplémentaires sont nécessaires pour ajouter des balises qui rendent votre contenu plus facilement compréhensible par ceux qui utilisent des lecteurs d'écran ou d'autres dispositifs d'assistance.</p><p>L'élément <code>ul</code> de notre liste dans le premier CodePen <code>display: contents</code> en est un parfait exemple. Vous pourriez obtenir le même résultat visuel en aplatissant le balisage et en n'utilisant pas de liste du tout. Toutefois, si le contenu est sémantiquement une liste, qu'il est mieux compris et lu par un lecteur d'écran comme une liste, il doit être balisé comme tel.</p><p>Si vous souhaitez ensuite que les éléments enfants fassent partie d'une mise en page flex ou grid, comme si la boîte de l'<code>ul</code> n'existait pas, vous devriez pouvoir utiliser <code>display: contents</code> pour faire disparaître magiquement la boîte et la rendre ainsi — tout en laissant la sémantique en place. La spécification indique que cela devrait être le cas,</p><figure class="quote"><blockquote cite="https://drafts.csswg.org/css-display/#the-display-properties">
<p>La propriété display n'a aucun effet sur la sémantique d'un élément : celle-ci est définie par le langage du document et n'est pas affectée par CSS. À l'exception de la valeur none, qui affecte également la sortie sonore/parlée et l'interactivité d'un élément et de ses descendants, la propriété display n'affecte que la mise en page visuelle : son but est de laisser aux concepteurs la liberté de modifier le comportement de mise en page d'un élément sans affecter la sémantique sous-jacente du document.</p>
</blockquote>
<figcaption><cite><a href="https://drafts.csswg.org/css-display/#the-display-properties">2. Box Layout Modes: the display property</a></cite></figcaption></figure><p>Comme nous l'avons déjà vu, la valeur <code>none</code> masque l'élément aux lecteurs d'écran, cependant, les autres valeurs de <code>display</code> sont toujours là pour nous permettre de changer la façon dont les choses s'affichent <em>visuellement</em>. Elles ne doivent pas toucher à la sémantique du document.</p><p>C'est pourquoi beaucoup d'entre nous ont été surpris de constater que <code>display: contents</code> supprimait en fait l'élément de l'arbre d'accessibilité dans les deux navigateurs (Chrome et Firefox) qui l'avaient mis en œuvre. Cela changeait donc la sémantique du document, de sorte qu'un lecteur d'écran ne savait pas qu'une liste était une liste une fois que l'ul avait été supprimé à l'aide de <code>display: contents</code>. Il s'agit d'un bogue de navigateur — et d'un bogue sérieux.</p><p>L'an dernier, Hidde de Vries a évoqué ce problème dans son billet "<a href="https://hidde.blog/more-accessible-markup-with-display-contents/">More Accessible Markup with display:contents</a>" et a utilement soulevé des problèmes auprès des différents navigateurs afin de les sensibiliser et de les amener à travailler sur une correction. Firefox a partiellement corrigé le problème, bien que des problèmes subsistent avec certains éléments tels que le bouton. Le problème fait l'objet d'un travail actif dans Chrome. Il existe également un problème pour WebKit.</p><p>Jusqu'à ce que ces problèmes soient résolus et que les versions des navigateurs qui présentaient le problème ne soient plus utilisées, vous devez être très prudent lorsque vous utilisez <code>display: contents</code> sur tout ce qui véhicule des informations sémantiques et doit être exposé à la technologie d'assistance. Comme le déclare Adrian Roselli,</p><figure class="quote"><blockquote cite=""><div>Pour l'instant, n'utilisez display : contents que si vous avez l'intention de tester avec une technologie d'assistance et que vous pouvez confirmer que les résultats fonctionnent pour les utilisateurs.</div></blockquote>
<figcaption>— Adrian Roselli</figcaption></figure><p>Il existe des endroits où vous pouvez utiliser <code>display: contents</code> en toute sécurité sans cette préoccupation. Par exemple, si vous devez ajouter des balises supplémentaires pour créer des solutions de repli pour votre grille de mises en page flexibles dans les anciens navigateurs. Les navigateurs qui prennent en charge <code>display: contents</code> prennent également en charge grid et flexbox. Vous pouvez donc utiliser <code>display: contents</code> sans ajouter d'éléments <code>div</code> redondants. Dans l'exemple ci-dessous, j'ai créé une grille basée sur float, avec des wrappers de rangées.J'utilise ensuite <code>display: contents</code> pour supprimer les wrappers de rangées et permettre à tous les éléments de devenir des grid items et donc de faire partie de la mise en page grid. Cela pourrait vous donner un outil supplémentaire lors de la création de solutions de repli pour des mises en page avancées. En effet, si vous devez ajouter des balises supplémentaires, vous pouvez les supprimer avec <code>display: contents</code> lors de la création de votre grille ou de votre mise en page flexible. Je pense que cette utilisation ne devrait pas poser de problème — mais si quelqu'un dispose de meilleures informations que moi en matière d'accessibilité et peut signaler un problème, qu'il le fasse dans les commentaires.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/PgLJPb">Smashing Box Generation: removing row wrappers with display: contents;</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Pour conclure</h2><p>Cet article s'est penché sur les valeurs de génération de boîtes de la propriété <code>display</code>. J'espère que vous comprenez mieux maintenant le comportement différent de <code>display: none</code> — qui supprime complètement une boîte et tous ses enfants, et de <code>display: contents</code> qui supprime uniquement la boîte elle-même. Vous devriez également comprendre les problèmes potentiels liés à l'utilisation de ces méthodes en matière d'accessibilité.</p></div>]]></description>
      <link>https://la-cascade.io/articles/approfondir-la-propriete-display-generation-de-boite</link>
      <guid>https://la-cascade.io/articles/approfondir-la-propriete-display-generation-de-boite</guid>
      <pubDate>Fri, 06 Mar 2020 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Approfondir la propriété display : les deux valeurs de display]]></title>
      <description><![CDATA[<p><em>Nous parlons beaucoup de Flexbox et de Grid Layout, mais ces méthodes de mise en page sont, à la base, des valeurs de la propriété CSS display, une puissante propriété qui ne reçoit pas toute l'attention qu'elle mérite. Rachel Andrew y jette un coup d'œil dans une courte série.</em></p><div class="articleContent"><p>Une mise en page <code>flex</code> ou <code>grid</code> commence par la déclaration <code>display: flex</code> ou <code>display: grid</code>. Ces méthodes de mise en page sont des valeurs de la propriété <a href="denied:javascript:void(0)">CSS display</a>. Nous avons tendance à ne pas beaucoup parler de cette propriété en tant que telle, nous concentrant plutôt sur les valeurs de <code>flex</code> ou de <code>grid</code>. Cependant, il y a des choses intéressantes à comprendre au sujet de <code>display</code> et de la façon dont elle est définie, qui vous faciliteront grandement la vie lorsque vous utiliserez CSS pour votre mise en page.</p><p>Dans cet article, le premier d'une série de deux, je vais examiner la manière dont les valeurs de <code>display</code> sont définies dans la spécification de niveau 3. Il s'agit d'un changement par rapport à la façon dont nous définissions <code>display</code> dans les versions précédentes de CSS. Même s'ils peuvent déranger, de prime abord, ceux d'entre nous qui font du CSS depuis de nombreuses années, je pense que ces changements aident vraiment à expliquer ce qui se passe lorsque nous modifions la valeur <code>display</code> d'un élément.</p><h2>Éléments block et inline</h2><p>L'une des premières choses que nous enseignons aux personnes qui découvrent le CSS, ce sont les concepts d'éléments en <code>block</code> et <code>inline</code>. Nous expliquons que certains éléments de la page sont <code>display : block</code> et qu'ils possèdent, de ce fait, certaines caractéristiques. Ils s'étirent dans le sens de la ligne, en occupant tout l'espace disponible. Ils s'ouvrent sur une nouvelle ligne ; nous pouvons leur donner une largeur, une hauteur, une marge ainsi qu'un remplissage, et ces propriétés éloigneront d'autres éléments de la page.</p><p>Nous savons également que certains éléments sont <code>display : inline</code>. Les éléments en ligne sont comme les mots d'une phrase ; ils ne provoquent pas un saut à la ligne, ils réservent un caractère d'espace blanc entre eux. Si vous ajoutez des marges et du padding, ces éléments s'afficheront mais ne repousseront pas les autres éléments.</p><p>Le comportement des éléments block et inline est fondamental pour CSS et pour qu'un document HTML correctement balisé soit lisible par défaut. Cette disposition est appelée "Block and Inline Layout" (<em>disposition en bloc et en ligne</em>) ou “Normal Flow” (<em>flux normal</em>), car c'est la façon dont les éléments se disposent si nous ne faisons rien d'autre pour eux.</p><h2>Valeurs internes et externes de display</h2><p>Nous comprenons ces notions de block et inline, mais que se passe-t-il si nous appliquons <code>display: grid</code> à un élément ? Est-ce quelque chose de complètement différent ? Si nous regardons un composant sur lequel nous avons spécifié <code>display: grid</code>, en tant qu'élément parent dans la mise en page il se comporte comme un élément de niveau bloc. L'élément s'étire et occupe tout l'espace disponible dans la dimension en ligne, il commence sur une nouvelle ligne. Il se comporte exactement comme un élément de type bloc en termes de comportement par rapport au reste de la mise en page. Pourtant nous n'avons pas dit <code>display: block</code>, n'est-ce pas ?</p><p>En fait, il s'avère que si. Dans la <a href="https://www.w3.org/TR/css-display-3/">spécification Display</a>, niveau 3, la valeur de <code>display</code> est définie par deux mots-clés. Ces mots-clés définissent la valeur <strong>externe</strong> de display, qui sera <code>inline</code> ou <code>block</code> et définira donc <em>comment l'élément se comporte dans la mise en page par rapport aux éléments qui l'entourent</em>. Ils définissent également la valeur <strong>interne</strong> de l'élément — ou comment <em>les enfants directs</em> de cet élément se comportent.</p><p>Autrement dit, que lorsque vous écrivez <code>display: grid</code>, ce que vous dites réellement c'est <code>display : block grid</code>. Vous demandez <em>un conteneur de grille de niveau bloc</em>. Un élément qui aura tous les attributs de <code>block</code> - vous pouvez lui donner une <code>height</code> et une <code>width</code>, une <code>margin</code> et un <code>padding</code>, et il s'étirera pour remplir le conteneur. Les enfants de ce conteneur, cependant, ont reçu la valeur interne de grid et deviennent donc des <code>items</code> de grille. Le comportement de ces <em><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#griditem">grid items</a></em> est défini dans la spécification de grille CSS : la spécification de <code>display</code> nous donne un moyen d'indiquer au navigateur que c'est la méthode de mise en page que nous voulons utiliser.</p><p>Je pense que cette façon de considérer <code>display</code> est extrêmement utile ; elle explique de façon claire et directe ce que nous faisons avec les différentes méthodes de mise en page. Si vous deviez spécifier <code>display: inline flex</code>, à quoi vous attendriez-vous ? Eh bien sans doute à une boîte se comportant comme un élément inline, avec des enfants qui seraient des items flex.</p><p>Il y a quelques autres choses qui s'expliquent facilement lorsqu'on envisage <code>display</code> de cette nouvelle manière, et je vais en examiner quelques-unes dans la suite de cet article.</p><h2>Nous revenons toujours au flux normal</h2><p>Pour comprendre ces propriétés d'affichage internes et externes, il peut être utile d'observer ce qui se passe si nous ne modifions pas du tout la valeur d'affichage. Si nous écrivons du HTML et que nous l'affichons dans un navigateur, nous obtenons une disposition en bloc et en ligne, ou un flux normal. Les éléments s'affichent comme des éléments bloc ou en ligne.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/ZZzPQE">Block and Inline Layout</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>L'exemple ci-dessous contient des balises que j'ai transformées en objet média, en faisant en sorte que les <code>div</code> <code>display: flex</code> (les deux enfants directs) deviennent des items flex, de sorte que l'image se trouve maintenant dans une rangée avec le contenu. Si vous regardez le contenu cependant, il y a un titre et un paragraphe qui s'affichent à nouveau en flux normal. Les enfants directs de l'objet média sont devenus des items flex ; leurs enfants reviennent à un flux normal à moins que nous ne changions la valeur de display sur l'item flex. Le conteneur flex lui-même est une boîte de niveau bloc, comme vous pouvez le voir par le fait que la bordure s'étend jusqu'aux bords de son parent.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/ZZzPQE">Block and Inline Layout with Flex Component</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si vous travaillez ainsi, les éléments de votre page se disposeront d'eux-mêmes avec cette belle disposition de flux normal lisible, plutôt que de lutter contre et d'essayer de tout placer. Vous êtes également moins susceptible de rencontrer des problèmes d'accessibilité, car vous travaillez avec l'ordre du document, ce qui est exactement ce que fait un lecteur d'écran ou une personne qui navigue dans le document via la tabulation.</p><h2>Expliquer <code>flow-root</code> et <code>inline-block</code></h2><p>La valeur de <code>inline-block</code> est également susceptible d'être familière à ceux d'entre nous qui font du CSS depuis un certain temps. Cette valeur est un moyen d'<a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline">obtenir certains comportements de bloc sur un élément inline</a>. Par exemple, un élément <a href="https://la-cascade.io/articles/'inline-block'">inline-block</a> peut avoir une largeur et une hauteur. Un élément avec <code>display: inline-block</code> se comporte également d'une manière intéressante en ce qu'il crée un contexte de formatage de type bloc (<em>Block Formatting Context</em>, BFC).</p><p>Un BFC fait certaines choses utiles en termes de mise en page, par exemple, il contient des floats. Pour en savoir plus sur les contextes de mise en forme des blocs, consultez mon article précédent intitulé "<a href="https://www.smashingmagazine.com/2017/12/understanding-css-layout-block-formatting-context/">Understanding CSS Layout And The Block Formatting Context</a>". Par conséquent, dire <code>display: inline-block</code> vous donne une <em>boîte inline</em> qui établit également un BFC.</p><p>Comme vous le découvrirez (si vous lisez l'article susmentionné sur le Contexte de formatage block), il existe une valeur plus récente de display qui crée aussi explicitement un BFC. Il s'agit de la valeur <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/display#flow-root"><code>flow-root</code></a>. Cette valeur crée un BFC sur un bloc, plutôt que sur un élément inline.</p><ul><li><code>display : inline-block</code> vous donne un BFC sur une boîte inline.</li>
<li><code>display : flow-root</code> vous donne un BFC sur une boîte block.</li>
</ul><p>Vous vous dites probablement que tout cela est un peu confus : pourquoi avons-nous deux mots-clés complètement différents ici, et qu'est-il arrivé à la syntaxe à deux valeurs dont nous parlions auparavant ? Eh bien cela nous amène justement à ce que je dois maintenant expliquer à propos de <code>display</code> : <em>CSS a un historique dont nous devons tenir compte</em> en termes de propriété <code>display</code>.</p><h3>Valeurs historiques de la propriété display</h3><p>La spécification CSS2 détaillait les valeurs suivantes pour la propriété <code>display</code> :</p><ul><li><code>inline</code></li>
<li><code>bloc</code></li>
<li><code>inline-block</code></li>
<li><code>list-item</code></li>
<li><code>none</code></li>
<li><code>table</code></li>
<li><code>inline-table</code></li>
</ul><p>Nous avons également défini les diverses propriétés internes du tableau, telles que <code>table-cell</code>, dont nous ne nous occuperons pas dans cet article.</p><p>Nous avons ensuite ajouté à celles-ci quelques valeurs pour l'affichage, afin de prendre en charge la mise en page flex et grid :</p><ul><li><code>grid</code></li>
<li><code>inline-grid</code></li>
<li><code>flex</code></li>
<li><code>inline-flex</code></li>
</ul><p>Remarque : la spécification définit également <code>ruby</code> et <code>inline-ruby</code> pour prendre en charge le texte Ruby, ce que vous pouvez lire dans <a href="https://drafts.csswg.org/css-ruby-1/#ruby-def">la spécification Ruby</a>.</p><p>Ce sont toutes des valeurs uniques pour la propriété <code>display</code>, définies avant que la spécification ne soit mise à jour. Un aspect fondamental de la construction de CSS est que nous ne devons jamais casser le Web ; <strong>nous ne pouvons pas <em>simplement</em> changer les choses</strong>. Nous ne pouvons pas décider soudainement que tout le monde doit utiliser cette nouvelle syntaxe à deux valeurs et que, par conséquent, tous les sites Web construits avec la syntaxe à une seule valeur se casseront si un développeur ne revient pas en arrière pour les corriger !</p><p>En réfléchissant à ce problème, vous apprécierez peut-être cette <a href="https://wiki.csswg.org/ideas/mistakes">liste d'erreurs</a> dans la conception de CSS qui sont moins des erreurs dans de nombreux cas que des choses qui ont été conçues sans boule de cristal pour voir dans l'avenir ! Cependant, le fait est que nous ne pouvons pas casser le Web, c'est pourquoi nous avons cette situation où actuellement les navigateurs supportent un ensemble de valeurs uniques pour l'affichage, et la spécification passe à deux valeurs pour l'affichage.</p><p>La façon dont nous contournons cette situation est de spécifier des valeurs anciennes et courtes pour l'affichage, ce qui inclut toutes ces valeurs uniques. Cela signifie qu'un mappage peut être défini entre les valeurs uniques et les nouvelles valeurs à deux mots-clés. Ce qui nous donne le tableau de valeurs suivant :</p><table class="specificTable"><thead><tr><th>Valeur Simple</th>
<th>Valeur en 2 mots</th>
<th>Description</th>
</tr></thead><tbody><tr><td><code>block</code></td>
<td><code>block flow</code></td>
<td>Block box with normal flow inner</td>
</tr><tr><td><code>flow-root</code></td>
<td><code>block flow-root</code></td>
<td>Block box defining a BFC</td>
</tr><tr><td><code>inline</code></td>
<td><code>inline flow</code></td>
<td>Inline box with normal flow inner</td>
</tr><tr><td><code>inline-block</code></td>
<td><code>inline flow-root</code></td>
<td>Inline box defining a BFC</td>
</tr><tr><td><code>list-item</code></td>
<td><code>block flow list-item</code></td>
<td>Block box with normal flow inner and additional marker box</td>
</tr><tr><td><code>flex</code></td>
<td><code>block flex</code></td>
<td>Block box with inner flex layout</td>
</tr><tr><td><code>inline-flex</code></td>
<td><code>inline flex</code></td>
<td>Inline box with inner flex layout</td>
</tr><tr><td><code>grid</code></td>
<td><code>block grid</code></td>
<td>Block box with inner grid layout</td>
</tr><tr><td><code>inline-grid</code></td>
<td><code>inline grid</code></td>
<td>Inline box with inner grid layout</td>
</tr><tr><td><code>table</code></td>
<td><code>block table</code></td>
<td>Block box with inner table layout</td>
</tr><tr><td><code>inline-table</code></td>
<td><code>inline table</code></td>
<td>Inline box with inner table layout</td>
</tr></tbody></table><p>Pour expliquer comment ça marche, nous prenons l'exemple d'un conteneur de grille. Dans le monde à deux valeurs, nous créerions un conteneur de grille de niveau bloc avec :</p><pre class="language-css">.container {
  display: block grid;
}</pre><p>Cependant, le mot-clé <em>legacy</em> fait la même chose :</p><pre class="language-css">.container {
  display: grid;
}</pre><p>Si, à la place, nous voulions un conteneur de grille en ligne, dans le monde à deux valeurs, nous utiliserions :</p><pre class="language-css">.container {
  display: inline grid;
}</pre><p>et avec les valeurs <em>legacy</em> :</p><pre class="language-css">.container {
  display: inline-grid;
}</pre><p>Après ce petit détour historique, nous pouvons maintenant revenir au point de départ de cette conversation et nous pencher sur <code>display: inline-block</code>. En regardant le tableau, vous pouvez voir que c'est défini dans le monde à deux valeurs comme <code>display: inline flow-root</code>. Il correspond maintenant à <code>display: flow-root</code> qui, dans un monde à deux valeurs, serait <code>display: block flow-root</code>. Un peu de rangement et de clarification de la façon dont ces choses sont définies. Une refactorisation de CSS, si vous voulez.</p><h2>Prise en charge de la syntaxe à deux valeurs par les navigateurs</h2><p>Pour l'instant, les navigateurs ne prennent pas en charge la syntaxe à deux valeurs pour la propriété display. Le bogue d'implémentation pour Firefox peut être trouvé <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038294">ici</a>. L'implémentation — lorsqu'elle aura lieu — consistera essentiellement à aliaser les anciennes valeurs vers les versions à deux valeurs. Il faudra donc attendre un bon moment avant que vous puissiez réellement utiliser ces versions à deux valeurs dans votre code. Cependant, ce n'est pas vraiment le sujet de cet article. Je pense plutôt que le fait d'examiner les valeurs d'affichage à la lumière du modèle à deux valeurs permet d'expliquer une grande partie de ce qui se passe.</p><p>Lorsque vous définissez la disposition d'une boîte en CSS, vous définissez ce qui arrive à cette boîte en termes de <strong>comportement par rapport à toutes les autres boîtes de la mise en page</strong>. Vous définissez également le comportement des enfants de cette boîte. Vous pouvez penser de cette manière bien avant de pouvoir déclarer explicitement les valeurs comme deux choses distinctes, car les mots-clés hérités correspondent à ces valeurs, et ça vous aidera à comprendre ce qui se passe lorsque vous modifiez la valeur de <code>display</code>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/approfondir-la-propriete-display-les%20deux-valeurs-de-display</link>
      <guid>https://la-cascade.io/articles/approfondir-la-propriete-display-les%20deux-valeurs-de-display</guid>
      <pubDate>Wed, 04 Mar 2020 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Approfondir la propriété display : les deux valeurs de display]]></title>
      <description><![CDATA[<p><em>Nous parlons beaucoup de Flexbox et de Grid Layout, mais ces méthodes de mise en page sont, à la base, des valeurs de la propriété CSS display, une puissante propriété qui ne reçoit pas toute l'attention qu'elle mérite. Rachel Andrew y jette un coup d'œil dans une courte série.</em></p><div class="articleContent"><p>Une mise en page <code>flex</code> ou <code>grid</code> commence par la déclaration <code>display: flex</code> ou <code>display: grid</code>. Ces méthodes de mise en page sont des valeurs de la propriété <a href="denied:javascript:void(0)">CSS display</a>. Nous avons tendance à ne pas beaucoup parler de cette propriété en tant que telle, nous concentrant plutôt sur les valeurs de <code>flex</code> ou de <code>grid</code>. Cependant, il y a des choses intéressantes à comprendre au sujet de <code>display</code> et de la façon dont elle est définie, qui vous faciliteront grandement la vie lorsque vous utiliserez CSS pour votre mise en page.</p><p>Dans cet article, le premier d'une série de deux, je vais examiner la manière dont les valeurs de <code>display</code> sont définies dans la spécification de niveau 3. Il s'agit d'un changement par rapport à la façon dont nous définissions <code>display</code> dans les versions précédentes de CSS. Même s'ils peuvent déranger, de prime abord, ceux d'entre nous qui font du CSS depuis de nombreuses années, je pense que ces changements aident vraiment à expliquer ce qui se passe lorsque nous modifions la valeur <code>display</code> d'un élément.</p><h2>Éléments block et inline</h2><p>L'une des premières choses que nous enseignons aux personnes qui découvrent le CSS, ce sont les concepts d'éléments en <code>block</code> et <code>inline</code>. Nous expliquons que certains éléments de la page sont <code>display : block</code> et qu'ils possèdent, de ce fait, certaines caractéristiques. Ils s'étirent dans le sens de la ligne, en occupant tout l'espace disponible. Ils s'ouvrent sur une nouvelle ligne ; nous pouvons leur donner une largeur, une hauteur, une marge ainsi qu'un remplissage, et ces propriétés éloigneront d'autres éléments de la page.</p><p>Nous savons également que certains éléments sont <code>display : inline</code>. Les éléments en ligne sont comme les mots d'une phrase ; ils ne provoquent pas un saut à la ligne, ils réservent un caractère d'espace blanc entre eux. Si vous ajoutez des marges et du padding, ces éléments s'afficheront mais ne repousseront pas les autres éléments.</p><p>Le comportement des éléments block et inline est fondamental pour CSS et pour qu'un document HTML correctement balisé soit lisible par défaut. Cette disposition est appelée "Block and Inline Layout" (<em>disposition en bloc et en ligne</em>) ou “Normal Flow” (<em>flux normal</em>), car c'est la façon dont les éléments se disposent si nous ne faisons rien d'autre pour eux.</p><h2>Valeurs internes et externes de display</h2><p>Nous comprenons ces notions de block et inline, mais que se passe-t-il si nous appliquons <code>display: grid</code> à un élément ? Est-ce quelque chose de complètement différent ? Si nous regardons un composant sur lequel nous avons spécifié <code>display: grid</code>, en tant qu'élément parent dans la mise en page il se comporte comme un élément de niveau bloc. L'élément s'étire et occupe tout l'espace disponible dans la dimension en ligne, il commence sur une nouvelle ligne. Il se comporte exactement comme un élément de type bloc en termes de comportement par rapport au reste de la mise en page. Pourtant nous n'avons pas dit <code>display: block</code>, n'est-ce pas ?</p><p>En fait, il s'avère que si. Dans la <a href="https://www.w3.org/TR/css-display-3/">spécification Display</a>, niveau 3, la valeur de <code>display</code> est définie par deux mots-clés. Ces mots-clés définissent la valeur <strong>externe</strong> de display, qui sera <code>inline</code> ou <code>block</code> et définira donc <em>comment l'élément se comporte dans la mise en page par rapport aux éléments qui l'entourent</em>. Ils définissent également la valeur <strong>interne</strong> de l'élément — ou comment <em>les enfants directs</em> de cet élément se comportent.</p><p>Autrement dit, que lorsque vous écrivez <code>display: grid</code>, ce que vous dites réellement c'est <code>display : block grid</code>. Vous demandez <em>un conteneur de grille de niveau bloc</em>. Un élément qui aura tous les attributs de <code>block</code> - vous pouvez lui donner une <code>height</code> et une <code>width</code>, une <code>margin</code> et un <code>padding</code>, et il s'étirera pour remplir le conteneur. Les enfants de ce conteneur, cependant, ont reçu la valeur interne de grid et deviennent donc des <code>items</code> de grille. Le comportement de ces <em><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#griditem">grid items</a></em> est défini dans la spécification de grille CSS : la spécification de <code>display</code> nous donne un moyen d'indiquer au navigateur que c'est la méthode de mise en page que nous voulons utiliser.</p><p>Je pense que cette façon de considérer <code>display</code> est extrêmement utile ; elle explique de façon claire et directe ce que nous faisons avec les différentes méthodes de mise en page. Si vous deviez spécifier <code>display: inline flex</code>, à quoi vous attendriez-vous ? Eh bien sans doute à une boîte se comportant comme un élément inline, avec des enfants qui seraient des items flex.</p><p>Il y a quelques autres choses qui s'expliquent facilement lorsqu'on envisage <code>display</code> de cette nouvelle manière, et je vais en examiner quelques-unes dans la suite de cet article.</p><h2>Nous revenons toujours au flux normal</h2><p>Pour comprendre ces propriétés d'affichage internes et externes, il peut être utile d'observer ce qui se passe si nous ne modifions pas du tout la valeur d'affichage. Si nous écrivons du HTML et que nous l'affichons dans un navigateur, nous obtenons une disposition en bloc et en ligne, ou un flux normal. Les éléments s'affichent comme des éléments bloc ou en ligne.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/ZZzPQE">Block and Inline Layout</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>L'exemple ci-dessous contient des balises que j'ai transformées en objet média, en faisant en sorte que les <code>div</code> <code>display: flex</code> (les deux enfants directs) deviennent des items flex, de sorte que l'image se trouve maintenant dans une rangée avec le contenu. Si vous regardez le contenu cependant, il y a un titre et un paragraphe qui s'affichent à nouveau en flux normal. Les enfants directs de l'objet média sont devenus des items flex ; leurs enfants reviennent à un flux normal à moins que nous ne changions la valeur de display sur l'item flex. Le conteneur flex lui-même est une boîte de niveau bloc, comme vous pouvez le voir par le fait que la bordure s'étend jusqu'aux bords de son parent.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/ZZzPQE">Block and Inline Layout with Flex Component</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si vous travaillez ainsi, les éléments de votre page se disposeront d'eux-mêmes avec cette belle disposition de flux normal lisible, plutôt que de lutter contre et d'essayer de tout placer. Vous êtes également moins susceptible de rencontrer des problèmes d'accessibilité, car vous travaillez avec l'ordre du document, ce qui est exactement ce que fait un lecteur d'écran ou une personne qui navigue dans le document via la tabulation.</p><h2>Expliquer <code>flow-root</code> et <code>inline-block</code></h2><p>La valeur de <code>inline-block</code> est également susceptible d'être familière à ceux d'entre nous qui font du CSS depuis un certain temps. Cette valeur est un moyen d'<a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline">obtenir certains comportements de bloc sur un élément inline</a>. Par exemple, un élément <a href="https://la-cascade.io/articles/'inline-block'">inline-block</a> peut avoir une largeur et une hauteur. Un élément avec <code>display: inline-block</code> se comporte également d'une manière intéressante en ce qu'il crée un contexte de formatage de type bloc (<em>Block Formatting Context</em>, BFC).</p><p>Un BFC fait certaines choses utiles en termes de mise en page, par exemple, il contient des floats. Pour en savoir plus sur les contextes de mise en forme des blocs, consultez mon article précédent intitulé "<a href="https://www.smashingmagazine.com/2017/12/understanding-css-layout-block-formatting-context/">Understanding CSS Layout And The Block Formatting Context</a>". Par conséquent, dire <code>display: inline-block</code> vous donne une <em>boîte inline</em> qui établit également un BFC.</p><p>Comme vous le découvrirez (si vous lisez l'article susmentionné sur le Contexte de formatage block), il existe une valeur plus récente de display qui crée aussi explicitement un BFC. Il s'agit de la valeur <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/display#flow-root"><code>flow-root</code></a>. Cette valeur crée un BFC sur un bloc, plutôt que sur un élément inline.</p><ul><li><code>display : inline-block</code> vous donne un BFC sur une boîte inline.</li>
<li><code>display : flow-root</code> vous donne un BFC sur une boîte block.</li>
</ul><p>Vous vous dites probablement que tout cela est un peu confus : pourquoi avons-nous deux mots-clés complètement différents ici, et qu'est-il arrivé à la syntaxe à deux valeurs dont nous parlions auparavant ? Eh bien cela nous amène justement à ce que je dois maintenant expliquer à propos de <code>display</code> : <em>CSS a un historique dont nous devons tenir compte</em> en termes de propriété <code>display</code>.</p><h3>Valeurs historiques de la propriété display</h3><p>La spécification CSS2 détaillait les valeurs suivantes pour la propriété <code>display</code> :</p><ul><li><code>inline</code></li>
<li><code>bloc</code></li>
<li><code>inline-block</code></li>
<li><code>list-item</code></li>
<li><code>none</code></li>
<li><code>table</code></li>
<li><code>inline-table</code></li>
</ul><p>Nous avons également défini les diverses propriétés internes du tableau, telles que <code>table-cell</code>, dont nous ne nous occuperons pas dans cet article.</p><p>Nous avons ensuite ajouté à celles-ci quelques valeurs pour l'affichage, afin de prendre en charge la mise en page flex et grid :</p><ul><li><code>grid</code></li>
<li><code>inline-grid</code></li>
<li><code>flex</code></li>
<li><code>inline-flex</code></li>
</ul><p>Remarque : la spécification définit également <code>ruby</code> et <code>inline-ruby</code> pour prendre en charge le texte Ruby, ce que vous pouvez lire dans <a href="https://drafts.csswg.org/css-ruby-1/#ruby-def">la spécification Ruby</a>.</p><p>Ce sont toutes des valeurs uniques pour la propriété <code>display</code>, définies avant que la spécification ne soit mise à jour. Un aspect fondamental de la construction de CSS est que nous ne devons jamais casser le Web ; <strong>nous ne pouvons pas <em>simplement</em> changer les choses</strong>. Nous ne pouvons pas décider soudainement que tout le monde doit utiliser cette nouvelle syntaxe à deux valeurs et que, par conséquent, tous les sites Web construits avec la syntaxe à une seule valeur se casseront si un développeur ne revient pas en arrière pour les corriger !</p><p>En réfléchissant à ce problème, vous apprécierez peut-être cette <a href="https://wiki.csswg.org/ideas/mistakes">liste d'erreurs</a> dans la conception de CSS qui sont moins des erreurs dans de nombreux cas que des choses qui ont été conçues sans boule de cristal pour voir dans l'avenir ! Cependant, le fait est que nous ne pouvons pas casser le Web, c'est pourquoi nous avons cette situation où actuellement les navigateurs supportent un ensemble de valeurs uniques pour l'affichage, et la spécification passe à deux valeurs pour l'affichage.</p><p>La façon dont nous contournons cette situation est de spécifier des valeurs anciennes et courtes pour l'affichage, ce qui inclut toutes ces valeurs uniques. Cela signifie qu'un mappage peut être défini entre les valeurs uniques et les nouvelles valeurs à deux mots-clés. Ce qui nous donne le tableau de valeurs suivant :</p><table class="specificTable"><thead><tr><th>Valeur Simple</th>
<th>Valeur en 2 mots</th>
<th>Description</th>
</tr></thead><tbody><tr><td><code>block</code></td>
<td><code>block flow</code></td>
<td>Block box with normal flow inner</td>
</tr><tr><td><code>flow-root</code></td>
<td><code>block flow-root</code></td>
<td>Block box defining a BFC</td>
</tr><tr><td><code>inline</code></td>
<td><code>inline flow</code></td>
<td>Inline box with normal flow inner</td>
</tr><tr><td><code>inline-block</code></td>
<td><code>inline flow-root</code></td>
<td>Inline box defining a BFC</td>
</tr><tr><td><code>list-item</code></td>
<td><code>block flow list-item</code></td>
<td>Block box with normal flow inner and additional marker box</td>
</tr><tr><td><code>flex</code></td>
<td><code>block flex</code></td>
<td>Block box with inner flex layout</td>
</tr><tr><td><code>inline-flex</code></td>
<td><code>inline flex</code></td>
<td>Inline box with inner flex layout</td>
</tr><tr><td><code>grid</code></td>
<td><code>block grid</code></td>
<td>Block box with inner grid layout</td>
</tr><tr><td><code>inline-grid</code></td>
<td><code>inline grid</code></td>
<td>Inline box with inner grid layout</td>
</tr><tr><td><code>table</code></td>
<td><code>block table</code></td>
<td>Block box with inner table layout</td>
</tr><tr><td><code>inline-table</code></td>
<td><code>inline table</code></td>
<td>Inline box with inner table layout</td>
</tr></tbody></table><p>Pour expliquer comment ça marche, nous prenons l'exemple d'un conteneur de grille. Dans le monde à deux valeurs, nous créerions un conteneur de grille de niveau bloc avec :</p><pre class="language-css">.container {
  display: block grid;
}</pre><p>Cependant, le mot-clé <em>legacy</em> fait la même chose :</p><pre class="language-css">.container {
  display: grid;
}</pre><p>Si, à la place, nous voulions un conteneur de grille en ligne, dans le monde à deux valeurs, nous utiliserions :</p><pre class="language-css">.container {
  display: inline grid;
}</pre><p>et avec les valeurs <em>legacy</em> :</p><pre class="language-css">.container {
  display: inline-grid;
}</pre><p>Après ce petit détour historique, nous pouvons maintenant revenir au point de départ de cette conversation et nous pencher sur <code>display: inline-block</code>. En regardant le tableau, vous pouvez voir que c'est défini dans le monde à deux valeurs comme <code>display: inline flow-root</code>. Il correspond maintenant à <code>display: flow-root</code> qui, dans un monde à deux valeurs, serait <code>display: block flow-root</code>. Un peu de rangement et de clarification de la façon dont ces choses sont définies. Une refactorisation de CSS, si vous voulez.</p><h2>Prise en charge de la syntaxe à deux valeurs par les navigateurs</h2><p>Pour l'instant, les navigateurs ne prennent pas en charge la syntaxe à deux valeurs pour la propriété display. Le bogue d'implémentation pour Firefox peut être trouvé <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1038294">ici</a>. L'implémentation — lorsqu'elle aura lieu — consistera essentiellement à aliaser les anciennes valeurs vers les versions à deux valeurs. Il faudra donc attendre un bon moment avant que vous puissiez réellement utiliser ces versions à deux valeurs dans votre code. Cependant, ce n'est pas vraiment le sujet de cet article. Je pense plutôt que le fait d'examiner les valeurs d'affichage à la lumière du modèle à deux valeurs permet d'expliquer une grande partie de ce qui se passe.</p><p>Lorsque vous définissez la disposition d'une boîte en CSS, vous définissez ce qui arrive à cette boîte en termes de <strong>comportement par rapport à toutes les autres boîtes de la mise en page</strong>. Vous définissez également le comportement des enfants de cette boîte. Vous pouvez penser de cette manière bien avant de pouvoir déclarer explicitement les valeurs comme deux choses distinctes, car les mots-clés hérités correspondent à ces valeurs, et ça vous aidera à comprendre ce qui se passe lorsque vous modifiez la valeur de <code>display</code>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/approfondir-la-propriete-display-les-deux-valeurs-de-display</link>
      <guid>https://la-cascade.io/articles/approfondir-la-propriete-display-les-deux-valeurs-de-display</guid>
      <pubDate>Wed, 04 Mar 2020 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Sticky footer, de 5 façons]]></title>
      <description><![CDATA[<p><em>Une brève histoire des sticky footers, par Chris Coyier, depuis les pieds de page collants à l'ancienne jusqu'aux techniques Flexbox et CSS-Grid.</em></p><div class="articleContent"><p>Un sticky footer ("pied de page collant" ou "bas de page adhérant") est un pied de page qui reste "collé" au bas de la fenêtre du navigateur — mais pas toujours : s'il y a assez de contenu pour remplir la fenêtre, le footer suit le contenu et n'apparaît pas, si au contraire il n'y a pas assez de contenu, le footer sera collé en bas de page.</p><figure><img src="https://la-cascade.io/images/sticky_footer-compressor.jpeg" alt="" /></figure><p>Voici 5 façons possibles de créer un sticky footer, des plus anciennes aux plus récentes :</p><h2>Marges négatives sur les wrappers</h2><p>Autrefois on utilisait un élément qui enveloppait tout le contenu à l'exception du pied de page. Cet élément "wrapper" avait une marge négative égale à la hauteur du pied de page.</p><pre class="language-html">&lt;body&gt;
  &lt;div class="wrapper"&gt;
    content
    &lt;div class="push"&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;footer class="footer"&gt;&lt;/footer&gt;
&lt;/body&gt;</pre><p>et</p><pre class="language-css">html,
body {
  height: 100%;
  margin: 0;
}
.wrapper {
  min-height: 100%;
  /* Égal à la hauteur du footer */
  /* Tient compte aussi d'une possible margin-bottom du dernier enfant */
  margin-bottom: -50px;
}
.footer,
.push {
  height: 50px;
}</pre><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<em>Pen</em><a href="https://codepen.io/chriscoyier/pen/VjZmGj">Sticky Footer with Negative Margin 1</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Pour y parvenir on a utilisé un élément supplémentaire (le <code>.push</code>) pour s'assurer que la marge négative ne tire pas le footer vers le haut ce qui aurait recouvert une partie du contenu.</p><h2>Marge supérieure négative sur le footer</h2><p><a href="https://www.cssstickyfooter.com/">Cette autre technique</a> ne faisait pas appel à un élément <em>push</em> mais à un élément enveloppant supplémentaire dans lequel on appliquait un padding inférieur correspondant. Là encore, pour éviter que la marge négative ne fasse passer le footer par-dessus un contenu.</p><pre class="language-html">&lt;body&gt;
  &lt;div class="content"&gt;
    &lt;div class="content-inside"&gt;content&lt;/div&gt;
  &lt;/div&gt;
  &lt;footer class="footer"&gt;&lt;/footer&gt;
&lt;/body&gt;</pre><p>et</p><pre class="language-css">html,
body {
  height: 100%;
  margin: 0;
}
.content {
  min-height: 100%;
}
.content-inside {
  padding: 20px;
  padding-bottom: 50px;
}
.footer {
  height: 50px;
  margin-top: -50px;
}</pre><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<em>Pen</em><a href="https://codepen.io/chriscoyier/pen/aZoBMb">Sticky Footer with Negative Margin 2</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Le point commun à ces deux techniques est qu'elles requièrent toutes deux des éléments HTML supplémentaires qui n'ont d'autre utilité que positionnelle.</p><h2>Hauteur du wrapper calculée</h2><p><a href="https://priteshgupta.com/2016/05/sticky-css-footer/">Une façon</a> d'éviter le recours à des éléments HTML inutiles consiste à ajuster la hauteur de l'élément enveloppant à l'aide de CSS <code>calc()</code>. Il n'y a plus de tuilage, ce sont simplement deux éléments empilés l'un sur l'autre ayant une hauteur totale de 100%.</p><pre class="language-html">&lt;body&gt;
  &lt;div class="content"&gt;content&lt;/div&gt;
  &lt;footer class="footer"&gt;&lt;/footer&gt;
&lt;/body&gt;</pre><p>et</p><pre class="language-css">.content {
  min-height: calc(100vh - 70px);
}
.footer {
  height: 50px;
}</pre><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<em>Pen</em><a href="https://codepen.io/chriscoyier/pen/jqRXBz">Sticky Footer with calc();</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez les 70px dans la formule de <code>calc()</code>, comparés aux 50px de la taille fixe du footer. On suppose en fait que le dernier item du contenu aura une marge inférieure de 20px. C'est donc la somme de cette marge et de la hauteur du footer qu'il convient de soustraire de la hauteur du viewport. Et remarquez aussi que nous utilisons les unités viewport ici (<code>vh</code>) afin d'éviter d'avoir à régler la hauteur de <code>body</code> à 100% avant de pouvoir régler celle du wrapper à 100%.</p><h2>Il y a Flexbox</h2><p>Le grand problème des trois techniques précédentes est qu'elles requièrent un footer de hauteur fixe. Dans le design web, les hauteurs fixes sont en général un mauvais choix, le contenu peut changer, les choses sont flexibles et donc les hauteurs fixes devraient être évitées. La solution <a href="https://la-cascade.io/tags/flexbox">Flexbox</a> non seulement ne nécessite pas d'élément supplémentaire mais permet d'avoir une hauteur de footer variable.</p><pre class="language-html">&lt;body&gt;
  &lt;div class="content"&gt;content&lt;/div&gt;
  &lt;footer class="footer"&gt;&lt;/footer&gt;
&lt;/body&gt;</pre><p>et</p><pre class="language-css">html,
body {
  height: 100%;
}
body {
  display: flex;
  flex-direction: column;
}
.content {
  flex: 1 0 auto;
}
.footer {
  flex-shrink: 0;
}</pre><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<em>Pen</em><a href="https://codepen.io/chriscoyier/pen/RRbKrL">Sticky Footer with Flexbox</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>On pourrait même ajouter un header ou d'autres éléments. Le "truc" avec Flexbox c'est :</p><ul><li>soit <code>flex: 1</code> sur l'élément enfant qu'on veut agrandir pour qu'il remplisse l'espace (ici, le contenu),</li>
<li>soit <code>margin-top: auto</code> pour pousser l'élément enfant aussi loin que possible de son voisin (ou toute autre marge selon la direction souhaitée).</li>
</ul><p>N'oubliez pas que nous avons un <a href="https://la-cascade.io/articles/flexbox-guide-complet/">guide complet sur Flexbox</a> ici même pour plus d'infos.</p><h2>Il y a CSS Grid</h2><p><a href="https://la-cascade.io/tags/cssgrid">CSS Grid Layout</a> est plus récent que Flexbox mais <a href="https://caniuse.com/#feat=css-grid">largement supporté aujourd'hui</a>. On peut l'utiliser facilement pour créer un sticky footer.</p><pre class="language-html">&lt;body&gt;
  &lt;div class="content"&gt;content&lt;/div&gt;
  &lt;footer class="footer"&gt;&lt;/footer&gt;
&lt;/body&gt;</pre><p>et</p><pre class="language-css">html {
  height: 100%;
}
body {
  min-height: 100%;
  display: grid;
  grid-template-rows: 1fr auto;
}
.footer {
  grid-row-start: 2;
  grid-row-end: 3;
}</pre><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<em>Pen</em><a href="https://codepen.io/chriscoyier/pen/YWKNrE">Sticky Footer with Grid</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>N'oubliez pas que nous avons un <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet">guide complet sur CSS Grid</a> ici même pour plus d'infos.</p></div>]]></description>
      <link>https://la-cascade.io/articles/sticky-footer-de-5-facons</link>
      <guid>https://la-cascade.io/articles/sticky-footer-de-5-facons</guid>
      <pubDate>Fri, 03 Jan 2020 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Listes CSS, marqueurs et compteurs]]></title>
      <description><![CDATA[<p><em>Styliser des listes en CSS plus facile qu'on ne le pense . Dans cet article, Rachel commence par examiner les listes en CSS, puis passe à certaines fonctionnalités intéressantes définies dans la spécification CSS Lists - les marqueurs et les compteurs.</em></p><div class="articleContent"><p>Les listes en CSS ont des propriétés propres qui nous donnent le style de liste standard que nous attendons : une liste non ordonnée gagne une puce de liste, de type disque, et les listes ordonnées sont numérotées. Mon intérêt pour l'exploration plus détaillée des listes est né du travail que j'ai effectué pour <a href="https://developer.mozilla.org/fr/docs/Web/CSS/::marker">documenter le pseudo-élément <code>::marker</code></a> pour <a href="https://developer.mozilla.org/fr/">MDN</a>. Ce pseudo-élément est livré dans Firefox 68 et il est publié aujourd'hui. Avec le pseudo-élément <code>::marker</code> à notre disposition, nous pouvons commencer à faire des choses intéressantes avec les listes, et dans cet article, je vais vous en dire plus.</p><h2>Déconstruire une liste</h2><p>Vous n'avez peut-être pas beaucoup exploré les listes, bien que nous les utilisions fréquemment dans notre balisage. De nombreuses choses peuvent être balisées de manière assez logique sous forme de liste : les instructions étape par étape ou les éléments classés peuvent être décrits assez naturellement par une liste ordonnée <code>&lt;ol&gt;</code>, de nombreuses choses dans une conception de page peuvent être décrites à l'aide d'une liste non ordonnée <code>&lt;ul&gt;</code>. Par exemple, ne utilisation très courante de l'élément liste consiste à baliser la navigation, puisqu'il s'agit d'une liste de destinations sur le site. Pour notre exploration, commençons par découvrir ce qu'est exactement une liste en CSS.</p><p>Comme pour beaucoup de choses en CSS, les listes se voient appliquer certaines <em>valeurs initiales</em>. Ces valeurs leur donnent l'apparence d'une liste. Ces valeurs spéciales commencent par l'information selon laquelle un élément de liste possède la propriété <code>display</code> avec une valeur de <code>list-item</code>. Cela crée <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline">une boîte de niveau bloc</a>, ainsi qu'une boîte de marqueur supplémentaire. La boîte de marqueur est l'endroit où la puce, ou le numéro de la liste, est ajouté.</p><p>Les listes ont été définies très tôt dans CSS, et une grande partie de la définition des listes telles que nous les utilisons aujourd'hui provient de CSS2. <a href="https://www.w3.org/TR/CSS2/generate.html#lists">La spécification CSS2 décrit un élément de liste</a> comme suit :</p><blockquote>
<p>"<em>Un élément affiché avec <code>display : list-item</code> génère un bloc principal pour le contenu de l'élément et, selon les valeurs de <code>list-style-type</code> et <code>list-style-image</code>, éventuellement aussi un bloc marqueur comme indication visuelle que l'élément est un élément de liste.</em>"</p>
</blockquote><p>La <em>boîte de bloc principale</em> est la boîte principale de l'élément et contient tous les enfants, car un élément de liste peut contenir d'autres balises. La boîte de marqueur est placée par rapport à cette boîte principale. La spécification détaille ensuite le fait que toute couleur d'arrière-plan s'appliquera uniquement derrière cette boîte principale, et non derrière le marqueur. Elle précise également que le marqueur peut être défini sur l'une des valeurs prédéfinies :</p><ul><li><code>disc</code></li>
<li><code>circle</code></li>
<li><code>square</code></li>
<li><code>decimal</code></li>
<li><code>decimal-leading-zero</code></li>
<li><code>lower-roman</code></li>
<li><code>upper-roman</code></li>
<li><code>lower-greek</code></li>
<li><code>lower-latin</code></li>
<li><code>upper-latin</code></li>
<li><code>armenian</code></li>
<li><code>georgian</code></li>
<li><code>lower-alpha</code></li>
<li><code>upper-alpha</code></li>
<li><code>none</code></li>
<li><code>inherit</code></li>
</ul><p>La <a href="https://drafts.csswg.org/css-display/#list-items">spécification d'affichage de niveau 3 définit <code>display : list-item</code></a> avec les autres valeurs possibles pour la propriété <code>display</code>. Elle renvoie à CSS 2.1 — comme de nombreuses propriétés et valeurs CSS qui proviennent de CSS2 — mais décrit le mot-clé <code>list-item</code> comme "faisant en sorte que l'élément génère un pseudo-élément <code>::marker</code>".</p><p>La spécification de niveau 3 introduit également la possibilité de créer un élément de liste en ligne (<code>inline</code>) avec la syntaxe à deux valeurs utilisée <code>display : inline list-item</code>. Ceci n'est pas encore implémenté par les navigateurs.</p><h2>Création de boîtes marqueur sur des éléments autres que des listes</h2><p>Comme pour les autres valeurs de <code>display</code>, il est parfaitement valable de donner à tout élément HTML un type d'affichage de <code>list-item</code> (si vous souhaitez générer un pseudo-élément <code>::marker</code> sur l'élément). L'élément ne deviendra pas sémantiquement un élément de liste, mais il ne s'affichera visuellement que comme un élément de liste, et pourra donc avoir un <code>::marker</code>. Lorsque nous aborderons le pseudo-élément <code>::marker</code> ci-dessous, vous découvrirez certains cas où donner à d'autres éléments <code>display : list-item</code> peut être utile.</p><h2>La spécification des listes CSS de niveau 3, ::marker et les compteurs</h2><p>La spécification d'affichage étend et clarifie la définition des listes que nous trouvons dans CSS2, cependant, il existe également une spécification qui définit le comportement des listes en détail : la <a href="https://www.w3.org/TR/css-lists-3/">spécification CSS Lists Level 3</a>. Comme le comportement de base des éléments de liste est défini dans <code>display</code>, cette spécification détaille la boîte de marqueurs générée lorsque quelque chose a <code>display : list-item</code> ainsi que les compteurs qui sont utilisés par défaut lorsque vous créez une liste ordonnée. Ces caractéristiques permettent d'accéder à certaines fonctionnalités potentiellement utiles.</p><h2>Le pseudo-élément ::marker</h2><p>Le pseudo-élément <code>::marker</code> vous permet de cibler le marqueur de liste — séparément du contenu de l'élément de liste. Cela n'était pas possible dans les versions précédentes de CSS. Par conséquent, si vous modifiez la couleur ou la taille de la police du <code>ul</code> ou du <code>li</code>, cela modifie également la couleur et la taille de la police des marqueurs. Pour faire quelque chose d'apparemment simple comme avoir des puces de liste de couleur différente de celle du texte, il faudrait soit envelopper le contenu de l'élément de liste dans un <code>span</code> (ou utiliser une image pour le marqueur).</p><pre class="language-css">ul {
  color: #00b7a8;
}
ul span {
  color #333;
}</pre><p>Avec le pseudo-élément <code>::marker</code>, la chose la plus simple que vous pourriez vouloir essayer est d'avoir une couleur de puce à texte différente, ce qui signifie qu'au lieu du code dans l'exemple ci-dessus, vous pouvez utiliser :</p><pre class="language-css">ul {
  color: #333;
}
ul ::marker {
  color: #00b7a8;
}</pre><p>Vous pouvez également utiliser une taille et une police de caractères différentes pour la numérotation d'une liste ordonnée.</p><pre class="language-css">ol ::marker {
  font-size: 200%;
  color: #00b7a8;
  font-family: 'Comic Sans MS', cursive, sans-serif;
}</pre><p>Vous pouvez voir tout cela dans un navigateur compatible en utilisant mon exemple CodePen :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/VJQyoR">Smashing: colored bullets with and without ::marker</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Vous pouvez utiliser le pseudo-élément <code>::marker</code> sur les éléments qui ne sont pas des listes. Dans le code ci-dessous, j'ai défini un titre pour <code>display : list-item</code>. Cela lui donne une puce et donc une boîte <code>::marker</code> à cibler.</p><p>J'ai changé la puce pour utiliser un emoji :</p><pre class="language-css">h1 {
  display: list-item;
}
h1::marker {
  content: '?';
}</pre><figure><img src="https://la-cascade.io/images/heading.webp" alt="Dans firefox on peut voir l'emoji utilisé comme marqueur" /></figure><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/wLyyMG">Smashing heading and ::marker</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Dans l'exemple ci-dessus, j'ai utilisé du contenu généré dans les règles relatives au marqueur. Seul un petit sous-ensemble de propriétés CSS est disponible pour une utilisation sur <code>::marker</code>. Il s'agit notamment des propriétés de police et de la couleur, mais aussi de la propriété content, permettant d'inclure du contenu généré.</p><p>L'ajout de la propriété <code>content</code> comme propriété autorisée pour <code>::marker</code> est récent, cependant, elle est incluse dans l'implémentation de Firefox. Cet ajout nous permet de faire des choses comme inclure une chaîne de texte dans un <code>::marker</code>. Elle offre également des possibilités supplémentaires pour le formatage des marqueurs lorsque vous combinez l'utilisation de compteurs avec <code>::marker</code>.</p><h2>Prise en charge par les navigateurs et solutions de repli</h2><p>Pour les navigateurs qui ne prennent pas en charge le pseudo-élément <code>::marker</code>, la solution de repli est le marqueur ordinaire qui aurait été affiché de toute façon. Malheureusement, nous ne pouvons pas actuellement utiliser les <em>Feature Queries</em> pour détecter la prise en charge de sélecteurs tels que ce pseudo-élément, bien qu'un <a href="https://github.com/w3c/csswg-drafts/issues/3207">"ticket" ait été ouvert</a> concernant l'ajout de cette fonctionnalité à la spécification. Cela signifie que vous ne pouvez pas avoir une "fourche" dans votre code pour faire une chose lorsque vous avez la prise en charge et autre chose si vous ne l'avez pas. Dans la plupart des cas, se rabattre sur le marqueur ordinaire sera une solution raisonnable.</p><h2>Compteurs</h2><p>Les listes ordonnées ont une numérotation de liste — ce qui est réalisé par le biais d'un compteur CSS. La spécification CSS Lists décrit donc également ces compteurs. Nous pouvons accéder aux compteurs et les créer nous-mêmes, ce qui, combiné au pseudo-élément ::marker, peut nous donner des fonctionnalités utiles. Ces compteurs peuvent également être utilisés dans du contenu généré ordinaire (non <code>::marker</code>).</p><p>Si j'ai une liste d'étapes numérotées (et que je souhaite écrire "Étape 1", "Étape 2", etc.), je peux le faire en utilisant le contenu généré dans mon marqueur et en ajoutant le compteur list-item, qui représente le compteur intégré :</p><pre class="language-css">::marker {
  content: 'Etape ' counter(list-item) ': ';
}</pre><figure><img src="https://la-cascade.io/images/counter.webp" alt="Dans firefox on peut voir le compteur, préfixé par le mot 'Step'" /></figure><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/BgRaoz">Smashing heading and ::marker</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Compteurs imbriqués</h2><p>Si vous avez des listes imbriquées, une façon courante de les numéroter est de donner à l'élément de premier niveau un nombre entier, (1), puis aux éléments enfants (1.1, 1.2) et à leurs enfants (1.1.1, 1.1.2), et ainsi de suite. Vous pouvez y parvenir en utilisant d'autres fonctionnalités des compteurs.</p><p>Lorsque vous imbriquez des listes HTML, vous vous retrouvez avec plusieurs compteurs du même nom — imbriqués les uns dans les autres. Vous pouvez accéder à l'imbrication des compteurs à l'aide de la fonction <code>counters()</code>.</p><p>Dans le code ci-dessous, j'utilise <code>counters()</code> pour formater mes marqueurs de liste comme décrit ci-dessus. Le premier argument de <code>counters()</code> est le nom du compteur à utiliser. J'utilise le compteur intégré <code>list-item</code>. Le deuxième argument est une chaîne — c'est ce qui sera concaténé entre les compteurs de sortie (j'utilise un <code>.</code>). Enfin, j'ajoute un <code>:</code> à l'extérieur de la fonction compteur mais à l'intérieur de la valeur du contenu afin que la sortie de mon compteur soit séparée du contenu par un deux-points.</p><pre class="language-css">::marker {
  content: counters(list-item, '.') ':';
  color: #00b7a8;
  font-weight: bold;
}</pre><p>Cela me donne une sortie comme dans l'image. Si vous utilisez un navigateur qui prend en charge <code>::marker</code> et les compteurs, vous pouvez le voir fonctionner dans l'exemple CodePen - essayez de changer la chaîne de caractères d'un <code>.</code> à autre chose pour voir comment cela change la sortie.</p><figure><img src="https://la-cascade.io/images/firefox-nested-counters.webp" alt="Dans firefox on peut voir la numérotation des listes et sous-listes séparées par un point" /></figure><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/VJbwxL">Nested Counters</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Quelle est la différence entre counter() et counters() ?</h2><p>La fonction <code>counter()</code> que nous avons utilisée dans le premier exemple pour écrire nos étapes utilise uniquement le compteur le plus intérieur. Par conséquent, dans la situation où vous avez un ensemble de listes imbriquées, vous écrirez le compteur qui correspond au niveau où vous vous trouvez actuellement.</p><p>La fonction <code>counters()</code> écrit essentiellement cette branche entière et vous donne la possibilité de concaténer une chaîne entre les compteurs de la branche. Ainsi, si vous avez un élément de liste avec un compteur de 2 (qui fait partie d'une liste imbriquée dans un élément de liste avec un compteur de 4), alors la branche contient :</p><p>Vous pouvez l'afficher sous la forme 4.2 dans le marqueur en utilisant :</p><pre class="language-css">::marker {
  content: counters(list-item, '.');
}</pre><h3>Compteurs sur d'autres éléments</h3><p>Les compteurs peuvent être utilisés sur des éléments qui ne sont pas des listes — soit pour afficher un marqueur — auquel cas l'élément devra avoir <code>display : list-item</code> - soit pour afficher du contenu généré régulièrement. Les compteurs sont largement utilisés dans la production de livres, afin de permettre la numérotation des chapitres et des figures, entre autres choses. Il n'y a aucune raison de ne pas adopter une approche similaire sur le Web, en particulier pour les articles plus longs.</p><p>Les propriétés CSS définies dans la spécification CSS Lists qui traitent de ces compteurs sont :</p><ul><li><code>counter-set</code></li>
<li><code>counter-reset</code></li>
<li><code>counter-increment</code></li>
</ul><p>Pour voir comment elles fonctionnent en dehors des listes, nous pouvons examiner un exemple d'utilisation de compteurs pour numéroter les titres d'un document.</p><p>La première chose à faire est de créer un compteur d'en-têtes sur l'élément <code>body</code>, prêt à être utilisé. Pour ce faire, j'utilise la propriété <code>counter-reset</code>. Les propriétés <code>counter-reset</code> et <code>counter-set</code> sont très similaires. La propriété <code>counter-reset</code> créera un nouveau compteur si un compteur du nom spécifié n'existe pas déjà, mais créera également des compteurs imbriqués comme décrit ci-dessus si un compteur de ce nom existe. La propriété <code>counter-set</code>, quant à elle, créera un nouveau compteur uniquement s'il n'existe pas de compteur de ce nom. Cependant, <code>counter-set</code> n'est pas aussi bien supporté par les navigateurs que <code>counter-reset</code>. Je choisis donc la voie la plus pratique :</p><pre class="language-css">body {
  counter-reset: heading-counter;
}</pre><p>Maintenant que j'ai un compteur, je peux utiliser la propriété <code>counter-increment</code> sur le sélecteur pour les en-têtes ; cela devrait incrémenter le compteur chaque fois que le sélecteur correspond.</p><pre class="language-css">h2 {
  counter-increment: heading-counter;
}</pre><p>Pour voir la valeur, je dois la sortir dans le document. Je peux le faire en utilisant le contenu généré et en l'ajoutant avant le titre, comme le montre l'exemple CodePen suivant :</p><pre class="language-css">h2::before {
  content: counter(heading-counter) ' : ';
  color: #00b7a8;
  font-weight: bold;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/gNGjxq">Smashing: headings and counters</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Sinon, je pourrais transformer l'élément <code>h2</code> en élément de liste et utiliser ensuite <code>::marker</code>, comme illustré ci-dessous. Comme déjà détaillé, l'utilisation de l'élément <code>::marker</code> a une prise en charge limitée par les navigateurs. Dans Firefox, vous devriez voir le compteur utilisé comme marqueur pour le titre, tandis que les autres navigateurs afficheront la puce par défaut.</p><pre class="language-css">h2 {
  display: list-item;
}
h2::marker {
  content: counter(heading-counter) ': ';
  color: #00b7a8;
  font-weight: bold;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/pXWZay">Smashing: headings, markers and counters</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Compteurs sur les éléments de formulaire</h2><p>Il y a aussi un peu d'interactivité que vous pouvez réaliser en utilisant les compteurs CSS — des choses que vous imaginiez peut-être possible uniquement avec JavaScript :</p><p>J'ai un formulaire qui comporte un certain nombre de champs obligatoires. Le statut obligatoire peut être sélectionné en CSS avec une pseudo-classe <code>:required</code>, et le fait qu'un champ n'ait pas été rempli peut être détecté au moyen de la pseudo-classe <code>:invalid</code>. Cela signifie que nous pouvons vérifier les champs qui sont à la fois requis et invalides, et incrémenter un compteur. Il suffit ensuite de l'afficher sous forme de contenu généré.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/vqpJdM">Smashing counting required form fields</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>L'utilité de cette valeur dans la réalité est discutable — étant donné que nous ne pouvons pas vraiment en faire autre chose que de la coller dans le contenu généré. Il existe également des inquiétudes quant à l'inaccessibilité du contenu généré pour certains lecteurs d'écran. Par conséquent, toute utilisation plus que décorative devra prévoir d'autres moyens d'accéder à ces informations. Lisez <a href="https://tink.uk/accessibility-support-for-css-generated-content/">"Accessibility Support For CSS Generated Content"</a> et les informations plus récentes, <a href="https://www.powermapper.com/tests/screen-readers/content/css-generated-content/">"CSS Content Property Screen Reader Compatibility"</a> pour plus de détails concernant l'accessibilité et le contenu généré.</p><p>Toutefois, cela démontre que les compteurs peuvent réaliser des choses plus utiles que la simple numérotation de listes. Il se peut qu'un jour ces connaissances vous soient utiles pour résoudre un problème sur lequel vous travaillez.</p><h3>En savoir plus</h3><p>Cet article s'est avéré assez éloigné de la stylisation des listes, bien que tout ce que j'ai décrit se trouve dans la spécification CSS Lists. Vous pouvez trouver plus d'informations sur les choses décrites dans les liens ci-dessous.</p><ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/::marker">::marker</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/counter-set">counter-set</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/counter-reset">counter-reset</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/counter-increment">counter-increment</a></li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Counter_Styles/Using_CSS_counters">"Utiliser les compteurs", docs web MDN</a></li>
<li><a href="https://css-tricks.com/counting-css-counters-css-grid/">"Compter avec les compteurs CSS et la grille CSS," CSS-Tricks</a></li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/listes-css-marqueurs-et-compteurs</link>
      <guid>https://la-cascade.io/articles/listes-css-marqueurs-et-compteurs</guid>
      <pubDate>Mon, 29 Jul 2019 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Alignement en CSS, un guide complet]]></title>
      <description><![CDATA[<p><em>Tout sur l'alignement en CSS par Rachel Andrew. Les choses ont beaucoup évolué dernièrement avec Flexbox, CSS Grid et la spécification Box Alignment. Dans la continuité de ses articles de référence déjà traduits dans la Cascade.</em></p><div class="articleContent"><p>Il existe aujourd'hui bien des façons d'aligner les choses en CSS et il n'est pas toujours évident de faire un choix. Connaître les options qui s'offrent à nous est encore la meilleure façon de concevoir les solutions optimales pour résoudre un problème.</p><p>Dans cet article, je vais passer en revue les différentes méthodes d'alignement qui existent aujourd'hui. Mais plutôt que de donner un mode d'emploi pour chacune, je vais examiner les points d'achoppement que l'on peut rencontrer et je renverrai à des articles de référence plus détaillés si vous souhaitez approfondir le sujet. Comme souvent en CSS, le plus important est de comprendre les <em>fondamentaux des méthodes</em>, le reste est affaire de détails.</p><h2>Alignement du texte et des éléments inline</h2><p>Quand on a du texte et autres éléments <em>inline</em> dans une page, chaque ligne de contenu est traitée comme une boîte de ligne (<em>line-box</em>). La propriété <code>text-align</code> alignera ce contenu dans la page — par exemple si vous voulez centrer votre texte ou le justifier. Mais parfois vous voudrez aligner les choses à l'intérieur de cette boîte de ligne par rapport à d'autres choses, par exemple si vous avez une icône affichée à côté du texte, ou bien des textes de taille différente ( <em>NdT : si vous avez besoin de rafraîchir vos connaissances sur inline et block, l'article <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline/">CSS Block, Inline et Inline-Block</a> remettra tout en place !</em>).</p><p>Dans l'exemple ci-dessous, j'ai mis un bout de texte à côté d'une image inline. J'utilise <code>vertical-align: middle</code> sur l'image pour aligner le texte par rapport au milieu de l'image ( <em>NdT : pour modifier les valeurs, cliquez sur "Edit on CodePen"</em>).</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/jJJLBR/">vertical-align</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h3>La propriété line-height et l'alignement</h3><p>La propriété <code>line-height</code> modifie la dimension de la boîte de ligne et peut donc avoir des conséquences sur l'alignement. L'exemple qui suit utilise une valeur élevée de hauteur de ligne (150 px) et j'ai aligné l'image sur <code>top</code>. L'image est donc alignée sur le haut de la boîte de ligne et non sur le haut du texte. Si vous supprimez cette <code>line-height</code>, ou si vous lui donnez une valeur inférieure à la dimension de l'image, alors l'image et le texte s'aligneront sur le haut du texte.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/eXXGOB/">vertical-align</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>La propriété <code>line-height</code> et la gestion de la taille du texte sont en réalité assez compliquées, je ne vais pas me lancer dans ce sujet ici, mais si vous souhaitez aligner précisément les éléments inline et si vous souhaitez comprendre le détail de ce qui se passe, je vous recommande la lecture de <a href="https://iamvdo.me/blog/css-avance-metriques-des-fontes-line-height-et-vertical-align">CSS avancé : métrique des fontes, line height et vertical align</a> par Vincent de Oliveira.</p><h3>Quand utiliser la propriété vertical-align ?</h3><p>La propriété <code>vertical-align</code> est utile pour aligner les éléments inline. Cela comprend aussi les éléments affichés avec <code>display: inline-block</code>. Le contenu des cellules de tableaux peut également être aligné avec cette propriété.</p><p>La propriété <code>vertical-align</code> n'a aucun effet sur les items flex ou grid et par conséquent si elle est utilisée dans le cadre d'une stratégie de solution de rechange (<em>fallback</em>), elle cessera d'être effective dès lors que l'élément parent sera transformé en conteneur flex ou grid. Par exemple, dans l'exemple ci-dessous, j'ai un ensemble d'items alignés via <code>display: inline-block</code> ce qui signifie que j'ai la possibilité d'aligner les items même si mon navigateur n'est pas compatible avec Flexbox.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/QoPMYR/">alignment with display: inline-block</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Dans l'exemple suivant, j'ai traité l'<code>inline-block</code> comme un <em>fallback</em> de Flexbox. Les propriétés d'alignement ne s'appliquent plus et je peux ajouter <code>align-items</code> pour aligner mes items dans Flexbox. Vous pouvez remarquer que c'est bien la méthode Flexbox qui aligne mes items parce que les gouttières qui les séparent dans la vue précédente ont disparu.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/xBeLBg/">alignment with display: inline-block as flex fallback</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>C'est parce que <code>vertical-align</code> marche avec les cellules de tableaux que le "truc" permettant de <a href="https://www.vanseodesign.com/blog/demo/vertical-centering/table-cell.php">centrer verticalement un item via <code>display: table-cell</code></a> fonctionne.</p><p>Maintenant que nous avons de meilleures méthodes pour aligner les boîtes en CSS (comme nous allons le voir tout de suite), nous n'avons plus besoin de recourir aux propriétés <code>vertical-align</code> et <code>text-align</code> ailleurs que là où elles remplissent leur fonction initiale, à savoir avec les éléments inline et textuels. Sur ces formats, elles demeurent parfaitement valides — par conséquent si vous souhaitez aligner des éléments inline ce sont elles, et non l'alignement de boîte, qu'il convient d'utiliser.</p><h2>Alignement de boîte</h2><p>La <a href="https://www.w3.org/TR/css-align-3/">spécification Box Alignment</a> s'intéresse à tout le reste. La spécification détaille les propriétés d'alignement suivantes :</p><ul><li>justify-content</li>
<li>align-content</li>
<li>justify-self</li>
<li>align-self</li>
<li>justify-items</li>
<li>align-items</li>
</ul><p>Peut-être pensez-vous que ces propriétés font partie de la spécification Flexbox, voire Grid. À l'origine, c'est là qu'elles sont nées en effet et d'ailleurs elles existent encore dans la spécification de niveau 1 <a href="https://www.w3.org/TR/css-flexbox-1/">Flexbox</a>. Cependant, elles ont été déplacées dans une spécification séparée lorsqu'il est apparu qu'elles avaient une portée plus générale. Nous les utilisons maintenant aussi avec <a href="https://www.w3.org/TR/css-grid-1/">CSS Grid Layout</a> et elles sont spécifiées pour d'autres méthodes de mise en page, même si les navigateurs actuels ne sont pas encore compatibles.</p><p>Par conséquent, la prochaine fois que quelqu'un sur Internet vous dira que l'alignement vertical est la chose la plus difficile qui soit en CSS, vous pourrez lui répondre ceci (ça tient même dans un tweet) :</p><pre>.container {
  display: flex;
  align-items: center;
  justify-content: center;
}</pre><p>Dans le futur il est même possible qu'on puisse se dispenser de <code>display: flex</code>, une fois les propriétés Box Alignment implémentées pour Block Layout. Pour l'instant en tout cas, il est toujours nécessaire de faire du parent un conteneur flex si l'on veut aligner verticalement et horizontalement.</p><h2>Les deux sortes d'alignement</h2><p>Quand on aligne des items flex ou grid, on a en fait deux choses à aligner :</p><ol><li>On a de <strong>l'espace libre</strong> dans notre container flex ou dans notre grille (une fois les éléments ou les pistes affichées).</li>
<li>On a <strong>l'élément lui-même</strong> à l'intérieur de la surface grid, ou sur l'axe transversal dans le conteneur flex.</li>
</ol><p>Je vous ai montré quelques propriétés précédemment, toutes ces propriétés d'alignement peuvent être vues comme appartenant à deux groupes. Celles qui s'occupent de la distribution de l'espace libre et celles qui alignent l'élément lui-même.</p><h3>Gestion de l'espace libre : align-content et justify-content</h3><p>Les propriétés dont le nom se termine par <code>-content</code> ont pour objet la distribution de l'espace. Lorsque vous utilisez <code>align-content</code> ou <code>justify-content</code>, vous répartissez l'espace disponible entre les pistes de grilles (<em><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/#gridtrack">grid tracks</a></em>) ou entre les items flex. Ces propriétés ne modifient pas les dimensions des items flex ou grid, mais déplacent les items en fonction de l'espace disponible.</p><p>Ci-dessous nous avons deux exemples, un flex et un grid. Tous deux ont un conteneur plus grand que nécessaire, par conséquent je peux utiliser <code>align-content</code> et <code>justify-content</code> pour répartir cet espace.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<a href="https://codepen.io/rachelandrew/pen/gEyGaQ/">justify-content and align-content</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h3>Déplacement des items : justify-self, align-self, justify-items et align-items</h3><p>Et puis nous avons <code>align-self</code> et <code>justify-self</code> qui s'appliquent à des items flex ou grid individuels. On peut également utiliser <code>align-items</code> et <code>justify-items</code> sur le conteneur pour appliquer toutes les propriétés en une fois. Ces propriétés s'appliquent à l'item flex ou grid, en déplaçant le contenu à l'intérieur de la <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/#gridarea">zone grid</a> ou de la ligne flex.</p><ul><li><strong>Grid Layout</strong> : les deux propriétés sont disponibles, vous pouvez déplacer l'item sur les axes block et inline.</li>
<li><strong>Flex Layout</strong> : on peut seulement aligner le long de l'axe perpendiculaire car l'axe principal n'est contrôlé qu'au niveau de la répartition de l'espace. Donc si vos items sont sur une rangée, vous pouvez utiliser <code>align-self</code> pour les déplacer verticalement à l'intérieur de la ligne.</li>
</ul><p>Dans l'exemple qui suit, j'ai un conteneur flex et un conteneur grid et j'utilise <code>align-items</code> et <code>align-self</code> dans Flexbox pour déplacer les items vers le haut ou le bas le long de l'axe perpendiculaire (<em>cross axis</em>). Si vous utilisez Firefox et que vous inspectez l'élément avec l'Inspecteur de Flexbox, vous verrez la dimension du conteneur flex ainsi que la façon dont les items sont déplacés verticalement à l'intérieur.</p><figure role="group"><img src="https://la-cascade.io/images/sm-align-flex-self-alignment-compressor.png" alt="" /></figure><p>Dans Grid, je peux utiliser les quatre propriétés pour déplacer les items à l'intérieur de leur zone de grille. Là encore, l'Inspecteur Grid de Firefox vous aidera à jouer avec les alignements. Avec les lignes en filigrane, on voit clairement la zone dans laquelle le contenu est déplacé :</p><figure role="group"><img src="https://la-cascade.io/images/sm-align-grid-self-alignment-compressor.png" alt="" /></figure><p>Cliquez sur <em>Edit on Codepen</em> pour modifier les valeurs :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/xBejYV/">justify-self, align-self, justify-items, align-items</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2 class="softTitleBlue">align et justify vous paraissent encore confus ?</h2><p>Parmi les problèmes souvent mentionnés concernant les propriétés d'alignement de Grid et Flexbox, il y a la difficulté à se rappeler laquelle utiliser : aligner ou justifier ? quelle direction correspond à chacune ?</p><p>Pour Grid Layout, vous devez savoir si vous alignez dans la direction Block ou Inline. Cela dépend de votre mode d'écriture : pour le français, la direction Block correspond à l'empilement des blocs, c'est donc la direction verticale. La direction Inline correspond au sens de l'écriture, c'est donc (en français du moins) de gauche à droite horizontalement.</p><p>Pour aligner dans la direction Block, vous utiliserez les propriétés commençant par <code>align-</code>. Vous utiliserez <code>align-content</code> pour répartir l'espace entre les pistes de grille, s'il y a de l'espace libre à l'intérieur de votre conteneur grid, et vous utiliserez <code>align-items</code> ou <code>align-self</code> pour déplacer un item à l'intérieur de la zone de grille où il se trouve.</p><p>Dans l'exemple suivant, nous avons deux mises en page grid. L'une a un <code>writing-mode: horizontal-tb</code> (le mode par défaut pour le français) et l'autre un <code>writing-mode: vertical-rl</code>. C'est la seule différence entre les deux. Vous voyez que les propriétés d'alignement appliquées fonctionnent exactement de la même façon sur l'axe block dans les deux modes.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/rRbYmr/">Block axis alignment</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Pour aligner dans la direction inline, utilisez les propriétés commençant par <code>justify-</code>. Utilisez <code>justify-content</code> pour répartir l'espace entre les pistes de grille et <code>justify-items</code> ou <code>justify-self</code> pour aligner les items à l'intérieur de leur zone de grille dans la direction inline.</p><p>Là encore, j'ai deux exemples de mise en page grid pour vous montrer qu'un inline est toujours un inline, quel que soit le mode d'écriture.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/eXoeEK/">Inline axis alignment</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Avec Flexbox, c'est un peu plus compliqué car nous avons un axe principal (<em>main axis</em>) qui peut être changé en <code>row</code> ou en <code>column</code>. Alors occupons-nous d'abord de cet axe principal. Il est déterminé avec la propriété <code>flex-direction</code>. La valeur par défaut est <code>row</code>, ce qui disposera les items flex en rangée dans le mode d'écriture que vous utilisez — en français les items sont donc alignés horizontalement quand nous créons un conteneur flex. Nous pouvons changer la direction de l'axe principal avec <code>flex-direction: column</code> et les items s'aligneront sur une colonne, ce qui signifie qu'ils seront disposés selon la direction block pour ce mode d'écriture.</p><p>C'est parce qu'il est possibe de changer la direction de l'axe que <strong>la question la plus importante à se poser en Flexbox est "quel axe est mon axe principal?"</strong>. Une fois que vous le savez, l'alignement (sur votre axe principal) s'effectue via <code>justify-content</code>. Peu importe que votre axe principal soit une rangée ou une colonne. Vous contrôlez l'espace <em>entre</em> les items flex avec <code>justify-content</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/pYBdda/">justify-content in flexbox</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Sur l'axe perpendiculaire, vous pouvez utiliser <code>align-items</code> qui alignera les items à l'intérieur du conteneur flex ou de la ligne flex si votre conteneur flex a plusieurs lignes. Si vous avez un conteneur flex comportant plusieurs lignes utilisant <code>flex-wrap: wrap</code> <em>et</em> qu'il y a de l'espace libre dans ce conteneur, vous pouvez utiliser <code>align-content</code> pour répartir l'espace sur l'axe perpendiculaire.</p><p>L'exemple suivant montre un conteneur flex affiché comme rangée puis comme colonne :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/mogqLP/">Cross axis alignment flexbox</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Quand justify-content ou align-content ne marchent pas</h2><p>Les propriétés <code>justify-content</code> et <code>align-content</code> de Grid et Flexbox servent à <strong>distribuer l'espace libre</strong>. Il convient donc de vérifier que vous avez bien de l'espace disponible.</p><p>Voici un exemple flex. J'ai réglé la direction de l'axe principal <code>flex-direction: row</code> et j'ai trois items. Ils n'occupent pas tout l'espace dans le conteneur, j'ai encore de la place sur l'axe principal, la valeur initiale de <code>justify-content</code> est <code>flex-start</code>, par conséquent mes items s'alignent tous à partir du point de départ et il me reste de l'espace disponible à la fin. Sur cette vue, l'espace est mis en valeur par l'Inspecteur de Firefox.</p><figure role="group"><img src="https://la-cascade.io/images/sm-align-spare-space-end-compressor.png" alt="" /></figure><p>Si je change la valeur de <code>flex-direction</code> pour <code>space-between</code>, l'espace disponible est maintenant réparti entre les items :</p><figure role="group"><img src="https://la-cascade.io/images/sm-align-spare-space-between-compressor.png" alt="" /></figure><p>Si j'ajoute maintenant du contenu supplémentaire à mes items, de façon à ce qu'ils deviennent plus longs et et que je n'aie plus d'espace disponible, alors <code>justify-content</code> ne fait plus rien. Tout simplement parce qu'il n'y a plus d'espace à répartir.</p><figure role="group"><img src="https://la-cascade.io/images/sm-align-no-space-compressor.png" alt="" /></figure><p>On me pose souvent la question de savoir pourquoi <code>justify-content</code> ne fonctionne pas lorsque <code>flex-direction</code> a pour valeur <code>column</code>. Eh bien c'est généralement parce qu'il n'y a pas d'espace à répartir. Si vous reprenez l'exemple qui précède, et que vous le transformez en <code>flex-direction: column</code>, les items s'afficheront en colonne mais il n'y aura pas d'espace disponible en-dessous des items comme c'est le cas avec <code>flex-direction: row</code>. Pourquoi ? Parce que quand vous créez un conteneur flex avec <code>display: flex</code>, vous avez un conteneur flex de niveau bloc. Il prendra tout l'espace possible dans la direction inline. En CSS, les objets ne s'étirent pas dans la direction bloc, donc pas d'espace supplémentaire disponible.</p><figure role="group"><img src="https://la-cascade.io/images/sm-align-column-no-space-compressor.png" alt="" /></figure><p>Ajoutez une hauteur à votre conteneur et — s'il y a plus d'espace que nécessaire pour afficher les items — vous aurez de l'espace disponible et <code>justify-content</code> fonctionnera sur votre colonne.</p><figure role="group"><img src="https://la-cascade.io/images/sm-align-column-space-between-compressor.png" alt="" /></figure><h2>Pourquoi n'y a-t-il pas de justify-self dans Flexbox ?</h2><p>Grid Layout implémente toutes les propriétés de boîtes pour chacun des axes parce que nous avons toujours affaire à deux axes dans Grid. Nous créons des pistes (qui peuvent laisser de l'espace supplémentaire dans le conteneur grid, pour chacune des directions) et donc nous pouvons répartir cet espace avec <code>align-content</code> ou <code>justify-content</code>. Nous avons également les zones de grille (<em>grid-areas</em>) et il arrive que l'élément n'occupe pas tout l'espace de cette zone, nous pouvons alors utiliser <code>align-self</code> ou <code>justify-self</code> pour déplacer le contenu dans la zone (ou bien <code>align-items</code>, <code>justify-items</code> pour changer l'alignement de tous les items).</p><p>Contrairement à Grid, Flexbox n'a pas de pistes. Sur l'axe principal, tout ce que nous pouvons faire c'est répartir l'espace entre les items. Pas de piste, pas de zone non plus pour répartir les items.C'est pourquoi il n'y a pas de propriété <code>justify-self</code> sur l'axe principal dans Flexbox.</p><p>Parfois cependant, vous voudrez avoir la possibilité d'aligner un item ou une partie d'un groupe d'items d'une autre façon. Un pattern assez courant serait une barre de navigation éclatée, avec un item séparé du reste du groupe. Dans ce type de situation, la spécification conseille l'utilisation de marges automatiques.</p><p>Une marge <code>auto</code> prendra tout l'espace dans la direction où elle est appliquée, ce qui explique qu'on puisse centrer un bloc (par exemple notre page principale) avec des marges gauche et droite auto. Lorsqu'on a margin auto des deux côtés, chacune des marges essaie de prendre tout l'espace et repousse le bloc vers le centre. Pour notre rangée d'items flex, nous pouvons ajouter <code>margin-left: auto</code> à l'item que nous voulons séparer, et tant qu'il reste de l'espace disponible dans le conteneur flex, nous avons une séparation. Et dès qu'il n'y a plus d'espace supplémentaire disponible, les items reprennent leur comportement habituel d'items flex.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/wOZmBG/">auto margins</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Flexbox et les micro-composants</h2><p>Un point qu'on néglige souvent c'est l'utilité de Flexbox pour résoudre de micro-tâches de mise en page, là où parfois on penserait que <code>vertical-align</code> est la solution. J'utilise souvent Flexbox pour obtenir de beaux alignements de petits motifs, par exemple aligner une icône sur un texte, aligner deux textes de fontes différentes sur leur ligne de base, ou aligner correctement des champs de formulaires avec les boutons. Si vous vous débattez avec <code>vertical-align</code>, essayez Flexbox. Et n'oubliez pas que vous pouvez créer un conteneur flex inline si vous voulez avec <code>display: inline-flex</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/aMxYWQ/">inline-flex</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Rien n'interdit d'utiliser Flexbox ou même Grid pour de petites tâches de mise en page.Ils ne sont aucunement réservés aux grands layouts. Faites des essais avec ce qui est disponible et voyez ce qui vous convient le mieux.</p><p>On se demande souvent ce qui est la bonne ou la mauvaise manière de faire quelque chose. En réalité, il n'y a souvent pas ne bon ou de mauvais. Une petite différence dans votre pattern aura pour conséquence que Flexbox est la solution la plus appropriée, là où sinon vous utiliseriez plutôt <code>vertical-align</code>.</p><h3>En résumé</h3><p>Pour récapituler, voici un résumé rapide des bases de l'alignement. Si vous gardez ces quelques règles en mémoire, vous devriez pouvoir aligner à peu près tout.</p><ol><li>Alignement de texte ou d'élément inline   ➜   <code>text-align</code>, <code>vertical-align</code> et <code>line-height</code>.</li>
<li>Item à aligner au centre d'une page ou d'un conteneur   ➜   faites du conteneur un conteneur flex et utilisez <code>align-items: center</code> et <code>justify-content: center</code>.</li>
<li>Pour les mises en page Grid, les propriétés commençant par <code>align-</code> fonctionnent dans la direction bloc. Celles qui commencent par <code>justify-</code> fonctionnent dans la direction inline.</li>
<li>Pour les mises en page Flex, les propriétés commençant par <code>align-</code> fonctionnent sur l'axe perpendiculaire. Celles qui commencent par <code>justify-</code> fonctionnent sur l'axe principal.</li>
<li>Les propriétés <code>justify-content</code> et <code>align-content</code> répartissent l'espace supplémentaire. Si vous n'avez pas d'espace supplémentaire disponibledans votre conteneur flex ou grid, ces propriétés ne feront rien.</li>
<li>Si vous pensez avoir besoin de <code>justify-self</code> dans Flexbox, peut-être une marge auto vous donnera-t-elle la solution.</li>
<li>Vous pouvez utiliser Grid et Flexbox et les propriétés d'alignement pour de micro tâches aussi bien que pour vos composants essentiels. Expérimentez !</li>
</ol><p>Pour plus d'information sur les alignements, consultez ces ressources :</p><ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Box_Alignment">CSS Box Alignment MDN</a> (en français)</li>
<li><a href="https://la-cascade.io/articles/css-flexbox-et-lalignement-guide-complet/">CSS Flexbox et l'alignement, guide complet</a></li>
<li><a href="https://rachelandrew.co.uk/css/cheatsheets/box-alignment">Box Alignment Cheatsheet</a></li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/alignement-en-css-guide-complet</link>
      <guid>https://la-cascade.io/articles/alignement-en-css-guide-complet</guid>
      <pubDate>Sat, 18 May 2019 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Comment fonctionne calc()]]></title>
      <description><![CDATA[<p><em>La fonction calc( ) de CSS nous permet de calculer des valeurs de propriétés. Ire Aderinokun passe en revue son fonctionnement, son utilité et quelques cas pratiques.</em></p><div class="articleContent"><p>La fonction <code>calc()</code> de CSS nous permet de calculer des valeurs de propriétés. Par exemple, au lieu de déclarer des valeurs fixes pour la largeur d'un élément, nous pouvons utiliser <code>calc()</code> pour spécifier que la largeur sera le résultat de l'addition de deux valeurs numériques (ou plus).</p><pre>.foo {
    width: calc(100px + 50px);
}</pre><h2>Pourquoi calc( ) ?</h2><p>Si vous avez déjà utilisé des préprocesseurs comme Sass, l'exemple qui précède vous est sans doute familier ( <em>NdT : sinon, voir le <a href="https://sass-guidelin.es/fr/">guide de style Sass</a></em>).</p><pre>.foo {
    width: 100px + 50px;
}
// Ou en utilisant des variables Sass
$width-one: 100px;
$width-two: 50px;
.bar {
    width: $width-one + $width-two;
}</pre><p>Toutefois, la fonction <code>calc()</code> est une meilleure solution, pour deux raisons.</p><p>D'abord parce qu'elle permet de mélanger des unités différentes. En particulier, nous pouvons utiliser des pourcentages et des unités de viewport avec des unités absolues telles que les pixels. Par exemple nous pouvons créer une expression qui va soutraire une valeur en pixels à une valeur en pourcentage.</p><pre>.foo {
    width: calc(100% - 50px);
}</pre><p>Dans cet exemple, l'élément <code>foo</code> aura toujours une largeur de 50px inférieure à 100% de son élément parent.</p><p>Ensuite parce qu'avec <code>calc()</code> la valeur calculée est l'expression elle-même et non la valeur résultant de l'expression. Je m'explique : lorsqu'on construit des expressions mathématiques avec les préprocesseurs, la valeur passée au navigateur est la valeur <em>résultant de l'expression</em> :</p><pre>// Valeur spécifiée en SCSS
.foo {
    width: 100px + 50px;
}
// Le SCSS est compilé en CSS
// La valeur passée au navigateur :
.foo {
    width: 150px;
}</pre><p>Avec <code>calc()</code> la valeur parsée par le navigateur est <em>l'expression elle-même</em> :</p><pre>// Valeur spécifiée en CSS
.foo {
    width: calc(100% - 50px);
}
// Valeur calculée dans le navigateur
.foo {
    width: calc(100% - 50px);
}</pre><p>Du coup les valeurs sont dynamiques et s'adaptent aux changements de viewport. Nous pouvons avoir un élément avec une hauteur de viewport moins une valeur absolue, il s'adaptera aux changements du viewport.</p><h3>Utiliser calc( )</h3><p>On peut utiliser la fonction <code>calc()</code> pour additionner, soustraire, multiplier ou diviser des valeurs numériques de propriétés : les data types <code>&lt;length&gt;</code>, <code>&lt;frequency&gt;</code>, <code>&lt;angle&gt;</code>, <code>&lt;time&gt;</code>, <code>&lt;number&gt;</code>, ou <code>&lt;integer&gt;</code>.</p><p>Voici quelques exemples :</p><pre>.foo {
    width: calc(50vmax + 3rem);
    padding: calc(1vw + 1em);
    transform: rotate( calc(1turn + 28deg) );
    background: hsl(100, calc(3 * 20%), 40%);
    font-size: calc(50vw / 3);
}</pre><h3>Imbriquer les calc( )</h3><p>On peut même imbriquer les fonctions <code>calc()</code>. Les fonctions entre parenthèses seront traitées comme de simples expressions. Si nous prenons par exemple :</p><pre>.foo {
    width: calc( 100% / calc(100px * 2) );
}</pre><p>la valeur calculée de cette fonction sera :</p><pre>.foo {
    width: calc( 100% / (100px * 2) );
}</pre><h3>Compatibilité</h3><p>La fonction <code>calc()</code> est largement supportée. Pour voir la compatibilité à la date de lecture de cet article, vous pouvez consulter — comme toujours — <a href="https://caniuse.com/#feat=calc">CanIUse</a>.</p><p>Si un navigateur n'est pas compatible, toute l'expression propriété-valeur est ignorée. Par conséquent la solution de rechange (<em>fallback</em>) est simple à mettre en oeuvre, il suffit de fournir une valeur statique qui sera utilisée à la place.</p><pre>.foo {
    width: 90%; /* Fallback pour les anciens navigateurs */
    width: calc(100% - 50px);
}</pre><h2>Quand utiliser calc( ) ?</h2><p>On peut utiliser cette fonction dans diverses situations.</p><h3>Exemple 1 - Centrer des éléments</h3><p><code>calc()</code> nous offre une solution de plus au problème classique du <a href="https://la-cascade.io/articles/centrer-en-css-un-guide-complet/">centrage horizontal et vertical</a> des éléments à l'intérieur d'un conteneur. Si nous connaissons les dimensions de l'élément enfant, une solution typique est d'utiliser des marges négatives pour déplacer l'élément de la moitié de sa hauteur et de sa largeur :</p><pre>// Avec un élément .foo ayant pour hauteur et pour largeur 300px
.foo {
    position: absolute
    top: 50%;
    left: 50%;
    marging-top: -150px;
    margin-left: -150px;
}</pre><p>Avec la fonction <code>calc()</code> nous obtenons le même résultat en n'utilisant que les propriétés <code>top</code> et <code>left</code>.</p><pre>.foo {
    position: absolute
    top: calc(50% - 150px);
    left: calc(50% - 150px);
}</pre><p>De telles méthodes sont sans doute moins nécessaires maintenant que nous avons <a href="https://la-cascade.io/tags/flexbox/">Flexbox</a>, cependant dans des cas où Flexbox ne peut être utilisé, par exemple si l'élément doit avoir une position absolue ou fixe, cette méthode reste utile.</p><h3>Exemple 2 - Créer une dimension de grille à partir de root</h3><p>On peut utiliser la fonction <code>calc()</code> pour créer une grille basée sur le viewport avec l'unité <code>rem</code>. Pour cela, on définit dans l'<a href="https://developer.mozilla.org/fr/docs/Web/CSS/:root">élément racine</a> (<em>root</em>) la font-size comme une fraction de la largeur du viewport.</p><pre>html {
        font-size: calc(100vw / 30);
}</pre><p>Maintenant <code>1 rem</code> correspond à 1/30 de la largeur du viewport. Tous les textes dans notre page seront mis à l'échelle automatiquement en fonction du viewport et la même quantité de texte apparaîtra toujours à l'écran quelle que soit sa taille :</p><p></p><img src="https://res.cloudinary.com/ireaderinokun/image/upload/c_scale,q_59,w_780/v1486662717/ezgif.com-optimize_w09wsb.jpg" alt="image d'un écran redimensionné, montrant comment le texte s'adapte tout en restant aux mêmes proportions" /><p>Si nous donnons à d'autres éléments non-textuels des dimensions en unités <code>rem</code>, ìls se comporteront de la même manière.</p><h3>Exemple 3 - Clarté</h3><p>Enfin, <code>calc()</code> peut s'avérer utile pour rendre les calculs plus évidents à comprendre. Si vous voulez qu'un groupe d'éléments aient pour dimension 1/6 de la largeur de leur conteneur parent, vous pourriez l'écrire ainsi :</p><pre>.foo {
        width: 16.666666667%;
}</pre><p>Mais pour les lecteurs de votre CSS, ce serait bien plus clair ainsi :</p><pre>.foo {
        width: calc(100% / 6);
}</pre><p><strong>Ressources complémentaires en français</strong></p><ul><li><a href="https://www.alsacreations.com/article/lire/1630-la-fonction-calc-en-css.html">La fonction calc() en CSS</a>, par Raphaël Goetter</li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/calc">calc()</a> dans MDN</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/comment-fonctionne-calc</link>
      <guid>https://la-cascade.io/articles/comment-fonctionne-calc</guid>
      <pubDate>Sat, 12 Jan 2019 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[La propriété CSS visibility et l'accessibilité]]></title>
      <description><![CDATA[<p><em>Le DOM (Document Object Model) est une interface pour vos pages web. C'est une API permettant aux programmes de lire et de manipuler le contenu de la page, sa structure et ses styles. Passons tout cela en revue pour comprendre comment ça marche.</em></p><div class="articleContent"><p>J'ai rencontré un problème dernièrement avec le contenu textuel d'un de mes <code>&lt;button&gt;</code> qui n'apparaissait pas dans l'arbre d'accessibilité (<a href="https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree">accessibility tree</a>, <em>NdT : un arbre un peu similaire au <a href="https://la-cascade.io/articles/le-dom-cest-quoi-exactement/">DOM</a> mais comportant uniquement les éléments utiles aux technologies d'assistance</em>) et par conséquent n'était pas visible pour les lecteurs d'écran. Après débogage, je me suis rendue compte que la raison en était que j'animais un texte visuellement en modifiant son opacité et, surtout, la propriété CSS <code>visibility</code>.</p><p>C'était clairement un loupé, vu ce que j'ai écrit précédemment sur la façon de <a href="https://la-cascade.io/articles/cacher-des-elements-avec-css/">cacher des éléments avec CSS</a>. Cela m'a amenée à repenser au comportement de la propriété <code>visibility</code>, en particulier à sa valeur <code>hidden</code>, dans sa relation avec les différentes sortes de "visibilités" — visuelle, spatiale, technologies d'assistance, interactions. Quand nous utilisons le terme "visibilité", nous pensons à la vision, mais la propriété <code>visibility</code> ne concerne pas que la visibilité "visuelle".</p><h2>visibility: hidden et la visibilité visuelle</h2><p>Lorsque nous considérons le domaine de la vision, la règle <code>visibility: hidden</code> a l'effet attendu, l'élément devient plus ou moins "invisible".</p><pre>Il a disparu ! ---&gt; &lt;span style="visibility: hidden;"&gt;J'ai disparu !&lt;/span&gt; eh oui</pre><p>Le résultat :</p><p>Il a disparu ! ---&gt; J'ai disparu ! eh oui</p><p>Pour comprendre exactement ce qui se passe, revenons sur le <a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/?hl=FR">chemin critique du rendu</a>. Typiquement, une fois déterminés les styles de la page, trois choses se passent :</p><ul><li>Mise en page - quel espace prend l'élément dans la page ?</li>
<li>Peinture - quelle est la valeur de chaque pixel ?</li>
<li>Composite - dans quel ordre sont peints les pixels ?</li>
</ul><p>Pour un élément auquel s'applique la règle <code>visibility: hidden</code>, on pourrait penser que les navigateurs optimiseraient le travail de rendu en ne tenant pas compte des étapes 2 et 3 puisqu'aucun pixel ne sera affiché là où l'élément devrait se trouver. Bien que rien ne soit dit dans la spécification sur une telle optimisation, il est utile d'imaginer un tel mécanisme pour penser au fonctionnement de la règle.</p><h2>visibility: hidden et espace</h2><p>Il est techniquement exact de dire qu'un élément est invisible lorsque la règle <code>visibility: hidden</code> lui est appliquée, cependant on peut objecter qu'il occupe toujours l'espace sur la page.</p><p>Comme mentionné précédemment, un élément ne passe peut-être pas par les étapes 2 &amp; 3, peinture et composite, mais il n'échappe pas à l'étape 1 de mise en page. Autrement dit, même si les pixels ne sont pas peints, ils occupent toujours de l'espace dans la page — un peu comme Harry Potter et sa cape d'invisibilité, vous ne le voyez pas mais il est toujours là.</p><p>Prenons trois éléments <code>&lt;div&gt;</code> de 100 px chacun, et appliquons la règle <code>visibility: hidden</code> au deuxième.</p><pre>&lt;style&gt;
    div {
        width: 100px;
        display: inline-block;
        background-color: #ffdb3a;
    }
&lt;/style&gt;
&lt;div&gt;Un&lt;/div&gt;
&lt;div style="visibility: hidden;"&gt;Deux&lt;/div&gt;
&lt;div&gt;Trois&lt;/div&gt;</pre><p>Un</p><p>Deux</p><p>Trois</p><p>Bien que "visuellement caché", on ne peut pas dire que l'élément du milieu soit réellement invisible puisqu'il occupe toujours l'espace.</p><h2>visibility: hidden et interactivité</h2><p>Du fait qu'un élément occupe toujours l'espace, même s'il est techniquement "caché", on pourrait penser que la règle <code>visibility: hidden</code> a le même effet que <code>opacity: 0</code>. En réalité, la règle <code>visibility: hidden</code> est beaucoup plus proche de <code>display: none</code>.</p><p>Toute interaction avec des éléments tels que des formulaires ou des liens sera impossible.</p><p>Considérons le <code>&lt;button&gt;</code> ci-dessous qui devrait envoyer une alerte sur un clic.</p><pre>Il a disparu ! ---&gt;
&lt;button style="visibility: hidden;"
        onclick="alert('Hello!')"&gt;J'ai disparu !&lt;/button&gt;
&lt;--- On ne peut pas cliquer dessus !</pre><p>Il a disparu ! ---&gt;  &lt;--- On ne peut pas cliquer dessus !</p><p>Le bouton a beau conserver son espace physique, il a perdu son interactivité.</p><h2>visibility: hidden et technologies d'assistance</h2><p>La principale raison pour laquelle la règle <code>visibility: hidden</code> ne concerne pas que le domaine de la vision est qu'elle affecte également les technologies d'assistance. Lorsque nous appliquons <code>visibility: hidden</code> à un élément, la règle le supprime de l'arbre d'accessibilité, ce qui le rend invisible aux technologies telles que les lecteurs d’écran.</p><p>Prenons par exemple le problème que j'ai rencontré. J'ai un <code>&lt;button&gt;</code> et une <code>&lt;span&gt;</code> imbriquée.</p><pre>&lt;button&gt;
    &lt;span style="visibility: hidden"&gt;Button label here&lt;/span&gt;
&lt;/button&gt;</pre><p>Si nous jetons un coup d'oeil aux propriétés d'accessibilité de l'élément dans DevTool, nous voyons que le <code>&lt;button&gt;</code> semble ne pas avoir de label et par conséquent n'a pas de nom accessible.</p><figure><img src="https://la-cascade.io/images/devtool-with-accessibility-panel-compressor.png" alt="Copie d'écran de Chrome DevTool lorsqu'on inspecte le bouton ci-dessus dont le nom n'est pas accessible" /></figure><p>Conclusion : la propriété <code>visibility</code> semble n'affecter que l'aspect visuel des éléments, mais nous avons vu qu'elle fait bien plus que cela.</p></div>]]></description>
      <link>https://la-cascade.io/articles/la-propriete-css-visibility-et-laccessibilite</link>
      <guid>https://la-cascade.io/articles/la-propriete-css-visibility-et-laccessibilite</guid>
      <pubDate>Sun, 16 Dec 2018 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Flexbox et la dimension des boîtes]]></title>
      <description><![CDATA[<p><em>Nous allons explorer le dimensionnement en Flexbox, qui est souvent un casse-tête : comment Flexbox décide-t-il de la taille de nos items ?</em></p><div class="articleContent"><p> <em>NdT : Les articles précédents ont été traduits dans la Cascade</em> :</p><ul><li><a href="https://la-cascade.io/articles/que-se-passe-t-il-quand-on-cree-un-flexbox-flex-container/">Que se passe-t-il quand on crée un flexbox flex-container ?</a></li>
<li><a href="https://la-cascade.io/articles/css-flexbox-et-lalignement-guide-complet/">CSS Flexbox et l'alignement, guide complet</a>.</li>
</ul><h2>Affichage initial des items flex</h2><p>Si j’ai un ensemble d’items ayant des contenus de longueur variable et que je règle leur parent sur <code>display: flex</code>, ils s’afficheront sous forme de ligne et s’aligneront au début de cet axe. Dans l'exemple ci-dessous, mes trois items ont un contenu réduit et ils peuvent afficher ces contenus sous forme de ligne ininterrompue. Il y a un espace à la fin du conteneur flex que les items n'occupent pas car la valeur initiale de <code>flex-grow</code> est <code>0</code>, c'est à dire <em>pas d'expansion</em>.</p><figure role="group"><img src="https://la-cascade.io/images/flexbox-sizing-flex-items-compressor.png" alt="" /><figcaption>Les items flex ont suffisamment d'espace pour être alignés sur une seule ligne</figcaption></figure><p>Si j'ajoute du texte à ces éléments, ils finissent par remplir le conteneur et des retours à la ligne apparaissent. Les boîtes se voient attribuer un espace correspondant à la longueur de texte qu'elles contiennent — un item avec beaucoup de texte a plus d'espace. Du coup, on ne se retrouve pas avec une colonne maigrichonne contenant beaucoup de texte lorsque l’item suivant ne contient qu’un seul mot.</p><figure role="group"><img src="https://la-cascade.io/images/flexbox-sizing-flex-items-longer-compressor.png" width="1143" height="471" alt="" /><figcaption>L'espace est réparti de façon à donner plus de place à un item de contenu plus long</figcaption></figure><p>Ce comportement vous paraîtra sans doute familier si vous avez déjà utilisé Flexbox, et peut-être vous êtes-vous déjà demandé comment le navigateur effectuait ces redimensionnements, d'autant que si vous comparez les navigateurs modernes, vous pouvez constater qu'ils font tous la même chose. La raison en est que des détails comme celui-ci sont définis <em>dans la spécification même</em>, afin de s'assurer que quel que soit le navigateur on sache toujours comment fonctionne ce calcul. Nous pouvons utiliser la spécification pour trouver cette information par nous-mêmes.</p><h2>Spécification de dimensionnement CSS intrinsèque et extrinsèque</h2><p>Lorsqu'on examine le dimensionnement dans la spécification Flexbox, on découvre assez vite qu'une grande partie des informations dont on a besoin se trouve dans une autre spécification — <a href="https://www.w3.org/TR/css-sizing-3/">CSS Intrinsic et Extrinsic Sizing</a>. En effet, les concepts de dimensionnement que nous utilisons ne sont pas propres à Flexbox, de la même manière que les propriétés d’alignement ne sont pas propres à Flexbox, comme nous l'avons vu dans l'article précédent. Cependant, pour savoir comment ces dimensionnement sont utilisées dans Flexbox, il faut revenir à la spécification Flexbox. Pour vous éviter d'avoir à faire des allers-retours dans les specs, je vais donc vous donner quelques définitions-clés, que je vais utiliser dans la suite de l’article.</p><h3>Taille préférée</h3><p>La <a href="https://www.w3.org/TR/css-sizing-3/#preferred-size-properties">taille préférée</a> d'une boîte est la taille définie par une <code>width</code> ou une <code>height</code>, ou par les alias logiques <code>inline-size</code> et <code>block-size</code> pour ces propriétés. Lorsque vous utilisez :</p><pre>.box {
    width: 500px;
}</pre><p>ou l'alias logique <code>inline-size</code> :</p><pre>.box {
    inline-size: 500px;
}</pre><p>...vous déclarez que vous souhaitez que votre boîte ait une largeur de 500 pixels ou 500 pixels dans la direction <code>inline</code>.</p><h3>min-content size</h3><p>La <a href="https://www.w3.org/TR/css-sizing-3/#min-content-inline-size">taille minimale</a> du contenu, <code>min-content</code>, est la plus petite taille possible pour une boîte sans créer d'overflow. Si votre boîte contient du texte, toutes les opportunités possibles de retour à la ligne (<a href="https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap">soft</a>) seront utilisées.</p><h3>max-content size</h3><p>La <a href="https://www.w3.org/TR/css-sizing-3/#max-content-inline-size">taille maximale</a> du contenu, <code>max-content</code>, est la plus grande taille que la boîte puisse prendre afin de contenir le contenu. Si la boîte contient du texte sans retour à la ligne, elle apparaîtra sous la forme d'une longue chaîne de caractères ininterrompue.</p><h3>Taille principale d'un item flex</h3><p>La <a href="https://www.w3.org/TR/css-flexbox-1/#box-model">taille principale</a> d'un élément flexible est la taille qu'il a dans la dimension principale (<em>main</em>). Si vous travaillez dans une rangée — en français — alors la taille principale est sa largeur. Dans une colonne en français, la taille principale est sa hauteur.</p><p>Les items ont également une taille principale minimale et maximale définie par leur <code>min-width</code> ou leur <code>min-height</code> dans la dimension principale.</p><h2>Comprendre la taille d'un élément flexible</h2><p>Maintenant que certains termes sont définis, nous pouvons examiner la façon dont nos éléments flex sont dimensionnés. La valeur initiale des propriétés <code>flex</code> est la suivante:</p><ul><li><code>flex-grow: 0</code></li>
<li><code>flex-shrink: 1</code></li>
<li><code>flex-basis: auto</code></li>
</ul><p>Le calcul des dimensions part de <code>flex-basis</code>. Si nous donnons à <code>flex-basis</code> la valeur <code>0</code>, et à <code>flex-grow</code> la valeur <code>1</code>, alors nos boîtes n'ont pas de largeur initiale et par conséquent l'espace à l'intérieur du conteneur flex est partagé de manière égale.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/vzaJMW/">Smashing Flexbox Series 3: flex: 1 1 0;</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si par contre <code>flex-basis</code> a pour valeur <code>auto</code> et <code>flex-grow: 1</code>, alors l'espace disponible est distribué en prenant en compte la taille du contenu.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/XPBejj/">Smashing Flexbox Series 3: flex: 1 1 auto short text</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Lorsqu'il n'y a pas d'espace disponible, par exemple quand notre contenu ne tient pas sur une ligne unique, alors il n'y a pas d'espace à distribuer.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/bxjoeZ/">Smashing Flexbox Series 3: flex: 1 1 auto long text</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Il est donc important de bien comprendre <code>auto</code> si nous voulons savoir comment Flexbox détermine la taille des boîtes. La valeur d'<code>auto</code> sera notre point de départ.</p><h2>Définir auto</h2><p>Lorsque <code>auto</code> est la valeur d'une propriété CSS, il a une signification spécifique à <em>ce contexte</em>. Le CSS Working Group a passé beaucoup de temps à clarifier la signification de <code>auto</code> selon les contextes, comme l'explique <a href="https://vimeo.com/134597090">cette présentation</a>.</p><p>Nous pouvons trouver le sens de <code>auto</code> utilisé en tant que <code>flex-basis</code> dans la spécification. Les termes définis tout à l'heure devraient nous permettre d'analyser cette phrase:</p><blockquote>
<p>Lorsque spécifié sur un item flex, le mot-clé <code>auto</code> va chercher la valeur de la propriété de taille principale pour l'utiliser comme <code>flex-basis</code>. Si cette valeur est elle-même <code>auto</code>, alors la valeur utilisée est <code>content</code>.</p>
</blockquote><p>Autrement dit, si notre <code>flex-basis</code> est <code>auto</code>, Flexbox examine la propriété de taille principale définie. Par exemple, nous aurions une taille principale si nous avions donné une largeur à l’un au moins de nos articles flexibles. Dans l'exemple ci-dessous, les éléments ont tous une largeur de 110 px, cette taille est donc utilisée comme taille principale, car la valeur initiale de <code>flex-basis</code> est <code>auto</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/mGjBxQ/">Smashing Flexbox Series 3: flex items with a width</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Cependant, notre exemple a des items sans <code>width</code> ce qui signifie que leur dimension principale est <code>auto</code>, et nous passons donc à la suite de la phrase "si cette valeur est elle-même <code>auto</code>, alors la valeur utilisée est <code>content</code>".</p><p>Nous devons maintenant regarder ce que dit la spec à propos du mot-clé <code>content</code>. Voici une autre valeur que nous pouvons utiliser pour notre <code>flex-basis</code>(dans les navigateurs compatibles), par exemple :</p><pre>.item {
    flex: 1 1 content;
}</pre><p>La spécification définit <code>content</code>ainsi :</p><blockquote>
<p>Il indique un dimensionnement automatique basé sur le contenu du flex item. Typiquement, il est équivalent à la dimension max-content mais avec des ajustements permettant de traiter les ratios d'aspect, les contraintes de dimensionnement intrinsèque et les flux orthogonaux"</p>
</blockquote><p>Dans notre exemple, avec des items flex contenant du texte, nous pouvons ignorer certains ajustements complexes et considérer <code>content</code> comme étant la dimension <code>max-content</code>.</p><p>Ceci explique pourquoi, lorsque nous avons peu de texte dans chaque item, nous n'avons pas de retour à la ligne. Les items flex sont dimensionnés automatiquement, Flexbox cherche leur dimension <code>max-content</code>, les items s'ajustent à cette taille dans leur conteneur, et le tour est joué.</p><p>L'histoire ne s'arrête pas là, lorsque nous ajoutons du contenu les boîtes ne restent pas à la dimension <code>max-content</code>. Sinon, elles sortiraient du conteneur avec un overflow. Une fois qu'il a rempli le container, le contenu retourne à la ligne et les items prennent des tailles différentes en fonction de leur contenu.</p><h2>Résolution des tailles flexibles</h2><p>À partir d'ici, la spécification devient raisonnablement complexe. Voici les prochaines étapes.</p><p>D'abord, ajouter la taille principale de tous les items et voir si elle est supérieure ou inférieure à l'espace disponible dans le container. Si la taille du conteneur est supérieure, nous passons à <code>flex-grow</code> puisque nous avons de l'espace pour nous étendre.</p><figure role="group"><img src="https://la-cascade.io/images/flexbox-sizing-flex-items-compressor-1.png" alt="" /><figcaption>Dans ce premier cas, nos items ont de la place disponible pour s'étendre</figcaption></figure><p>Par contre, si la taille du conteneur est inférieure au total, nous nous tournons vers <code>flex-shrink</code> car nous devons nous serrer.</p><figure role="group"><img src="https://la-cascade.io/images/flexbox-sizing-flex-items-overflow-compressor.png" alt="" /><figcaption>Dans le second cas, nos items sont trop grands et doivent être réduits pour s'adapter à la taille du conteneur</figcaption></figure><p>Il est possible de choisir une taille pour certains items, qui deviennent ainsi "inflexibles". Si nous utilisons <code>flex-grow</code>, cela inclurait tous les éléments qui ont <code>flex-grow: 0</code>. C'est le scénario que nous avons lorsque nos articles flexibles ont de la place dans le conteneur. La valeur initiale de <code>flex-grow</code> est <code>0</code>, nos items deviennent donc aussi grands que leur largeur maximale et ne grandissent plus à partir de leur taille principale.</p><p>Si nous utilisons <code>flex-shrink</code>, cela inclura tous les éléments avec <code>flex-shrink: 0</code>. Nous pouvons voir ce qui se passe dans cette étape si nous donnons à notre ensemble d’items flex un facteur de <code>flex-shrink</code> de <code>0</code>. Les éléments sont figés dans leur état <code>max-content</code> et ainsi ne peuvent pas s'organiser eux-mêmes de manière flexible pour tenir dans le conteneur.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/LJBeWp/">Smashing Flexbox Series 3: flex: 0 0 auto</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Dans notre cas, avec leur valeurs initiales d'items flex, nos items peuvent se réduire. Nous continuons donc, et l'algorithme entre dans une boucle lui permettant de calculer l'espace à attribuer ou à réduire. Nous utilisons <code>flex-shrink</code>puisque la taille totale de nos items est supérieure à la taille du conteneur — nous devons donc réduire l'espace.</p><p>Le facteur <code>flex-shrink</code> est multiplié par la <em>taille de base interne</em>, ici c'est la taille <code>max-content</code>. Cela donne une valeur avec laquelle réduire l'espace. Si les éléments retirent de l'espace uniquement en fonction du facteur de <code>flex-shrink</code>, les éléments de petite taille risquent en principe de disparaître car tout leur espace a été supprimé, tandis que l'élément le plus volumineux peut encore être réduit.</p><blockquote>
<p>Dans cette boucle, il existe une étape supplémentaire pour rechercher les éléments qui deviendraient plus petits ou plus grands que leur taille principale cible. Dans ce cas, l'élément cesse de croître ou de se réduire. Encore une fois, ceci permet d'éviter que certains objets ne deviennent minuscules ou énormes par rapport au reste des objets.</p>
</blockquote><p>Tout cela a été simplifié du point de vue des spécifications, car je n'ai pas examiné certains des scénarios les plus limites. Vous pouvez vous en passer si vous souhaitez laisser Flexbox agir à votre place ou si vous ne recherchez pas la perfection au pixel près. Garder à l'esprit les deux mécanismes suivants vous aidera dans la plupart des cas :</p><ul><li>Si vous êtes en mode <code>grow</code> depuis <code>auto</code>, alors <code>flex-basis</code> sera traitée comme n'importe quelle largeur ou hauteur de l'item ou comme son max-content. L'espace sera ensuite attribué en fonction du facteur <code>flex-grow</code> en utilisant cette dimension comme point de départ.</li>
<li>Si vous êtes en mode <code>shrink</code> depuis <code>auto</code>, alors <code>flex-basis</code> sera traitée comme n'importe quelle largeur ou hauteur de l'item ou comme son max-content. L'espace sera alors rétréci ou supprimé en fonction de la taille de <code>flex-basis</code> multipliée par le facteur <code>flex-shrink</code> et donc proportionnellement à la taille max-content des items.</li>
</ul><h3>Contrôler grow et shrink</h3><p>J'ai passé la plus grande partie de cet article à décrire ce que fait Flexbox lorsqu'il se débrouille tout seul. Vous pouvez bien sûr exercer un meilleur contrôle sur vos items flexibles en utilisant les propriétés <code>flex</code>. J'espère qu'elles vous paraîtront maintenant plus prévisibles grâce à une bonne compréhension de ce qui se passe en coulisses.</p><p>Si vous définissez votre propre <code>flex-basis</code> ou si vous attribuez à l'élément lui-même une taille ensuite utilisée comme <code>flex-basis</code>, vous reprenez le contrôle de l'algorithme, en indiquant à Flexbox que vous souhaitez augmenter ou réduire cette taille. Vous pouvez désactiver complètement la croissance ou la réduction en réglant <code>flex-grow</code> ou <code>flex-shrink</code> sur <code>0</code>.</p><p>Un dernier point sur cette question du contrôle : lorsque vous sentez monter le désir de mieux contrôler les éléments flexibles, prenez un moment pour vérifier que vous utilisez la bonne méthode de layout : si vous essayez d’aligner des éléments flexibles en deux dimensions, vous feriez sans doute mieux de choisir <a href="https://la-cascade.io/tags/cssgrid/">Grid Layout</a>.</p><h3>Débogage des problèmes liés à la taille</h3><p>Si vos items flex atteignent une dimension inattendue, c'est généralement dû au fait que votre <code>flex-basis</code> est <code>auto</code> et que quelque chose donne à votre item une largeur, qui est ensuite utilisée comme <code>flex-basis</code>. L'inspection de l'élément dans DevTools peut aider à identifier la provenance de la dimension. Vous pouvez également essayer de définir une <code>flex-basis</code> de <code>0</code>, ce qui obligera Flexbox à traiter l'élément comme s'il avait une largeur nulle. Même si vous n'obtenez pas un résultat souhaité, cela vous aidera à identifier la valeur de <code>flex-basis</code> utilisée, laquelle est peut-être la cause de vos problèmes de dimensionnement.</p><h3>Espaces ou gouttières flex</h3><p>Une fonctionnalité très demandée de Flexbox serait la possibilité de spécifier des espaces ou des gouttières entre les éléments flex comme on peut le faire avec CSS Grid Layout. Cette fonctionnalité est spécifiée pour Flexbox dans le cadre de Box Alignment et la première mise en œuvre du navigateur est en route. Pour Firefox ça devrait sortir avec Firefox 63. L'exemple suivant peut être visualisé dans Firefox Nightly.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/NLBEKG/">Smashing Flexbox Series 3: flex-gaps</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><figure role="group"><img itemprop="url" src="https://la-cascade.io/images/flexbox-sizing-flex-gaps-compressor.png" alt="" /><figcaption>L'image vue dans Firefox 63</figcaption></figure><p>Comme pour Grid Layout, la taille de la gouttière est prise en compte avant que l'espace ne soit distribué aux items flex.</p><h3>On récapitule</h3><p>Dans cet article, j’ai essayé d’expliquer en détail comment Flexbox définit la taille des éléments flexibles. Cela peut sembler un peu théorique, cependant, prendre un peu de temps pour comprendre le fonctionnement de cette solution peut vous faire gagner un temps considérable lors de l’utilisation de Flexbox dans vos layouts. Je trouve très utile de revenir au fait que, par défaut, Flexbox essaie de vous donner la présentation la plus judicieuse d’un ensemble d'items de tailles variables. Si un élément a plus de contenu, il dispose de plus d'espace. Si votre design et vous n'êtes pas d'accord avec ce que Flexbox estime préférable, vous pouvez reprendre le contrôle en définissant votre propre <code>flex-basis</code>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-flexbox-et-la-dimension-des-boites</link>
      <guid>https://la-cascade.io/articles/css-flexbox-et-la-dimension-des-boites</guid>
      <pubDate>Mon, 10 Dec 2018 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Flexbox et l'alignement, guide complet]]></title>
      <description><![CDATA[<p><em>Dans cet article, nous examinons les propriétés d'alignement de Flexbox tout en découvrant quelques règles de base qui nous aideront à nous rappeler comment elles fonctionnent sur les axes principal et transversal</em></p><div class="articleContent"><p>Dans <a href="https://la-cascade.io/articles/que-se-passe-t-il-quand-on-cree-un-flexbox-flex-container/">le premier article de cette série</a>, j'ai expliqué ce qui se passait lorsqu'on déclare <code>display: flex</code> sur un élément. Ici, nous allons examiner les propriétés d'alignement et la façon dont elles fonctionnent dans Flexbox. Si <code>align</code> et <code>justify</code> vous ont donné des migraines par le passé, j'espère que cet article rendra les choses plus claires !</p><h2>Une histoire de l'alignement Flexbox</h2><p>Depuis le début de CSS Layout, l'alignement correct des éléments sur les deux axes a toujours semblé le problème le plus ardu en matière de conception de sites Web. La capacité d'aligner correctement des éléments et des groupes d'éléments a donc été, pour beaucoup d'entre nous, l'apport le plus excitant de Flexbox. L'alignement est devenu aussi simple que deux lignes de CSS :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/WKLYEX/">Smashing Flexbox Series 2: center an item</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Les propriétés d'alignement que vous considérez peut-être comme des propriétés Flexbox sont maintenant entièrement définies dans <a href="https://www.w3.org/TR/css-align-3/">la spécification d'alignement de boîte</a> (<em>Box Alignment</em>). Cette spécification détaille le fonctionnement de l'alignement dans les divers contextes de layout. Cela signifie que nous pouvons utiliser les mêmes propriétés d'alignement dans CSS Grid que celles utilisées dans Flexbox – et à l'avenir dans d'autres contextes de layout. Par conséquent, toute nouvelle capacité d'alignement pour Flexbox sera décrite en détail dans la spécification Box Alignment et non dans un futur niveau de Flexbox.</p><h2>Les Propriétés</h2><p>Beaucoup de gens me disent qu’ils ont du mal à se rappeler s’ils doivent utiliser des propriétés qui commencent par <code>align-</code> ou celles qui commencent par <code>justify-</code> dans Flexbox. Ce qu'il faut retenir :</p><ul><li><code>justify-</code> effectue l'alignement de l'axe principal. Alignement dans la même direction que votre <code>flex-direction</code></li>
<li><code>align-</code> effectue un alignement transversal. Alignement dans la direction perpendiculaire à votre <code>flex-direction</code>.</li>
</ul><p>Il est vraiment utile ici de penser en termes d’axe principal et d’axe transversal plutôt que d’horizontale et de verticale.</p><h3>Alignement sur l'axe principal avec justify-content</h3><p>Commençons par l'alignement de l'axe principal. Sur cet axe, nous alignons à l'aide de la propriété <code>justify-content</code>. Cette propriété considère l'ensemble de nos éléments flexibles comme un groupe et contrôle la répartition de l'espace entre les éléments.</p><p>La valeur initiale de <code>justify-content</code> est <code>flex-start</code>. C’est pourquoi, lorsque vous déclarez <code>display: flex</code>, tous les items flexibles sont alignés à partir du début de la ligne flex. Si vous avez une <code>flex-direction</code> de <code>row</code> et que vous parlez une langue écrite de gauche à droite comme l'anglais, les éléments commenceront à gauche.</p><figure role="group"><img src="https://la-cascade.io/images/justify-content-flex-start-compressor.png" alt="" /><figcaption>Les items s'alignent depuis le point de départ</figcaption></figure><p>Remarquez que la propriété <code>justify-content</code> ne peut faire quelque chose <strong>que s'il y a un espace disponible à distribuer</strong>. Par conséquent, si vos items flexibles occupent toute la place sur l'axe principal, l'utilisation de <code>justify-content</code> ne changera rien.</p><figure role="group"><img src="https://la-cascade.io/images/justify-content-no-space-compressor.png" alt="" /><figcaption>Il n'y a pas d'espace à partager</figcaption></figure><p>Si nous donnons à <code>justify-content</code> la valeur <code>flex-end</code>, alors tous les items sont déplacés vers la fin de la ligne. L'espace disponible, s'il y en a, est maintenant placé en début de ligne.</p><figure role="group"><img src="https://la-cascade.io/images/justify-content-flex-end-compressor.png" alt="" /><figcaption>Les items s'alignent sur le point d'arrivée</figcaption></figure><p>Nous pouvons faire d'autres choses avec cet espace. Nous pourrions souhaiter qu’il soit distribué entre nos items flexibles, en utilisant <code>justify-content: space-between</code>. Dans ce cas, le premier et le dernier élément seront alignés avec les extrémités du conteneur et tout l’espace sera partagé de manière égale entre les éléments.</p><figure role="group"><img src="https://la-cascade.io/images/justify-content-space-between-compressor.png" alt="" /><figcaption>L'espace libre est réparti entre les items</figcaption></figure><p>Nous pouvons demander que l’espace soit réparti autour de nos éléments flexibles, en utilisant <code>justify-content: space-around</code>. Dans ce cas, l'espace disponible est partagé et placé de chaque côté de l'élément.</p><figure role="group"><img src="https://la-cascade.io/images/justify-content-space-around-compressor.png" alt="" /><figcaption>Les items ont de l'espace de chaque côté</figcaption></figure><p>Une valeur plus récente de <code>justify-content</code> peut être trouvée dans la spécification Box Alignment. Elle n'apparaît pas dans la spécification Flexbox. Cette valeur est <code>space-evenly</code>. Dans ce cas, les éléments seront répartis de manière uniforme dans le conteneur et l'espace supplémentaire sera partagé entre les éléments et de chaque côté.</p><figure role="group"><img src="https://la-cascade.io/images/justify-content-space-evenly-compressor.png" alt="" /><figcaption>Les éléments sont uniformément répartis</figcaption></figure><p>Vous pouvez jouer avec toutes ces valeurs dans la démo :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/Owraaj/">justify-content with flex-direction: row</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Ces valeurs fonctionnent de la même manière si votre <code>flex-direction</code> est <code>column</code>. Il est possible toutefois que la colonne n'offre pas autant d'espace disponible, à moins d'ajouter une hauteur ou une dimension de bloc au conteneur flex comme dans la démo suivante :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/zLyMyV/">justify-content with flex-direction: column</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h3>Alignement sur l'axe transversal avec align-content</h3><p>Si vous avez ajouté <code>flex-wrap: wrap</code> à votre conteneur flex et que vous avez plusieurs lignes flex, vous pouvez utiliser <code>align-content</code> pour aligner vos lignes flex sur l'axe transversal. Toutefois, il vous faudra disposer d'un espace supplémentaire sur l'axe transversal. Dans la démonstration ci-dessous, mon axe transversal fonctionne dans la direction bloc comme une colonne et j'ai défini la hauteur du conteneur flex à 60vh. C'est plus que l'espace nécessaire pour afficher mes items flex, j'ai donc de la place verticalement dans le conteneur.</p><p>Je peux ensuite utiliser <code>align-content</code> avec les valeurs ci-dessous :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/pZqqMJ/">Smashing Flexbox Series 2: align-content with flex-direction: row</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si ma <code>flex-direction</code> était <code>column</code> alors <code>align-content</code> fonctionnerait comme dans l'exemple suivant :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/MBZZNy/">Smashing Flexbox Series 2: align-content with flex-direction: column</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Tout comme précédemment avec <code>justify-content</code>, nous traitons les lignes comme un groupe et nous distribuons l'espace disponible.</p><h3>Le raccourci place-content</h3><p>Dans la spécification Box Alignment, on trouve le raccourci <code>place-content</code>. Avec cette propriété, vous pouvez définir en même temps <code>justify-content</code> et <code>align-content</code>. La première valeur est pour <code>align-content</code>, la seconde pour <code>justify-content</code> :</p><pre>.container {
    place-content: space-between stretch;
}</pre><p>équivaut à :</p><pre>.container {
    align-content: space-between;
    justify-content: stretch;
}</pre><p>Si par contre vous ne définissez qu'une seule valeur, <code>align-content</code> et <code>justify-content</code> prennent cette valeur :</p><pre>.container {
    place-content: space-between;
}</pre><p>équivaut à :</p><pre>.container {
    align-content: space-between;
    justify-content: space-between;
}</pre><h3>Alignement sur l'axe transversal avec align-items</h3><p>Nous savons maintenant que nous pouvons aligner notre ensemble d'items flex ou nos lignes flex comme un groupe. Cependant, nous pourrions souhaiter aligner nos éléments d’une autre manière : <strong>aligner les éléments les uns par rapport aux autres</strong> sur l’axe transversal. Votre conteneur flex a une hauteur. Cette hauteur peut être définie par la hauteur de l'élément le plus grand, comme dans cette image.</p><figure role="group"><img src="https://la-cascade.io/images/container-height-of-item-compressor.png" alt="" /><figcaption>La hauteur du conteneur est définie par celle du 3e élément</figcaption></figure><p>Mais on pourrait aussi la définir en ajoutant une hauteur au conteneur flex :</p><figure role="group"><img src="https://la-cascade.io/images/container-added-height-compressor.png" alt="" /><figcaption>La hauteur du conteneur est définie comme une dimension du conteneur</figcaption></figure><p>La raison pour laquelle les éléments flexibles semblent s’étirer jusqu’à atteindre la taille de l’élément le plus grand est que la valeur initiale d’<code>align-items</code> est <code>stretch</code>. Les items s'étirent sur l'axe transversal pour prendre la taille du conteneur flexible dans cette direction.</p><p>Notez qu'en ce qui concerne <code>align-items</code>, si vous avez un conteneur flex multi-lignes, chaque ligne se comporte comme un nouveau conteneur Flex. L'item le plus grand de cette ligne définirait la taille de tous les items de cette ligne.</p><p>En plus de la valeur initiale de stretch, vous pouvez attribuer à <code>align-items</code> la valeur de <code>flex-start</code>. Dans ce cas, les items s'alignent au début du conteneur et ne s'étirent plus en hauteur.</p><figure role="group"><img src="https://la-cascade.io/images/align-items-flex-start-compressor.png" alt="" /><figcaption>Les items sont alignés au départ de l'axe transversal</figcaption></figure><p>La valeur <code>flex-end</code> les déplace à la fin de l'axe transversal :</p><figure role="group"><img src="https://la-cascade.io/images/align-items-flex-end-compressor.png" alt="" /><figcaption>Les items sont alignés à la fin de l'axe transversal</figcaption></figure><p>Si vous utilisez la valeur <code>center</code>, les items sont centrés les uns par rapport aux autres :</p><figure role="group"><img src="https://la-cascade.io/images/align-items-center-compressor.png" alt="" /><figcaption>Les items sont centrés sur l'axe transversal</figcaption></figure><p>Enfin, nous pouvons aligner les items sur la <a href="https://fr.wikipedia.org/wiki/Ligne_de_base_(typographie)">ligne de base</a>, permettant ainsi de s'assurer que le <em>texte</em> est aligné, ce qui ne serait pas nécessairement le cas si l'alignement se faisait sur le contenu.</p><figure role="group"><img src="https://la-cascade.io/images/align-items-baseline-compressor.png" alt="" /><figcaption>Les items sont centrés sur la ligne de base</figcaption></figure><p>Vous pouvez jouer avec toutes ces valeurs dans la démo :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/WKLBpv/">Smashing Flexbox Series 2: align-items with flex direction: row</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h3>Alignement individuel avec align-self</h3><p>La propriété <code>align-items</code> vous permet de définir l'alignement de tous les éléments en même temps. En réalité, cela permet de définir toutes les valeurs <code>align-self</code> sur les éléments flex individuels de manière groupée. Vous pouvez également utiliser la propriété <code>align-self</code> sur tout élément flex individuel pour l'aligner à l'intérieur de la ligne flex et par rapport aux autres éléments flex.</p><p>Dans l'exemple suivant, j'ai utilisé <code>align-items</code> sur le conteneur pour définir l'alignement du groupe sur <code>center</code>, mais j'ai également utilisé <code>align-self</code> sur le premier et le dernier éléments pour modifier leur valeur d'alignement (vérifiez en cliquant sur CSS).</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/KBbLmz/">Smashing Flexbox Series 2: align-self</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Pourquoi n'y a-t-il pas de justify-self ?</h2><p>Une question souvent posée est de savoir pourquoi il n'est pas possible d'aligner un élément ou un groupe d'éléments sur l'axe principal. Pourquoi n'y a-t-il pas de propriété <code>-self</code> pour l'alignement sur l'axe principal dans Flexbox ? Si vous considérez <code>justify-content</code> et <code>align-content</code> comme étant une façon de distribuer l'espace, la raison pour laquelle ils ne sont pas auto-alignés devient plus évidente. Nous traitons les éléments flexibles en tant que groupe et distribuons l'espace disponible d'une manière ou d'une autre - au début ou à la fin du groupe, ou entre les éléments.</p><p>Il pourrait également être utile de réfléchir à la manière dont <code>justify-content</code> et <code>align-content</code> fonctionnent dans <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/">CSS Grid Layout</a>. Dans Grid, ces propriétés sont utilisées pour répartir l'espace disponible dans le conteneur de grille <em>entre</em> les pistes (<em>tracks</em>) de la grille. Une fois encore, nous prenons les pistes en tant que groupe et ces propriétés nous permettent de répartir l'éventuel espace supplémentaire entre elles. Comme nous agissons sur un groupe, à la fois dans Grid et dans Flexbox, nous ne pouvons pas cibler un élément seul et faire quelque chose de différent avec celui-ci. Cependant, il existe un moyen de réaliser le type de présentation auquel vous pensez lorsque vous souhaitez une propriété <code>-self</code> sur l'axe principal, et ce moyen c'est l'utilisation de marges automatiques.</p><h2>Utiliser les marges automatiques sur l'axe principal</h2><p>Si vous avez déjà centré un bloc dans CSS (par exemple le wrapper du contenu de votre page principale, en définissant une marge <code>auto</code> à gauche et à droite), vous avez déjà une expérience du comportement des marges automatiques. Une marge réglée sur <code>auto</code> essayera de devenir aussi grande que possible dans la direction dans laquelle elle a été définie. Lorsque les marges sont utilisées pour centrer un bloc, nous définissons les positions gauche et droite sur <code>auto</code>, chacune essaye de prendre le plus de place possible et pousse notre bloc au centre.</p><p>Les marges automatiques fonctionnent très bien dans Flexbox pour aligner des éléments uniques ou des groupes d’éléments sur l’axe principal. Dans l'exemple qui suit, je réalise un <em>design pattern</em> très courant. J'ai une barre de navigation utilisant Flexbox, les éléments sont affichés sur une ligne et utilisent la valeur initiale de <code>justify-content: start</code>. J'aimerais que le dernier élément soit affiché séparément des autres, à la fin de la ligne flex – en supposant qu'il y ait suffisamment d'espace sur la ligne pour le faire.</p><p>Je cible cet item et je lui donne une marge gauche <code>auto</code>. Cela a pour effet que la marge essaie d'obtenir le plus d'espace possible à gauche de l'élément, ce qui entraîne le déplacement de l'élément complètement à droite.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/oMJROm/">Smashing Flexbox Series 2: main axis alignment with auto margins</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Si vous utilisez les marges automatiques sur l'axe principal, <code>justify-content</code> n'aura plus d'effet puisque les marges automatiques auront pris tout l'espace qui aurait pu être utilisé par <code>justify-content</code>.</p><h2>Alignement de repli</h2><p>Chaque méthode d’alignement détaille un alignement de repli (<em>fallback</em>), c’est à dire ce qui se produira si l’alignement que vous avez demandé ne peut pas être réalisé. Par exemple, si vous n'avez qu'un seul élément dans un conteneur flexible et demandez <code>justify-content: space-between</code>, que devrait-il se passer ? La réponse est que l'alignement de repli <code>flex-start</code> est utilisé et que votre item individuel s'alignera au début du conteneur flex. Dans le cas de <code>justify-content: space-around</code>, un alignement de repli <code>center</code>est utilisé.</p><p>Dans la spécification actuelle, vous ne pouvez pas modifier l'alignement de repli. Si vous préférez que le repli de <code>space-between</code> soit <code>center</code> plutôt que <code>flex-start</code>, il n'y a pas moyen de le faire. Cependant, <a href="https://www.w3.org/TR/css-align-3/#distribution-values">une note dans la spécification</a> indique que les niveaux futurs devraient le permettre.</p><h2>Alignement safe et unsafe</h2><p>Un ajout plus récent à la spécification Box Alignment est le concept d'alignement sécurisé / non sécurisé à l'aide des mots clés <code>safe</code> et <code>unsafe</code>.</p><p>Dans le code suivant, le dernier élément est trop large pour le conteneur et, avec un alignement non sécurisé et le conteneur flexible sur le côté gauche de la page, l'élément est coupé : le débordement se situe en dehors des limites de la page.</p><pre>.container {
    display: flex;
    flex-direction: column;
    width: 100px;
    align-items: unsafe center;
}
.item:last-child {
    width: 200px;
}</pre><figure role="group"><img src="https://la-cascade.io/images/unsafe-alignment-compressor.png" alt="" /><figcaption>Un alignement non sécurisé vous donnera l'alignement que vous souhaitez mais vous pouvez y perdre des données</figcaption></figure><p>Un alignement sécurisé évite la perte de données, en déplaçant le débordement vers l'autre côté.</p><pre>.container {
    display: flex;
    flex-direction: column;
    width: 100px;
    align-items: safe center;
}
.item:last-child {
    width: 200px;
}</pre><figure role="group"><img src="https://la-cascade.io/images/safe-alignment-compressor.png" alt="" /><figcaption>Un alignement sécurisé essaie d'éviter la perte de données</figcaption></figure><p>Ces mots-clés ont un support navigateur encore limité mais ils sont une bonne illustration du contrôle supplémentaire apporté à Flexbox via la spécification Box Alignment.</p><h3>Récapitulation</h3><p>Les propriétés d'alignement ont commencé sous forme de liste dans Flexbox, mais elles ont maintenant leur propre spécification et s'appliquent à d'autres contextes de layout. Quelques points-clés vous aideront à vous rappeler comment les utiliser dans Flexbox:</p><ul><li><code>justify-</code> l'axe principal et <code>align-</code> l'axe transversal;</li>
<li>Pour utiliser <code>align-content</code> et <code>justify-content</code>, vous avez besoin d'espace disponible.</li>
<li>Les propriétés <code>align-content</code> et <code>justify-content</code> traitent les éléments en tant que groupe, en partageant de l'espace. Par conséquent, vous ne pouvez pas cibler un élément individuel et il n’existe donc pas d’alignement de type <code>-self</code> pour ces propriétés;</li>
<li>Si vous souhaitez aligner un élément ou diviser un groupe sur l'axe principal, utilisez les marges automatiques pour le faire.</li>
<li>La propriété <code>align-items</code> définit toutes les valeurs <code>align-self</code> en tant que groupe. Utilisez <code>align-self</code> sur le flex enfant pour définir la valeur d'un élément individuel.</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/css-flexbox-et-lalignement-guide-complet</link>
      <guid>https://la-cascade.io/articles/css-flexbox-et-lalignement-guide-complet</guid>
      <pubDate>Sun, 09 Dec 2018 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Le DOM, c'est quoi exactement ?]]></title>
      <description><![CDATA[<p><em>Le DOM (Document Object Model) est une interface pour vos pages web. C'est une API permettant aux programmes de lire et de manipuler le contenu de la page, sa structure et ses styles. Passons tout cela en revue pour comprendre comment ça marche.</em></p><div class="articleContent"><h2>Comment une page web est-elle construite ?</h2><p>Le cheminement d'un navigateur partant d'un document source HTML pour finalement afficher une page stylée et interactive s'appelle le chemin critique du rendu (<em>critical rendering path</em>). Ce processus peut comporter de nombreuses étapes, comme je le montre dans <a href="https://bitsofco.de/understanding-the-critical-rendering-path/">mon article sur le sujet</a>, mais celles-ci peuvent être regroupées en deux grandes étapes. La première consiste en <strong>l'analyse du document</strong> par le navigateur pour déterminer ce qui sera finalement rendu sur la page, et la seconde est <strong>le rendu</strong> par le navigateur.</p><figure><img src="https://la-cascade.io/images/HTML-to-Render-Tree-to-Final-compressor.png" alt="la décomposition du processus en deux étapes" /></figure><p>La première étape permet de construire l'arbre de rendu (<em>render tree</em>), une représentation sous forme d'arbre des <strong>éléments HTML</strong> qui seront rendus sur la page ainsi que leurs styles associés. Pour cela, le navigateur a besoin de deux choses :</p><ol><li>le CSSOM, une représentation des styles associés aux éléments</li>
<li>le DOM, la représentation des éléments</li>
</ol><h2>Comment le DOM est créé, et à quoi il ressemble</h2><p>Le DOM est une représentation du document HTML source. Comme nous le verrons plus loin, il comporte quelques différences, mais il s’agit pour l'essentiel d’une conversion de la structure et du contenu du document HTML en un modèle objet utilisable par divers programmes.</p><p>La structure d'objet du DOM est représentée par ce qu'on appelle une "arborescence de noeuds" (<em>node tree</em>). On l'appelle ainsi parce qu'il peut être considéré comme un arbre qui se ramifie en plusieurs branches enfants, chacune pouvant avoir des feuilles. Le premier parent est l'élément racine <code>&lt;html&gt;</code>, les "branches" enfants sont les <strong>éléments</strong> imbriqués et les "feuilles" sont le <strong>contenu</strong> des éléments.</p><p>Prenons par exemple ce document HTML :</p><pre>&lt;!doctype html&gt;
&lt;html lang="en"&gt;
 &lt;head&gt;
   &lt;title&gt;My first web page&lt;/title&gt;
  &lt;/head&gt;
 &lt;body&gt;
    &lt;h1&gt;Hello, world!&lt;/h1&gt;
    &lt;p&gt;How are you?&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p>Ce document peut être représenté comme une arborescence de noeuds :</p><figure><img src="https://la-cascade.io/images/node-tree-example-compressor.png" alt="" /></figure><h2>Ce que n'est pas le DOM</h2><p>De l'exemple ci-dessus on pourrait conclure que le DOM est un mapping exact du document source HTML ou de ce que vous voyez dans votre DevTools. Cependant, il y a des différences. Pour bien comprendre ce qu'est le DOM, nous devons d'abord comprendre ce qu'il n'est <strong>pas</strong>.</p><h3>Le DOM n'est pas votre HTML source</h3><p>Bien que créé à partir du document source HTML, le DOM n'en est pas toujours l'exact reflet. Il peut en différer dans deux cas :</p><h4>1. Lorsque le HTML n'est pas valide</h4><p>Le DOM est une interface pour les documents HTML valides. Pendant le processus de création du DOM, le navigateur peut être amené à corriger des informations invalides.</p><p>Prenons ce document HTML par exemple :</p><pre>&lt;!doctype html&gt;
&lt;html&gt;
Hello, world!
&lt;/html&gt;</pre><p>Il manque les éléments <code>&lt;head&gt;</code> et <code>&lt;body&gt;</code> à ce document, alors qu'ils sont requis dans un HTML valide. Si nous inspectons l'arborescence créée, nous pouvons constater que l'erreur a été corrigée :</p><figure><img src="https://la-cascade.io/images/corrected-html-compressor.png" alt="" /></figure><h4>2. Lorsque le DOM est modifié par JavaScript</h4><p>En plus d'être une interface permettant de visualiser le contenu d'un document HTML, le DOM peut être modifié, ce qui en fait une ressource vivante.</p><p>Nous pouvons par exemple créer des noeuds supplémentaires via JavaScript.</p><pre>var newParagraph = document.createElement("p");
var paragraphContent = document.createTextNode("I'm new!");
newParagraph.appendChild(paragraphContent);
document.body.appendChild(newParagraph);</pre><p>Le DOM sera mis à jour, mais bien entendu notre document source HTML restera inchangé.</p><h3>Le DOM n'est pas ce que vous voyez dans le navigateur</h3><p>Ce que vous voyez dans le viewport de votre navigateur c'est l'arbre de rendu qui, nous l'avons vu, est un mélange de DOM et de CSSOM. Ce qui distingue le DOM de l'arbre de rendu c'est que ce dernier ne comprend que ce qui sera "peint" à l'écran. De ce fait, il exclut les éléments visuellement cachés, par exemple ceux stylés <code>display: none</code>.</p><pre>&lt;!doctype html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;&lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Hello, world!&lt;/h1&gt;
    &lt;p style="display: none;"&gt;How are you?&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p>Le DOM comprendra l'élément<code>&lt;p&gt;</code>:</p><figure><img src="https://la-cascade.io/images/dom-with-p-compressor.png" alt="" /></figure><p>Cependant l'arbre de rendu — et donc ce qui est visible dans le viewport — ne comprendra pas cet élément.</p><figure><img src="https://la-cascade.io/images/rendertree-without-p-compressor.png" alt="" /></figure><h3>Le DOM n'est pas ce que vous voyez dans DevTools</h3><p>Cette différence ne tient pas à grand chose car l'inspecteur d'éléments DevTools offre la meilleure approximation du DOM disponible dans le navigateur. Toutefois DevTools inclut des informations qui ne sont pas dans le DOM.</p><p>Le meilleur exemple en est <a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after/">les pseudo-éléments CSS</a> créées via les sélecteurs <code>::before</code> et <code>::after</code>. Ils font partie du CSSOM et de l'arbre de rendu mais techniquement ils n'appartiennent pas au DOM puisque celui-ci est construit à partir du seul document source HTML, qui ne comprend pas les styles appliqués aux éléments.</p><p>Bien que ne faisant pas partie du DOM, les pseudo-éléments apparaissent dans notre inspecteur DevTools :</p><figure><img src="https://la-cascade.io/images/Pseudo-element-in-devtools-inspector.png" alt="" /></figure><p>C'est la raison pour laquelle les pseudo-éléments ne peuvent pas être ciblés par JavaScript, parce qu'ils ne font pas partie du DOM !</p><h2>On récapitule</h2><p>Le DOM est une interface vers un document HTML. Il est utilisé par les navigateurs dans une première étape pour déterminer ce qui peut être rendu à l'écran, et par JavaScript pour modifier le contenu, la structure ou le style de la page.</p><p>Bien que similaire à d'autres formes de documents source HTML, il en diffère en plusieurs points :</p><ul><li>son HTML est toujours valide</li>
<li>c'est un modèle vivant qui peut être modifié par JavaScript</li>
<li>il ne comprend pas de pseudo-éléments (p.ex. <code>::after</code>)</li>
<li>il ne comprend pas d'élémens cachés (p.ex. via <code>display: none</code>)</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/le-dom-cest-quoi-exactement</link>
      <guid>https://la-cascade.io/articles/le-dom-cest-quoi-exactement</guid>
      <pubDate>Sat, 01 Dec 2018 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Que se passe-t-il quand on crée un Flexbox flex container?]]></title>
      <description><![CDATA[<p><em>Lorsque les gens trouvent Flexbox difficile ou déroutant, c'est souvent parce qu'ils essaient de l'utiliser comme Grid layout.</em></p><div class="articleContent"><p><em>PETIT RÉSUMÉ: dans un monde idéal, CSS Grid et Flexbox seraient arrivés ensemble, déjà parfaits pour constituer à eux deux un système de layout pour le Web. Mais au lieu de cela, nous avons d’abord eu Flexbox et, comme il était bien meilleur que</em> floats <em>pour créer des dispositions de type grille, nous nous sommes retrouvés avec beaucoup de systèmes de grille basés sur Flexbox. En fait, lorsque les gens trouvent Flexbox difficile ou déroutant, c'est souvent parce qu'ils essaient de l'utiliser comme Grid layout</em>.</p><p>Dans cette courte série d’articles, je vais passer un peu de temps à décomposer en détail Flexbox, comme je l’ai fait dans le passé avec Grid. Nous verrons ce pour quoi Flexbox a été conçu, ce qu'il fait vraiment bien et ce pourquoi il ne serait pas le meilleur choix de méthode de layout. Dans cet article, nous examinerons en détail ce qui se passe réellement lorsque vous ajoutez <code>display: flex</code> à votre feuille de style.</p><h2>Un conteneur Flex, s'il vous plaît!</h2><p>Pour utiliser Flexbox, vous avez besoin d’un élément qui sera le conteneur flex. Dans votre CSS, vous utilisez <code>display: flex</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/PBRGQO/">Smashing Flexbox Series 1: display: flex;</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Prenons un peu de temps pour réfléchir à ce que <code>display: flex</code> signifie vraiment. Dans le <a href="https://www.w3.org/TR/css-display-3/">module CSS Display niveau 3</a>, chaque valeur d'affichage est décrite comme une combinaison de deux choses : un modèle d'affichage interne et un modèle d'affichage externe. Lorsque nous ajoutons <code>display: flex</code>, nous définissons en réalité <code>display: block flex</code>. Le type d'affichage externe de notre conteneur flex est <code>block</code>; il agit comme un élément de niveau bloc dans un flux normal. Le type d'affichage interne est <code>flex</code>, ce qui aura pour effet que les éléments situés à l'intérieur de notre conteneur participeront au layout flex.</p><p>C’est une chose à laquelle vous n’auriez peut-être jamais vraiment pensé mais que vous comprenez probablement de toute façon : Le conteneur flex se comporte lui-même comme n'importe quel autre bloc de votre page. Si vous avez un paragraphe suivi d'un conteneur flex, les deux se comportent comme les éléments de niveau bloc auxquels sommes habitués.</p><p>Nous pouvons également définir notre conteneur avec une valeur de <code>inline-flex</code>, ce qui revient à utiliser <code>display: inline flex</code>, c’est-à-dire un conteneur flex qui agit comme un élément de niveau <code>inline</code>, avec des enfants participant au layout flex. Les enfants de notre conteneur inline flex se comportent de la même manière que les enfants de notre conteneur block flex. La différence réside dans la manière dont le conteneur lui-même se comporte dans la mise en page générale.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/YjaGvZ/">Smashing Flexbox Series 1: display: inline-flex;</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Il est très utile de raisonner à partir de ce concept d'éléments ayant d'une part <strong>un type d'affichage externe</strong>, définissant la manière dont ils se comportent en tant que boîte, et d'autre part <strong>un type d'affichage interne</strong> dictant le comportement de leurs enfants. Vous pouvez appliquer cette approche à n’importe quelle boîte CSS. Comment agit cet élément? Comment agissent les enfants de cet élément? Les réponses renvoient aux modèles d'affichage externe et interne.</p><h2>Rangées ou colonnes ?</h2><p>Une fois défini notre conteneur flex, certaines valeurs initiales doivent être précisées. Sans l'ajout de propriétés supplémentaires, les éléments flex s'affichent sous forme de rangée car la valeur initiale de la propriété <code>flex-direction</code> est <code>row</code>. Si vous ne le définissez pas, vous obtenez une rangée.</p><p>On utilise la propriété <code>flex-direction</code> pour définir la direction de l'axe principal. Les autres valeurs de <code>flex-direction</code> sont:</p><ul><li><code>column</code></li>
<li><code>row-reverse</code></li>
<li><code>column-reverse</code></li>
</ul><p>Si nos items (éléments individuels) sont sur une rangée, ils sont placés avec le premier au départ de la dimension inline et s'affichent dans l'ordre dans lequel ils apparaissent dans la source. Dans la spécification, ce point de départ est décrit comme le <code>main-start</code> :</p><figure role="group"><img src="https://la-cascade.io/images/row-main-start-compressor.png" alt="" /><figcaption><strong>main-start</strong> est le départ de la dimension inline</figcaption></figure><p>Si nous utilisons la valeur <code>column</code>, les items s'affichent à partir du point de départ de la dimension block, et par conséquent forment une colonne.</p><figure role="group"><img src="https://la-cascade.io/images/column-main-start-compressor.png" alt="" /><figcaption><strong>main-start</strong> est le départ de la dimension block</figcaption></figure><p>Si nous utilisons <code>row-reverse</code>, alors <code>main-start</code>et <code>main-end</code> sont inversés et les items s'affichent l'un après l'autre dans l'ordre inverse.</p><figure role="group"><img src="https://la-cascade.io/images/row-reverse-main-start-compressor.png" alt="" /><figcaption><strong>main-start</strong> est à la fin de la dimension inline</figcaption></figure><p>La valeur <code>column-reverse</code> fait la même chose. Il est important de se rappeler que ces valeurs ne changent pas l’ordre des items, elles modifient simplement le point de départ du flux d’éléments: en basculant <code>main-start</code>. Nos items s'affichent donc dans l'ordre inverse, mais c'est parce qu'ils commencent à se placer à l'autre bout du conteneur.</p><p>L'effet est purement visuel. Nous demandons aux items de s'afficher eux-mêmes en commençant par l'autre côté mais ils circulent toujours dans le même ordre, celui utilisé par votre lecteur d'écran, qui est aussi celui de tabulation. Par conséquent, il est important de ne jamais utiliser <code>row-reverse</code> lorsque vous voulez vraiment changer l'ordre des éléments. Faites ce changement dans votre document.</p><h2>Les deux axes de Flexbox</h2><p>Nous avons déjà exposé une caractéristique importante de Flexbox: la possibilité de basculer l’axe principal de rangée à colonne, qui peut sembler complexe. Il est souvent plus facile de comprendre l’alignement dans Grid layout. Avec Grid, comme on travaille en deux dimensions, on peut aligner les deux axes à peu près de la même manière. Flexbox est un peu plus compliqué car différentes choses se produisent selon que vous travaillez avec l'axe principal ou avec l'axe transversal.</p><p>Nous avons déjà rencontré l’axe principal (<em>main-axis</em>), c’est-à-dire l’axe que vous définissez comme valeur de <code>flex-direction</code>. L'axe transversal (<em>cross-axis</em>) est l'autre dimension. Si vous avez défini <code>flex-direction: row</code>, votre axe principal est le long de la rangée et votre axe transversal descend le long de la colonne. Avec <code>flex-direction: column</code>, l'axe principal suit la colonne et votre axe transversal le long des rangées. C’est ici que nous devons explorer une autre caractéristique importante de Flexbox, à savoir le fait qu’elle n’est pas liée aux dimensions physiques de l’écran. Nous ne parlons pas d’une ligne allant de gauche à droite, ni d’une colonne de haut en bas, car ce n’est pas toujours le cas.</p><h3>Modes d'écriture</h3><p>Lorsque j'ai décrit la rangée et la colonne, j'ai mentionné les dimensions <code>block</code> et <code>inline</code>. Cet article est écrit à l'origine en anglais, qui est un mode d'écriture horizontal. Cela signifie que lorsque vous demandez à Flexbox de vous donner une ligne, vous obtenez un affichage horizontal de vos éléments flexibles. Dans ce cas, main-start est à gauche - l'endroit où les phrases commencent en anglais.</p><p>Si je travaillais dans une langue écrite de droite à gauche telle que l'arabe, le bord de départ serait à droite:</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/JBLEdZ/">Smashing Flexbox Series 1: row with rtl text</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Les valeurs initiales de flexbox signifient que si tout ce que je fais est de créer un conteneur flex, mes items partiront de la droite et s'afficheront en se déplaçant vers la gauche. Le point de départ dans la direction inline est l'endroit où les phrases commencent dans le mode d'écriture que vous utilisez.</p><p>Si vous vous trouvez en mode d'écriture verticale et demandez une rangée, celle-ci s'exécutera verticalement, car c'est ainsi que les rangées de texte s'affichent dans un langage vertical. Vous pouvez essayer ceci en ajoutant la propriété <code>writing-mode</code> à votre conteneur flex et en lui attribuant la valeur <code>vertical-lr</code>. Désormais, lorsque vous définissez <code>flex-direction</code> sur <code>row</code>, vous obtenez une colonne verticale d'éléments.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/oMqBXa/">Smashing Flexbox Series 1: row with a vertical writing mode</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Ainsi, une rangée peut se dérouler horizontalement, avec un <code>main-start</code> à gauche ou à droite, et verticalement avec un <code>main-start</code> en haut. C’est toujours une <code>flex-direction</code> de <code>row</code> même si nos esprits habitués au texte horizontal ont du mal à penser une ligne qui court verticalement !</p><p>Pour que les éléments s'affichent dans la dimension <code>block</code>, définissez la valeur de <code>flex-direction</code> sur <code>column</code> ou <code>column-reverse</code>. En anglais (ou en arabe), nous voyons ensuite les éléments s’afficher de manière superposée jusqu'en bas de la page, en commençant par le sommet du conteneur.</p><p>Dans un mode d'écriture vertical, la dimension <code>block</code> traverse la page, car il s'agit de la direction des blocs dans ces modes d'écriture. Si vous demandez une colonne dans <code>vertical-lr</code>, vos blocs iront de gauche à droite verticalement:</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/yqKgeb/">Smashing Flexbox Series 1: column in vertical-lr writing mode</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Toutefois, quelle que soit la direction d'affichage des blocs, si vous travaillez avec une colonne, vous travaillez dans la dimension <code>block</code>.</p><p>Pour comprendre la terminologie de Grid et Flexbox, il est utile de bien saisir qu'une rangée ou une colonne peut être exécutée dans différentes directions physiques. Nous ne faisons pas référence à "gauche et droite" ou "haut et bas" dans Flexbox et Grid car nous ne faisons aucune hypothèse quant au mode d’écriture de notre document. CSS est de plus en plus conscient des différences de mode écriture. Si vous êtes intéressés par d'autres propriétés et valeurs implémentées de la sorte en CSS, lisez mon article sur les <a href="https://www.smashingmagazine.com/2018/03/understanding-logical-properties-values/">propriétés et valeurs logiques</a>.</p><p>En résumé, rappelez-vous que:</p><ul><li>
<p><strong>flex-direction : row</strong></p>
<ul><li>axe principal = dimension inline</li>
<li>main-start sera l'endroit où les phrases commencent dans ce mode d'écriture</li>
<li>axe transversal = dimension block</li>
</ul></li>
<li>
<p><strong>flex-direction : column</strong></p>
<ul><li>axe principal = dimension block</li>
<li>main-start sera le point de départ des blocs dans ce mode d'écriture</li>
<li>axe transversal = dimension inline</li>
</ul></li>
</ul><h2>Alignement initial</h2><p>D'autres choses se produisent lorsque nous utilisons <code>display: flex</code>. Un alignement initial se produit. Dans un prochain article de cette série, nous examinerons en détail l’alignement, mais dans notre exploration de <code>display: flex</code>, nous devrions déjà examiner <em>les valeurs initiales appliquées</em>.</p><p>Remarque: il est à noter que, bien que ces propriétés d'alignement trouvent leur origine dans la spécification Flexbox, elles seront à terme <a href="https://www.w3.org/TR/css-flexbox-1/#alignment">remplacées par la spécification BoxAlignement</a>.</p><h3>Alignement sur l'axe principal</h3><p>La valeur initiale de <code>justify-content</code> est <code>flex-start</code>. Tout se passe comme si notre CSS était:</p><pre>.container {
    display: flex;
    justify-content: flex-start;
}</pre><p>C'est la raison pour laquelle nos items flex s'alignent au départ du conteneur flex. C’est aussi la raison pour laquelle, lorsque nous définissons <code>row-reverse</code>, ils basculent de l'autre côté, qui devient alors le départ de l’axe principal.</p><p>Lorsque vous voyez une propriété d’alignement qui commence par <code>justify-</code>, elle s’applique à l’axe principal de Flexbox. Donc <code>justify-content</code> effectue l'alignement sur l'axe principal et aligne nos éléments au début.</p><p>Les autres valeurs possibles pour <code>justify-content</code> sont :</p><ul><li><code>flex-end</code></li>
<li><code>center</code></li>
<li><code>space-around</code></li>
<li><code>space-between</code></li>
<li><code>space-evenly</code> (ajouté dans Box Alignment)</li>
</ul><p>Ces valeurs gèrent la distribution de l'espace disponible dans le conteneur flex, c'est ainsi que les éléments sont déplacés ou espacés. Par exemple, si vous ajoutez <code>justify-content: space-between</code>, tout l'espace disponible est partagé entre les éléments. Cependant, cela ne peut se produire que s'il existe <em>effectivement</em> un espace libre. Si vous aviez un conteneur flex sans espace supplémentaire après que tous les items aient été disposés, alors <code>justify-content</code> ne ferait rien du tout.</p><p>Vous pouvez le constater aisément si vous changez votre <code>flex-direction</code> en <code>column</code>. Si vous n'indiquez pas de hauteur sur le conteneur flex, il n’y aura pas d’espace libre entre les items, donc utiliser <code>justify-content: space-between</code> n'aura aucun effet. Si vous ajoutez une hauteur et faites en sorte que le conteneur soit plus grand que ce qui est nécessaire pour afficher les éléments, alors la propriété aura un effet :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/wxmgrW/">Smashing Flexbox Series 1: column with a height</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h3>Alignement croisé</h3><p>Les items sont également alignés sur l'axe transversal avec un conteneur flex à une seule ligne. Cela revient à aligner les boîtes les unes contre les autres sur la ligne. Dans l'exemple suivant, l'une de nos boîtes comporte plus de contenu que toutes les autres. Quelque chose dit aux autres cases de s’étirer à la même hauteur. Ce quelque chose est la propriété <code>align-items</code>, qui a pour valeur initiale <code>stretch</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/GBxryJ/">Smashing Flexbox Series 1: align-items</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>Lorsque vous voyez une propriété d'alignement qui commence par <code>align-</code> et que vous êtes dans une flexbox, vous avez alors affaire à un alignement transversal et <code>align-items</code> aligne les éléments dans la ligne de flex. Les autres valeurs possibles sont:</p><ul><li><code>flex-start</code></li>
<li><code>flex-end</code></li>
<li><code>center</code></li>
<li><code>baseline</code></li>
</ul><p>Si vous ne souhaitez pas que les hauteurs des boîtes soient toutes étirées pour correspondre à la plus haute, <code>align-items: flex-start</code> les alignera toutes sur le bord supérieur de départ de l'axe transversal.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/RBMKyN/">Smashing Flexbox Series 1: align-items: flex-start</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><h2>Valeurs initiales pour les éléments flex</h2><p>Enfin, les éléments flex eux-mêmes ont également des valeurs initiales, elles sont définies sur:</p><ul><li><code>flex-grow: 0</code></li>
<li><code>flex-shrink: 1</code></li>
<li><code>flex-basis: auto</code></li>
</ul><p>Cela signifie que nos éléments ne s'agrandiront pas par défaut pour occuper l'espace disponible sur l'axe principal. Si <code>flex-grow</code> avait une valeur positive, les éléments grandiraient et occuperaient tout l'espace disponible.</p><p>Les items peuvent être réduits, cependant, puisque <code>flex-shrink</code> est défini sur la valeur positive de 1. Cela signifie que si nous avons un conteneur flex très étroit, les éléments seront aussi petits que possible avant tout débordement. C'est un comportement qui fait sens: en général, nous voulons que les choses restent à l'intérieur de leurs boîtes et ne débordent pas s'il y a assez d'espace pour les afficher.</p><p>Afin d'obtenir la meilleure mise en page possible par défaut, <code>flex-basis</code> est réglé sur <code>auto</code>. Nous verrons ce que cela signifie dans un futur article de cette série. Cependant, la plupart du temps, on peut voir <code>auto</code> comme "assez grand pour correspondre au contenu". Lorsque des éléments flexibles remplissent le conteneur et que l’un de ces éléments a un contenu plus volumineux que les autres, l’élément le plus gros dispose de plus d’espace.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/JBLWJo/">Smashing Flexbox Series 1: initial values of flex items</a>de rachelandrew dans<a href="https://codepen.io">CodePen</a></div><p>C’est la flexibilité de Flexbox en action. Avec une <code>flex-basis</code> réglée sur <code>auto</code> et aucun dimensionnement appliqué aux éléments, les items flexibles ont une taille de base égale à la taille <code>max-content</code>. Ce serait la taille qu'ils auraient s'ils s'étendaient sans retour à la ligne. Ensuite, l’espace est pris à chaque item en proportion, comme indiqué dans la remarque suivante de la spécification flexbox.</p><blockquote>
<p>Remarque: le facteur <code>flex-shrink</code> est multiplié par la taille de la base de flex lors de la répartition de l’espace négatif. Cela répartit l’espace négatif proportionnellement à la capacité de réduction de l’item, de sorte que, par exemple, un petit item ne sera pas réduit à zéro avant qu'un article plus grand ait été sensiblement réduit.</p>
</blockquote><p>Le plus gros item a moins de place, nous obtenons donc la mise en page finale. Vous pouvez comparer les deux captures d'écran ci-dessous, toutes deux prises à partir de l'exemple précédent. Dans la première capture d'écran, la troisième zone a un contenu moins volumineux et, par conséquent, nos colonnes ont une distribution d'espace plus égale.</p><figure role="group"><img src="https://la-cascade.io/images/shrinking-auto-compressor.png" alt="" /><figcaption>Les items s'ajustent pour donner plus d'espace à l'item le plus volumineux</figcaption></figure><p>Flexbox nous aide ici à obtenir un résultat final raisonnable, sans autre intervention de la part de la personne qui écrit le CSS. Plutôt que de réduire l'espace de manière uniforme et de finir avec un élément très grand affichant péniblement quelques mots sur chaque ligne, il attribue à cet élément davantage d'espace. Ce type de comportement est la clé des cas d'utilisation réels de Flexbox. Flexbox est à son meilleur lorsqu'il est utilisé pour placer des ensembles d'éléments – le long d'un axe – de manière flexible et soucieuse du contenu. J'aborde un peu les détails ici, mais nous examinerons plus en détail ces algorithmes plus tard dans cette série.</p><h2>Résumé</h2><p>Dans cet article, je me suis intéressée aux valeurs initiales de Flexbox afin d’expliquer ce qui se passe réellement lorsque vous dites <code>display: flex</code>. Il y en a un nombre surprenant et ces quelques propriétés contiennent de nombreuses caractéristiques-clés des layouts flex.</p><p>Les mises en page flex sont flexibles : elles essaient de faire de bons choix par défaut concernant votre contenu – réduire ou étirer pour obtenir la meilleure lisibilité. Les mises en page flex prennent en compte le mode d'écriture : les directions des rangées et des colonnes se rapportent au mode d'écriture utilisé. Les layout flex permettent l’alignement des éléments en tant que groupe sur l’axe principal, en choisissant la manière dont l’espace est réparti. Ils permettent l'alignement des éléments dans leur rangée flex, en les déplaçant sur l'axe transversal les uns par rapport aux autres. Il est important de noter que les mises en page flexibles comprennent la taille de votre contenu et tentent de prendre les bonnes décisions de base pour l'afficher. Dans les prochains articles, nous explorerons ces domaines plus en profondeur et nous examinerons plus précisément quand et pourquoi nous pourrions choisir d'utiliser Flexbox.</p></div>]]></description>
      <link>https://la-cascade.io/articles/que-se-passe-t-il-quand-on-cree-un-flexbox-flex-container</link>
      <guid>https://la-cascade.io/articles/que-se-passe-t-il-quand-on-cree-un-flexbox-flex-container</guid>
      <pubDate>Sun, 28 Oct 2018 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Comment fonctionne CSS display: contents]]></title>
      <description><![CDATA[<p><em>Nous pouvons contrôler la façon dont la boîte et ses enfants sont dessinés sur la page grâce à la propriété CSS display</em></p><div class="articleContent"><p>Comme je le rappelle souvent, chaque élément de l'<a href="http://web.simmons.edu/~grabiner/comm244/weekfour/document-tree.html">arbre qui représente notre document</a> (<em>document tree</em>) est <a href="https://la-cascade.io/articles/controler-le-modele-de-boite/">une boîte rectangulaire</a>. Grosso modo, cette boîte est faite de deux sections, l'une est la boîte elle-même — comprenant bordures, padding et marges — l'autre est le contenu.</p><figure role="group"><img src="https://la-cascade.io/images/box-and-content-compressor.png" alt="" /></figure><p>Nous pouvons contrôler la façon dont cette boîte et ses enfants sont dessinés sur la page grâce à la propriété CSS <code>display</code>. La boîte peut être placée parmi ses "soeurs" comme du texte, via <code>inline</code> et nous pouvons même lui donner le comportement d'une table via <code>table</code>.</p><p>Il n'y a que deux valeurs de la propriété <code>display</code> qui permettent à un élément de générer (ou pas) une boîte. La valeur <code>None</code> aura pour effet que ni la boîte ni son contenu ne seront affichés sur la page. La valeur <code>contents</code>, elle, aura pour effet de bien afficher la boîte <em>mais d'omettre totalement la boîte qui l'entoure</em>.</p><h2>Que se passe-t-il quand on utilise display: contents ?</h2><p>Le plus simple pour le comprendre est d'imaginer qu'on a oublié les balises ouvrante et fermante de l'élément. Comme le dit <a href="https://www.w3.org/TR/css-display-3/#box-generation">la spécification</a> :</p><blockquote cite="https://www.w3.org/TR/css-display-3/#box-generation">
<p>Pour ce qui est de la génération d'une boîte et de son affichage, l'élément doit être traité comme s'il avait été remplacé par son contenu dans l'arbre du document.</p>
<p><cite><a href="https://www.w3.org/TR/css-display-3/#box-generation">2.5. Box Generation: the none and contents keywords</a></cite></p>
</blockquote><p>Prenons le balisage suivant :</p><pre>&lt;div class="outer"&gt;
  I’m some content
  &lt;div class="inner"&gt;I’m some inner content&lt;/div&gt;
&lt;/div&gt;</pre><p>et les styles suivants :</p><pre>.outer {
  border: 2px solid lightcoral;
  background-color: lightpink;
  padding: 20px;
}
.inner {
  background-color: #ffdb3a;
  padding: 20px;
}</pre><p>L'affichage attendu est :</p><figure role="group"><img src="https://la-cascade.io/images/draw-compressor.png" alt="la boîte inner est affichée à l'intérieur de la boîte outer" /></figure><p>Mais si nous ajoutons <code>display: contents</code> à l'élément <code>.outer</code> , voici ce que nous obtenons :</p><figure role="group"><img src="https://la-cascade.io/images/display-contents-compressor.png" alt="la boîte outer a disparu, il ne reste que son contenu : I'm some content" /></figure><p>Visuellement, le résultat est exactement ce que nous obtiendrions en omettant les balises ouvrante et fermante de l'élément <code>outer</code>.</p><pre>I’m some content
&lt;div class="inner"&gt;I’m some inner content&lt;/div&gt;</pre><h2>Quid de... ?</h2><p>Cette règle CSS, bien que simple en apparence, a quelques comportements spécifiques. Le point important à garder à l'esprit est que la règle <code>display: contents</code> n'affecte que l'affichage de la boîte, <strong>il ne modifie en rien le balisage lui-même</strong>.</p><h3>Quid des attributs de l'élément ?</h3><p><em>Si, en pratique, l'élement est remplacé par son contenu, quelle est la conséquence pour ses attributs ?</em> Puisque son remplacement est pour l'essentiel purement visuel, <strong>nous pouvons toujours sélectionner, cibler et interagir avec l'élément via ses attributs</strong>.</p><p>Par exemple nous pouvons cibler l'élément avec son ID pour le référencer avec <code>aria-labelledby</code>:</p><pre>&lt;div id="label" style="display: contents;"&gt;Label here!&lt;/div&gt;
&lt;button aria-labelledby="label"&gt;&lt;button&gt;</pre><p>Toutefois j'ai constaté que nous ne pouvons plus naviguer vers l'élément au moyen d'un <a href="https://fr.wikipedia.org/wiki/Identificateur_de_fragment">identificateur de fragment</a> (<em>fragment identifier</em>) :</p><pre>&lt;div id="target" style="display: contents;"&gt;Target Content&lt;/div&gt;
&lt;script&gt;
  window.location.hash = "target";
  // =&gt; Nothing happens
&lt;/script&gt;</pre><h3>Quid des events JS ?</h3><p>Comme nous venons de le voir, nous pouvons cibler un élément sur lequel a été appliqué <code>display: contents</code>. En fait, nous pouvons même cibler un élément ayant un style <code>display: none</code> mais l'event ne sera jamais déclenché parce que nous ne pouvons pas interagir avec l'élément. Cependant avec <code>display: contents</code> le contenu de l'élément étant toujours visible, nous pouvons interagir avec lui <em>à travers son contenu</em>.</p><p>Si par exemple nous appliquons un event listener pour un click sur l'élément, et que nous loggons la valeur de <code>this</code>, nous obtenons toujours l'élément extérieur (<em>outer</em>) parce qu'il existe toujours dans le document.</p><pre>&lt;div class="outer"&gt;I’m some content&lt;/div&gt;
&lt;script&gt;
  document.querySelector(".outer").addEventListener("click", function(event) {
    console.log(this);
    // =&gt; &lt;div class="outer"&gt;&lt;/div&gt;
  });
&lt;/script&gt;</pre><h3>Quid des pseudo-éléments ?</h3><p>Les pseudo-éléments d'un élément auquel est appliqué <code>display: contents</code> sont considérés comme ses enfants et sont donc affichés normalement. ( <em>NdT : pour une intro facile aux pseudo-éléments, voir ici un article sur <a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after/">les pseudo éléments css before et after</a></em>.)</p><pre>&lt;style&gt;
  .outer { display: contents; }
  .outer::before { content: "Before" }
  .outer::after { content: "After" }
&lt;/style&gt;
&lt;div class="outer"&gt;I’m some content&lt;/div&gt;</pre><p>Le balisage ci-dessus donnera le résultat suivant :</p><figure role="group"><img src="https://la-cascade.io/images/pseudo-elements-compressor.png" alt="affichage du texte suivant : before i'm some content after" /></figure><h3>Quid des formulaires, images et autres éléments remplacés ?</h3><p>Les <a href="https://la-cascade.io/articles/quest-ce-quun-element-remplace/">éléments remplacés</a> et certains formulaires ont un comportement différent lorsqu'on leur applique <code>content: display</code>.</p><h4>Les éléments remplacés</h4><p>Les éléments remplacés sont des éléments dont l'apparence et les "boîtes"sont contrôlées par une ressource externe – c'est le cas par exemple des images. Supprimer la boîte pour de tels éléments n'a pas réellement de sens car la notion de boîte n'est pas claire les concernant. Pour ces éléments, <code>display: contents</code> fonctionne exactement comme <code>display: none</code>. Ni la boîte ni son contenu ne seront affichés.</p><h4>Les formulaires</h4><p>Les éléments de formulaires semblent constitués d'une simple boîte, mais sous le capot ils sont en réalité constitués de nombreux éléments. Tout comme pour les éléments remplacés, supprimer la boîte n'a pas de sens car il n'y a pas <em>une</em> boîte. Du coup, pour les éléments de formulaires tels que <code>&lt;select&gt;</code>, <code>&lt;input&gt;</code> et <code>&lt;textarea&gt;</code>, <code>display: contents</code> fonctionne exactement comme <code>display: none</code>.</p><p>(Voir <a href="https://www.w3.org/TR/css-display-3/#unbox-htm">la liste des éléments pour lesquels display: contents fonctionne différemment</a>)</p><h3>Quid des boutons et des liens ?</h3><p>Les éléments <code>&lt;button&gt;</code> et <code>&lt;a&gt;</code> n'ont pas de comportement particulier avec <code>display: contents</code>. Cependant il est utile de savoir comment cette règle les affecte car cela peut ne pas sembler évident.</p><h4>Les boutons</h4><p>Les boutons ne sont pas constitués de boîtes, par conséquent <code>display: contents</code> ne fera que supprimer la boîte enveloppant le bouton, en ne laissant que le contenu du bouton. Si on l'utilise avec un formulaire, un clic sur ce bouton aura toujours pour effet de soumettre le formulaire et, comme nous l'avons vu, n'importe quel event listener sur le bouton fonctionnera normalement.</p><h4>Les liens</h4><p>La même chose s'applique aux liens, la boîte container est visuellement supprimée, ne laissant apparaître que le contenu du lien. Dans la mesure où les attributs ne sont généralement pas affectés par cette règle CSS, le lien fonctionnera toujours correctement et pourra être utilisé pour naviguer comme normalement.</p><h3>Quelle est l'utilité de display: contents ?</h3><p>Autrefois nous devions organiser notre HTML d'une façon qui fonctionne à la fois sémantiquement et pour notre style CSS. Cela a conduit parfois à créer trop d'éléments pour la sémantique, parfois trop peu pour le style, en particulier des éléments "frères". Ce dernier cas est particulièrement pertinent avec l'arrivée de CSS Grid Layout qui, au moins aujourd'hui, doit pouvoir travailler avec des éléments "frères".</p><p>Prenons par exemple ce layout :</p><figure role="group"><img src="https://la-cascade.io/images/two-layouts-compressor.png" alt="" /></figure><p>Nous avons deux cartes placées côte à côte, chacune comprenant un titre, un paragraphe et un footer. Nous voulons que les sections aient la même hauteur pour toutes les cartes, indépendamment du contenu de chacune. Par exemple, la 2e carte a un titre de 3 lignes, la 1re carte a un titre de 1 ligne, mais les hauteurs de titres des deux cartes devraient être identiques.</p><p>Nous pourrions y arriver avec CSS Grid, mais pour cela il faudrait que tous les éléments dans une carte soient des "frères". Il nous faudrait organiser notre HTML comme ceci par exemple :</p><pre>&lt;div class="grid"&gt;
  &lt;h2&gt;This is a heading&lt;/h2&gt;
  &lt;p&gt;...&lt;/p&gt;
  &lt;p&gt;Footer stuff&lt;/p&gt;
  &lt;h2&gt;This is a really really really super duper loooong heading&lt;/h2&gt;
  &lt;p&gt;...&lt;/p&gt;
  &lt;p&gt;Footer stuff&lt;/p&gt;
&lt;/div&gt;</pre><p>et nous pourrions appliquer les styles suivants :</p><pre>.grid {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: repeat(2, 1fr);
  grid-column-gap: 20px;
}</pre><p>La structuration de ce document n'est certes pas incorrecte, mais il y aurait plus de sens à regrouper chaque carte dans un élément <code>&lt;article&gt;</code>. C'est ici que <code>display: contents</code> entre en scène, nous donnant le meilleur des deux mondes — en permettant un balisage sémantique tout en permettant d'organiser notre layout .</p><pre>&lt;div class="grid"&gt;
  &lt;article style="display: contents;"&gt;
    &lt;h2&gt;This is a heading&lt;/h2&gt;
    &lt;p&gt;...&lt;/p&gt;
    &lt;p&gt;Footer stuff&lt;/p&gt;
  &lt;/article&gt;
  &lt;article style="display: contents;"&gt;
    &lt;h2&gt;This is a really really really super duper loooong heading&lt;/h2&gt;
    &lt;p&gt;...&lt;/p&gt;
    &lt;p&gt;Footer stuff&lt;/p&gt;
  &lt;/article&gt;
&lt;/div&gt;</pre><h3>Compatibilité</h3><p>Comme toujours, <a href="https://caniuse.com/#feat=css-display-contents">la compatibilité peut être vérifiée sur CanIUse</a>, elle est bonne aujourd'hui, à l'exception de IE.</p><p>Si vous souhaitez assurer une compatibilité maximale, vous pouvez considérer cette feature comme une amélioration progressive (<em>progressive enhancement</em>) et utiliser une solution de rechange (<em>fallback</em>) appropriée.</p><pre>article {
  display: grid;
  grid-template-rows: 200px 1fr auto; /* e.g. Use a fixed height for the header */
}
@supports (display: contents) {
  article { display: contents; }
}</pre></div>]]></description>
      <link>https://la-cascade.io/articles/comment-fonctionne-css-display-content</link>
      <guid>https://la-cascade.io/articles/comment-fonctionne-css-display-content</guid>
      <pubDate>Sat, 20 Oct 2018 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[L'imbrication des sélecteurs dans Sass]]></title>
      <description><![CDATA[<p><em>L'imbrication de sélecteurs est une fonctionnalité des préprocesseurs CSS d'utilisation tellement courante qu'elle peut devenir problématique. Par Kitty Giraudel.</em></p><div class="articleContent"><p>L'imbrication de sélecteurs est une fonctionnalité des préprocesseurs CSS d'utilisation courante. Tellement courante qu'elle peut devenir problématique. Kitty Giraudel, notre grand spécialiste de Sass, défend une position originale et radicale.</p><p>Il y a quelques jours, j'ai envoyé un tweet au sujet de l'imbrication des sélecteurs (<em>selector nesting</em>) pour dire qu'ils me créaient plus de problèmes qu'ils n'en résolvaient.</p><p>Certains étaient d'accord, d'autres non, mais en tout cas cela a permis d'échanger des idées intéressantes et je me suis dit que j'en ferais bien un petit article.</p><h2>Qu'est-ce que l'imbrication de sélecteurs?</h2><p>L'imbrication de sélecteurs est une fonctionnalité des préprocesseurs CSS qui permet d'emboîter des sélecteurs à l'intérieur d'autres sélecteurs pour créer des raccourcis d'écriture. Par exemple :</p><pre class="language-scss">.parent {
  color: red;
  .child {
    color: blue;
  }
}</pre><p>...sera compilé en ceci :</p><pre class="language-CSS">.parent {
  color: red;
}
.parent .child {
  color: blue;
}</pre><p>Dans cet exemple, <code>.child</code> est emboîté dans <code>.parent</code> afin d'éviter la répétition du sélecteur parent.</p><p>Ça peut-être tout à fait utile, mais j'ai le sentiment que cette fonctionnalité est très largement sur-utilisée au point que nous en arrivons aujourd'hui à devoir résoudre des problèmes créés par une imbrication inconsidérée.</p><h2>Où est le problème de l'imbrication?</h2><p>En soi, il n'y a pas de problème, la fonctionnalité a un sens. Le problème, comme souvent, est dans la façon dont nous utilisons cette fonctionnalité. Permettez-moi de commencer par deux exemples.</p><p>Le premier est de <a href="http://www.phase2technology.com/blog/everything-you-need-to-know-about-sass-3-4/">Micah Godbolt</a> :</p><pre class="language-SCSS">.tabs {
  .tab {
    background: red;
    &amp;:hover {
      background: white;
    }
    .tab-link {
      color: white;
      @at-root #{selector-replace(&amp;, '.tab', '.tab:hover')}{color: red;}
    }
  }
}</pre><p>Le second est de <a href="http://sassmeister.com/gist/306744db88c2b6deef78">Zi Qiu</a> :</p><pre class="language-SCSS">.root {
  width: 400px;
  margin: 0 auto;
  .links {
    .link {
      display: inline-block;
      &amp; ~ .link {
        margin-left: 10px;
      }
      a {
        padding: 10px 40px;
        cursor: pointer;
        background: gray;
        &amp;:hover {
          background: blue;
          color: white;
          font-size: 700;
        }
        .icon {
          margin-right: 5px;
          @include selector-modifier(-2 ':hover', 1 suffix '.zh'){
            color: red;
            background: green;
          }
          @include selector-modifier(-2 ':hover', 1 suffix '.en') {
            color: yellow;
            background: green;
          }
        }
      }
    }
  }
}</pre><p>Une précision pour commencer : Ce code est intelligent. Je ne prétends en aucune façon qu'il s'agisse d'un mauvais code, et je suppose qu'il fonctionne exactement comme il faut.</p><p>Maintenant, si je vous demande ce que ces deux exemples sont censés réaliser ? En y jetant un coup d'oeil rapide, seriez-vous capable de le dire ?</p><p>Moi non plus. Parce que c'est compliqué.</p><h3>L'imbrication complique le code</h3><p>Les deux exemples qui précèdent utilisent des fonctions de sélecteurs (de Sass 3.4) pour réécrire partiellement le contexte du sélecteur courant (<code>&amp;</code>).</p><p>Donc, si je ne me trompe pas, ils utilisent du code supplémentaire afin d'écrire moins de code, et ajoutent une couche de complexité. Pourquoi ne pas écrire un code simple dès l'origine ?</p><p>Je l'ai déjà dit : les fonctions de sélecteurs ne sont pas faites pour une utilisation standard. Je crois que Chris Eppstein et Natalie Weizenbaum ont dit explicitement qu'ils ajoutaient cette fonctionnalité pour aider les développeurs de frameworks.</p><p><em>Remarque : si vous trouvez un cas d'utilisation légitime pour les fonctions de sélecteurs, qui résoud vraiment un problème, je vous serais reconnaissant de me le montrer, ça m'intéresserait beaucoup</em>.</p><h3>Le sélecteur de référence est ambigu</h3><p>Dans Sass, le sélecteur de référence (<code>&amp;</code>) peut parfois être ambigu. Selon la façon dont on l'utilise, il peut produire un résultat totalement différent. Voici une série d'exemples simples.</p><pre class="language-SCSS">/* SCSS */
.element {
  &amp;:hover {
    color: red;
  }
}
/* CSS */
.element:hover {
  color: red;
}</pre><pre class="language-SCSS">/* SCSS */
.element {
  &amp;hover {
    color: red;
  }
}
/* CSS */
.element:hover {
  color: red;
  }</pre><pre class="language-SCSS">/* SCSS */
.element {
  &amp; .hover {
    color: red;
  }
}
/* CSS */
.element .hover {
  color: red;
  }</pre><pre class="language-SCSS">/* SCSS */
.element {
  &amp;-hover {
    color: red;
  }
}
/* CSS */
.element-hover {
  color: red;
}</pre><pre class="language-SCSS">/* SCSS */
.element {
  &amp;.hover {
    color: red;
  }
}
/* CSS */
.element.hover {
  color: red:
}</pre><pre class="language-SCSS">/* SCSS */
.element {
  .hover&amp; {
    color: red;
  }
}
/* Syntax Error */
Invalid CSS after ".hover": expected "{", was "&amp;"`
`"&amp;" may only be used at the beginning of a compound selector.</pre><pre class="language-SCSS">/* SCSS */
.element {
  &amp;:hover &amp; {
    color: red;
  }
}
/* CSS */
.element:hover .element {
  color: red;
}</pre><pre class="language-SCSS">/* SCSS */
.element {
  &amp;:hover {
    &amp; {
      color: red;
    }
  }
}
/* CSS */
.element:hover {color: red;
}</pre><p>Et nous restons ici dans la simplicité en n'utilisant qu'un seul sélecteur. Inutile de préciser que lorsque vous multipliez les références à l'intérieur d'une règle, les choses peuvent vite devenir complexes.</p><p>En fait, certaines opérations fonctionnent, d'autres non (remarquez le message d'erreur dans l'un des exemples). Certains génèrent un sélecteur composé, d'autres non. En fonction du projet, en fonction de l'expérience Sass du prochain développeur qui utilisera le code, ces choses peuvent s'avérer difficiles à débugger.</p><h3>Des sélecteurs introuvables</h3><p>Là, je commence à devenir tatillon. Mais il y a quelque chose que je n'aime pas et qui consiste à utiliser l'imbrication pour créer des sélecteurs du type BEM</p><pre class="language-SCSS">.block {
  /* Some CSS declarations */
  &amp;--modifier {
    /* Some CSS declarations for the modifier */
  }
  &amp;__element {
    /* Some CSS for the element */
    &amp;--modifier {
      /* Some CSS for the modifier of the element */
    }
  }
}</pre><p>Avant d'expliquer pourquoi je n'aime pas cela, regardons comment ce code est compilé :</p><pre class="language-CSS">.block {
  /* Some CSS declarations */
}
.block--modifier {
  /* Some CSS declarations for the modifier */
}
.block__element {
  /* Some CSS for the element */
}
.block__element--modifier {
   /* Some CSS for the modifier of the element */
}</pre><p>D'un côté, ça permet d'éviter la répétition de <code>.block</code> dans chaque sélecteur, ce qui pourrait être dommage quand vous avez des noms de blocs comme <code>.profil-utilisateur</code>.</p><p>Mais d'un autre côté, ça crée de nouveaux sélecteurs sortis de nulle part et sur lesquels aucune recherche n'est possible : que se passe-t-il si un développeur veut trouver le CSS de <code>.block__element</code> ? Il y a des chances qu'il le cherche à partir de son environnement de développement et qu'il ne trouve rien parce que ce sélecteur n'a jamais été créé comme tel.</p><p>En fait, j'ai l'impression que je ne suis pas le seul à penser ainsi. <a href="https://twitter.com/kaelig">Kaelig</a>, qui a travaillé un temps au Guardian, a envoyé un tweet allant dans le même sens.</p><p>De plus, je pense qu'il est meilleur de répéter le nom de base. De cette manière, on voit clairement ce qui se passe.</p><p>Je devrais ajouter que les source maps peuvent aider dans une certaine mesure, mais ils ne changent rien au fait qu'on ne peut effectuer de recherche sur la base du code.</p><h2>Quand peut-on imbriquer?</h2><p>Si vous-même et votre équipe êtes à l'aise avec la complexité, on peut toujours imbriquer !</p><p>Si vous me posez la question, mon sentiment est que l'ajout de pseudo-classes et de pseudo-éléments est à peu près le seul cas où ça vaut la peine. Par exemple </p><pre class="language-SCSS">.element {
  /* Some CSS declarations */
  &amp;:hover,
  &amp;:focus {
    /* More CSS declarations for hover/focus state */
  }
  &amp;::before {
    /* Some CSS declarations for before pseudo-element */
  }
}</pre><p>C'est le meilleur cas d'utilisation de l'imbrication de sélecteurs. Non seulement il permet d'éviter la répétition du même sélecteur, mais en plus il permet de définir l'étendue de cet élément (états et enfants virtuels) à l'intérieur du même ensemble de règles CSS. Enfin, <code>&amp;</code> n'est pas ambigu : il signifie <code>.element</code>, ni plus, ni moins.</p><p>Un autre cas d'utilisation intéressante de l'imbrication est lorsque vous voulez appliquer quelques styles personnalisés à un sélecteur <em>simple</em> en fonction du contexte. Par exemple lorsqu'on utilise les hooks CSS de Modernizr :</p><pre class="language-SCSS">.element {
  /* Some CSS declarations */
  .no-csstransforms &amp; {
    /* Some CSS declarations when CSS transforms are not supported */
  }
}</pre><p>Dans ce scénario, j'ai l'impression qu'il est clair que <code>.no-csstransforms &amp;</code> sert à contextualiser le sélecteur courant à chaque fois que les transformations CSS ne sont pas supportées. Cela dit, c'est quand même à la limité de ce que je considère acceptable.</p><h2>Quelles sont les recommandations?</h2><p>Écrire un CSS simple. Reprenons l'exemple de Micah, qui est un peu compliqué, mais pas suffisamment pour être difficile à réécrire.</p><p>Le code d'origine, dont l'objectif est d'appliquer des styles à une table :</p><pre class="language-SCSS">.tabs {overflow: hidden;
  .tab {
    background: red;
    &amp;:hover {
      background: white;
    }
    .tab-link {
      color: white;
      @at-root #{
        selector-replace(&amp;, '.tab', '.tab:hover') {
        color: red;
      }
    }
  }
}</pre><p>...pourrait être écrit ainsi :</p><pre class="language-SCSS">.tabs {
   overflow: hidden;
}
.tab {
background: red;
&amp;:hover {
  background: white;
  }
}
.tab-link {
  color: white;
  .tab:hover &amp;
  {
    color: red;
  }
}</pre><p>Je ne peux pas imaginer une seule raison de préférer la première version du code. Elle est non seulement plus longue mais également moins explicite et elle utilise des fonctionnalités Sass qui ne sont pas nécessairement connues de tous les développeurs.</p><p>Remarquez que le résultat en CSS n'est pas exactement identique car nous avons aussi simplifié le code. Plutôt que d'avoir des sélecteurs de la taille de <code>.tabs .tab .tab-link</code>, nous avons utilisé <code>.tab-link</code>, plus simple.</p><p>Sur ce point, on n'est plus vraiment dans une discussion sur l'imbrication des sélecteurs, mais plutôt sur les conventions de nommage et sur la méthodologie des sélecteurs. Lorsqu'on utilise BEM par exemple, on nomme les choses selon ce qu'elles sont, plutôt que selon l'endroit où elles sont, ce qui aboutit souvent à des sélecteurs simples (c'est à dire non composés), et donc à moins d'imbrication.</p><p>Selon les <a href="http://cssguidelin.es/#css-selectors">directives CSS</a> de Harry Roberts :</p><p>Il est important lorsqu'on écrit du CSS de donner la bonne portée à nos sélecteurs, et de sélectionner la bonne chose pour les bonnes raisons (...) Étant donnée la nature toujours changeante de la plupart des projets UI, et la tendance à aller vers des architectures basées sur des composants, il est de notre intérêt d'appliquer un style aux choses en fonction non de l'endroit où elles sont, mais de ce qu'elles sont.</p><p>Une bonne règle générale, s'agissant des sélecteurs CSS, est <em>plus on fait court et mieux c'est</em>. Non seulement à tout niveau (performance, simplicité, portabilité, intention, etc.) mais il se trouve qu'il est beaucoup plus simple d'éviter les accidents d'imbrication de sélecteurs lorsque les sélecteurs sont courts.</p><h2>Pour conclure</h2><p>À chaque fois que je dis que l'imbrication de sélecteurs n'est pas une bonne idée, les gens me disent “mais je n'ai jamais rencontré un tel problème”, “je l'utilise tous les jours sans problème”, “c'est parce que tu fais des trucs de dingue avec ça”. Bien sûr, il n'y a pas de problème avec la fonctionnalité elle-même.</p><p>Les préprocesseurs ne produisent pas de mauvais code, ce sont les mauvais développeurs qui le font. Et ici, on ne parle même pas du résultat produit, mais de ce qu'on entre initialement. Le code devient de moins en moins lisible lorsqu'on y ajoute des couches de complexité supplémentaires. L'imbrication des sélecteurs est l'une d'elles.</p><p>On nous a donné l'imbrication et nous en avons abusé. Puis on nous a donné les fonctions de sélecteurs pour réparer la confusion que nous avions créée. Tout ça est erroné.</p><p>Utilisez Sass, ou n'importe quel préprocesseur, pour simplifier votre code, pas pour le rendre plus complexe.</p></div>]]></description>
      <link>https://la-cascade.io/articles/limbrication-des-selecteurs-dans-sass</link>
      <guid>https://la-cascade.io/articles/limbrication-des-selecteurs-dans-sass</guid>
      <pubDate>Mon, 03 Sep 2018 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Sass mixin ou placeholder]]></title>
      <description><![CDATA[<p><em>Kitty Giraudel est un spécialiste internationalement reconnu de Sass. Il explique ici clairement et simplement la différence entre mixin et placeholder, comment utiliser l'un ou l'autre ou... combiner les deux.</em></p><div class="articleContent"><p>Quand j’ai commencé à m’amuser avec Sass il y a un an et demi, j’ai mis un peu de temps à comprendre la différence entre <a href="https://sass-lang.com/guide#topic-6">inclure un mixin</a> et <a href="https://sass-lang.com/documentation/at-rules/extend#placeholder-selectors">étendre un placeholder</a>. En fait, la notion même de placeholder relevait un peu de la magie noire pour moi.</p><p>Si vous êtes dans le même cas, pas d’inquiétude. Aujourd’hui nous allons apprendre exactement à quoi sert un mixin, et quand utiliser un placeholder. Vous verrez qu’ils ont chacun leur utilité et ne doivent pas être confondus.</p><p>Remarque : Je parle ici de Sass, mais ce que je décris pourrait s’appliquer à d’autres préprocesseurs CSS, tels Stylus ou LESS, vous pouvez donc adapter le contenu de cet article à l’outil de votre choix.</p><p>Pour commencer, un petit rappel sur les mixins et les placeholders.</p><h2>Un petit mix</h2><p>Un mixin est une directive qui vous permet de définir des règles multiples dépendant de plusieurs arguments. Un peu comme une fonction qui au lieu de retourner une valeur renverrait du contenu CSS. Voici la définition donnée par <a href="https://sass-lang.com/documentation/at-rules/mixin">Sass Reference</a> :</p><blockquote>
<p><em>Les mixins vous permettent de définir des styles qui peuvent être réutilisés dans votre feuille de style sans avoir besoin de recourir à des classes non-sémantiques telles que <code>.float-left</code>. Les mixins peuvent aussi contenir des règles CSS et tout ce qui est permis dans un document Sass. Ils peuvent prendre des arguments qui vous permettent de produire de nombreux styles avec très peu de mixins</em>.</p>
</blockquote><p>Voilà pour la terminologie. Supposons maintenant que vous ayez repéré quelques déclarations répétées plusieurs fois dans votre feuille de style. Vous connaissez <a href="http://fr.wikipedia.org/wiki/Ne_vous_r%C3%A9p%C3%A9tez_pas">le principe DRY</a> (Don’t Repeat Yourself) et vous décidez de corriger cela en écrivant un mixin :</p><pre class="language-scss">@mixin center() {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.container {
  @include center();
  /* Other styles here... */
}
/* Other styles... */
.image-cover {
  @include center;
}</pre><p><em>NB : si vous ne passez pas d’argument dans votre mixin, vous pouvez omettre les parenthèses. Vous pouvez même les omettre dans la définition du mixin.</em></p><p>Avec ce mixin, vous n’avez pas besoin de répéter ces trois lignes à chaque fois que vous voulez centrer un élément, il suffit d’inclure le mixin. Pratique, non ?</p><p>Parfois vous aurez besoin de construire des "raccourcis" pour quelques propriétés. Par exemple, <code>width</code> et <code>height</code>. N’êtes-vous pas fatigué d’écrire toujours ces mêmes lignes, surtout quand elles ont la même valeur ? Réglons ça avec un mixin !</p><pre class="language-scss">@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}</pre><p>Simple, n’est-ce pas ? Remarquez que j’ai rendu le paramètre <code>$height</code> optionnel en lui donnant la même valeur par défaut que <code>$width</code>, directement dans la définition du mixin. Maintenant, à chaque fois que vous voudrez définir les dimensions d’un élément, vous pourrez écrire simplement :</p><pre class="language-scss">.icon {
  @include size(32px);
}
.cover {
  @include size(100%, 10em);
}</pre><p><em>NB: pour un autre exemple de syntaxe "sucrée", vous pouvez consulter <a href="http://hugogiraudel.com/2013/08/05/offsets-sass-mixin/">celle</a> que j’ai réalisée pour éviter d’avoir à écrire <code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code> et <code>position</code> à chaque fois que je veux un positionnement différent de <code>static</code>.</em></p><h2>Placeholders</h2><p>Les placeholders sont un peu bizarres. Ce sont des classes qui ne sont pas rendues commes telles lorsque votre SCSS est compilé. Et alors ? me direz-vous. En fait, tout irait bien s’il n’y avait cette directive <code>@extend</code>. Mais commençons par le commencement, voici comment on écrit un placeholder :</p><pre class="language-scss">%center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}</pre><p>En gros, c’est exactement comme écrire une classe, sauf qu’elle est préfixée avec <code>%</code> au lieu d’un point. Le placeholder suit les mêmes règles de nommage que les classes.</p><p>Si maintenant vous compilez votre SCSS, vous ne verrez pas ce code dans le fichier généré en CSS. Pour l’instant, ce placeholder est totalement inutile. Pour qu’il serve à quelque chose, il faut utiliser <code>@extend</code> :</p><pre class="language-scss">.container {
  @extend %center;
}</pre><p>Sass va aller chercher le contenu du placeholder <code>%center</code> pour l’appliquer à <code>.container</code>.</p><p>Autre application extrêmement utile d’<code>@extend</code>, vous pouvez étendre des sélecteurs CSS existants, de la façon suivante :</p><pre class="language-scss">.table-zebra {
  @extend .table;
  tr:nth-of-type(even) {
    background: rgba(0, 0, 0, 0.5);
  }
}</pre><p>C’est un cas d’usage très courant. Dans l’exemple ci-dessus, nous demandons à la classe <code>.table-zebra</code> de se comporter exactement comme la classe <code>.table</code> (en étendant les règles relatives à cette dernière), puis nous ajoutons des règles spécifiques à zebra.</p><p>L’extension de sélecteurs est très pratique quand vous développez votre site/application avec des composants modulaires. Pour en savoir plus sur le sujet, vous pouvez consulter l’article <a href="https://la-cascade.io/articles/sass-tout-sur-extend/">Sass : tout sur @extend</a>.</p><h2>Lequel utiliser ?</h2><p>Eh bien, comme toujours dans notre domaine, <em>ça dépend</em>. Cela dépend du contexte et de votre objectif.</p><p>Le meilleur conseil serait : si vous avez besoin de variables, utilisez un mixin. Sinon, étendez un placeholder. Il y a deux raisons à cela :</p><ul><li>D’abord, on ne peut pas passer de variables dans un placeholder, donc vous ne pourrez pas générer un CSS spécifique au contexte, comme vous le pourriez avec un mixin.</li>
<li>Ensuite, la façon dont Sass gère les mixins les rend assez peu pratiques lorsqu’ils ne sont pas utilisés avec des variables contextuelles. Pour le dire simplement : Sass recopie le rendu de votre mixin à chaque fois que vous l’utilisez, ce qui a pour résultat un code dupliqué (contraire au principe DRY) et des feuilles de styles alourdies.</li>
</ul><p>Si nous reprenons notre tout premier exemple :</p><pre class="language-scss">@mixin center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.container {
  @include center;
}
.image-cover {
  @include center;
}</pre><p>Le résultat CSS après compilation sera :</p><pre class="language-css">.container {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.image-cover {
  display: block;
  margin-left: auto;
  margin-right: auto;
}</pre><p>Vous remarquez la duplication de CSS. Ce n’est pas bien grave s’il n’y a que 3 lignes de code, mais vous imaginez ce que ça peut donner avec des mixins plus complexes et utilisés plus souvent dans un projet. Essayons de réécrire notre petit exemple en utilisant maintenant un placeholder :</p><pre class="language-scss">%center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.container {
  @extend %center;
}
.image-cover {
  @extend %center;
}</pre><p>Voici le résultat CSS après compilation :</p><pre class="language-css">.container,
.image-cover {
  display: block;
  margin-left: auto;
  margin-right: auto;
}</pre><p>Beaucoup mieux ! La compilation s’effectue par <a href="http://reference.sitepoint.com/css/selectorgrouping">groupage de sélecteurs</a>, sans répétition de styles. Conclusion : lorsque vous voulez éviter d’écrire les mêmes propriétés, si vous savez qu’elles ne varieront pas, il faut utiliser un placeholder.</p><p>Par contre, si vous voulez écrire les mêmes propriétés mais avec des valeurs différentes, le mixin est préférable. Et si vous avez un groupe de valeurs fixes et variables, vous pouvez essayer une combinaison des deux.</p><pre class="language-scss">%center {
  margin-left: auto;
  margin-right: auto;
  display: block;
}
@mixin skin($color, $size) {
  @extend %center;
  background: $color;
  height: $size;
}
a {
  @include skin(pink, 10em);
}
b {
  @include skin(blue, 90px);
}</pre><p>Dans cet exemple, le mixin étend le placeholder pour les valeurs fixes, ce qui génère un CSS propre :</p><pre class="language-css">a,
b {
  margin-left: auto;
  margin-right: auto;
  display: block;
}
a {
  background: pink;
  height: 10em;
}
b {
  background: blue;
  height: 90px;
}</pre><p>Et voilà !</p></div>]]></description>
      <link>https://la-cascade.io/articles/sass-mixin-ou-placeholder</link>
      <guid>https://la-cascade.io/articles/sass-mixin-ou-placeholder</guid>
      <pubDate>Wed, 08 Aug 2018 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Créer des systèmes de menu accessibles]]></title>
      <description><![CDATA[<p><em>Il existe de nombreux types de menus différents sur le Web. Créer des expériences inclusives est une question d'utilisation des bons modèles de menu aux bons endroits, avec le balisage et le comportement adéquats.</em></p><div class="articleContent"><p>Note de l'éditeur : Cet article a été initialement publié dans l'ouvrage <a href="https://www.smashingmagazine.com/printed-books/inclusive-components/">Inclusive Components</a>.</p><p>La classification est difficile. Prenez les crabes, par exemple. Les bernard-l'hermite, les crabes en porcelaine et les limules ne sont pas — taxonomiquement parlant — de vrais crabes. Mais cela ne nous empêche pas d'utiliser le suffixe "crabe". La situation devient plus confuse lorsque, au fil du temps et grâce à un processus appelé carcinisation, les faux crabes évoluent pour ressembler davantage aux vrais crabes. C'est le cas du crabe royal, qui aurait été autrefois un bernard-l'hermite. Imaginez la taille de leur carapace !</p><p>En design, nous faisons souvent la même erreur de donner le même nom à des choses différentes. Elles semblent similaires, mais les apparences peuvent être trompeuses. Cela peut avoir un effet malheureux sur la clarté de votre bibliothèque de composants. En termes d'inclusion, cela peut également vous conduire à réaffecter un composant inapproprié sur le plan sémantique et comportemental. Les utilisateurs s'attendront à une chose et en obtiendront une autre.</p><p>Le terme "dropdown" nomme un exemple classique. Beaucoup de choses "tombent" (<em>drop down</em>) dans les interfaces, notamment l'ensemble des <code>&lt;options&gt;</code> d'un élément <code>&lt;select&gt;</code>, et la liste de liens révélée par JavaScript qui constitue un sous-menu de navigation. Même nom, mais des choses bien différentes. (Certaines personnes les appellent "pulldowns", bien sûr, mais n'en parlons pas).</p><p>Les dropdowns composés d'un ensemble d'options sont souvent appelés "menus", et je veux en parler ici. Nous allons concevoir un vrai menu, mais il y aura beaucoup à dire en cours de route sur les menus pas vraiment vrais.</p><p>Commençons par un quiz. La boîte de liens qui pend de la barre de navigation dans l'illustration est-elle un menu ?</p><figure role="group"><img src="https://la-cascade.io/images/1-menu-buttons-800w-opt.png" width="800" height="262" alt="Une barre de navigation avec un lien vers une boutique, sous lequel se trouve un ensemble de trois autres liens vers des costumes de chiens, des gaufriers et des orbes magiques respectivement." /><figcaption>Une barre de navigation avec un lien vers une boutique, sous lequel se trouve un ensemble de trois autres liens vers des costumes de chiens, des gaufriers et des orbes magiques respectivement.</figcaption></figure><p>La réponse est non, ce n'est pas un vrai menu.</p><p>Une convention de longue date veut que les schémas de navigation soient composés de listes de liens. Une convention presque aussi ancienne veut que la sous-navigation soit fournie sous forme de listes de liens imbriqués. Si je supprimais le CSS du composant illustré ci-dessus, je devrais voir quelque chose comme ci-dessous, mais coloré en bleu et en Times New Roman.</p><ul><li>Home</li>
<li>About</li>
<li>Shop
<ul><li>Dog costumes</li>
<li>Waffle irons</li>
<li>Magical orbs</li>
</ul></li>
<li>Contact</li>
</ul><p>Sémantiquement parlant, les listes de liens imbriqués sont correctes dans ce contexte. Les systèmes de navigation sont en réalité des <strong>tables des matières</strong> et c'est ainsi que les tables des matières sont structurées. La seule chose qui nous fait vraiment penser à un "menu" est le style des listes imbriquées et la façon dont elles sont révélées au survol ou au focus.</p><p>C'est là que certains font fausse route et commencent à ajouter la sémantique WAI-ARIA : <code>aria-haspopup="true"</code>, <code>role="menu"</code>, <code>role="menuitem"</code> etc. Ces éléments ont leur place, comme nous allons le voir, mais pas ici. En voici les deux raisons :</p><ol><li>Les menus ARIA ne sont pas destinés à la navigation mais au <strong>comportement de l'application</strong>. Imaginez le système de menu d'une application de bureau.</li>
<li>Le lien de niveau supérieur doit être utilisable <em>comme un lien</em>, ce qui signifie qu'il ne se comporte pas comme un bouton de menu.</li>
</ol><p>Concernant le point (2) : Lorsque l'on parcourt une région de navigation comportant des sous-menus, on s'attend à ce que chaque sous-menu apparaisse au survol ou au focus du lien de "niveau supérieur" ("Shop" dans l'illustration). Cela permet à la fois de révéler le sous-menu et de placer ses propres liens dans l'ordre de focalisation. Avec un peu d'aide de JavaScript capturant les événements de focalisation et de floutage pour maintenir l'apparence des sous-menus pendant qu'ils sont nécessaires, une personne utilisant le clavier devrait être capable de parcourir chaque lien de chaque niveau, tour à tour.</p><p>Les boutons de menu qui prennent la propriété <code>aria-haspopup="true"</code> ne se comportent pas ainsi. Ils sont activés au clic et n'ont d'autre but que de révéler un menu secret.</p><figure role="group"><img src="https://la-cascade.io/images/2-menu-buttons-800w-opt.png" alt="À gauche : un bouton de menu intitulé 'menu' avec une icône de flèche pointant vers le bas et l'état aria-expanded = false. A droite : Le même bouton de menu mais avec le menu ouvert. Ce bouton est dans l'état aria-expanded = true." /><figcaption>À gauche : un bouton de menu intitulé 'menu' avec une icône de flèche pointant vers le bas et l'état aria-expanded = false. A droite : Le même bouton de menu mais avec le menu ouvert. Ce bouton est dans l'état aria-expanded = true.</figcaption></figure><p>Comme illustré, le fait que ce menu soit ouvert ou fermé doit être communiqué avec <code>aria-expanded</code>. Vous ne devez modifier cet état qu'au moment du clic, et non au moment du focus. Les utilisateurs ne s'attendent généralement pas à un changement d'état explicite lors d'un simple événement de focus. Dans notre système de navigation, l'état ne change pas vraiment ; c'est juste une astuce de style. D'un point de vue comportemental, nous pouvons avancer par tabulation dans la navigation comme si cette astuce d'affichage et de masquage ne se produisait pas.</p><h2>Le problème des sous-menus de navigation</h2><p>Les sous-menus de navigation (ou "dropdowns" pour certains) fonctionnent bien avec une souris ou un clavier, mais ils ne sont pas très performants au toucher. Lorsque vous appuyez pour la première fois sur le lien supérieur "Boutique" dans notre exemple, vous lui demandez à la fois d'ouvrir le sous-menu et de suivre le lien.</p><p>Il y a deux résolutions possibles ici :</p><ol><li>Empêcher le comportement par défaut des liens de haut niveau (<code>e.preventDefault()</code>) et écrire dans la sémantique et le comportement complets des menus WAI-ARIA.</li>
<li>S'assurer que chaque page de destination de haut niveau possède une table des matières, comme alternative au sous-menu.</li>
</ol><p>(1) n'est pas satisfaisant car, comme je l'ai noté précédemment, ces types de sémantique et de comportements ne sont pas attendus dans ce contexte, où les liens sont les contrôles du sujet. De plus, les utilisateurs ne pourraient plus naviguer vers une page de niveau supérieur, si elle existe.</p><h2>Note : quels appareils sont des appareils tactiles ?</h2><p>Il est tentant de penser "ce n'est pas une super solution, mais je ne l'ajouterai que pour les interfaces tactiles". Le problème est le suivant : comment détecter si un appareil a un écran tactile ?</p><p>Vous ne devriez certainement pas assimiler "petit écran" à "activé par le toucher". Ayant travaillé dans le même bureau que des personnes fabriquant des écrans tactiles pour des musées, je peux vous assurer que certains des plus grands écrans qui existent sont des écrans tactiles. Les ordinateurs portables à double clavier et à entrée tactile sont également de plus en plus nombreux.</p><p>De même, beaucoup de petits appareils, mais pas tous, sont des appareils tactiles. Dans le domaine de la conception inclusive, vous ne pouvez pas vous permettre de faire des suppositions.</p><p>La résolution (2) est plus inclusive et plus robuste dans la mesure où elle fournit un "repli" pour les utilisateurs de toutes les entrées. Mais les guillemets autour du terme de repli sont délibérés car je pense que les tables de contenu dans les pages sont un moyen <em>supérieur</em> de fournir la navigation.</p><p>L'équipe primée des <a href="https://www.gov.uk/guidance/content-design/organising-and-grouping-content-on-gov-uk">Services numériques du gouvernement</a> semble être d'accord. Vous les avez peut-être aussi vus sur Wikipédia.</p><figure role="group"><img src="https://la-cascade.io/images/3-gds-wikipedia-opt.png" alt="Les tables de contenu de Gov.uk sont minimales avec des tirets comme styles de liste. Wikipedia propose une boîte grise bordée d'éléments numérotés. Les deux sont étiquetés contenus." /><figcaption>Les tables de contenu de Gov.uk sont minimales avec des tirets comme styles de liste. Wikipedia propose une boîte grise bordée d'éléments numérotés. Les deux sont des contenus étiquetés.</figcaption></figure><h2>Tables des matières</h2><p>Les tables des matières constituent une navigation pour des pages ou des sections de pages connexes et doivent être sémantiquement similaires aux régions de navigation du site principal, en utilisant un élément <code>&lt;nav&gt;</code>, une liste et un mécanisme d'étiquetage de groupe.</p><pre class="language-html">&lt;nav aria-labelledby="sections-heading"&gt;
  &lt;h2 id="sections-heading"&gt;Produits&lt;/h2&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;a href="/produits/costumes-de-chien"&gt;Costumes-de-chien&lt;/a&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href="/produits/fers à gaufrer"&gt;Fers à gaufrer&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/produits/magical-orbs"&gt;Magical orbs&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;
&lt;!-- chaque section, dans l'ordre, ici --&gt;</pre><h2>Notes</h2><ul><li>Dans cet exemple, nous imaginons que chaque section est sa propre page, comme elle l'aurait été dans le sous-menu déroulant.</li>
<li>Il est important que chacune de ces pages "Boutique" ait la même structure, avec cette table des matières "Produits" présente au même endroit. La cohérence favorise la compréhension.</li>
<li>La liste regroupe les articles et les énumère en sortie de technologie d'assistance, par exemple via la voix synthétique d'un lecteur d'écran.</li>
<li>Le <code>&lt;nav&gt;</code> est étiqueté de manière récursive par le titre à l'aide de <code>aria-labelledby</code>. Cela signifie que "navigation produits" sera annoncé dans la plupart des lecteurs d'écran lorsqu'on entre dans la région par la tabulation. Cela signifie également que la "navigation des produits" sera détaillée dans les interfaces d'éléments des lecteurs d'écran, à partir desquels les utilisateurs peuvent naviguer directement vers les régions.</li>
</ul><h2>Tout sur une seule page</h2><p>Si vous pouvez faire tenir toutes les sections sur une seule page sans qu'elle devienne trop longue et difficile à faire défiler, c'est encore mieux. Il suffit de créer un lien vers l'identifiant de chaque section. Par exemple, <code>href="#waffle-irons"</code> devrait pointer vers <code>id="waffle-irons"</code>.</p><pre class="language-html">&lt;nav aria-labelledby="sections-heading"&gt;
    &lt;h2 id="sections-heading"&gt;Produits&lt;/h2&gt;
    &lt;ul&gt;
        &lt;li&gt;&lt;a href="#dog-costumes"&gt;Costumes pour chiens&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=#waffle-irons"&gt;Fers à gaufres&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href="#magical-orbs"&gt;Les orbes magiques&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
&lt;/nav&gt;
&lt;!-- section costumes de chiens ici --&gt;
&lt;section id="#waffle-irons" tabindex="-1"&gt;
&lt;h2&gt;Fers à gaufres&lt;/h2&gt;
&lt;/section&gt;
&lt;!-- section orbes magiques ici --&gt;</pre><p>(Remarque : certains navigateurs sont peu doués pour envoyer réellement le focus sur les fragments de page liés. Placer <code>tabindex="-1"</code> sur le fragment cible résout ce problème).</p><p>Lorsqu'un site a beaucoup de contenu, une architecture d'information soigneusement construite, exprimée par l'utilisation libérale de "menus" de tables des matières est infiniment préférable à un système de liste déroulante précaire et peu maniable. Non seulement il est plus facile de le rendre réactif et nécessite moins de code, mais il rend les choses plus claires : là où les listes déroulantes dissimulent la structure, les tables des matières la mettent à nu.</p><p>Certains sites, dont le site <a href="https://www.gov.uk/guidance/content-design/organising-and-grouping-content-on-gov-uk">gov.uk</a> du Government Digital Service, comprennent des pages d'index (ou de "sujets") qui ne sont que des tables des matières. C'est un concept tellement puissant que le populaire générateur de sites statiques Hugo <a href="https://gohugo.io/templates/lists/">génère de telles pages par défaut</a>.</p><figure role="group"><img src="https://la-cascade.io/images/4-menu-buttons-800w-opt.png" alt="Diagramme de style arbre généalogique avec la page d'accueil du sujet en haut et deux ramifications de pages individuelles. Chacune des ramifications de la page individuelle possède plusieurs ramifications de section de page." /><figcaption>Diagramme de type arbre généalogique avec la page d'accueil du sujet en haut et deux ramifications de pages individuelles. Chacune des ramifications de la page individuelle possède plusieurs ramifications de section de page.</figcaption></figure><p>L'architecture de l'information est une partie importante de l'inclusion. Un site mal organisé peut être aussi techniquement conforme que vous le souhaitez, il aliènera quand même de nombreux utilisateurs — en particulier ceux souffrant de troubles cognitifs, ou ceux qui sont pressés par le temps.</p><h2>Boutons du menu de navigation</h2><p>Tant que nous sommes sur le sujet des faux menus de navigation, il serait négligent de ma part de ne pas parler des boutons de menu de navigation. Vous les avez presque certainement vus désignés par une icône "hamburger" ou "navicon" à trois lignes.</p><p>Même avec une architecture d'information épurée et un seul niveau de liens de navigation, l'espace sur les petits écrans est précieux. En cachant la navigation derrière un bouton, il reste plus de place pour le contenu principal dans la fenêtre d'affichage.</p><p>Un bouton de navigation est ce qui se rapproche le plus d'un véritable bouton de menu que nous avons étudié jusqu'à présent. Puisqu'il a pour but de faire basculer la disponibilité d'un menu en cas de clic, il doit :</p><ol><li>S'identifier comme un bouton, et non un lien ;</li>
<li>Identifier l'état déployé ou replié de son menu correspondant (qui, en termes stricts, est juste une liste de liens).</li>
</ol><h2>Amélioration progressive</h2><p>Mais ne nous emballons pas. Nous devons tenir compte de l'amélioration progressive et examiner comment cela fonctionnerait sans JavaScript.</p><p>Dans un document HTML non amélioré, on ne peut pas faire grand-chose à faire avec des boutons (à l'exception des boutons de soumission, mais cela n'a rien à voir avec ce que nous voulons réaliser ici). Au lieu de cela, peut-être devrions-nous commencer par un simple lien qui nous amène à la navigation ?</p><pre class="language-html">&lt;a href="#navigation"&gt;navigation&lt;/a&gt;
&lt;!-- un peu de contenu ici peut-être --&gt;
&lt;nav id="navigation"&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href="/"&gt;Home&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/about"&gt;About&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/shop"&gt;Shop&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/contact"&gt;Contact&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;</pre><p>Il n'y a pas grand intérêt à avoir le lien à moins qu'il n'y ait beaucoup de contenu entre le lien et la navigation. Puisque la navigation du site devrait presque toujours apparaître près du sommet de l'ordre des sources, ce n'est pas nécessaire. Donc, en réalité, un menu de navigation en l'absence de JavaScript devrait juste être... une navigation.</p><pre class="language-html">&lt;nav id="navigation"&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href="/"&gt;Home&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/about"&gt;About&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/shop"&gt;Shop&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/contact"&gt;Contact&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;</pre><p>Vous améliorez ceci en ajoutant le bouton, dans son état initial, et en masquant la navigation (à l'aide de l'attribut <code>hidden</code>) :</p><pre class="language-html">&lt;nav id="navigation"&gt;
  &lt;button aria-expanded="false"&gt;Menu&lt;/button&gt;
  &lt;ul hidden&gt;
    &lt;li&gt;&lt;a href="/"&gt;Home&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/about"&gt;About&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/shop"&gt;Shop&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/contact"&gt;Contact&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;</pre><p>Certains anciens navigateurs — vous savez lesquels — ne prennent pas en charge le mode caché, alors pensez à mettre ce qui suit dans votre CSS. Cela résout le problème car <code>display : none</code> cache le menu aux technologies d'assistance et supprime les liens de l'ordre de focus.</p><pre class="language-css">[hidden] {
  display: none;
}</pre><p>Tout faire pour prendre en charge les anciens logiciels est, bien sûr, un acte de conception inclusive quand certains navigateurs ne peuvent ou ne veulent pas faire de mise à niveau.</p><h2>Placement</h2><p>Là où beaucoup de gens se trompent, c'est en plaçant le bouton <em>en dehors</em> de la région. Cela signifie que les utilisateurs de lecteurs d'écran qui se déplacent vers le <code>&lt;nav&gt;</code> en utilisant un raccourci le trouveraient vide, ce qui n'est pas très utile. Avec la liste cachée aux lecteurs d'écran, ils rencontreraient simplement ceci :</p><pre class="language-html">&lt;nav id="navigation"&gt;&lt;/nav&gt;</pre><p>Voici comment nous pourrions faire basculer l'état :</p><pre class="language-js">var navButton = document.querySelector('nav button')
navButton.addEventListener('click', function () {
  let expanded =
    this.getAttribute('aria-expanded') === 'true' || false
  this.setAttribute('aria-expanded', !expanded)
  let menu = this.nextElementSibling
  menu.hidden = !menu.hidden
})</pre><h2>Aria-controls</h2><p>Comme je l'ai écrit dans <a href="https://heydonworks.com/article/aria-controls-is-poop/">Aria-controls Is Poop</a>, l'attribut <code>aria-controls</code>, destiné à aider les utilisateurs de lecteurs d'écran à naviguer d'un élément "contrôlant" à un élément contrôlé, n'est pris en charge que par le lecteur d'écran JAWS. Vous ne pouvez donc tout simplement pas vous y fier.</p><p>En l'absence d'une bonne méthode pour diriger les utilisateurs entre les éléments, vous devez plutôt vous assurer que l'un des éléments suivants est vrai :</p><ol><li>Le premier lien de la liste étendue est le suivant dans l'ordre de focalisation après le bouton (comme dans l'exemple de code précédent).</li>
<li>Le premier lien est mis en évidence de manière programmatique lors de la révélation de la liste.</li>
</ol><p>Dans ce cas, je recommande (1). C'est beaucoup plus simple, car vous n'avez pas à vous soucier de ramener le focus sur le bouton et sur quel(s) événement(s) le faire. De plus, il n'y a actuellement rien en place pour avertir les utilisateurs que leur focus va être déplacé vers un autre endroit. Dans les vrais menus dont nous parlerons bientôt, c'est le travail de <code>aria-haspopup="true"</code>.</p><p>L'utilisation des contrôles aria ne fait pas vraiment de mal, sauf qu'elle rend la lecture dans les lecteurs d'écran plus verbeuse. Cependant, certains utilisateurs de JAWS peuvent s'y attendre. Voici comment il serait appliqué, en utilisant l'id de la liste comme chiffre :</p><pre class="language-html">&lt;nav id="navigation"&gt;
  &lt;button aria-expanded="false" aria-controls="menu-list"&gt;
    Menu
  &lt;/button&gt;
  &lt;ul id="menu-list" hidden&gt;
    &lt;li&gt;&lt;a href="/"&gt;Home&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/about"&gt;About&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/shop"&gt;Shop&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="/contact"&gt;Contact&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;</pre><h2>Les rôles menu et menuitem</h2><p>Un <em>vrai</em> menu (au sens WAI-ARIA) doit s'identifier comme tel en utilisant le rôle <code>menu</code> (pour le conteneur) et, généralement, les enfants <code>menuitem</code> (<a href="https://www.w3.org/WAI/tutorials/menus/application-menus/">d'autres rôles enfants peuvent s'appliquer</a>). Ces rôles parent et enfant fonctionnent ensemble pour fournir des informations aux technologies d'assistance. Voici comment une liste pourrait être augmentée pour avoir une sémantique de menu :</p><pre class="language-html">&lt;ul role="menu"&gt;
  &lt;li role="menuitem"&gt;Item 1&lt;/li&gt;
  &lt;li role="menuitem"&gt;Item 2&lt;/li&gt;
  &lt;li role="menuitem"&gt;Item 3&lt;/li&gt;
&lt;/ul&gt;</pre><p>Puisque notre menu de navigation commence à se comporter un peu comme un "vrai" menu, ces éléments ne devraient-ils pas être présents ?</p><p>La réponse courte est : non. La réponse longue est : non, car nos éléments de liste contiennent des liens et <a href="https://w3c.github.io/html-aria/#index-aria-menuitem">les éléments <code>menuitem</code> ne sont pas destinés à avoir des descendants interactifs</a>. C'est-à-dire que <em>ce sont eux</em> les contrôles du menu.</p><p>Nous pourrions, bien sûr, supprimer la sémantique de liste des <code>&lt;li&gt;</code>s en utilisant <code>role="presentation"</code> ou <code>role="none"</code> (qui sont équivalents) et placer le rôle <code>menuitem</code> sur chaque lien. Toutefois, cela supprimerait le rôle de lien implicite. En d'autres termes, l'exemple à suivre serait annoncé comme "Accueil, élément de menu", et non "Accueil, lien" ou "Accueil, élément de menu, lien". Les rôles ARIA remplacent simplement les rôles HTML.</p><pre class="language-html">&lt;!-- sera lu comme "Home, menu item" --&gt;
&lt;li role="présentation"&gt;
  &lt;a href="/" role="menuitem"&gt;Home&lt;/a&gt;
&lt;/li&gt;</pre><p>Nous voulons que l'utilisateur sache qu'il utilise un lien et qu'il puisse s'attendre à un comportement de lien, donc ce n'est pas bon. Comme je l'ai dit, les vrais menus sont destinés au comportement des applications (pilotées par JavaScript).</p><p>Ce qui nous reste est une sorte de composant hybride, qui n'est pas tout à fait un vrai menu mais qui indique au moins aux utilisateurs si la liste de liens est ouverte, grâce à l'état <code>aria-expanded</code>. C'est un pattern tout à fait satisfaisant pour les menus de navigation.</p><h2>Note : L'élément <code>&lt;select&gt;</code> ?</h2><p>Si vous êtes impliqué dans le design responsif depuis le début, vous vous souvenez peut-être d'un modèle selon lequel la navigation était condensée dans un élément <code>&lt;select&gt;</code> pour les fenêtres d'affichage étroites.</p><figure role="group"><img src="https://la-cascade.io/images/5-menu-buttons-800w-opt.png" alt="téléphone portable avec élément de sélection montrant 'home' sélectionné en haut de la fenêtre." /><figcaption>téléphone portable avec élément de sélection montrant "home" sélectionné en haut de la fenêtre.</figcaption></figure><p>Comme pour <a href="https://inclusive-components.design/toggle-button/">les boutons de basculement à base de cases à cocher dont nous avons parlé ailleurs</a>, l'utilisation d'un élément natif qui se comporte à peu près comme prévu sans script supplémentaire est un bon choix pour l'efficacité et — surtout sur mobile — les performances. Et les éléments <code>&lt;select&gt;</code> <em>sont</em> d'une certaine manière des menus, avec une sémantique similaire à celle du menu déclenché par un bouton que nous allons bientôt construire.</p><p>Toutefois, tout comme pour le bouton de basculement de la case à cocher (<em>checkbox toggle button</em>), nous utilisons un élément associé à la saisie d'une entrée, et non pas simplement au fait de faire un choix. Cela risque de créer une certaine confusion chez de nombreux utilisateurs — d'autant plus que ce modèle utilise JavaScript pour que l'<code>&lt;option&gt;</code> sélectionnée se comporte comme un lien. Le changement de contexte inattendu qui en découle est considéré comme un échec selon le critère 3.2.2 On Input (Level A) des WCAG.</p><h2>Les vrais menus</h2><p>Maintenant que nous avons parlé des faux menus et des quasi-menus, le moment est venu de créer un <em>vrai menu</em>, tel qu'ouvert et fermé par un vrai bouton de menu. À partir de maintenant, je ferai référence au bouton et au menu ensemble comme étant simplement un "bouton de menu".</p><p>Mais à quels égards notre bouton de menu sera-t-il vrai ? Eh bien, il s'agira d'un composant de menu destiné à choisir des options dans l'application concernée, qui implémente toute la sémantique attendue et les comportements correspondants à considérer comme conventionnels pour un tel outil.</p><p>Comme nous l'avons déjà mentionné, ces conventions proviennent de la conception d'applications de bureau. L'attribution ARIA et la gestion du focus régie par JavaScript sont nécessaires pour les imiter pleinement. L'objectif d'ARIA est en partie d'aider les développeurs Web à créer des expériences Web riches sans rompre avec les conventions d'utilisation forgées dans le monde natif.</p><p>Dans cet exemple, nous allons imaginer que notre application est une sorte de jeu ou de quiz. Notre bouton de menu permettra à l'utilisateur de choisir un niveau de difficulté. Avec toute la sémantique en place, le menu ressemble à ceci :</p><pre class="language-html">&lt;button aria-haspopup="true" aria-expanded="false"&gt;
  Difficulty &lt;span aria-hidden="true"&gt;&amp;#x25be;&lt;/span&gt;
&lt;/button&gt;
&lt;div role="menu"&gt;
  &lt;button role="menuitem"&gt;Easy&lt;/button&gt;
  &lt;button role="menuitem"&gt;Medium&lt;/button&gt;
  &lt;button role="menuitem"&gt;Incredibly Hard&lt;/button&gt;
&lt;/div&gt;</pre><h2>Notes</h2><ul><li>La propriété <code>aria-haspopup</code> indique simplement que le bouton sécrète un menu. Elle avertit que, lorsque le bouton est pressé, l'utilisateur sera déplacé vers le menu "popup" (nous couvrirons le comportement du focus sous peu). Sa valeur ne change pas — elle reste <code>true</code> à tout moment.</li>
<li>Le <code>&lt;span&gt;</code> à l'intérieur du bouton contient le point unicode d'un petit triangle noir pointant vers le bas. Cette convention indique visuellement ce que l'<code>aria-haspopup</code> fait non visuellement — qu'en appuyant sur le bouton, quelque chose sera révélé en dessous. L'attribut <code>aria-hidden="true"</code> empêche les lecteurs d'écran d'annoncer "triangle pointant vers le bas" ou autre. Grâce à <code>aria-haspopup</code>, elle n'est pas nécessaire dans le contexte non visuel.</li>
<li>La propriété <code>aria-haspopup</code> est complétée par <code>aria-expanded</code>. Celle-ci indique à l'utilisateur l'état actuel du menu, ouvert (développé) ou fermé (replié), en basculant entre les valeurs <code>true</code> et <code>false</code>.</li>
<li>Le menu lui-même prend le rôle (bien nommé) de <code>menu</code>. Il prend des descendants avec le rôle <code>menuitem</code>. Il n'est pas nécessaire qu'ils soient des enfants <em>directs</em> de l'élément menu, mais ils le sont dans ce cas, pour des raisons de simplicité.</li>
</ul><h2>Comportement du clavier et du focus</h2><p>Lorsqu'il s'agit de rendre les contrôles interactifs accessibles au clavier, la meilleure chose que vous puissiez faire est d'utiliser les bons éléments. Comme nous utilisons ici des éléments <code>&lt;button&gt;</code>, nous pouvons être sûrs que les événements de clic se déclencheront lors de la frappe des touches <em>Entrée</em> et <em>Espace</em>, <a href="https://developer.mozilla.org/fr/docs/Web/API/HTMLButtonElement">comme spécifié dans l'interface <code>HTMLButtonElement</code></a>. Cela signifie également que nous pouvons désactiver les éléments de menu à l'aide de la propriété <code>disabled</code> associée au bouton.</p><p>Mais l'interaction clavier des boutons de menu ne s'arrête pas là. Voici un résumé de tous les comportements de focus et de clavier que nous allons mettre en œuvre, sur la base des <a href="https://www.w3.org/WAI/ARIA/apg/#menubutton">pratiques de création WAI-ARIA 1.1</a> :</p><table class="specificTable" data-tablesaw-mode="swipe" data-tablesaw-minimap=""><tbody><tr><td data-label=""><kbd>Entrée</kbd>, <kbd>Espace</kbd> ou <kbd>↓</kbd> sur le bouton de menu</td>
<td data-label="">Ouvre le menu</td>
</tr><tr><td data-label=""><kbd>↓</kbd> sur un élément de menu</td>
<td data-label="">Déplace le focus vers l'élément de menu suivant, ou le premier élément de menu si vous êtes sur le dernier</td>
</tr><tr><td data-label=""><kbd>↑</kbd> sur un élément de menu</td>
<td data-label="">Déplace le focus sur l'élément de menu précédent, ou le dernier élément de menu si vous êtes sur le premier</td>
</tr><tr><td data-label=""><kbd>↑</kbd> sur le bouton de menu</td>
<td data-label="">Ferme le menu s'il est ouvert</td>
</tr><tr><td data-label=""><kbd>Esc</kbd> sur un élément de menu</td>
<td data-label="">Ferme le menu et met le focus sur le bouton de menu</td>
</tr></tbody></table><p>L'avantage de déplacer le focus entre les éléments de menu à l'aide des touches fléchées est que la tabulation est préservée pour sortir du menu. Dans la pratique, cela signifie que les utilisateurs ne doivent pas passer par chaque élément de menu pour quitter le menu — une énorme amélioration pour la convivialité, surtout lorsqu'il y a beaucoup d'éléments de menu.</p><p>L'application de <code>tabindex="-1"</code> rend les éléments de menu non focusables par <code>Tab</code> mais préserve la possibilité de focaliser les éléments de manière programmatique, lors de la capture des frappes sur les touches fléchées.</p><pre class="language-html">&lt;button aria-haspopup="true" aria-expanded="false"&gt;
  Difficulty &lt;span aria-hidden="true"&gt;&amp;#x25be;&lt;/span&gt;
&lt;/button&gt;
&lt;div role="menu"&gt;
  &lt;button role="menuitem" tabindex="-1"&gt;Easy&lt;/button&gt;
  &lt;button role="menuitem" tabindex="-1"&gt;Medium&lt;/button&gt;
  &lt;button role="menuitem" tabindex="-1"&gt;Incredibly Hard&lt;/button&gt;
&lt;/div&gt;</pre><h2>La méthode "open"</h2><p>Dans le cadre d'une bonne conception d'API, nous pouvons construire des méthodes pour gérer les différents événements.</p><p>Par exemple, la méthode <code>open</code> doit faire passer la valeur <code>aria-expanded</code> à <code>true</code>, changer la propriété <code>hidden</code> du menu à <code>false</code>, et focaliser le premier <code>menuitem</code> du menu qui n'est pas désactivé :</p><pre class="language-js">MenuButton.prototype.open = function () {
    this.button.setAttribute('aria-expanded', true) ;
    this.menu.hidden = false ;
    this.menu.querySelector(':not(\[disabled]))').focus() ;
    retourner ceci ;
}</pre><p>Nous pouvons exécuter cette méthode lorsque l'utilisateur appuie sur la touche flèche vers le bas sur une instance de bouton de menu focalisée :</p><pre class="language-js">this.button.addEventListener(
  'keydown',
  function (e) {
    if (e.keyCode === 40) {
      this.open()
    }
  }.bind(this)
)</pre><p>En outre, un développeur utilisant ce script pourra désormais ouvrir le menu de manière programmatique :</p><pre class="language-js">exampleMenuButton = new MenuButton(document.querySelector('\[aria-haspopup]])) ;
exampleMenuButton.open() ;</pre><h2>Note : Le hack des cases à cocher</h2><p>Dans la mesure du possible, il est préférable de ne pas utiliser JavaScript, sauf si vous en avez besoin. L'implication d'une troisième technologie au-dessus de HTML et CSS est nécessairement une augmentation de la complexité et de la fragilité du système. Cependant, les composants ne peuvent pas tous être construits de manière satisfaisante sans JavaScript dans le mix.</p><p>Dans le cas des boutons de menu, l'enthousiasme pour les faire "fonctionner sans JavaScript" a conduit à ce que l'on appelle le "checkbox hack". Il s'agit d'utiliser l'état coché (ou non coché) d'une case à cocher cachée pour basculer la visibilité d'un élément de menu à l'aide de CSS.</p><pre class="language-css">/* menu fermé */
[type='checkbox'] + [role='menu'] {
  display: none;
}
/* menu ouvert */
[type='checkbox']:checked + [role='menu'] {
  display: block;
}</pre><p>Pour les utilisateurs de lecteurs d'écran, le rôle de la case à cocher et l'état coché n'ont aucun sens dans ce contexte. Ce problème peut être partiellement résolu en ajoutant <code>role="bouton"</code> à la case à cocher.</p><pre class="language-html">&lt;input
  type="checkbox"
  role="button"
  aria-haspopup="true"
  id="toggle"
/&gt;</pre><p>Malheureusement, cela supprime la communication implicite de l'état coché, nous privant ainsi d'un retour d'état sans JavaScript (même s'il aurait été pauvre en tant que "coché" dans ce contexte).</p><p>Mais il est possible de parodier l'<code>aria-expanded</code>. Il suffit de fournir à notre étiquette deux <code>&lt;span&gt;</code> comme ci-dessous.</p><pre class="language-html">&lt;input type="checkbox" role="button" aria-haspopup="true" id="toggle" class="vh"&gt;
&lt;label for="toggle" data-opens-menu&gt; Difficulty &lt;span class="vh expanded-text"&gt;expanded&amp;lt;/span&gt;
    &lt;span class="vh collapsed-text"&gt;collapsed&lt;/span&gt;
    &lt;span aria-hidden="true"&gt;&amp;#x25be;&lt;/span&gt;
&lt;/label&gt;</pre><p>Ces deux éléments sont masqués visuellement à l'aide de <a href="https://www.a11yproject.com/posts/how-to-hide-content/">la classe <code>visually-hidden</code></a>, mais — selon l'état dans lequel nous nous trouvons — un seul est également masqué aux lecteurs d'écran. C'est-à-dire qu'un seul a <code>display : none</code>, et ceci est déterminé par l'état coché existant (mais non communiqué) :</p><pre class="language-css">/* classe pour masquer visuellement les spans */
.vh {
  position: absolute !important ;
  clip: rect(1px, 1px, 1px, 1px);
  padding: 0 !important ;
  border: 0 !important ;
  height: 1px !important ;
  width: 1px !important ;
  overflow: hidden;
}
/* révéler le libellé d'état correct aux lecteurs d'écran en fonction de l'état */
[type='checkbox']:checked + label .expanded-text {
  display: inline;
}
[type='checkbox']:checked + label .collapsed-text {
  display: none;
}
[type='checkbox']:not(:checked) + label .expanded-text {
  display: none;
}
[type='checkbox']:not(:checked) + label .collapsed-text {
  display: inline;
}</pre><p>C'est très astucieux, mais notre bouton de menu est toujours incomplet, car les comportements de focus attendus dont nous avons parlé ne peuvent pas être mis en œuvre sans JavaScript.</p><p>Ces comportements sont conventionnels et attendus, ce qui rend le bouton plus utilisable. Cependant, si vous avez vraiment besoin d'implémenter un bouton de menu sans JavaScript, c'est à peu près ce que vous pouvez faire de mieux. Étant donné que le bouton de menu de navigation réduit dont j'ai parlé précédemment offre un contenu de menu qui ne dépend pas lui-même de JavaScript (c'est-à-dire des liens), cette approche peut être une option appropriée.</p><p>Pour le plaisir, voici un codePen implémentant un bouton de menu de navigation sans JavaScript.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<a href="https://codepen.io/heydon/pen/vmKVJK">Navigation menu button example no JS</a>de heydon dans<a href="https://codepen.io">CodePen</a></div><p>(Note : Seule la barre d'espace ouvre le menu).</p><h2>L'événement "choisir"</h2><p>L'exécution de certaines méthodes doit émettre des événements afin que nous puissions mettre en place des écouteurs (<em>listeners</em>). Par exemple, nous pouvons émettre un événement <code>choose</code> lorsqu'un utilisateur clique sur un élément de menu. Nous pouvons le configurer en utilisant <code>CustomEvent</code>, qui nous permet de passer un argument à la propriété <code>detail</code> de l'événement. Dans ce cas, l'argument (<code>choice</code>) serait le nœud DOM de l'élément de menu choisi.</p><pre class="language-js">MenuButton.prototype.choose = function (choice) {
  // Define the 'choose' event
  var chooseEvent = new CustomEvent('choose', {
    detail: {
      choice: choice,
    },
  })
  // Dispatch the event
  this.button.dispatchEvent(chooseEvent)
  return this
}</pre><p>Il y a toutes sortes de choses que nous pouvons faire avec ce mécanisme. Peut-être avons-nous une région active configurée avec un id de <code>menuFeedback</code> :</p><pre class="language-html">&lt;div role="alert" id="menuFeedback"&gt;&lt;/div&gt;</pre><p>Maintenant, nous pouvons configurer un écouteur et remplir la région en direct avec les informations sécrétées dans l'événement :</p><pre class="language-js">exampleMenuButton.addEventListener('choose', function (e) {
  // Get the node's text content (label)
  var choiceLabel = e.details.choice.textContent
  // Get the live region node
  var liveRegion = document.getElementById('menuFeedback')
  // Populate the live region
  liveRegion.textContent = 'Your difficulty level is ${choiceLabel}'
})</pre><figure role="group"><img src="https://la-cascade.io/images/6-menu-buttons-800w-opt.png" alt="Lorsqu'un utilisateur choisit une option, le menu se ferme et le focus est renvoyé sur le bouton de menu. Il est important que les utilisateurs soient ramenés à l'élément déclencheur après la fermeture du menu." /><figcaption>Lorsqu'un utilisateur choisit une option, le menu se ferme et le focus est renvoyé sur le bouton de menu. Il est important que les utilisateurs soient ramenés à l'élément déclencheur après la fermeture du menu.</figcaption></figure><p>Lorsqu'un élément de menu est sélectionné, l'utilisateur du lecteur d'écran entend "Vous avez choisi [étiquette de l'élément de menu]". Une région en direct (définie ici avec l'attribution <code>role="alert"</code>) annonce son contenu dans les lecteurs d'écran chaque fois que ce contenu change. La région en direct n'est pas obligatoire, mais c'est un exemple de ce qui pourrait se passer dans l'interface en réponse au choix de l'utilisateur dans le menu.</p><h2>Choix persistants</h2><p>Tous les éléments de menu ne servent pas à choisir des paramètres persistants. Beaucoup d'entre eux agissent comme des boutons standard qui déclenchent quelque chose dans l'interface lorsqu'on appuie. Cependant, dans le cas de notre bouton de menu de difficulté, nous aimerions indiquer quel est le paramètre de difficulté actuel — celui choisi en dernier.</p><p>L'attribut <code>aria-checked="true"</code> fonctionne pour les éléments qui, au lieu de <code>menuitem</code>, prennent le rôle de <code>menuitemradio</code>. Le balisage amélioré, avec le deuxième élément coché (défini) ressemble à ceci :</p><pre class="language-html">&lt;button aria-haspopup="true" aria-expanded="false"&gt;
  Difficulty
  &lt;span aria-hidden="true"&gt;&amp;#x25be;&lt;/span&gt;
&lt;/button&gt;
&lt;div role="menu"&gt;
  &lt;button role="menuitemradio" tabindex="-1"&gt;Easy&lt;/button&gt;
  &lt;button role="menuitemradio" aria-checked="true" tabindex="-1"&gt;
    Medium
  &lt;/button&gt;
  &lt;button role="menuitemradio" tabindex="-1"&gt;Incredibly Hard&lt;/button&gt;
&lt;/div&gt;</pre><p>Les menus natifs de nombreuses plateformes indiquent les éléments choisis à l'aide de coches. Nous pouvons le faire sans problème en utilisant un peu de CSS supplémentaire :</p><pre class="language-css">[role='menuitem'] [aria-checked='true']::before {
  content: '\2713\0020';
}</pre><p>Lorsque vous parcourez le menu avec un lecteur d'écran en cours d'exécution, le fait de mettre le focus sur cet élément coché entraînera une annonce du type "case à cocher, élément de menu moyen, coché".</p><p>Le comportement à l'ouverture d'un menu avec un <code>menuitemradio</code> coché diffère légèrement. Au lieu de focaliser le premier élément (activé) du menu, c'est l'élément <em>coché</em> qui est focalisé.</p><figure role="group"><img src="https://la-cascade.io/images/7-menu-buttons-large-opt.png" alt="Le bouton de menu démarre avec le menu non ouvert. À l'ouverture, le deuxième paramètre de difficulté (moyen) est mis en évidence. Il est préfixé d'une coche en fonction de la présence de l'attribut aria-checked." /><figcaption>Le bouton de menu démarre avec le menu non ouvert. À l'ouverture, le deuxième paramètre de difficulté (moyen) est mis en évidence. Il est préfixé d'une coche en fonction de la présence de l'attribut aria-checked.</figcaption></figure><p>Quel est l'avantage de ce comportement ? L'utilisateur (tout utilisateur) se voit rappeler l'option qu'il a précédemment sélectionnée. Dans les menus comportant de nombreuses options incrémentielles (par exemple, un ensemble de niveaux de zoom), les personnes opérant par clavier sont placées dans la position optimale pour effectuer leur réglage.</p><h2>Utilisation du bouton de menu avec un lecteur d'écran</h2><p><a href="https://www.youtube.com/embed/Aw_HMHdId88">Dans cette vidéo</a> (NdT : <em>en anglais, mais regardez la pour entre le lecteur d'écran</em>), je vous montre comment utiliser le bouton de menu avec le lecteur d'écran Voiceover et Chrome. L'exemple utilise des éléments avec <code>menuitemradio</code>, <code>aria-checked</code> et le comportement focus discuté. On peut s'attendre à des expériences similaires dans toute la gamme des logiciels de lecture d'écran populaires.</p><h2>Bouton de menu inclusif sur Github</h2><p><a href="https://la-cascade.io/auteurs/kitty-giraudel">Kitty Giraudel</a> et moi avons travaillé ensemble sur la création d'un composant de bouton de menu avec les fonctionnalités API que j'ai décrites, et plus encore. Vous devez remercier Hugo pour bon nombre de ces fonctionnalités, car elles sont basées sur le travail qu'il a effectué sur <a href="https://github.com/KittyGiraudel/a11y-dialog">a11y-dialog</a> — un dialogue modal accessible. Il est disponible sur <a href="https://github.com/Heydon/inclusive-menu-button">Github</a> et NPM :</p><pre class="language-js">npm i inclusive-menu-button --save</pre><p>En outre, Kitty a créé <a href="https://github.com/KittyGiraudel/react-menu-button">une version React</a> pour votre délectation.</p><h2>Liste de contrôle</h2><ul><li>N'utilisez pas la sémantique de menu ARIA dans les systèmes de menu de navigation.</li>
<li>Sur les sites à riche contenu, ne cachez pas la structure dans des menus de navigation imbriqués et alimentés par des menus déroulants.</li>
<li>Utilisez <code>aria-expanded</code> pour indiquer l'état ouvert/fermé d'un menu de navigation activé par un bouton.</li>
<li>Assurez-vous que ledit menu de navigation est le prochain dans l'ordre de focus après le bouton qui l'ouvre/le ferme.</li>
<li>Ne sacrifiez jamais la convivialité à la recherche de solutions sans JavaScript. C'est de la vanité.</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/creer-des-systemes-de-menu-accessibles</link>
      <guid>https://la-cascade.io/articles/creer-des-systemes-de-menu-accessibles</guid>
      <pubDate>Thu, 01 Mar 2018 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Sass et interpolation]]></title>
      <description><![CDATA[<p><em>Tout ce que vous avez toujours voulu savoir sur l'interpolation dans Sass, expliqué par Kitty Giraudel. Une bonne introduction toute simple et les cas d'utilisation principaux, pour interpoler avec plaisir.</em></p><div class="articleContent"><p>Depuis quelque temps vous jouez avec Sass, ça vous plaît bien et ça répond à la plupart de vos besoins, mais il y a ce truc que vous ne comprenez toujours pas très bien : <em>l'interpolation</em> - insérer des valeurs à l'intérieur d'autres valeurs. Eh bien nous allons y mettre un peu de clarté/</p><h2>Interpo... quoi ?</h2><p>L'interpolation, qu'on appelle aussi <em>interpolation de variable</em> ou <em>substitution de variable</em> n'est pas une originalité de Sass, en fait on la trouve dans de nombreux langages (PHP, Perl, Ruby, Tcl, Groovy, Unix shells...). On parle souvent d'<em>interpoler une variable</em> ou d'<em>interpoler une expression</em>. Pour le dire vite, interpoler consiste à évaluer une expression ou une chaîne de caractères contenant une ou plusieurs variables, et à remplacer lesdites variables par leurs valeurs correspondantes stockées en mémoire.</p><p>Hmmm...</p><p>Bon, prenons un exemple. Si vous avez des notions de PHP, ce sera facile à comprendre. Admettons que vous vouliez afficher une chaîne de caractères contenant une variable. La façon habituelle de le faire est :</p><pre class="language-php">$description = "awesome";
echo "Tuts+ is " . $description . "!";</pre><p>Ceci n'est pas une interpolation. C'est une <em>&gt;concaténation</em> de caractères. En gros, on accroche ensemble trois chaînes de caractères : <code>"Tuts+ is "</code> , <code>"awesome"</code> et <code>"!"</code>. Mais nous pourrions tout aussi bien utiliser l'interpolation :</p><pre class="language-php">$description = "awesome";
echo "Tuts+ is ${description}!";</pre><p>Les accolades qui entourent la variable indiquent à PHP d'afficher la valeur de la variable à l'intérieur de la chaîne de caractères. Remarquez au passage qu'il faut des guillemets pour que ça marche en PHP (comme dans la plupart des langages).</p><p>Voilà pour l'interpolation de variable ou d'expression. Vous pouvez utiliser la concaténation ou l'interpolation, comme vous voulez, mais disons que l'interpolation apporte un surcroît de douceur syntactique.</p><h2>Et Sass là-dedans ?</h2><p>Regardons maintenant comment fonctionne la substitution de variable dans Sass.</p><p>Les noms de variables, dans Sass comme dans PHP, portent le préfixe <code>$</code>. La comparaison s'arrête là, car pour l'interpolation Sass et PHP se comportent différemment. La raison est que Sass est construit en Ruby, qui utilise <code>#{}</code> pour la substitution d'expression.</p><p>En Sass vous feriez :</p><pre class="language-scss">$description: 'awesome';
@warn "Tuts+ is #{$description}!";</pre><p>Remarquez qu'avec Sass le signe <code>$</code> n'est pas supprimé dans le nom de la variable, contrairement à PHP. Celle-ci est simplement encapsulée, avec <code>$</code>, à l'intérieur de <code>#{}</code>. À remarquer également le fait que vous pouvez interpoler n'importe quel type de variable, pas uniquement des chaînes de caractères. Par exemple :</p><pre class="language-scss">$answer: 42;
@warn "The Answer to the Ultimate Question of Life, the Universe, and Everything is #{$answer}.";</pre><h2>Quand utiliser l'interpolation ?</h2><p>Maintenant que nous avons compris ce qu'est l'interpolation et comment elle fonctionne dans Sass, il est temps de passer à des cas d'utilisation. Pour le premier, nous allons reprendre ce que nous venons de faire avec la directive <code>@warn</code>, qui affiche un contenu dans la console.</p><h3>Chaînes de caractères</h3><p>Supposons que vous ayez une <em>map</em> de couleurs que vous avez appelée <code>$colors</code> (une <em>map</em> est une variable qui emmagasine des paires de clés/valeurs, comme une table ou un <a href="http://en.wikipedia.org/wiki/Array">array</a>), mais que vous en ayez assez de taper <code>map-get($colors, ...)</code> : vous construisez une petite fonction <code>color()</code> qui va chercher la couleur correspondant à la clé passée en argument. C'est très simple :</p><pre class="language-scss">// _config.scss
$colors: (
  'primary': tomato,
  'secondary': hotpink,
);
// _function.scss
@function color($key) {
  @return map-get($colors, $key);
}
// _component.scss
.el {
  background-color: color(primary);
}</pre><p>Pas mal, mais il faudrait y ajouter un message d'alerte au cas où la clé n'existerait pas, ou si vous faites une faute de frappe (au passage, cette <a href="http://webdesign.tutsplus.com/tutorials/an-introduction-to-error-handling-in-sass--cms-19996">introduction au traitement des erreurs</a> peut vous intéresser). Pour ce faire, on utilise la directive <code>@warn</code> à l'intérieur de la fonction <code>color()</code>.</p><pre class="language-scss">@function color($key) {
  @if not map-has-key($colors, $key) {
    @warn "Key not found.";
  }
  @return map-get($colors, $key);
}</pre><p>OK, et maintenant si vous avez envie d'identifier la clé qui n'a pas été trouvée :</p><pre class="language-scss">@function color($key) {
  @if not map-has-key($colors, $key) {
    @warn "Key `#{$key}` not found.";
  }
  @return map-get($colors, $key);
}</pre><p>Et boum, voilà notre interpolation de variable. Appeler <code>color(awesomeness)</code> enverra le message suivant dans la console : <code>Key 'awesomeness' not found</code>.</p><p>C'est bien, mais nous ne connaissons pas réellement le contexte. Pour nous aider à l'avenir, nous pourrions ajouter le nom de la table (map) à l'intérieur du message d'erreur.</p><pre class="language-scss">@function color($key) {
  @if not map-has-key($colors, $key) {
    @warn "Key `#{$key}` not found in $colors map.";
  }
  @return map-get($colors, $key);
}</pre><p>Dans ce cas, puisque la variable <code>$colors</code> n'a pas été interpolée, son nom sera affiché dans le message d'erreur. <code>Key 'awesomeness' not found in $colors map.</code></p><h3>Fonctions CSS</h3><p>Jusqu'à présent, nous avons vu le cas d'utilisation le plus banal de substitution de variable : afficher le contenu d'une variable à l'intérieur d'une chaîne de caractères. C'est un bon exemple, mais il y en a un encore meilleur : les variables dans les fonctions CSS, par exemple dans <a href="http://www.alsacreations.com/article/lire/1630-la-fonction-calc-en-css.html"><code>calc()</code></a>.</p><p>Admettons que vous vouliez dimensionner votre container principal en fonction de la largeur du sidebar. Comme vous êtes un développeur consciencieux, vous avez enregistré cette largeur dans une variable, vous pouvez donc écrire ceci :</p><pre class="language-scss">$sidebar-width: 250px;
.main {
  width: calc(100% - $sidebar-width);
}</pre><p>Et là, surprise ! Ça ne marche pas. Il n'y a pas d'erreur Sass, mais votre container n'est pas dimensionné comme il faut. Si vous inspectez ses styles avec DevTools, vous verrez ceci - rayé parce que c'est invalide : <code>t.main {width: calc(100% - $sidebar-width);}</code></p><p>Penchons-nous là-dessus une minute. <code>calc()</code>est une fonction CSS, pas une fonction Sass. Cela signifie que Sass interprète l'expression tout entière comme une chaîne de caractères. Pour le vérifier, vous pouvez faire :</p><pre class="language-scss">$type-of-expression: type-of(calc(100% - $sidebar-width));
// string</pre><p>Puisque c'est une chaîne de caractères, Sass se comporte comme précédemment avec <code>$colors</code> dans notre chaîne de caractères <code>@warn</code> , donc <code>$sidebar-width</code> est considéré comme une chaîne de caractères et elle est affichée comme telle. Mais ce n'est pas ce que nous voulons, n'est-ce pas ? Alors interpolons !</p><pre class="language-scss">t.main {
  width: calc(100% - #{$sidebar-width});
}</pre><p>Maintenant, lorsque Sass compile la feuille de style, il remplace <code>#{$sidebar-width}</code> par la valeur associée à <code>$sidebar-width</code>, dans ce cas <code>250px</code>, ce qui donne l'expression CSS valide suivante : <code>t.main {width: calc(100% - 250px);}</code></p><p>Mission accomplie ! Nous avons parlé de <code>calc()</code>, mais nous aurions pu utiliser <code>url()</code>, <code>linear-gradient()</code>, <code>radial-gradient()</code>, <code>cubic-bezier()</code> et toute autre fonction CSS native, y compris toutes les <a href="http://la-cascade.io/articles/combinateurs-et-pseudo-classes-css/">pseudo-classes</a>.</p><p>Par exemple :</p><pre class="language-scss">t@for $i from 1 through $max {
  .el:nth-of-type(#{$i}) {
    // ...
  }
}</pre><p>C'est un cas que vous avez sans doute déjà rencontré : l'utilisation d'une boucle <code>for</code> en conjonction avec les sélecteurs <code>:nth-*()</code>. Là encore, vous devez interpoler la variable pour qu'elle apparaisse correctement dans le CSS final.</p><p>En résumé : Sass traite les fonctions CSS comme des chaînes de caractères, ce qui vous impose d'échapper toute variable utilisée dans la fonction si vous voulez que le CSS soit correct.</p><h3>Directives CSS</h3><p>Passons maintenant à un autre cas intéressant d'utilisation de l'interpolation, les directives CSS comme <code>@support</code>, <code>@page</code> et surtout <code>@media</code>.</p><p>Il s'agit ici de la façon dont Sass analyse les directives CSS <code>@</code>, en particulier la directive media. J'ai mis mon nez dans le code Sass et, bien que mon niveau de Ruby ne soit pas top, j'ai trouvé des choses intéressantes :</p><pre class="language-ruby">def query_expr
  interp = interpolation
  return interp if interp
  return unless tok(/\(/)
  res = ['(']
  ss
  res &lt;&lt; sass_script(:parse)
  if tok(/:/)
    res &lt;&lt; ': '
    ss
    res &lt;&lt; sass_script(:parse)
  end
  res &lt;&lt; tok!(/\)/)
  ss
  res
end</pre><p>En gros, les premières lignes disent à Sass de retourner la media query s'il y a une expression interpolée, ou une erreur, sauf s'il trouve une ouverture de parenthèse, auquel cas il doit continuer et analyser le reste. Essayons avec un exemple :</p><pre class="language-scss">$value: screen;
@media $value {
  // ...
}</pre><p>Sans surprise, c'est un échec :<code>Invalid CSS after "@media": expected media query (e.g. print, screen, print and screen), was "$value{"</code></p><p>Comme l'indique le message d'erreur, Sass attendait une media query. Il faut interpoler votre variable si elle arrive juste après <code>@media</code>, par exemple :</p><pre class="language-scss">$value: screen;
@media #{$value} {
  // ...
}</pre><p>Comme nous l'avons déduit de notre petite escapade en Ruby, si <code>@media</code> est directement suivi de parenthèses <code>()</code>, nous n'avons plus besoin d'interpoler la variable parce que Sass évaluera tout ce qui se trouve à l'intérieur des parenthèses. Par exemple :</p><pre class="language-scss">$value: 1336px;
@media (max-width: $value) {
  // ...
}</pre><p>Dans ce cas, Sass évalue l'expression <code>(max-width: $value)</code>, la transforme en <code>(max-width: 1337px)</code> pour aboutir à un résultat CSS valide, il n'y a donc pas besoin d'échapper la variable.</p><p>Pourquoi les développeurs de Sass l'ont-ils conçu ainsi, j'ai posé la question à Nathan Weizenbaum et voici sa réponse :</p><blockquote>
<p><em>D'une manière générale, nous ne voulons pas autoriser l'utilisation de variables "brutes" là où les expressions SassScript ne peuvent être utilisées. C'est le cas des media queries, car SassScript peut être ambigu dans ce contexte (en particulier les maps)</em>.</p>
</blockquote><h3>Sélecteurs</h3><p>Un dernier exemple de cas d'utilisation où nous aurons besoin d'interpoler les variables Sass : Lorsque nous utilisons une variable comme sélecteur, ou comme partie d'un sélecteur. Ce n'est peut-être pas un cas très courant, mais il n'est pas non plus si rare :</p><pre class="language-scss">$value: custom;
selector-$value {
  property: value;
}</pre><p>Malheureusement, ça ne marche pas :<code>Invalid CSS after "selector-": expected "{", was "$value {"</code></p><p>C'est à peu près la même raison que pour les media queries. Sass a sa propre façon d'analyser les sélecteurs CSS. S'il rencontre quelque chose d'inattendu, par exemple un <code>$</code> non échappé, il crashe.</p><p>Heureusement, ce problème est facile à résoudre, et vous connaissez déjà la solution : l'interpolation !</p><pre class="language-scss">$value: custom;
selector-#{$value} {
  property: value;
}</pre><h3>Conclusion</h3><p>En définitive, l'interpolation Sass n'est pas si simple. Il existe des cas où vous devrez échapper votre variable, d'autres où ce ne sera pas nécessaire. À partir de là, il y a deux façons de faire :</p><ul><li>soit vous attendez un message d'erreur, et vous échappez</li>
<li>soit vous échappez tout mais avec des valeurs CSS régulières (dont vous savez qu'elles fonctionnent).</li>
</ul><p>J'espère en tout cas que cet article vous aura permis de mieux comprendre comment fonctionne l'interpolation de variable.</p></div>]]></description>
      <link>https://la-cascade.io/articles/sass-et-interpolation</link>
      <guid>https://la-cascade.io/articles/sass-et-interpolation</guid>
      <pubDate>Sat, 04 Nov 2017 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Grid : comment fonctionne minmax()]]></title>
      <description><![CDATA[<p><em>La fonction minmax() est l'une des plus utiles parmi les nouveautés introduites par la spécification CSS Grid Layout. Ire Aderinokun la présente à sa façon habituelle: systématique, claire et complète!</em></p><div class="articleContent"><p>La fonction <strong>minmax()</strong> introduite par la <a href="https://www.w3.org/TR/css-grid-1/#valdef-grid-template-columns-minmax">spécification</a> CSS Grid Layout est l'une de ses fonctionnalités les plus utiles. <strong>Cette fonction nous permet d'écrire un CSS extrêmement puissant et succinct</strong> : nous pouvons maintenant donner pour valeur à une <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/#gridtrack">piste de grille</a> (<em>grid track</em>) une fonction acceptant une valeur minimum et une valeur maximum.</p><h2>La fonction minmax()</h2><p>La fonction <code>minmax()</code> définit un espace supérieur ou égal à une valeur minimum et inférieur ou égal à une valeur maximum. Elle accepte deux paramètres, une valeur minimum et une valeur maximum.</p><pre>minmax(min, max)</pre><p>Si la valeur maximum définie est inférieure à la valeur minimum, elle n'est pas prise en compte, et la fonction est traitée comme si elle ne présentait qu'une valeur minimum.</p><p>La fonction <code>minmax()</code> accepte six types de valeurs :</p><ul><li>longueur</li>
<li>pourcentage</li>
<li>longueur flexible</li>
<li><code>max-content</code></li>
<li><code>min-content</code></li>
<li><code>auto</code></li>
</ul><p>Passons-les en revue un par un.</p><h3>Longueur</h3><p>La valeur la plus simple que nous puissions passer à <code>minmax()</code> est une longueur. Prenons par exemple cette grille simple, qui a trois colonnes et une rangée unique.</p><figure><img itemprop="url" src="https://la-cascade.io/images/default-minmax.png" alt="" /></figure><p>Avec la fonction <code>minmax()</code>, nous pouvons préciser que la cellule jaune doit avoir une largeur minimale de 100px et maximale de 200px. Lorsque l'écran est redimensionné, la valeur absolue change mais toujours entre ces deux limites.</p><pre>.grid {
    display: grid;
    grid-template-columns: minmax(100px, 200px) 1fr 1fr;
}
</pre><figure><img itemprop="url" src="https://la-cascade.io/images/length-1-compressor.gif" alt="" /></figure><p>Les deuxième et troisième colonnes se rétrécissent ou s'agrandissent pour occuper l'espace disponible de manière égale, mais la première aura toujours une largeur comprise entre 100 et 200px.</p><h3>Pourcentage</h3><p>Nous pouvons également utiliser les pourcentages. Admettons que nous voulions donner à notre cellule jaune une largeur minimale de 200px, pouvant aller jusqu'à 50% de la largeur de la grille.</p><pre>.grid {
    display: grid;
    grid-template-columns: minmax(200px, 50%) 1fr 1fr;
}</pre><figure><img itemprop="url" src="https://la-cascade.io/images/percentage-compressor.gif" alt="" /></figure><p>Nous pouvons réduire la largeur de l'écran autant que nous voulons, la largeur de la cellule jaune ne sera jamais inférieure à 200px. Par contre, lorsque l'espace le permet, elle s'agrandit jusqu'à atteindre la moitié de la largeur de la grille.</p><h3>Longueur flexible</h3><p>La longueur flexible, qui utilise l'unité <code>fr</code>, est une nouvelle unité introduite par la <a href="https://www.w3.org/TR/css-grid-1/">spécification CSS Grid Layout</a>. Cette longueur représente une fraction de l'espace disponible dans la <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/#gridcontainer">grille container</a> (<em>container grid</em>). Par exemple, si nous avons une grille de 100px de large, avec deux colonnes, l'une ayant une largeur fixe de 20px et l'autre une largeur de 1fr, cette dernière aura du coup une dimension de 80px puisqu'elle prend l'espace disponible dans la grille.</p><pre>.grid {
    display: grid;
    grid-template-columns: minmax(200px, 1fr) 1fr 1fr;
}</pre><figure><img itemprop="url" src="https://la-cascade.io/images/fr-compressor.gif" alt="" /></figure><p>Les colonnes ont toutes une dimension de 1fr dans les écrans larges, elles occupent donc le même espace dans la grille.</p><h3>max-content</h3><p>Le mot-clé <code>max-content</code> est une valeur particulière qui représente la "taille idéale" de la cellule. C'est la dimension minimale pour que le contenu de la cellule tienne sans encombre. Par exemple, si le contenu de la cellule est une phrase, la largeur idéale de la cellule sera celle qui permet à la phrase de tenir entièrement, sans retour à la ligne. Reprenons notre exemple précédent et précisons que la cellule jaune doit être à la fois un minimum et un maximum de <code>max-content</code>.</p><pre>.grid {
    display: grid;
    grid-template-columns: minmax(max-content, max-content) 1fr 1fr;
}</pre><figure><img itemprop="url" src="https://la-cascade.io/images/max-content-compressor.gif" alt="" /></figure><p>Comme on peut le voir, la colonne s'étend jusqu'à ce que la phrase tienne entièrement. Comme la minimale et la maximale ont pour valeur <code>max-content</code>, la largeur de la colonne reste toujours identique.</p><h3>min-content</h3><p>Le mot-clé <code>min-content</code> est elle aussi une valeur particulière. Elle représente la plus petite dimension telle que le contenu ne déborde pas — sauf si ce débordement est inévitable. Pour illustrer la différence entre <code>min-content</code> et <code>max-content</code>, nous pouvons utiliser le même contenu que dans l'exemple précédent mais avec les minimale et maximale égales à <code>min-content</code> :</p><pre>.grid {
    display: grid;
    grid-template-columns: minmax(min-content, min-content) 1fr 1fr;
}</pre><figure><img itemprop="url" src="https://la-cascade.io/images/min-content-compressor.gif" alt="" /></figure><p>On voit que le contenu de la cellule est disposé de façon à occuper le moins d'espace horizontal possible sans déborder de la cellule.</p><h3>auto</h3><p>Enfin, nous avons <code>auto</code>. Cette dernière valeur a une signification différente selon qu'on l'utilise comme valeur minimum ou maximum de la fonction <code>minmax()</code>. Si c'est le maximum, la valeur <code>auto</code> est équivalente à la valeur <code>max-content</code>. Si on l'utilise comme valeur minimum, <code>auto</code> représente la plus grande valeur minimale possible pour la cellule. Cette <em>plus grande valeur minimale</em> est différente de la valeur <code>min-content</code> et spécifiée par <code>min-width/min-height</code>. Pour l'illustrer, voici ce qui se passe lorsque la cellule jaune est réglée sur <code>auto</code> dans le minimum et le maximum.</p><pre>.grid {
    display: grid;
    grid-template-columns: minmax(auto, auto) 1fr 1fr;
}
</pre><figure><img itemprop="url" src="https://la-cascade.io/images/auto-compressor.gif" alt="" /></figure><h2>Design responsive sans media queries</h2><p>Comme nous l'avons vu, les cas d'utilisation de <code>minmax()</code> sont multiples. Mais peut-être le cas d'usage le plus courant et le plus utile est-il la possibilité de créer des designs responsive sans recours aux media queries.</p><p>Prenons cette grille par exemple :</p><figure><img itemprop="url" src="https://la-cascade.io/images/responsive-compressor.gif" alt="" /></figure><p>Chaque colonne de la grille a une largeur minimale de 200px. À mesure que l'écran est redimensionné, le nombre de colonnes change, pour s'adapter à leur largeur idéale. Avec CSS Grid et la fonction <code>minmax()</code>, c'est l'affaire de deux ligne de CSS :</p><pre>.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}</pre><p>À côté de la fonction <code>minmax()</code>, il y a deux autres ingrédients-clés :</p><ul><li><code>repeat()</code>: cette fonction nous permet de spécifier la même valeur pour plusieurs colonnes de la grille. Elle prend deux valeurs, le nombre de répétitions et la valeur à répéter.</li>
<li><code>auto-fit</code>: ce mot-clé peut être utilisé avec la fonction <code>repeat()</code>à la place du nombre de répétitions. Le nombre de colonnes est donc modifié de manière flexible, en fonction de la largeur possible pour chaque colonne.</li>
</ul><p>Une limite importante de cette technique toutefois est qu'elle ne fonctionne qu'avec des colonnes de largeur égale. Nous devons utiliser la fonction <code>repeat()</code>avec le mot-clé <code>auto-fit</code> car c'est ce qui permet la flexibilité du nombre de colonnes. Cela étant, si ce cas de figure correspond à vos besoin, c'est une technique très utile.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-grid-comment-fonctionne-minmax</link>
      <guid>https://la-cascade.io/articles/css-grid-comment-fonctionne-minmax</guid>
      <pubDate>Mon, 19 Jun 2017 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[JSON pour les débutants]]></title>
      <description><![CDATA[<p><em>JSON est un format de données facilitant le stockage et l'échange de données entre tous langages de programmation. Louis Lazaris propose une introduction simple, mais détaillée, pour comprendre JSON et JSONP.</em></p><div class="articleContent"><p>Si vous êtes nouveau dans le développement web, que vous avez des connaissances de HTML, CSS et même de JavaScript, JSON est important à connaître.</p><p>Même si vous connaissez déjà JSON et que vous l'avez utilisé dans un projet, il y a peut-être encore des choses que vous ne soupçonnez pas. Dans ce <strong>guide et tutoriel JSON</strong>, je vais essayer de présenter de manière approfondie JSON, son histoire et son utilité. Je terminerai avec une liste d'outils pratiques JSON qui pourront vous servir dans vos projets à venir.</p><h2>Qu'est-ce que JSON ?</h2><p><strong>JSON</strong> (prononciation à la française /ʒi.sɔn/ ou /dʒej.sɔn/ , ou à l'anglaise /ˈdʒeɪˌsən/ (comme <a href="https://www.youtube.com/watch?v=F4gJsKZvqE4">Jason Bourne</a> !) signifie <strong>JavaScript Object Notation</strong> et c'est un format de données. Autrement dit, c'est une façon de stocker des informations, un peu comme une base de données. Bien que créé indépendamment de la spécification <a href="https://fr.wikipedia.org/wiki/ECMAScript">ECMAScript</a>, il est maintenant lié à JavaScript qui inclut un <a href="https://tc39.github.io/ecma262/#sec-json-object">objet JSON</a>, et de nombreux développeurs l'incorporent quasiment comme un sous-ensemble du langage.</p><p>Voici un exemple de syntaxe JSON :</p><pre>{
  "espèce": "Dog",
  "race": "Labrador Retriever",
  "couleur": "Yellow",
  "âge": 6
}</pre><p>Comme vous le voyez, JSON est un format de données consistant en paires de nom/valeur (ou clé/valeur) ayant la forme de chaînes de caractères. Les nom et valeur sont séparés par deux points <code>:</code> et chaque paire est séparée de la suivante par une virgule.</p><p>Bien que trouvant sa source dans JavaScript, beaucoup de langages de programmation (si ce n'est tous ?) peuvent générer et lire le format JSON. Il est donc devenu très populaire pour le stockage, la lecture et le partage d'information dans les applications et services web.</p><h2>Une brève histoire de JSON</h2><p><a href="https://fr.wikipedia.org/wiki/Douglas_Crockford">Douglas Crockford</a> est l'inventeur de JSON et il maintient <a href="http://json.org/">le site officiel JSON.org</a> où il est présenté et discuté en détail. ( <em>NdT : vous pouvez écouter Douglas Crockford raconter <a href="https://www.youtube.com/watch?v=-C-JoyNuQJs">l'histoire de JSON</a> dans cette vidéo YouYube, intéressante aussi pour comprendre certaines caractéristiques du format)</em>.</p><p><a href="http://www.ecma-international.org/flat/publications/files/ECMA-ST/ECMA-404.pdf">La première spécification officielle</a> date de 2013, mais JSON remonte à bien plus loin. Le site web a été lancé en <a href="http://web.archive.org/web/20030228034147/http://www.crockford.com/JSON/index.html">2002</a>, Yahoo et Google ont commencé à utiliser JSON dès 2005 et 2006 respectivement, et JSON a décollé à partir de là. L'article de wikipedia contient beaucoup de <a href="https://en.wikipedia.org/wiki/JSON#History">détails sur son histoire</a> si vous voulez en savoir plus.</p><h2>Différences entre JSON et JavaScript Object</h2><p>Comme son nom l'indique, JSON est plus ou moins un object JavaScript, cependant il y a des différences. Tout d'abord, comme expliqué dans la spécification, "JSON est un format texte facilitant l'échange de données structurées entre tous les langages de programmation". Il est donc universel et non pas limité à JavaScript. En fait, il ne fait pas du tout partie de JavaScript, il est simplement dérivé de la façon dont les objets JavaScripts sont écrits.</p><p>En termes de syntaxe, il y a <strong>deux différences principales</strong>. Tout d'abord, tous les noms (clés) sont représentés sous forme de chaînes de caractères, autrement dit ils doivent être entre guillemets. Ceci par exemple n'est pas du JSON valide :</p><pre>// JSON non valide, mais objet JS valide
{
  foo: "bar"
}</pre><p>La façon correcte d'écrire ce JSON est :</p><pre>// JSON valide
{
  "foo": "bar"
}</pre><p>Remarquez que JSON requiert non seulement que le nom (la clé) soit entre guillemets, mais aussi que les guillemets soient doubles : les guillemets simples sont possibles sur les objets JavaScript, pas dans JSON.</p><p>L'autre différence majeure est dans le type de données que JSON peut stocker. JSON accepte les valeurs suivantes :</p><ul><li>Objet</li>
<li>Array</li>
<li>Nombre</li>
<li>Chaîne de caractères</li>
<li><code>true</code></li>
<li><code>false</code></li>
<li><code>null</code></li>
</ul><p>C'est assez similaire à ce qu'on trouve dans les objets JS, mais JSON étant représenté sous forme de texte on ne peut pas lui donner des choses du genre fonctions ou des valeurs dynamiques de dates utilisant <code>Date()</code>. Par conséquent, il n'y a pas de méthodes ou autres fonctionnalités dans JSON, <strong>il n'y a que du texte</strong>. Et c'est bien ainsi, car c'est ce qui en fait un format universel d'échange de données.</p><p>Il est important de noter qu'un morceau complet de JSON est lui-même techniquement un objet JSON, et le type <code>Objet</code> est ce qui permet d'imbriquer des objets JSON comme valeurs, un peu comme les objets dans JavaScript. Ci-dessous, on a un exemple d'objet JSON imbriqué :</p><pre>// JSON valide
{
  "species": "Dog",
  "breed": "Labrador Retriever",
  "age": 6,
  "traits": {
    "eyeColor": "brown",
    "coatColor": "yellow",
    "weight": "137lbs"
  }
}</pre><p>Ici, l'objet JSON racine a 4 paires de clés/valeurs (“species”, “breed”, “age”, et “traits”) mais la quatrième valeur est un objet imbriqué comprenant 3 paires de clés/valeurs. Et comme vous l'avez sans doute deviné, on peut imbriquer les objets à l'infini (mais restez raisonnable).</p><p>Un objet JavaScript ressemblerait à ceci :</p><pre>// objet JS; non valide en JSON
let myAnimal = {
  species: "dog",
  breed: "Labrador Retriever",
  age: 6,
  traits: {
    eyeColor: "brown",
    coatColor: "yellow",
    weight: "137lbs"
  }
}</pre><p>Vous voyez les différences avec JSON (les guillemets) et de plus, pour que l'objet soit utile en JavaScript il est créé comme valeur d'une variable (<code>myAnimal</code>).</p><h2>Comment stocker JSON ?</h2><p>JSON étant du texte, on peut le stocker où l'on veut. Dans une base de données, dans un fichier texte, un stockage client (cookies ou localStorage) ou via son propre format de fichier qui utilise l'extension <code>.json</code> (qui est en gros un fichier texte avec une extension <code>.json</code>).</p><p>Une fois le contenu JSON stocké, il reste donc à pouvoir le récupérer et le parser de manière appropriée. Selon les langages, il y a diverses façons de récupérer et parser JSON, mais puisque nous nous intéressons au développement front-end, je vais montrer comment le faire en JavaScript.</p><p>JavaScript propose deux méthodes, qui font partie de la spécification ECMAScript, pour réaliser deux tâches distinctes.</p><h2>Utiliser JSON.stringify()</h2><p>Admettons que votre application construise des données d'une manière ou d'une autre. Pour conserver ces données quelque part, elles doivent être converties en une chaîne de caractères (<em>string</em>) JSON valide. Vous pouvez le faire avec <code>JSON.stringify()</code> :</p><pre>let myJSON = {
  species: "Dog",
  breed: "Labrador Retriever",
  age: 6,
  traits: {
    eyeColor: "brown",
    coatColor: "yellow",
    weight: "137lbs"
  }
};
let myNewJSON = JSON.stringify(myJSON, null, '\t');
/* output of myNewJSON:
{
  "species": "Dog",
  "breed": "Labrador Retriever",
  "age": 6,
  "traits": {
    "eyeColor": "brown",
    "coatColor": "yellow",
    "weight": "137lbs"
  }
}
*/</pre><p><a href="https://jsbin.com/qesuwev/edit?html,js,console,output">Voir sur JS Bin</a></p><p>La méthode <code>JSON.stringify()</code> prend un paramètre obligatoire (le JSON que vous voulez convertir en <em>string</em>) et deux arguments optionnels. Le premier est une fonction de remplacement que vous pouvez utiliser pour filtrer certaines paires clé/valeur que vous ne voulez pas inclure. Je n'ai rien exclu dans mon exemple, donc j'ai indiqué <code>null</code> à la place de la fonction de remplacement. D'habitude je n'utilise pas <code>null</code>, mais je voulais utiliser le troisième argument et pour cela il est obligatoire de mentionner le second.</p><p>Le troisième paramètre est la valeur d'espace, il vous aide à formater le JSON de façon à le rendre plus lisible avec indentation, retour à la ligne, etc. Si vous utilisez un nombre pour le troisième argument, il représentera le nombre d'espaces pour l'indentation.</p><h2>Utiliser JSON.parse()</h2><p>À l'inverse, si vous recevez du JSON et que vous voulez l'utiliser dans votre JavaScript, vous pouvez utiliser la méthode <code>JSON.parse()</code> :</p><pre>let myJSON = '{
  "species":"Dog",
  "breed":"Labrador Retriever",
  "age":6,
  "traits":{
    "eyeColor":"brown",
    "coatColor":"yellow",
    "weight":"137lbs"
    }
  }';
let myNewJSON = JSON.parse(myJSON);
// logs a JavaScript object, not a string
console.log(myNewJSON);</pre><p><a href="https://jsbin.com/kujayek/edit?html,js,console,output">Voir sur JS Bin</a></p><p>Dans l'exemple ci-dessus, je crée manuellement une chaîne de caractères JSON que je stocke dans une variable. C'est juste pour la démonstration, dans un scénario réel le JSON pourrait venir d'une source externe ou d'un fichier JSON séparé.</p><p>La méthode <code>JSON.parse()</code> convertit la chaîne de caractères JSON en un objet que je peux manipuler avec JavaScript. La chaîne de caractères est le seul argument obligatoire de la méthode, mais vous pouvez ajouter un second argument optionnel que l'on appelle un <em>reviver</em> de la fonction. En voici un exemple, qui part du JSON précédent :</p><pre>let myNewJSON = JSON.parse(myJSON, function (name, value) {
  if (name === "species") {
    value = "Cat";
  }
  return value;
});</pre><p><a href="https://jsbin.com/kujayek/edit?html,js,console,output">Vous pouvez le voir sur JS Bin</a></p><p>Si vous regardez le résultat sur JS Bin, vous verrez que notre Labrador Retriever est devenu un chat. C'est juste un exemple qui nous montre que l'on peut modifier les valeurs d'un des noms. Pour plus d'infos sur ces fonctions, vous pouvez consulter <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/JSON/parse">MDN</a> ou cet article sur le <a href="http://www.dyn-web.com/tutorials/php-js/json/reviver.php">codage web dynamique</a>.</p><h2>Utiliser JavaScript pour manipuler du JSON</h2><p>Comme vous l'avez déjà deviné, une fois nos données JSON converties en objet JavaScript, nous pouvons y accéder comme à n'importe quel objet JS. Admettons que nous ayons parsé notre chaîne de caractères JSON et que la variable <code>myNewJSON</code> contienne le résultat, comme nous l'avons vu dans la section précédente. Nous pouvons maintenant utiliser ce qu'on appelle la <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Op%C3%A9rateurs/Op%C3%A9rateurs_de_membres">notation avec point</a> (<em>dot notation</em>) pour accéder aux différentes parties de la donnée JSON :</p><pre>console.log(myNewJSON.species); // "Dog"
console.log(myNewJSON.breed); // "Labrador Retriever"
console.log(myNewJSON.age); // 6</pre><p>Nous pouvons également accéder à l'objet imbriqué et aux valeurs situées à l'intérieur via la notation avec point :</p><pre>console.log(myNewJSON.traits);
/*
[object Object] {
  coatColor: "yellow",
  eyeColor: "brown",
  weight: "137lbs"
}
*/
console.log(myNewJSON.traits.coatColor); // "yellow"
console.log(myNewJSON.traits.eyeColor); // "brown"
console.log(myNewJSON.traits.weight); // "137lbs"</pre><p><a href="https://jsbin.com/necure/edit?html,js,console,output">Voir sur JS Bin</a></p><p>Nous pouvons ensuite faire ce que nous voulons de ces données, par exemple ajouter de nouvelles valeurs, changer les valeurs actuelles, effacer des paires de clés/valeurs...</p><pre>myNewJSON.age = 7;
delete myNewJSON.traits.weight;
myNewJSON.traits.cuddly = true;
console.log(myNewJSON);
/*
[object Object] {
  age: 7,
  species: "Dog",
  breed: "Labrador Retriever",
  traits: [object Object] {
    coatColor: "yellow",
    cuddly: true,
    eyeColor: "brown"
  }
}
*/</pre><p><a href="https://jsbin.com/fazetib/edit?html,js,console,output">Voir sur JS Bin</a></p><p>Dans le code ci-dessus, j'ai modifié la valeur de l'<code>age</code>, supprimé la propriété <code>weight</code> (poids) de l'objet <code>traits</code>, et ajouté une nouvelle propriété <code>cuddly</code> (câlin) à l'objet <code>traits</code>.</p><p>Nous pouvons ensuite utiliser <code>JSON.stringify()</code> pour convertir des nouvelles données dans le format d'origine de façon à pouvoir les stocker où nous voulons comme du JSON valide.</p><h2>JSON mieux que XML ?</h2><p>XML n'est certainement pas un format en voie de disparition, mais JSON le surpasse largement en popularité. Douglas Crockford explique <a href="http://www.json.org/xml.html">les avantages de JSON sur XML</a> ("le XML sans gras") et je cite un extrait ici :</p><blockquote>
<p>XML n'est pas idéal pour les échanges de données, de même qu'un tournevis n'est pas fait pour enfoncer des clous. Il porte avec lui un lourd bagage et ne correspond pas au modèle de données de la plupart des langages de programmation. Lorsque les programmeurs ont vu XML pour la première fois, ils ont été choqués par sa laideur et son inefficacité. Cette première réaction était la bonne. Il existe une autre notation textuelle qui posséde tous les avantages de XML et se révèle bien mieux adaptée aux échanges de données — cette notation est JSON.</p>
</blockquote><p>Il poursuit en détaillant les avantages proclamés de XML et en montrant pourquoi JSON fait mieux.</p><h2>Qu'est-ce que JSONP ?</h2><p>JSONP ("JSON with Padding") est une solution visant à surmonter les restrictions et limitations d'<a href="https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS">origines croisées</a> (<em>cross-origin</em>) liées aux requêtes pour des ressources localisées sur un domaine différent de celui à l'origine de la requête. Bob Ippolito a proposé en <a href="http://bob.ippoli.to/archives/2005/12/05/remote-json-jsonp/">2005</a> JSONP, peu de temps après la solution similaire de George Jempty <a href="https://web.archive.org/web/20060212113746/http://htmatters.net/htm/1/2005/07/evaling-JSON.cfm">appelée JSON++</a>.</p><p>JSON profite du fait que les éléments <code>&lt;script&gt;</code> ne sont pas liés par les limitations d'origines croisées. C'est ainsi que nous pouvons faire un lien vers des scripts situés sur des <a href="https://cdnjs.com/">CDN distants</a> sans problème.</p><p>Dans cet exemple, nous accédons à des données JSONP via un simple JavaScript :</p><pre>function doJSONP(result) {
  console.log(result.data);
}
let script = document.createElement('script');
script.src = 'https://api.github.com/users/impressivewebs?callback=doJSONP'
document.getElementsByTagName('body')[0].appendChild(script);</pre><p><a href="https://jsbin.com/hejedoq/edit?html,js,console,output">Voir sur JS Bin</a></p><p>Ce code crée un élément <code>&lt;script&gt;</code>, ajoute une URL dans l'attribut <code>src</code>, puis ajoute (<em>append</em>) le script au document. Dans cet exemple, j'accède à des données utilisateur spécifiques sur GitHub (mes propres données, en fait) en utilisant l'API de GitHub. Si vous ouvrez <a href="https://jsbin.com/hejedoq/edit?html,js,console,output">la démo</a>, vous verrez les données affichées dans la console.</p><p>Si vous utilisez jQuery, vous pouvez faire une requête similaire via la méthode <code>$.getJSON()</code> :</p><pre>$.getJSON('https://api.github.com/users/impressivewebs', function (result) {
  console.log(result);
});</pre><p><a href="https://jsbin.com/celisu/edit?html,js,console,output">Voir sur JS Bin</a></p><p>Remarquez que dans ce cas les données que je veux sont exactement celles qui sont retournées. Avec la version JavaScript, il me faut creuser un peu plus loin avec la propriété <code>data</code> pour obtenir le JSON voulu.</p><p>Dans tous les cas, après avoir obtenu le résultat je peux utiliser la notation avec point pour accéder aux paires clé/valeur. Par exemple je peux obtenir le nombre de mes <em>followers</em> sur GitHub, l'URL de mon avatar, ma quantité de <em>repos</em> publics et bien d'autres infos.</p><h2>Comment marche JSONP ?</h2><p>Pour comprendre comment fonctionne JSONP, il faut d'abord comprendre qu'un fichier JSON simple ne peut pas être utilisé de cette façon, sauf si le serveur prépare les données de façon à ce que la réponse soit correcte. Comment la technique JSONP résout-elle le problème ?</p><p>Dans l'exemple JavaScript précédent, vous avez sans doute remarqué que l'URL de l'API GitHub avait un paramètre attaché : <code>callback=doJSON</code>. Cette fonction de callback agit comme un emballage (ou un <em>padding</em>) nous permettant l'accès aux données, car normalement lorsque nous injectons des données JSON via un élément <code>&lt;script&gt;</code> il ne se passera rien, les contenus n'étant pas stockés dans une variable accessible dans notre JavaScript.</p><p>Avec JSONP, au lieu de :</p><pre>{
  "one": "value_1",
  "two": "value_2"
}</pre><p>...nous recevons ceci :</p><pre>callback({
  "one": "value_1",
  "two": "value_2"
});</pre><p>...où <code>callback</code> est le nom de mon callback. Dans mon exemple, ce serait <code>doJSON</code>.Donc, si vous souhaitez qu'on puisse accéder à votre JSON à partir d'un serveur distant, vous devez vous assurer qu'il sera envoyé avec le padding (c'est à dire la fonction d'emballage). Vous pouvez en voir un exemple (négatif) dans <a href="http://codepen.io/impressivewebs/pen/mWeNzN?editors=1111">ce codepen</a> où j'essaie d'accéder à <a href="http://gd.mlb.com/components/game/mlb/year_2016/month_10/day_04/gid_2016_10_04_balmlb_tormlb_1/plays.json">ces données de la Ligue de Baseball</a> mais le navigateur me répond par un message d'erreur "Uncaught SyntaxError: Unexpected token :" parce que la Ligue de Baseball n'a pas fait en sorte que ses données soient accessibles par JSONP.</p><p>Une discussion détaillée de la résolution de ce problème dépasse les limites de cet article, mais vous trouverez une solution simple dans <a href="http://stackoverflow.com/questions/9519209/how-do-i-set-up-jsonp">ce fil de Stack Overflow</a>.</p><p>Il faut faire attention aux problèmes de sécurité liés à JSONP, donc faites quelques recherches si vous avez un projet dans ce sens. Pour plus d'infos sur JSONP, vous pouvez consulter les ressources suivantes :</p><ul><li><a href="https://en.wikipedia.org/wiki/JSONP">JSONP</a> sur Wikipedia</li>
<li><a href="http://stackoverflow.com/questions/3839966/can-anyone-explain-what-jsonp-is-in-layman-terms">JSONP en termes simples</a> sur Stack Overflow</li>
<li><a href="https://www.metaltoad.com/blog/using-jsonp-safely">Utiliser JSONP en toute sécurité</a></li>
</ul><h2>Outils JSON</h2><p>Il existe de nombreux outils pour faire beaucoup de choses avec les données JSON. Voici une liste de quelques outils intéressants que j'ai rencontrés :</p><ul><li><a href="http://jsonlint.com/">JSONLint</a> — Un validateur de données JSON. C'est un bon outil pour apprendre les bases de la syntaxes et en quoi elle diffère de la syntaxe objet JavaScript.</li>
<li><a href="https://jsonbrowse.com/">json.browse</a> — Vous permet de naviguer, améliorer (<em>prettify</em>), manipuler du JSON à partir d'une source externe ou du JSON copié/collé. Une fonctionnalité intéressante est la possibilité de filtrer les données à partir d'un mot-clé.</li>
<li><a href="http://mb21.github.io/JSONedit/">JSONedit</a> — Un constructeur visuel de JSON qui facilite la construction de structures JSON complexes avec des types de données différents.</li>
<li><a href="http://json-schema.org/">JSON Schema</a> — Un vocabulaire vous permettant d'annoter et de valider des documents JSON.</li>
<li><a href="http://jsonapi.org/">JSON API</a> — Une spécification pour réaliser des API en JSON.</li>
<li><a href="http://www.csvjson.com/">CSVJSON</a> — Convertisseur de CSV et SQl en JSON</li>
<li><a href="http://jsonformatter.org/">JSON Formatter</a> — Outil en ligne pour valider, améliorer, minifier et convertir les données JSON.</li>
<li><a href="http://exceljson.com/">excelJSON</a> — Outil en ligne pour convertir du CSV ou TSV en JSON et JSON en CSV ou TSV.</li>
<li><a href="http://myjson.com/">Myjson</a> — Un entrepôt JSON simple pour votre appli web ou mobile.</li>
<li><a href="https://jsonbin.org/">jsonbin.org</a> — Un nouveau projet de Remy Sharp, "un entrepôt JSON comme service. Protégé par authentification les données sont stockée en JSON et peuvent être liées".</li>
<li><a href="https://www.kinto-storage.org/">Kinto</a> — Un entrepôt JSON générique avec possibilité de partage et de synchronisation.</li>
<li>JSON Generator — Outil en ligne pour générer des données aléatoires en JSON.</li>
<li>Hjson — Une extension de syntaxe pour JSON, afin de faciliter la lectire et la correction par les humains, avant d'envoyer les données à la machine.</li>
<li>JSON Selector Generator — Copiez/collez du JSON, puis cliquez sur n'importe quelle donnée et cet outil vous dira quel "sélecteur" utiliser en JavaScript pour accéder à cette donnée.</li>
</ul><p>Pour recevoir d'autres outils, vous pouvez vous inscrire à <a href="http://webtoolsweekly.com/">Web Tools Weekly</a>. N'hésitez pas à <a href="https://www.impressivewebs.com/what-is-json-introduction-guide-for-beginners/">ajouter des commentaires</a> ou à suggérer d'autres outils.</p><h3>Conclusion</h3><p>Si JSON était un concept relativement neuf pour vous, j'espère que cet article vous aura donné une bonne idée de ce qu'il peut vous apporter. JSON est une technologie solide, facile à utiliser et puissante parce qu'universelle.</p></div>]]></description>
      <link>https://la-cascade.io/articles/json-pour-les-debutants</link>
      <guid>https://la-cascade.io/articles/json-pour-les-debutants</guid>
      <pubDate>Thu, 23 Mar 2017 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Grid et Flexbox, le duo gagnant]]></title>
      <description><![CDATA[<p><em>CSS Grid et Flexbox sont faits pour fonctionner ensemble. Grid pour l'organisation générale, Flexbox pour les ajustements spécifiques. Chen Hui Jing le démontre avec un exemple magistral (et quelques bonus).</em></p><div class="articleContent"><h2>Plongée profonde dans CSS Grid</h2><p>Vous vous rappelez la réponse de <a href="https://la-cascade.io/auteurs/rachel-andrew">Rachel Andrew</a> à la question "utiliser CSS Grid ou Flexbox" ? Sinon vous pouvez <a href="https://www.youtube.com/watch?v=MXEzJ-IncX0&amp;feature=youtu.be&amp;t=1274">regarder la vidéo</a> (en anglais).</p><blockquote>
<p>Flexbox est fait pour les layouts unidimensionnels, CSS Grid est fait pour les layouts en 2 dimensions</p>
<p><cite><a href="https://la-cascade.io/auteurs/rachel-andrew">Rachel Andrew</a></cite></p>
</blockquote><p>Je suis sûre que beaucoup l'ont réalisé avant moi, mais avant ma relation torride d'un mois avec CSS Grid je ne m'étais pas rendue compte à quel point Flexbox et Grid sont faits pour s'entendre. C'était quelque chose du genre oeufs et bacon, pomme et cannelle, beurre de cacahuète et confiture — ah ça y est, j'ai faim tout d'un coup.</p><p>Vous avez peut-être vu que j'ai apporté une contribution au <a href="https://tympanus.net/codrops/css_reference/">CSS Reference de Codrops</a>. Sérieux, c'est une des meilleures choses qui me soit arrivées en 2016. Une des entrées qui manquaient encore était CSS Grid. Avant de m'y mettre, j'avais juste bricolé un peu avec Grid en construisant un prototype pour <a href="http://penang-hokkien.gitlab.io/">Penang Hokkien</a> utilisant Grid, histoire de voir si le mode vertical fonctionnerait mieux qu'avec Flexbox.</p><p>Et puis je me suis attelée au boulot et j'ai écrit <a href="https://tympanus.net/codrops/css_reference/grid/">l'article</a>.</p><p>3 semaines plus tard, j'avais l'impression d'avoir fusionné avec <a href="http://exvius.gamepedia.com/Metal_Cactuar">Metal Cactuar</a> puissance maximum (désolé, <em>Final Fantasy</em> fait partie de ma vie), autrement dit j'étais passé au niveau supérieur.</p><p>J'ai passé beaucoup de temps à éplucher la spécification, la lecture des <a href="https://blogs.igalia.com/mrego/">articles</a> de <a href="https://twitter.com/regocas">Manuel Rego Casasnovas</a> sur CSS Grid m'a beaucoup aidé ainsi que l'<a href="https://rachelandrew.co.uk/css/cheatsheets/box-alignment">antisèche de Rachel Andrew</a> à un moment de grande confusion.</p><p>Un conseil : quand vous essayez d'apprendre une nouvelle propriété CSS, ayez toujours sous la main un template vide avec lequel vous pourrez expérimenter. Ça m'a vraiment été utile avec une propriété aussi nouvelle que Grid. Je sais, il y a aussi <a href="https://codepen.io/">Codepen</a> et tout, mais rien ne vaut un template vierge pour une expérimentation libre de toute distraction.</p><h2>Exemples et démos</h2><p>Pour analyser toutes les propriétés, j'ai commencé à construire des grilles très basiques, juste pour voir le fonctionnement des valeurs de propriétés. Si vous avez regardé la syntaxe de <code>grid-template-rows</code> dans la spécification, vous savez que ce n'était pas une tâche triviale. Grid lui-même n'est compliqué à apprendre. Mais comme il a été conçu pour être flexible et puissant, il vous faudra un peu de temps pour rentrer dans son fonctionnement.</p><p>Quelques-unes des grilles basiques se sont transformées en démos. Certaines trouvaient leur inspiration dans des conversations avec des membres du <a href="https://www.meetup.com/fr-FR/CSS-Layout-Club/">CSS Layout Club</a>. J'ai aussi glané quelques idées dans le cours de Coursera <a href="https://www.coursera.org/learn/graphic-design-history">Ideas from the History of Graphic Design</a>, il y a plein de belles choses (la semaine dernière était consacrée au <a href="https://fr.wikipedia.org/wiki/Bauhaus">Bauhaus</a>).</p><p>Je suis tombée sur cette page de <a href="http://bibliothequekandinsky.centrepompidou.fr/imagesbk/RLPF727/M5050_X0031_LIV_RLPF0727.pdf">Malerei, Fotografie, Film</a> par <a href="https://fr.wikipedia.org/wiki/L%C3%A1szl%C3%B3_Moholy-Nagy">László Moholy-Nagy</a>, dont la mise en page utilisait une grille originale et l'idée m'est venue qu'on pouvait peut-être la réaliser en CSS...</p><figure role="group"><img src="https://la-cascade.io/images/126-640.jpeg" alt="grille texte et images, texte horizontal et vertical, symboles, fortes séparations" /><figcaption>Page 126 de Malerei, Fotografie, Film</figcaption></figure><h2>Le Bauhaus dans mon navigateur</h2><p>Voici comment j'ai procédé. J'ai dessiné les lignes de la grille par-dessus l'image en utilisant Sketch, de façon à me faire une idée du nombre de colonnes nécessaires. Dans cet exemple, c'était 1 large colonne suivie de 5 colonnes plus étroites de largeur égale, et j'ai laissé ensuite le navigateur se débrouiller avec la hauteur des rangées.</p><pre>.grid {
  display: grid;
  grid-template-columns: 30% 9% 9% 9% 9% 9%;
  justify-content: center; /* pour justifier la grille au centre du container */
}</pre><p>Ensuite, il y a eu tout le code de placement avec les propriétés <code>grid-row</code> et <code>grid-column</code>. Mais si vous regardez à nouveau l'image originale, vous verrez que le contenu de chaque cellule a son propre alignement. Par exemple, celui de la première cellule est à droite, celui de la deuxième est en bas à gauche, etc.</p><p>?? <em>NdT : pour consulter les définitions et utilisation des propriétés, voyez l'article <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet">CSS Grid Layout, guide complet</a>)</em>.</p><p>Mon premier réflexe, vu que j'avais cet alignement de boîtes, a été d'appliquer <code>justify-self</code> et <code>align-self</code> là où c'était nécessaire, pour ajuster les positions de contenu à l'intérieur de chaque cellule. Bien tenté, mais à côté... Le problème est que ces deux propriétés affectent la quantité d'espace occupée par la cellule.</p><p>Le design du Bauhaus présente des bordures noires très frappantes autour de chaque cellule. La propriété <code>border</code> s'applique à l'item de grille. Toute propriété d'alignement de grille autre que <code>stretch</code> adaptera la dimension de l'item grid à son contenu. Toute bordure appliquée à un item grid s'adaptera au contenu de l'item, par conséquent je ne pouvais pas procéder ainsi.</p><figure><img src="https://la-cascade.io/images/fit.svg" alt="les bordures sont sur les items, mais les dimensions de l'item ne sont pas celles de la cellule" /><figcaption>Ce ne sont pas les bordures souhaitées !</figcaption></figure><h2>Flexbox à la rescousse</h2><p>Par défaut, tous les items grid se comportent comme si leur alignement avait été réglé sur <code>stretch</code> sur chaque axe. J'ai donc laissé tomber, pour permettre à la grille de ressembler à une grille, et à la place, j'ai appliqué <code>display: flex</code> à l'item grid, ce qui m'a permis d'utiliser les propriétés d'alignement flex sur le container flex, pour positionner le contenu de mon item grid.</p><figure><img src="https://la-cascade.io/images/flex.svg" alt="les bordures correspondent aux lignes horizontales et verticales de la grille, et ne recouvrent pas les items lorsque ceux-ci s'étendent sur plusieurs cellules" /><figcaption>Ah voilà, cette fois-ci c'est bon.</figcaption></figure><pre>.grid__item:nth-child(5) {
  grid-row: 3 / 5;
  border-right: 1em solid;
  padding: 1em;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
}</pre><p>Le code ressemble à ce qui précède, mais ce que je veux souligner avant tout c'est qu'il s'agit d'une formidable technique pour la mise en page. Grid pour l'organisation générale, et Flexbox pour les ajustements spécifiques. Voici ce que ça donne <a href="http://codepen.io/huijing/pen/PpqomV">sur Codepen</a> si vous voulez voir le résultat final.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir le<em>Pen</em><a href="http://codepen.io/huijing/pen/PpqomV/">Malerei, Fotografie, Film (pg. 126)</a>de Chen Hui Jing dans<a href="https://codepen.io">CodePen</a></div><h2>Bonus : réaliser des formes en CSS</h2><p>À part les deux photos, tout ce qui est sur la page est réalisé en CSS, autrement dit la flèche et la roue dentée sont des <code>div</code> auxquelles j'ai appliqué des styles. J'aime faire des formes en CSS, avec une <code>div</code> unique si possible. Il suffit pour cela de quelques propriétés pratiques, <code>box-shadow</code>, <code>border</code> et <a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after/">les pseudo-éléments</a>.</p><h3>La flèche</h3><p>Les flèches sont assez simples à réaliser. Il vous faut juste un pseudo-élément pour la pointe. Le corps de la flèche est une simple <code>div</code> à laquelle on donne une <code>position: relative</code> de façon à positionner la pointe par rapport au corps. La pointe est un triangle, qu'on peut réaliser grâce à <a href="http://stackoverflow.com/questions/27492191/how-to-make-a-fancy-arrow-using-css">l'astuce de la bordure</a>.</p><pre>.arrow {
  width: 0.5em;
  height: 65%;
  background-color: #000;
  position: relative;
  &amp;::after {
    display: block;
    content: '';
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: -1em;
    border-style: solid;
    border-width: 1em 1em 0 1em;
    border-color: #000 transparent transparent transparent;
  }
}</pre><h3>La roue dentée</h3><p>Là, c'est un peu plus compliqué. Le corps de la roue est un cercle, réalisé via <code>border-radius: 50%</code>, mais les dents vont nous demander un peu de travail. Je n'ai pas pu le faire avec une seule <code>div</code> cette fois-ci (mais si quelqu'un y arrive, contactez-moi). J'ai ajouté une <code>div</code> interne. La bonne nouvelle c'est que toutes les dents ont une forme identique, donc l'astuce <code>box-shadow</code> peut être utilisée ici.</p><pre>.gear {
  height: 5em;
  width: 5em;
  background-color: #000;
  border-radius: 50%;
  position: relative;
  &amp;::before,
  &amp;::after {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: block;
    content: '';
  }
  &amp;::before {
    height: 3em;
    width: 1em;
    box-shadow: 0em -3em 0em 0em #000, 0em 3em 0 0em #000;
  }
  &amp;::after {
    height: 1em;
    width: 3em;
    box-shadow: 3em 0 0em 0em #000, -3em 0 0 0em #000;
  }
}</pre><p>Le corps de la roue et les 4 dents directionnées comme les aiguilles d'une boussole ont été réalisées avec une seule <code>div</code> et 2 pseudo-éléments. Pour les 4 autres dents, j'ai utilisé la <code>div</code> intérieure avec des pseudo-éléments et fait tourner les <code>box-shadow</code>. Je dois toujours résoudre le problème de <code>transform-origin</code> car je trouve qu'il y a encore une certaine asymétrie.</p><pre>.inner-gear {
  height: 2em;
  width: 2em;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: #e1e1d5;
  &amp;::before,
  &amp;::after {
    position: absolute;
    display: block;
    content: '';
  }
  &amp;::before {
    height: 3em;
    width: 1em;
    box-shadow: 0em -3em 0em 0em #000, 0em 3em 0 0em #000;
    transform: rotate(45deg);
    transform-origin: (75% 75%);
  }
  &amp;::after {
    height: 1em;
    width: 3em;
    box-shadow: 3em 0 0em 0em #000, -3em 0 0 0em #000;
    transform: rotate(45deg);
    transform-origin: (25% 75%);
  }
}</pre><h3>Conclusion</h3><p>CSS Grid est vraiment génial, et nous sommes nombreux à le penser. <a href="http://jensimmons.com/">Jen Simmons</a> a compilé une liste de bonnes ressources Grid, faites un tour sur <a href="http://jensimmons.com/post/feb-27-2017/learn-css-grid">Learn CSS Grid</a> et essayez de construire quelque chose avec Grid. Vous ne le regretterez pas !</p></div>]]></description>
      <link>https://la-cascade.io/articles/grid-et-flexbox-le-duo-gagnant</link>
      <guid>https://la-cascade.io/articles/grid-et-flexbox-le-duo-gagnant</guid>
      <pubDate>Sun, 05 Mar 2017 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Sass, tout sur @extend]]></title>
      <description><![CDATA[<p><em>Kitty Giraudel, notre grand spécialiste de Sass, est de retour. Il fait le point de façon précise et claire sur ce que personne ne vous avait jamais dit sur @extend.</em></p><div class="articleContent"><p>Sass nous offre énormément d’outils pour écrire un CSS cohérent et solide. L’un des plus puissants est <code>@extend</code>. La plupart des utilisateurs de Sass connaissent son utilisation, mais il reste quelques parties insuffisamment connues.</p><p>Commençons d’abord par les bases.</p><h2>Les bases d’@extend</h2><p>La directive @extend de Sass permet à un sélecteur d’hériter des styles d’un autre. C’est particulièrement utile dans une architecture basée sur les composants, en nous permettant de faire des variations à partir d’un composant.</p><p>Voici un cas très basique d’extension d’un sélecteur :</p><pre class="language-scss">.message {
  padding: 0.5em;
}
.message-error {
  @extend .message;
}</pre><p>qui est compilé en :</p><pre class="language-css">.message,
.message-error {
  padding: 0.5em;
}</pre><p>Facile, non ? Bien sûr l’extension n’est pas limitée aux classes, vous pouvez étendre à peu près tous les sélecteurs (p.ex. <code>a</code>), les IDs (p.ex. <code>#id</code>) etc. et bien sûr les <a href="https://la-cascade.io/articles/sass-mixin-ou-placeholder/#ph">placeholders</a> qui fonctionnent explicitement ainsi.</p><h2>Extension d’un sélecteur complexe</h2><p>La plupart du temps, on étend des sélecteurs simples (le plus souvent des classes), mais rien ne vous empêche d’étendre un sélecteur plus complexe, comme <code>.class element:pseudo</code> ou même :</p><pre class="language-scss">.message + .message {
  margin-bottom: 0.5em;
}
.message-error {
  @extend .message;
}</pre><p>qui sera rendu ainsi :</p><pre class="language-css">.message + .message,
.message-error + .message-error,
.message + .message-error,
.message-error + .message {
  margin-bottom: 0.5em;
}</pre><p>Le résultat est maintenant un peu plus complexe, mais si vous comprenez <code>@extend</code>, il ne devrait pas trop vous surprendre.</p><h2>Extensions multiples</h2><p>Vous savez certainement que vous pouvez étendre des sélecteurs multiples dans la même règle, mais saviez-vous que vous pouviez le faire avec une directive <code>@extend</code> unique ?</p><pre class="language-scss">.message {
  padding: 0.5em;
}
.important {
  font-weight: bold;
}
.message-error {
  @extend .message, .important;
}</pre><p>La compilation en CSS donne :</p><pre class="language-css">.message,
.message-error {
  padding: 0.5em;
}
.important,
.message-error {
  font-weight: bold;
}</pre><p>Si vous me posez la question, je vous dirais que cette méthode n’est pas ma préférée. Le code est certes plus concis, mais je le trouve plus difficile à lire. L’utilisation de directives distinctes pour chaque sélecteur étendu permet de mieux distinguer les sélecteurs et la façon dont ils sont étendus.</p><p>Vous pourriez certes réécrire la syntaxe ainsi :</p><pre class="language-scss">.message-error {
  @extend .message, .important;
}</pre><p>nmais est-ce vraiment plus lisible ?</p><p>Pour ma part, je continuerai à écrire <code>@extend</code> ligne par ligne, le résultat sera identique, mais chacun peut faire comme il veut.</p><h2>Enchaîner les extensions</h2><p>Nous venons de voir qu’un sélecteur peut être étendu depuis plusieurs sources. Mais vous pouvez également enchaîner vos directives :</p><pre class="language-scss">.message {
  padding: 0.5em;
}
.message-important {
  @extend .message;
  font-weight: bold;
}
.message-error {
  @extend .message-important;
}</pre><p>La compilation en CSS donne :</p><pre class="language-css">.message,
.message-important,
.message-error {
  padding: 0.5em;
}
.message-important,
message-error {
  font-weight: bold;
}</pre><p>L’exemple ci-dessus est valide, toutefois je vous conseille de ne pas procéder ainsi pour éviter quelques effets indésirables que nous allons examiner maintenant.</p><h2>Extension massive</h2><p>Certains considèrent que le CSS produit par la compilation est <em>horrible</em>, et parfois ils peuvent avoir raison. La directive <code>@extend</code> est si puissante qu’elle peut aboutir à des extensions <a href="http://pastebin.com/Jy9PqFTy">démesurées</a>. C’est pourquoi il faut toujours être attentif lorsqu’on étend un sélecteur car il étendra <em>toutes</em> les occurrences du sélecteur - ce qui peut rapidement compliquer les choses.</p><pre class="language-scss">.important {
  font-weight: bold;
}
.sidebar .important {
  color: red;
}
.message {
  @extend .important;
}</pre><p>La compilation en CSS donne :</p><pre class="language-css">.important,
.message {
  font-weight: bold;
}
.sidebar .important,
.sidebar .message {
  color: red;
}</pre><p>Comme vous le voyez, non seulement <code>.message</code> a hérité de <code>.important</code>, mais il a aussi hérité des instances où <code>.important</code> est un sélecteur descendant. Si c’est ce que vous aviez souhaité c’est parfait, mais il arrive que ce soit un effet non désiré, il convient donc d’être prudent avec la directive <code>@extend</code>, soit en s’assurant que le sélecteur à partir duquel vous faites l’extension n’existe qu’à un endroit dans votre CSS, soit en étendant un placeholder - qui est fait pour cela.</p><p>Dans tous les cas, rappelez-vous que <a href="http://thesassway.com/editorial/sass-doesnt-create-bad-code-bad-coders-do">Sass ne crée pas de mauvais code</a>, ce sont les mauvais développeurs qui le font.</p><h2>Préserver l’ordre des sources</h2><p>Une caractéristique peu connue de @extend dans Sass est la façon dont elle traite l’ordre des sources. Prenons le code suivant :</p><pre class="language-scss">.half-red {
  color: rgba(red, 0.5);
}
.message-error {
  color: red;
  @extend .half-red;
}</pre><p>Mis à part le côté non-sémantique du nommage des classes, le code est correct et vous vous attendez à un résultat du genre :</p><pre class="language-css">/* Ceci ne sera pas le résultat de la compilation ! */
.message-error {
  color: red;
  color: rgba(255, 0, 0, 0.5);
}</pre><p>Ce serait une façon simple de permettre une <a href="http://fr.wikipedia.org/wiki/Am%C3%A9lioration_progressive">dégradation élégante</a> pour les navigateurs anciens qui ne supportent pas <code>rgba()</code>. Pourtant, ce n’est pas le résultat que nous obtiendrons, au contraire nous aurons :</p><pre class="language-css">.half-red,
.message-error {
  color: rgba(255, 0, 0, 0.5);
}
.message-error {
  color: red;
}</pre><p>Mais pourquoi donc ? me direz-vous. Eh bien parce que la directive @extend fonctionne à l’envers. La <a href="https://sass-lang.com/documentation/at-rules/extend">documentation Sass</a> indique que :</p><blockquote>
<p><em>@extend fonctionne en insérant le "sélecteur étendant" partout où le "sélecteur étendu" apparaît dans la feuille de style</em>.</p>
</blockquote><p>Dans notre exemple, le "sélecteur étendant" est <code>.message-error</code> et le sélecteur étendu est <code>.half-red</code>.</p><h2>Extensions optionnelles</h2><p>Selon les applications sur lesquelles vous travaillez, vous êtes peut-être amenés à utiliser des frameworks tiers ou des widgets. Si certains sont écrits en Sass, rien ne vous empêche d’étendre des sélecteurs de ces fichiers.</p><p>Malheureusement, si le sélecteur étendu n’existe pas, Sass renverra un message d’erreur et la compilation échouera :</p><blockquote>
<p><em>".message-error" “ failed to @extend “.important”</em>.<em>The selector “.important” was not found</em>.<em>Use “@extend .important !optional” if the extend should be able to fail</em>.</p>
</blockquote><p>Comme vous le voyez, vous pouvez passer un flag <code>!optional</code> à vos imports pour éviter qu’ils n’échouent si le sélecteur étendu n’est pas trouvé. Ça peut être utile en cas de conflit entre les sélecteurs étendu et étendant :</p><pre class="language-scss">a.important {
  font-weight: bold;
}
p.message-error {
  @extend .important;
}</pre><p>De fait, cela enverra un message d’erreur car les deux sélecteurs sont spécifiés et il est donc impossible de les unifier :</p><blockquote>
<p><em>No selectors matching “</em><em>.important” could be unified with “p.message-error”</em>.<em>Use “@extend .important !optional” if the extend should be able to fail</em>.</p>
</blockquote><p>L’ajout de <code>!optional</code> à votre <code>@extend</code> résoudra ce problème.</p><h2>Extensions et media queries</h2><p>L’un des principaux problèmes avec <code>@extend</code> est son incompatibilité avec la directive <code>@media</code> : impossible d’étendre à l’intérieur de @media un sélecteur défini à l’extérieur. Malheureusement, Sass ne permet pas les extensions cross-media.</p><pre class="language-scss">.important {
  font-weight: bold;
}
@media (max-width: 767px) {
  .message-error {
    @extend .important;
  }
}</pre><p>Vous obtiendrez le message d’erreur suivant :</p><blockquote>
<p><em>You may not @extend an outer selector from within @media</em>.<em>You may only @extend selectors within the same directive</em>.</p>
</blockquote><p>Cela est dû au fait que @extend fonctionne en déplaçant les sélecteurs, pas les règles CSS, comme nous l’avons vu tout à l’heure au sujet de l’ordre des sources. Si Sass le permettait, alors l’extension d’un sélecteur situé dans un autre media query donnerait quelque chose comme cela :</p><pre class="language-scss">.règle, @media(max-width: 767px) { .autre-règle }, .encore-une-autre-règle {
  /* ... */
}</pre><p>...ce qui n’est clairement pas du CSS valide.</p><p>Ceci étant, les développeurs de Sass sont tout à fait conscients du problème, comme le montre le nombre d’occurrences sur leur repo : <a href="https://github.com/nex3/sass/issues/501">#501</a>, <a href="https://github.com/nex3/sass/issues/640">#640</a>, <a href="https://github.com/nex3/sass/issues/915">#915</a>, <a href="https://github.com/nex3/sass/issues/1050">#1050</a>, <a href="https://github.com/nex3/sass/issues/1083">#1083</a>.</p><p>Il est donc très probable qu’une solution soit proposée bientôt. Si l’on en croit <a href="https://github.com/nex3/sass/issues/640#issuecomment-16537355">ce commentaire</a> de Nex3 (un des principaux développeurs de Sass), ce serait une <em>mixin interpolation</em>.</p><h2>Bonnes pratiques</h2><p>En résumé, voici ce que j’appellerais les bonnes pratiques d’@extend.</p><ul><li>Vérifiez que le sélecteur étendu est présent, une seule fois, dans la feuille de style.</li>
<li>Évitez d’étendre depuis des sélecteurs imbriqués.</li>
<li>Évitez d’enchaîner les directives @extend.</li>
<li>N’essayez pas d’étendre à l’intérieur d’un media query, ça ne marchera pas.</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/sass-tout-sur-extend</link>
      <guid>https://la-cascade.io/articles/sass-tout-sur-extend</guid>
      <pubDate>Tue, 28 Feb 2017 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Les propriétés CSS Background]]></title>
      <description><![CDATA[<p><em>Méthodique et claire comme on la connaît, Ire Aderinokun fait le tour des propriétés background de CSS pour placer, dimensionner, répéter, etc les images d'arrière-plan. Une excellente introduction ou révision.</em></p><div class="articleContent"><p>Comme je l'ai déjà mentionné, <a href="https://la-cascade.io/articles/controler-le-modele-de-boite">tout élément dans l'arborescence du document est une boîte rectangulaire</a>. Chacune de ces boîtes possède un arrière-plan (<em>background</em>) qui peut être une image ou une couleur, ou être transparent. Ce background est contrôlé par 8 propriétés CSS — et une propriété raccourci.</p><h2>background-color</h2><p>La propriété <code>background-color</code> définit une couleur de background pour l'élément. Sa valeur peut être n'importe quelle valeur acceptée de couleur, ou le mot-clé <code>transparent</code>.</p><pre class="language-css">.left {
  background-color: #ffdb3a;
}
.middle {
  background-color: #67b3dd;
}
.right {
  background-color: transparent;
}</pre><figure><img src="https://la-cascade.io/images/color.png" alt="" /></figure><p>La couleur de background est dessinée à l'intérieur de la surface de la boîte spécifiée par la propriété <code>background-clip</code> que nous verrons tout à l'heure. Si des images de background sont également définies, la couche de couleur est dessinée en-dessous.</p><p>Contrairement aux couches d'images qui peuvent être multiples, on ne peut avoir qu'une seule couche de couleur pour un élément donné.</p><h2>background-image</h2><p>La propriété <code>background-image</code> définit une ou plusieurs images de background pour l'élément. Sa valeur est typiquement l'url d'une image définie avec la notation <code>url()</code>. On peut aussi utiliser la valeur <code>none</code>, qui comptera comme une couche vide.</p><pre class="language-css">.left {
  background-image: url('ire.png');
}
.right {
  background-image: none;
}</pre><figure><img src="https://la-cascade.io/images/bg-image-1.png" alt="" /></figure><p>On peut également spécifier des images de background multiples, chacune étant alors séparée par une virgule. Chaque image est placée en-dessous de celle qui la précède sur l'axe des z (z-axis).</p><pre class="language-css">.middle {
  background-image: url('khaled.png'), url('ire.png');
  /* Autres styles */
  background-repeat: no-repeat;
  background-size: 100px;
}</pre><figure><img src="https://la-cascade.io/images/bg-image-2.png" alt="" /></figure><h2>background-repeat</h2><p>Dans une mosaïque d'images, la propriété background-repeat contrôle la façon dont une image de background est tuilée après avoir été mise à dimension (via la propriété background-size) et positionnée (via la propriété background-position).</p><p>La valeur de cette propriété peut être l'un des mots-clés suivants : repeat-x, repeat-y, repeat, space, round, no-repeat. À part les deux premières (repeat-x et repeat-y), les autres valeurs peuvent être définies une seule fois pour l'axe des x et l'axe des y, ou définies pour chaque dimension individuellement.</p><pre class="language-css">.top-outer-left {
  background-repeat: repeat-x;
}
.top-inner-left {
  background-repeat: repeat-y;
}
.top-inner-right {
  background-repeat: repeat;
}
.top-outer-right {
  background-repeat: space;
}
.bottom-outer-left {
  background-repeat: round;
}
.bottom-inner-left {
  background-repeat: no-repeat;
}
.bottom-inner-right {
  background-repeat: space repeat;
}
.bottom-outer-right {
  background-repeat: round space;
}</pre><figure><img src="https://la-cascade.io/images/repeat.png" alt="" /></figure><h2>background-size</h2><p>La propriété background-size définit la taille de l'image de background. Elle prend pour valeur soit un mot-clé, soit une longueur, soit un pourcentage.</p><p>Les mots-clés disponibles pour cette propriété sont contain et cover. Le mot-clé contain redimensionne l'image à son maximum de façon à ce qu'elle soit contenue dans l'espace disponible, sans perdre aucune partie de l'image. cover par contre redimensionne l'image de façon à ce que tout la surface de background soit recouverte.</p><pre class="language-css">.left {
  background-size: contain;
  background-image: url('ire.png');
  background-repeat: no-repeat;
}
.right {
  background-size: cover; /* Les autres styles sont identiques à .left */
}</pre><figure><img src="https://la-cascade.io/images/bg-size-1.png" alt="" /></figure><p>Pour les valeurs de longueur et pourcentage, nous pouvons spécifier la largeur et la hauteur de l'image de background. Les valeurs en pourcentage sont calculées par rapport à la taille de l'élément.</p><pre class="language-css">.left {
  background-size: 50px; /* Les autres styles sont identiques à .left */
}
.right {
  background-size: 50% 80%; /* Les autres styles sont identiques à .left */
}</pre><figure><img src="https://la-cascade.io/images/bg-size-2.png" alt="" /></figure><h2>background-attachment</h2><p>La propriété background-attachment contrôle la façon dont l'image de background va défiler (<em>scroll</em>) par rapport au viewport et à l'élément. Elle peut prendre 3 valeurs.</p><p>Le mot-clé <code>fixed</code> signifie que l'image de background est fixée au viewport et ne se déplace pas, même lorsque l'utilisateur fait défiler la page. local signifie que le background est fixé à sa position dans l'élément. Si ce dernier est lié à un mécanisme de défilement et que l'image de background est positionnée en haut, lorsque l'utilisateur fera défiler la page vers le bas de l'élément l'image pourra disparaître de l'écran. Enfin, scroll signifie que l'image de background est fixe et ne défilera pas avec le contenu de son élément.</p><pre class="language-css">.left {
  background-attachment: fixed;
  background-size: 50%;
  background-image: url('ire.png');
  background-repeat: no-repeat;
  overflow: scroll;
}
.middle {
  background-attachment: local; /* Les autres styles sont identiques à .left */
}
.right {
  background-attachment: scroll; /* Les autres styles sont identiques à .left */
}</pre><figure><img src="https://la-cascade.io/images/attachment.gif" alt="" /></figure><h2>background-position</h2><p>Cette propriété, combinée à la propriété background-origin, définit la position de départ de l'image de background. Sa valeur peut être un mot-clé, une longueur ou un pourcentage, et nous pouvons spécifier la position le long de l'axe des x ou des y.</p><p>Les mots-clés disponibles sont <code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code> et <code>center</code>. Nous pouvons utiliser ces mots-clés en combinaison les uns avec les autres et si nous ne spécifions qu'un seul mot-clé, l'autre est présumé être <code>center</code>.</p><pre class="language-css">.top-left {
  background-position: top;
  background-size: 50%;
  background-image: url('ire.png');
  background-repeat: no-repeat;
}
.top-middle {
  background-position: right; /* Les autres styles sont identiques à .left */
}
.top-right {
  background-position: bottom; /* Les autres styles sont identiques à .left */
}
.bottom-left {
  background-position: left; /* Les autres styles sont identiques à .left */
}
.bottom-right {
  background-position: center; /* Les autres styles sont identiques à .left */
}</pre><figure><img src="https://la-cascade.io/images/bg-position-1.png" alt="" /></figure><p>Pour les valeurs égales à une longueur ou à un pourcentage, nous pouvons aussi spécifier la position le long de l'axe des x ou des y. Les valeurs en pourcentage sont relatives à l'élément contenant.</p><pre class="language-css">.left {
  background-position: 20px 70px; /* Les autres styles sont identiques à .left */
}
.right {
  background-position: 50%; /* Les autres styles sont identiques à .left */
}</pre><figure><img src="https://la-cascade.io/images/bg-position-2.png" alt="" /></figure><h2>background-origin</h2><p>La propriété <code>background-origin</code> spécifie selon quelle zone du modèle de boîte l'image de background doit être positionnée.</p><p>Les valeurs disponibles sont <code>border-box</code>, qui positionne l'image en fonction de la zone de bordure, <code>padding-box</code> qui utilise la zone de padding et <code>content-box</code> qui utilise la zone de contenu.</p><pre class="language-css">.left {
  background-origin: border-box;
  background-size: 50%;
  background-image: url('ire.png');
  background-repeat: no-repeat;
  background-position: top left;
  border: 10px dotted black;
  padding: 20px;
}
.middle {
  background-origin: padding-box; /* Les autres styles sont identiques à .left */
}
.right {
  background-origin: content-box; /* Les autres styles sont identiques à .left */
}</pre><figure><img src="https://la-cascade.io/images/bg-origin.png" alt="" /></figure><h2>background-clip</h2><p>La propriété <code>background-clip</code> détermine la surface sur laquelle le background sera peint. Comme la propriété <code>background-origin</code>, elle s'appuie sur les zones du modèle de boîte.</p><pre class="language-css">.left {
  background-clip: border-box;
  background-size: 50%;
  background-color: #ffdb3a;
  background-repeat: no-repeat;
  background-position: top left;
  border: 10px dotted black;
  padding: 20px;
}
.middle {
  background-clip: padding-box; /* Les autres styles sont identiques à .left */
}
.right {
  background-clip: content-box; /* Les autres styles sont identiques à .left */
}</pre><figure><img src="https://la-cascade.io/images/bg-clip.png" alt="" /></figure><h2>background</h2><p>Enfin, la propriété <code>background</code> est un raccourci des autres propriétés relatives au background. L'ordre des sous-propriétés est sans importance parce que les types de données sont différents. Cependant, pour les propriétés <code>background-origin</code> et <code>background-clip</code>, si une seule une zone du modèle de boîte est spécifiée, elle est valable pour les deux propriétés. Si deux zones sont spécifiées, la première s'applique à la propriété <code>background-origin</code>.</p><h2>Ressources complémentaires en français</h2><ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/background">Les ressources MDN sur background</a> (en français)</li>
<li><a href="https://www.alsacreations.com/astuce/lire/1628-placer-une-image-de-fond-coins-inferieur-droit.html">Placer une image de fond par rapport aux coins inférieur et droit</a>, par Geoffrey C. d'Alsacréations</li>
<li><a href="https://www.alsacreations.com/tuto/lire/808-arriere-plans-css3-background.html">Arrière-plans avec CSS3 Backgrounds</a>, par Simon K. d'Alsacréations</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/les-proprietes-css-background</link>
      <guid>https://la-cascade.io/articles/les-proprietes-css-background</guid>
      <pubDate>Mon, 06 Feb 2017 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[SVG, la syntaxe Path]]></title>
      <description><![CDATA[<p><em>L'élément path de SVG est l'outil de dessin le plus perfectionné qui soit, mais sa syntaxe ne semble pas aisée. Chris Coyier décortique brillamment ce langage, pas si compliqué finalement.</em></p><div class="articleContent"><p>L'élément <code>&lt;path&gt;</code> de SVG (<em>path</em> est le chemin) est l’outil de dessin le plus perfectionné qui soit. Il peut dessiner absolument n'importe quoi ! Sous le capot, d'après mes infos, tous les autres éléments utilisent path. Cet élément prend un argument unique pour décrire tout ce qu'il dessine : l'attribut <code>d</code>. Ce dernier a sa syntaxe bien à lui, qui peut paraître indéchiffrable : une kyrielle de chiffres et de lettres qui se suivent. Comme pour tout avec les ordinateurs, il y a une explication et, bien que non expert, j'ai pensé que ça pourrait être amusant de s'y plonger.</p><p>Voici un exemple de complexité moyenne :</p><pre>//SVG
&lt;path d="M213.1,6.7c-32.4-14.4-73.7,0-88.1,30.6C110.6,4.9,67.5-9.5,36.9,
6.7C2.8,22.9-13.4,62.4,13.5,110.9,C33.3,145.1,67.5,170.3,125,217c59.3-46.7,
93.5-71.9,111.5-106.1C263.4,64.2,247.2,22.9,213.1,6.7z"/&gt;</pre><p>On pourrait le reformater ainsi, le code serait toujours valide :</p><pre>&lt;path d="
  M 213.1,6.7
  c -32.4-14.4-73.7,0-88.1,30.6
  C 110.6,4.9,67.5-9.5,36.9,6.7
  C 2.8,22.9-13.4,62.4,13.5,110.9
  C 33.3,145.1,67.5,170.3,125,217
  c 59.3-46.7,93.5-71.9,111.5-106.1
  C 263.4,64.2,247.2,22.9,213.1,6.7z"
   /&gt;</pre><p>Les lettres sont des <strong>commandes</strong>. Les nombres sont des <strong>valeurs</strong> passées à ces commandes. Toutes les virgules sont optionnelles, on pourrait aussi bien avoir des espaces. Par exemple, la première commande est <code>M</code>. Métaphoriquement, <code>M</code> dit <em>prend ton crayon et déplace le exactement vers le point de coordonnées 231.1, 6.7</em>. On ne dessine rien pour l'instant, on déplace juste le crayon à ces coordonnées. Si d'autres commandes suivent, elles commenceront à cet endroit.</p><p><code>M</code> est juste une des multiples commandes disponibles pour path. Si j'ai bien compté, il y en a 18 en tout.</p><p>La plupart viennent par deux, il y a une version en majuscules et une version en minuscules. La version en majuscules est la version <strong>absolue</strong>, celle en minuscules est la version <strong>relative</strong>. Continuons avec notre exemple M :</p><ul><li><code>M 100,100</code> signifie <em>prend le crayon et déplace le exactement au point de coordonnées 100,100</em>.</li>
<li><code>m 100,100</code> signifie <em>déplace le crayon de 100 vers le bas et 100 vers la droite, à partir de l'endroit où tu te trouves</em>.</li>
</ul><p>Beaucoup de commandes fonctionnent ainsi. La version en minuscules intègre la position actuelle du "crayon".</p><p>Regardons deux commandes absolues :</p><p>commands&amp;lt;svg viewBox=&amp;quot;0 0 100 100&amp;quot;&amp;gt;
&amp;lt;path d=&amp;quot;M 50,50L 100,100&amp;quot; /&amp;gt;&amp;lt;/svg&amp;gt;Prendre le crayon et
l&amp;#x27;amener à 50,50Poser le crayon et tracer
une ligne vers 100,100</p><p>Suivies par une commande relative :</p><p>commands&amp;lt;svg viewBox=&amp;quot;0 0 100 100&amp;quot;&amp;gt;
&amp;lt;path d=&amp;quot;M 50,50L 100,100l 25,0&amp;quot; /&amp;gt;&amp;lt;/svg&amp;gt;De
la position courantealler à droite de 25</p><p>De même que les commandes <code>M</code> et <code>m</code>, <code>L</code> et <code>l</code> prennent deux nombres représentant des coordonnées absolues ou relatives. Il y a quatre autres commandes qui sont en fait des versions simplifiées des commandes de ligne. Elles dessinent aussi des lignes, mais ne prennent qu'une seule valeur: horizontale ou verticale. Lorsque nous avons utilisé <code>l 25,0</code> nous aurions pu utiliser <code>h 25</code> à la place, qui signifie <em>de l'endroit où se trouve le crayon actuellement, dessine vers la droite, de 25</em>. C'est juste plus succinct. Son grand frère <code>H</code>, comme on le devine, signifie dessiner vers la coordonnée horizontale exacte 25. <code>V</code> et <code>v</code> sont les équivalents pour la direction verticale. Vous vous en doutiez, pas vrai ?</p><p>Jetez un coup d'oeil à cette démo de Chris Nager, dans laquelle il dessine une croix avec un code incroyablement concis grâce aux coordonnées relatives :</p><p>Vous avez remarqué le dernier caractère utilisé par Chris ? <code>Z</code>. <code>Z</code> (ou <code>z</code>, ça n'a pas d'importance) "ferme" le chemin. Comme toutes les autres commandes, il est optionnel. C'est une manière facile de tracer une ligne droite directement vers le dernier point où le "crayon" a été posé (probablement une commande <code>M</code> ou <code>m</code>), qui vous évite d'avoir à répéter ce premier point et à utiliser une commande pour y parvenir.</p><p>commands&amp;lt;svg viewBox=&amp;quot;0 0 100 100&amp;quot;&amp;gt;
&amp;lt;path d=&amp;quot;M 50,50L 100,100l 25,0Z&amp;quot; /&amp;gt;&amp;lt;/svg&amp;gt;Tracer une ligne vers
le point de départ</p><p>Récapitulons les commandes dont nous disposons jusqu'à présent :</p><table class="specificTable"><tbody><tr><td><strong>M</strong> x,y</td>
<td>Aller vers les coordonnées absolues x,y</td>
</tr><tr><td><strong>m</strong> x,y</td>
<td>Aller de x vers la droite et de y vers le bas (ou gauche et haut si les valeurs sont négatives)</td>
</tr><tr><td><strong>L</strong> x,y</td>
<td>Tracer une ligne droite vers le point de coordonnées absolues x,y</td>
</tr><tr><td><strong>l</strong> x,y</td>
<td>Tracer une ligne droite vers un point situé à x vers la droite et y vers la gauche relativement (ou gauche et droite si les valeurs sont négatives</td>
</tr><tr><td><strong>H</strong> x</td>
<td>Tracer une ligne horizontale vers la coordonnée x exacte</td>
</tr><tr><td><strong>h</strong> x</td>
<td>Tracer une ligne horizontale à droite vers le x relatif (ou vers la gauche si la valeur est négative)</td>
</tr><tr><td><strong>V</strong> y</td>
<td>Tracer une ligne verticale vers la coordonnée y exacte</td>
</tr><tr><td><strong>v</strong> y</td>
<td>Tracer une ligne verticale en bas vers le y relatif (ou vers le haut si la valeur est négative)</td>
</tr><tr><td><strong>Z</strong> (ou <strong>z</strong>)</td>
<td>Tracer une ligne droite pour revenir au début du chemin</td>
</tr></tbody></table><p>Pour l'instant, nous n'avons eu affaire qu'à des lignes droites. Path est un élément et une syntaxe parfaitement acceptable pour cela, même si l'on pourrait avancer que des éléments comme <code>&lt;polygon&gt;</code> ont une syntaxe encore plus simple, quoiqu'un peu plus limitée (?? <a href="https://la-cascade.io/articles/les-bases-de-svg-polygones/">plus d'infos sur les polygones SVG</a> dans les bases SVG de La Cascade_.)</p><p>C'est avec les courbes que path montre ses super-pouvoirs ! Si vous voulez rappelez, le premier extrait de code que nous avons vu comportait un tas de commandes <code>C</code> et <code>c</code>. Ce sont les <a href="https://fr.wikipedia.org/wiki/Courbe_de_B%C3%A9zier">Courbes de Bézier</a> et elles ont besoin de plus d'infos pour faire leur boulot.</p><p>La commande C a besoin de trois points. Les deux premiers définissent la localisation des deux poignées, c'est un concept qui vous est sans doute familier si vous utilisez Adobe Illustrator ou Sketch.</p><figure><img src="https://la-cascade.io/images/two-handles.webp" alt="Une courbe de Bezier et ses deux poignées" /></figure><p>Le dernier des trois points est l'endroit où la courbe s'achève. Voici une illustration de la commande <code>C</code> :</p><p>commands&amp;lt;svg viewBox=&amp;quot;0 0 100 100&amp;quot;&amp;gt;
&amp;lt;path d=&amp;quot;M 25,50C25,100150,100150,50&amp;quot; /&amp;gt;&amp;lt;/svg&amp;gt;Bezier point #1Bezier point #2Point final</p><p>La commande <code>c</code> (minuscule) est exactement la même, sauf que les trois points utilisent des valeurs relatives.</p><p>La commande <code>S</code> (ou <code>s</code>) est la petite soeur des commandes <code>C</code> en ce sens qu'elle ne nécessite que deux points : elle <em>suppose</em> que son premier point de Bézier est le dernier point de Bezier de la commande S ou C qui précède.</p><p>commands&amp;lt;svg viewBox=&amp;quot;0 0 100 100&amp;quot;&amp;gt;
&amp;lt;path d=&amp;quot;M 25,100C 25,150 75,150 75,100S100,25150,75&amp;quot; /&amp;gt;&amp;lt;/svg&amp;gt;SUPPOSITION!Bezier PointPoint final</p><p>La commande <code>Q</code> est l'une des plus simples car elle ne requiert que deux points. Le point de Bézier requis est un point de contrôle "quadratique" de la courbe, tout se passe comme si le point de départ et d'arrivée partageaient un point unique qui serait l'extrémité de leur poignée respective. Autant parler de <code>T</code> dans la foulée : c'est la petite soeur de <code>Q</code>, comme <code>S</code> l'est de <code>C</code>. Lorsque T vient après Q, le point de contrôle est supposé être le même que le précédent, donc on n'a besoin de donner que le point final :</p><p>commands&amp;lt;svg viewBox=&amp;quot;0 0 100 100&amp;quot;&amp;gt;
&amp;lt;path d=&amp;quot;M 25,75Q50,15075,100T150,150&amp;quot; /&amp;gt;&amp;lt;/svg&amp;gt;Bezier PointPoint finalSUPPOSITION!Point final</p><p>La commande <code>A</code> est sans doute la plus compliquée. Ou du moins celle qui requiert le plus de données. On lui donne l'information définissant un ovale (sa largeur et sa hauteur, ou plus exactement la longueur du rayon x et la longueur du rayon y) et sa rotation, ainsi que le point final. Puis un peu plus d'info pour dire quel chemin vous voulez que votre <em>path</em> prenne le long de cet ovale. Extrait de MDN :</p><blockquote>
<p>Il y a deux ellipses possibles autour desquelles le chemin peut "voyager" et deux chemins possibles sur chaque ellipse, ce qui donne en tout quatre chemins possibles. Le premier argument est relatif à l'arc le plus grand, <code>large-arc-flag</code>. Il détermine simplement si l'on choisit l'arc qui est plus grand ou plus petit que 180 degrés; au final, ce flag détermine la direction que suivra l'arc autour d'un cercle donné. Le second argument est le <code>sweep-flag</code>, il détermine si l'arc doit commencer à se mouvoir selon un angle positif ou négatif, ce qui revient à choisir lequel des deux cercles on suit.</p>
</blockquote><p> NdT : Autre explication, tirée de <a href="http://svground.fr/paths.php">SVG Ground</a>, une bible (en français) pour SVG :</p><blockquote>
<p>la lettre qui commande le tracé d’un arc elliptique est A (ou a minuscule pour des coordonnées relatives). Les deux premiers paramètres sont respectivement la longueur du rayon x et la longueur du rayon y (ces deux rayons restent perpendiculaires). Le troisième est la rotation (sens direct, inverse des aiguilles d’une montre) en degrés de l’axe x de l’ellipse par rapport à l’axe des ordonnées. Le quatrième paramètre, appelé large-arc-flag, indique si on doit afficher l’arc dont la mesure fait plus de la moitié du périmètre de l’ellipse (dans ce cas, la valeur est 1), ou l’arc dont la mesure fait moins de la moitié du périmètre (valeur : 0). Le cinquième paramètre, appelé sweep-flag, indique quant à lui si l’arc doit être dessiné dans la direction négative des angles (dans lequel cas sa valeur est 0) ou dans la direction positive des angles (valeur : 1). Les deux derniers sont les coordonnées du point d’arrivée, les coordonnées du point de départ étant données par la commande précédant la commande A. La commande d’arc elliptique est à mon sens assez difficile à comprendre, mais une fois assimilée, elle est très simple d’utilisation. Il faut souvent beaucoup de tests avant de comprendre comment elle fonctionne.</p>
</blockquote><p>Le graphique de Joni Trythall expliquant la commande <code>A</code> dans <a href="https://www.sitepoint.com/closer-look-svg-path-data/">son article sur les chemins SVG</a> est assez clair :</p><figure><img src="https://la-cascade.io/images/curve3.webp" alt="" /></figure><p> NdT : <em>Exemple (modifié) tiré de l'article de Joni Trythall</em> :</p><pre>&lt;svg&gt;
    &lt;path fill=lightblue
          stroke="#333333"
          stroke-width="3"
          d="M100,20 a100,40 10 1,0 100,10" /&gt;
&lt;/svg&gt;</pre><p>Le premier et le dernier ensemble de valeurs (M100,20 &amp; 100,10) représentent les coordonnées initiales et finales. Le second ensemble de valeurs (a100,40) définit les deux rayons. Le troisième, la rotation (10). Enfin, les valeurs 1,0 (large-arc-flag &amp; sweep-flag) déterminent la façon dont l'arc est dessiné.</p><p>Ce qui donne :</p><p>Voici une explication écrite de ces commandes de courbes :</p><table class="specificTable"><tbody><tr><td><strong>C</strong> cX1,cY1 cX2,cY2 eX,eY</td>
<td>Dessine une courbe de Bezier à partir de <strong>deux</strong> points de contrôle et se termine à des coordonnées spécifiées</td>
</tr><tr><td><strong>c</strong></td>
<td>Idem, avec des valeurs relatives</td>
</tr><tr><td><strong>S</strong> cX2,cY2 eX,eY</td>
<td>En gros, une commande C qui part du principe que le premier point de contrôle de Bezier est le même que le dernier point de contrôle utilisé dans la commande S or C qui précèdent</td>
</tr><tr><td><strong>s</strong></td>
<td>Idem, avec des valeurs relatives</td>
</tr><tr><td><strong>Q</strong> cX,cY eX,eY</td>
<td>Dessine une courbe de Bezier à partir d'un <strong>unique</strong> point de contrôle et se termine à des coordonnées spécifiées</td>
</tr><tr><td><strong>q</strong></td>
<td>Idem, avec des valeurs relatives</td>
</tr><tr><td><strong>T</strong> eX,eY</td>
<td>En gros, une commande Q qui part du principe que le premier point de contrôle de Bezier est le même que le dernier point de contrôle utilisé dans la commande Q or T qui précèdent</td>
</tr><tr><td><strong>t</strong></td>
<td>Idem, avec des valeurs relatives</td>
</tr><tr><td><strong>A</strong> rX,rY rotation, arc, sweep, eX,eY</td>
<td>Dessine un arc basé sur la courbe d'un ovale. Définit d'abord la largeur et la hauteur de l'ovale. Puis la rotation de l'ovale. Avec le point final, cela fait deux ovales possibles. L'arc et la courbe ont pour valeur 0 ou 1 et déterminent quel ovale et quel chemin sera pris.</td>
</tr><tr><td><strong>a</strong></td>
<td>Idem, avec des valeurs relatives pour eX,eY</td>
</tr></tbody></table><p>Vous voulez voir des exemples ? OK :</p><p>Si vous le regardez avec un navigateur Blink récent et que vous avez une souris, vous verrez quelques animations au survol ! Eh oui, on peut mettre des données de <em>path</em> dans</p>CSS maintenant, par exemple :<pre>//SVG
&lt;svg viewBox="0 0 10 10"&gt;
  &lt;path d="M2,5 C2,8 8,8 8,5" /&gt;
&lt;/svg&gt;</pre><p>et :</p><pre>//CSS
svg:hover path {
  transition: d 0.2s;
  d: path("M2,5 C2,2 8,2 8,5");
}</pre></div>]]></description>
      <link>https://la-cascade.io/articles/svg-la-syntaxe-path</link>
      <guid>https://la-cascade.io/articles/svg-la-syntaxe-path</guid>
      <pubDate>Thu, 29 Dec 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre SVG viewBox]]></title>
      <description><![CDATA[<p><em>Tout savoir sur SVG viewbox. L'attribut viewBox est l'un des premiers qu'on rencontre quand on débute avec SVG, cette introduction de Dudley Storey vous simplifiera la vie.</em></p><div class="articleContent"><p>L'attribut <code>viewBox</code> est l'un des premiers qu'on rencontre quand on débute avec <a href="https://la-cascade.io/tags/svg/">SVG</a>, et potentiellement une grande source de confusion. Bien que largement couvert par d'autres auteurs — <a href="https://sarasoueidan.com/blog/svg-coordinate-systems/">la série d'articles de Sara Soueidan</a> pouvant être considérée comme une des sources canoniques sur le sujet — il manquait d'un "guide de départ" donnant les quelques détails nécessaires pour pouvoir se lancer dans les applications basiques du dessin vectoriel. C'est l'objectif de cet article.  <em>NdT : En complément, on pourra également consulter dans La Cascade les articles de Joni Trythall <a href="https://la-cascade.io/comprendre-svg-viewbox-et-viewport/">comprendre viewBox et viewPort</a> ainsi que <a href="https://la-cascade.io/comprendre-svg-preserveaspectratio/">comprendre SVG preserveAspectRatio</a></em>.</p><h2>Un canevas infini</h2><p>L'espace de dessin de SVG est infini : on peut dessiner à partir de n'importe quel point de coordonnées dans un document SVG. Toutefois, pour des raisons d'<em>affichage</em>, le document a généralement une dimension, comme un cadre ou un canevas. C'est ici qu'entre en jeu la viewBox.</p><p>On la trouve le plus souvent appliquée ainsi :</p><pre>&lt;svg viewBox="0 0 200 100"&gt;</pre><blockquote>
<p>?? Remarque : j'ai laissé de côté l'<a href="https://developer.mozilla.org/en/docs/Web/SVG/Namespaces_Crash_Course">espace de nom</a> pour la simplicité et la clarté des exemples. De plus, le background des exemples SVG sera apparent (en bleu clair) pour mieux montrer leur dimension réelle.</p>
</blockquote><p>La viewBox utilise 4 valeurs pour localiser deux coordonnées dans l'espace : les coins supérieur gauche et inférieur droit du SVG. Dans le code ci-dessus le coin supérieur gauche est défini comme <code>0 0</code> (valeur de x, puis valeur de y), et le coin inférieur droit comme 200 unités vers la droite et 100 unités vers le bas.</p><p>Deux points à noter ici :</p><ul><li>Les valeurs utilisées <em>ne comportent pas d'unité de mesure</em>. Il est préférable de ne pas les considérer en pixels, centimètres ou autres, mais simplement comme des unités génériques.</li>
<li>Même s'il est très courant que le coin supérieur gauche d'un document SVG commence à <code>0 0</code>, ce n'est pas obligatoire.</li>
</ul><p>Dans la plupart des applications de dessin vectoriel, la viewBox correspond au canevas ou à l'<em>artboard</em> préparé avant que vous ne commenciez à dessiner. Toutefois, de nombreuses applications, dont <a href="http://www.adobe.com/fr/products/illustrator.html">Adobe Illustrator</a> et <a href="https://www.sketch.com/">Sketch</a>, vont réduire la viewBox à la surface visible autour des éléments que vous aurez dessiné lorsqu'ils les exporteront en SVG. C'est une des raisons pour lesquelles il est important de bien comprendre la viewBox : vous pouvez ajuster le canevas du SVG directement dans le code, sans avoir à vous battre avec le comportement de votre application.</p><p>Un <a href="https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses/">élément SVG circle</a> dessiné sans attributs <code>cx</code> ou <code>cy</code> supposera que son centre est à <code>0 0</code> dans l'espace de coordonnées. Voyons ce que ça donne lorsque nous utilisons les valeurs viewBox que nous avons utilisées :</p><pre>&lt;svg viewBox="0 0 200 100"&gt;
    &lt;circle r="50"&gt;
&lt;/svg&gt;</pre><p>Ce qui produit :</p><p>Comme vous pouvez le constater, la viewBox ne détermine pas la taille de l'élément SVG rendu sur la page. Pour cela, il y a les attributs <code>width</code> et <code>height</code> et/ou n'importe quel CSS appliqué à SVG. Par contre, la viewBox détermine le <em>ratio d'aspect</em> de l'espace et la taille relative des éléments qui l'occupent.</p><blockquote>
<p>?? Remarquez également la capitale à l'intérieur de <code>viewBox</code> : SVG, qui est un langage de <a href="https://fr.wikipedia.org/wiki/Extensible_Markup_Language">la famille XML</a>, est sensible à la casse, donc l'attribut doit être écrit ainsi, avec un B majuscule, pour être reconnu.</p>
</blockquote><p>Si la viewBox est réduite, la taille apparente du cercle s'agrandit, relativement au document SVG, même si le rayon du cercle reste inchangé :</p><pre>&lt;svg viewBox="0 0 100 50"&gt;
    &lt;circle r="50"&gt;
&lt;/svg&gt;</pre><p>On pourrait voir cela comme un "zoom avant" dans le document. La viewBox nous permet une "mise à l'échelle" à l'intérieur d'un SVG.</p><p>Les éléments dessinés à l'extérieur de l'espace de la viewBox sont coupés. Ajoutons un autre élément <code>&lt;circle&gt;</code>, cette fois-ci avec des valeurs <code>cx</code> et <code>cy</code> ainsi qu'une couleur de remplissage (<em>fill</em>).</p><pre>&lt;svg viewBox="0 0 100 50"&gt;
    &lt;circle cx="150" cy="120" r="20" fill="red" /&gt;
&lt;/svg&gt;</pre><p>Du fait que l'élément se trouve en dehors des dimensions de la viewBox, on ne peut pas le voir. Le document SVG l'a automatiquement découpé. Changeons cela en modifiant les valeurs de la viewBox :</p><pre>&lt;svg viewBox="0 0 200 120"&gt;
    &lt;circle cx="150" cy="120" r="20" fill="red" /&gt;
&lt;/svg&gt;</pre><p>Ce qui nous donne :</p><p>Il est important de noter que les éléments SVG découpés en dehors de la viewBox sont toujours présents. Il peuvent être animés et revenir dans la surface visible. Mais par défaut ils ne sont pas visibles.</p><p>Il est également possible de faire apparaître des éléments cachés par les dimensions restrictives de la viewBox en appliquant <code>overflow: visible</code> au document SVG via CSS. Cependant, cela n'étendra pas le background SVG (s'il y en a un) de manière à s'adapter à l'élément :</p><figure role="group"><figcaption>L'élément caché réapparaît</figcaption></figure><h2>Sauvetage</h2><p>On peut également donner des valeurs négatives aux coordonnées du coin supérieur gauche de la viewBox. Dans certains scénarios, comme ceux évoqués en début d'article lorsque les éléments SVG sont exportés un peu trop serrés, cela peut s'avérer nécessaire.</p><p>Admettons que nous ayons ceci :</p><pre>&lt;svg viewBox="0 0 500 100"&gt;
    &lt;circle cx="50" cy="0" r="50" fill="red" /&gt;
&lt;/svg&gt;</pre><p>...qui crée :</p><p>Seule la partie inférieure du cercle est visible. Si nous diminuons la composante <code>y</code> du coin supérieur gauche de la viewBox, nous pouvons corriger le problème :</p><pre>&lt;svg viewBox="0 -40 500 100"&gt;
    &lt;circle cx="50" cy="0" r="50" fill="red" /&gt;
&lt;/svg&gt;</pre><p>Le résultat :</p><blockquote>
<p>?? L'ajout d'un padding à notre élément SVG aura le même effet, mais il n'exposera pas davantage un élément caché par la limite de la viewBox.</p>
</blockquote><p>Il est important de noter que modifier les valeurs de la viewBox ne changera pas le <em>point d'origine</em> du SVG globalement. Autrement dit, un cercle dessiné avec son centre à <code>0 0</code> sera complètement visible si le coin supérieur gauche est suffisamment déplacé vers l'extérieur. Le point d'origine, lui, n'est pas modifié.</p><h3>Conclusion</h3><p>Il y a bien d'autres choses à dire sur viewBox, mais cet article et les liens suggérés ci-dessous devraient vous suffire pour vous lancer dans SVG en toute confiance. Bon courage !</p><p>?? NdT : vous pouvez également consulter ici l'article de Joni Trythall <a href="https://la-cascade.io/articles/comprendre-svg-viewbox-et-viewport">Comprendre SVG viewBox et viewport</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-svg-viewbox</link>
      <guid>https://la-cascade.io/articles/comprendre-svg-viewbox</guid>
      <pubDate>Wed, 28 Dec 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS : n'oubliez pas l'impression papier!]]></title>
      <description><![CDATA[<p><em>Les utilisateurs continuent d'imprimer nos pages web : les optimiser pour l'impression papier est important pour l'accessibilité mais aussi, tout simplement, pour l'expérience utilisateur. Manuel Matuzovic nous donne quelques astuces.</em></p><div class="articleContent"><p><a href="https://twitter.com/AaronGustafson">Aaron Gustafson</a> a récemment envoyé <a href="https://twitter.com/AaronGustafson/status/788073583528538112">un tweet</a> à <a href="https://www.indiegogo.com/">Indiegogo</a> dans lequel il faisait remarquer que leurs pages de commandes n'étaient pas utilisables une fois imprimées.</p><figure><img src="https://la-cascade.io/images/aaron_tweet.png" alt="impression toute pourrie d'une page de formulaire de indiegogo" /></figure><p>Ce message m'a fait prendre conscience qu'il y avait un bail que je n'avais pas optimisé une page pour l'impression (ni même pensé à vérifier).Peut-être est-ce dû à mon obsession que tout fonctionne parfaitement pour toutes les formes et dimensions d'écrans, peut-être au fait que j'imprime rarement des pages web, le fait est que j'avais complètement oublié les feuilles de style d'impression (print style sheets) et... c'est pas bien.</p><p>Il est important d'optimiser nos pages web pour l'impression papier si nous souhaitons que nos sites soient le plus accessibles possible, quel que soit le medium. Nous ne devrions pas faire <a href="https://adactio.com/journal/11409">trop de suppositions</a> quant à nos utilisateurs et à leur comportement. Les gens continuent d'imprimer les pages web. Pensez par exemple aux articles de journaux ou de blogs, aux recettes de cuisine, aux informations de contact, aux plans, aux sites immobiliers... Quelqu'un quelque part essaiera un jour d'imprimer une de vos pages.</p><blockquote cite="/auteurs/heydon-pickering">
<p>J'ai laissé tomber les imprimantes il y a longtemps parce qu'elles tombaient toujours en panne après 10 minutes. Mais tout le monde n'est pas comme moi...</p>
<p><cite><a href="https://la-cascade.io/auteurs/heydon-pickering">Heydon Pickering</a> (Inclusive Design Patterns)</cite></p>
</blockquote><p>Si vous êtes dans la même situation que moi, j'espère que cet article vous aidera à remettre les choses en place. Et si vous n'avez pas encore optimisé vos pages pour l'impression avec CSS, les conseils qui suivent vont vous y aider.</p><h2>1. Intégrer les styles d'impression</h2><p>La meilleure façon de procéder est d'intégrer les styles liés à l'impression dans votre CSS, via une règle <code>@media</code>.</p><pre class="language-css">body {
  font-size: 18px;
}
@media print {
  /* les styles d'impression commencent ici */
  body {
    font-size: 28px;
  }
}</pre><p>Une autre façon de faire consiste à intégrer les styles dans votre HTML, mais la requête supplémentaire n'est pas une bonne pratique en termes de performances.</p><pre class="language-html">&lt;link media="print" href="print.css" /&gt;</pre><h2>2. Tester</h2><p>Inutile d'imprimer une page à chaque petit changement. Selon votre navigateur, vous pouvez exporter la page au format PDF, faire une prévisualisation de la page ou même débugger directement dans le navigateur.</p><h3>Émulation d'impression dans Firefox</h3><p>Pour cette dernière option, sur Firefox il suffit d'ouvrir la barre d'outils développeurs (Developper Toolbar Shift + F2 ou Tools &gt; Web Developper &gt; Developper Toolbar) et d'entrer media emulate print dans le champ de saisie situé en bas de la fenêtre du navigateur, et de faire enter. L'onglet actif se comportera comme si le media type était print jusqu'à ce que vous fermiez la page ou que vous la rafraîchissiez.</p><h3>Émulation d'impression dans Chrome</h3><p>Dans Chrome, ouvrez DevTools (CMD + Opt + I (macOS) ou Ctrl + Shift + I (Windows) ou View &gt; Developer &gt; Developer Tools) puis le menu déroulant de la console (Esc), dans "more tools" choisir "Rendering", choisir Emulate CSS Media et "Print".</p><figure><img src="https://la-cascade.io/images/chrome.png" alt="émulation d'impression dans chrome" /></figure><h2>3. Unités absolues</h2><p>Les unités absolues sont mauvaises pour l'affichage à l'écran mais excellentes pour l'impression. Dans les feuilles de style d'impression il est recommandé d'utiliser les unités absolues telles que cm, mm, in, pt ou pc.</p><pre class="language-css">section {
  margin-bottom: 2cm;
}</pre><h2>4. Règles spécifiques</h2><p>La règle <code>@page</code> permet de définir des propriétés spécifiques à la page, telles que les dimensions, l'orientation et les marges. C'est très pratique si par exemple vous souhaitez que toutes vos pages aient une certaine marge :</p><pre class="language-css">@media print {
  @page {
    margin: 1cm;
  }
}</pre><p>La règle <code>@page</code> est définie dans le module <a href="https://www.w3.org/TR/css-page-3/">Paged Media</a>, où l'on trouve des choses passionnantes, comme la possibilité de sélectionner la première page imprimée ou les pages vides, de positionner des éléments dans les coins de pages et <a href="https://www.smashingmagazine.com/2015/01/designing-for-print-with-css/">bien d'autres choses</a> encore. Vous pouvez même l'utiliser pour <a href="https://alistapart.com/article/building-books-with-css3/">réaliser des livres</a>.</p><h2>Contrôler les sauts de pages</h2><p>Les pages imprimées n'étant pas infinies, contrairement aux pages web, leur contenu devra le cas échéant donner lieu à un saut de page. Nous disposons de 5 propriétés pour contrôler ce qui se passe dans ce cas.</p><h3>Le saut de page se situe avant un élément</h3><p>Si nous voulons qu'un certain élément se trouve toujours au début d'une page, nous pouvons forcer un saut de page avec <code>page-break-before</code>.</p><pre class="language-css">section {
  page-break-before: always;
}</pre><p>Voir (en français) le détail de la propriété sur MDN : <a href="https://developer.mozilla.org/fr/docs/Web/CSS/page-break-before">page-break-before</a>.</p><h3>Le saut de page se situe après un élément</h3><p><code>page-break-after</code> nous permet de forcer ou d'éviter un saut de page après un élément.</p><pre class="language-css">h2 {
  page-break-after: always;
}</pre><p>Voir le détail de la propriété sur MDN : <a href="https://developer.mozilla.org/fr/docs/Web/CSS/page-break-after">page-break-after</a>.</p><h3>Le saut de page se situe à l'intérieur d'un élément</h3><p>Cette propriété est intéressante si vous voulez éviter qu'un élément ne soit partagé entre deux pages.</p><pre class="language-css">ul {
  page-break-inside: avoid;
}</pre><p>Voir le détail de la propriété sur MDN : <a href="https://developer.mozilla.org/fr/docs/Web/CSS/page-break-inside">page-break-inside</a>.</p><h2>Veuves et orphelines</h2><p>Parfois vous n'aurez pas besoin de forcer un saut de page, mais au moins de contrôler la façon dont plusieurs lignes sont affichées sur la page courante ou sur la suivante.Par exemple, si la dernière ligne d'un paragraphe ne tient pas sur la page, on imprimera deux lignes sur la page suivante, même si l'avant-dernière ligne n'était pas concernée. C'est parce que la propriété qui contrôle ce comportement — widows — est réglée par défaut sur la valeur 2. Nous pouvons la modifier.</p><pre class="language-css">p {
  widows: 4;
}</pre><p>Si c'est l'inverse et que seule une ligne tient sur la page courante, tout le paragraphe pourra être imprimé sur la page suivante. la propriété responsable est orphans et sa valeur par défaut est 2 également.</p><pre class="language-css">p {
  orphans: 3;
}</pre><p>Le code ci-dessus signifie que au moins 3 lignes doivent tenir sur la page courante, sinon le paragraphe entier sera imprimé sur la page suivante.</p><p>Attention, vérifiez bien le résultat dans votre navigateur, tous les navigateurs n'ont pas le même comportement. J'ai créé un <a href="https://codepen.io/matuzo/pen/oYvBjN">codepen</a> avec quelques exemples, et une <a href="https://cdpn.io/pen/debug/oYvBjN">version debug</a> pour tester plus facilement). Les propriétés et valeurs <a href="https://caniuse.com/css-page-break">ne fonctionnent pas toutes dans tous les navigateurs</a>, vérifiez vos styles d'impression avec plusieurs navigateurs.</p><p>NdT : pour plus d'infos sur les veuves et les orphelines, vous pouvez consulter l'article de Dudley Storey traduit dans La Cascade : <a href="https://la-cascade.io/articles/css-aider-la-veuve-et-lorphelin">CSS, aider la veuve &amp; l'orpheline</a>.</p><h2>6. Remettre les compteurs à zéro</h2><p>Il peut être souhaitable de remettre certains styles "à zéro" pour l'impression, comme <code>background-color</code>, <code>box-shadow</code> ou <code>color</code> par exemple. Voici un extrait du CSS de HTML5-boilerplate pour les styles d'impression :</p><pre class="language-css">*,
*:before,
*:after,
*:first-letter,
p:first-line,
div:first-line,
blockquote:first-line,
li:first-line {
  background: transparent !important;
  color: #000 !important;
  box-shadow: none !important;
  text-shadow: none !important;
}</pre><p>Les feuilles de style d'impression sont un des rares exemples où il est tout à fait correct d'utiliser <code>!important</code>.</p><h2>7. Supprimer le contenu inutile</h2><p>Pour éviter un gaspillage d'encre et de papier, il est important de supprimer ce qui n'a pas de sens à l'impression, comme certains aspects de pure présentation, les publicités, la navigation, etc. avec <code>display: none</code>.</p><p>Vous pourriez même ne montrer que le contenu principal et cacher tout le reste :</p><pre class="language-css">body &gt; *:not(main) {
  display: none;
}</pre><h2>8. Révéler les URLs des liens</h2><p>Les liens imprimés ne servent à rien si l'on ne sait pas où ils mènent. Il est très facile d'afficher la cible d'un lien à côté du texte.</p><pre class="language-css">a[href]:after {
  content: ' (' attr(href) ')';
}</pre><p>Bien sûr, cela affichera les liens relatifs, les liens absolus vers votre site, les ancres, etc... Peut-être qu'un truc comme ça fera mieux l'affaire :</p><pre class="language-css">a[href^='http']:not([href*='monsiteweb.com']):after {
  content: ' (' attr(href) ')';
}</pre><p>Oui, je sais... Bon, ces lignes signifient "afficher la valeur de l'attribut <code>href</code> à côté de chaque lien contenant un attribut <code>href</code> commençant par http mais n'ayant pas pour valeur monsiteweb.com.</p><h2>9. Révéler les abréviations</h2><p>Rappel : Les abréviations devraient être enveloppées dans un élément <code>&lt;abbr&gt;</code> et le nom entier inclus dans l'attribut <code>title</code>.</p><p>NdT : voir le détail. Les mettre en clair à l'impression peut être intéressant :</p><pre class="language-css">abbr[title]:after {
  content: ' (' attr(title) ')';
}</pre><h2>10. Forcer l'impression du background</h2><p>Normalement les navigateurs n'imprimeront pas les couleurs et images de background si vous ne le leur demandez pas. Vous pouvez forcer l'impression via la propriété non encore standardisée <code>print-color-adjust</code> :</p><pre class="language-css">header {
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}</pre><h2>11. Media Queries</h2><p>Si vous avez inclus des media queries comme celle qui suit, soyez conscient que les règles CSS de cette media query ne s'appliqueront pas à la feuille de style d'impression.</p><pre class="language-css">@media screen and (min-width: 48em) {
  /* media type limité à écran */
}</pre><p>Et pourquoi donc, direz-vous ? Eh bien parce que les règles CSS ne s'appliquent que si la <code>min-width</code> est de <code>48em</code> et le media-type est <code>screen</code>. Si vous supprimez le mot-clé <code>screen</code>, la media query est seulement limitée à <code>min-width</code>.</p><pre class="language-css">@media (min-width: 48em) {
  /* tous les media types */
}</pre><h2>12. Imprimer des cartes</h2><p>Les versions actuelles de Firefox et Chrome peuvent imprimer des cartes mais pas Safari. Certains services fournissent des cartes statiques que vous pouvez utiliser à la place.</p><pre class="language-css">.map {
  width: 400px;
  height: 300px;
  background-image: url('http://maps.googleapis.com/maps/api/staticmap?center=Wien+Floridsdorf&amp;zoom=13&amp;scale=false&amp;size=400x300&amp;maptype=roadmap&amp;format=png&amp;visual_refresh=true');
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}</pre><h2>13. QR Codes</h2><p>Vous trouverez des astuces intéressantes dans <a href="https://www.smashingmagazine.com/2013/03/tips-and-tricks-for-print-style-sheets/#print-qr-codes-for-easy-url-references">cet article de Smashing Magazine</a>. L'une d'elles consiste à fournir un QR code pour les pages imprimées de façon à éviter aux utilisateurs d'avoir à taper l'URL pour retourner à la version live de la page.</p><h3>Bonus 1 : Imprimer des pages non-optimisées</h3><p>Pendant mes recherches, j'ai trouvé un outil intéressant, créé entre autres par Chris Coyier, pour l'impression de pages non-optimisées. Avec <a href="https://css-tricks.github.io/The-Printliminator/">Printlimitator</a> vous pouvez supprimer des éléments en cliquant dessus.Il y a <a href="https://www.youtube.com/watch?v=Dt8hpqEIL1c">une démo sur YouTube</a> et le projet est sur <a href="https://github.com/CSS-Tricks/The-Printliminator">Github</a>.</p><h3>Bonus 2 : Gutenberg</h3><p>Si vous aimez les frameworks, vous pouvez essayer <a href="https://github.com/BafS/Gutenberg">Gutenberg</a>, il vous facilitera la vie pour tout ce qui concerne l'impression.</p><h3>Bonus 3 : Hartija</h3><p>Un autre framework pour les feuilles de style d'impression, par Vladimir Carrer, appelé <a href="https://github.com/vladocar/Hartija---CSS-Print-Framework">Hartija</a>.</p><p>Et voilà !</p><h4>Ressources complémentaires en anglais</h4><ul><li><a href="https://www.youtube.com/watch?v=jF-OQ-BrIAM">CSS Tips and Tricks: Add External URLs to Print Stylesheets</a>, vidéo par Corey Schafer</li>
<li><a href="https://www.smashingmagazine.com/2013/03/tips-and-tricks-for-print-style-sheets/">Tips and tricks for print style sheets</a></li>
<li><a href="https://stackoverflow.com/questions/9519556/faster-way-to-develop-and-test-print-stylesheets-avoid-print-preview-every-time">Faster way to develop and test print stylesheets - Stackoverflow</a></li>
<li><a href="https://www.smashingmagazine.com/2015/01/designing-for-print-with-css/">Designing For Print With CSS</a>, par Rachel Andrews</li>
</ul><h4>Ressources complémentaires en français</h4><ul><li><a href="https://www.alsacreations.com/tuto/lire/586-feuille-style-css-print-impression.html">Faire une feuille de style print pour l'impression</a>, par Alsacréations</li>
</ul><p>NdT : Cet article a été mis à jour en 2016, 2018 et 2019.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-noubliez-pas-limpression-papier</link>
      <guid>https://la-cascade.io/articles/css-noubliez-pas-limpression-papier</guid>
      <pubDate>Tue, 27 Dec 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Utiliser SVG use]]></title>
      <description><![CDATA[<p><em>use est l'outil de clonage de SVG, il permet de dupliquer des éléments existants ou prédéfinis et d'alléger votre code.</em></p><div class="articleContent"><p><code>use</code> est l'outil de clonage de <a href="https://la-cascade.io/tags/svg/">SVG</a> : il offre la possibilité de dupliquer des éléments existants ou prédéfinis, tout en permettant d'appliquer des modifications aux copies clonées. <code>use</code> est une façon simple d'alléger votre code SVG en utilisant <a href="https://fr.wikipedia.org/wiki/Ne_vous_r%C3%A9p%C3%A9tez_pas">les meilleurs principes DRY</a> ("Don't Repeat Yourself").</p><h2>Cas d'usage</h2><p>Voici quelques <code>use</code> cases :) Étant donné un élément SVG avec un <code>id</code>:</p><pre>&lt;circle cx="50" cy="50" r="10" fill="red" id="primcirc" /&gt;</pre><p>Nous pouvons répliquer cet élément avec <code>use</code> :</p><pre>&lt;use xlink:href="#primcirc" /&gt;</pre><blockquote>
<p>?? Remarque : l'utilisation de <code>xlink</code> dans la référence implique que l'<a href="https://developer.mozilla.org/en/docs/Web/SVG/Namespaces_Crash_Course">espace de nom</a> xlink soit déclaré dans l'élément racine SVG.</p>
</blockquote><p>La copie hérite de toutes les caractéristiques de l'original et par défaut ne peut en être distinguée, ce qui signifie que seules les modifications ajoutées en feront un élément unique. Toutefois, les modifications ne peuvent concerner ce qui a déjà été déclaré dans l'élément original. L'exemple suivant ne fonctionnera pas car il entre en contradiction avec l'original :</p><pre>&lt;use xlink:href="#primcirc" fill="blue" /&gt;</pre><p>La copie apparaîtra rouge, et non bleue, la couleur de remplissage (<em>fill</em>) ayant été définie dans l'élément source. Par contre l'ajout d'un <em>nouvel</em> attribut fonctionnera :</p><pre>&lt;use xlink:href="#primcirc" stroke="black" /&gt;</pre><p>Cette fois-ci, la copie aura toujours une couleur de remplissage rouge, mais des traits (<em>stroke</em>) de contours noirs.</p><h2>Utiliser defs</h2><p>Pour contourner le problème, l'élément "source" est souvent placé dans un élément <code>&lt;defs&gt;</code> comprenant les attributs qui ne seront <em>pas</em> modifiés dans les clones :</p><pre>&lt;defs&gt;
    &lt;circle r="10" id="primcirc" /&gt;
&lt;/defs&gt;</pre><p>Rien de ce qui apparaît dans un élément <code>&lt;defs&gt;</code> ne sera rendu dans le SVG, les éléments ainsi définis ne pouvant apparaître que via une référence. Dans ce cas, nous ajoutons au clone les attributs qui manquaient dans la définition originale :</p><pre>&lt;use xlink:href="#primcirc" cx="50" cy="50" fill="red" /&gt;</pre><p>Ceci crée la première instance visible de notre cercle. Il a un rayon de 5, hérité de l'original, mais sa position et sa couleur de remplissage lui sont propres. Nous pouvons facilement créer une autre copie en ajoutant une nouvelle référence <code>use</code> :</p><pre>&lt;use xlink:href="#primcirc" cx="80" cy="80" fill="yellow" /&gt;</pre><p>Les deux cercles ont un rayon égal à 5, dérivé (et non modifiable) de la définition originale, mais chacun a sa propre position et couleur de remplissage. Si la définition originale de l'élément comprenait une position...</p><pre>&lt;defs&gt;
    &lt;circle r="10" cx="50" cy="50" id="primcirc" /&gt;
&lt;/defs&gt;</pre><p>...alors nous pourrions modifier la position du clone en utilisant une transformation <code>transform</code> :</p><pre>&lt;use xlink:href="#primcirc" fill="yellow" transform="translate(50 50)" /&gt;</pre><blockquote>
<p>Remarque : les attributs prédéfinis peuvent être modifiés dans les clones référencés à l'aide de techniques similaires. Un changement de <code>fill</code> via <code>opacity</code> ou <code>blend-mode</code> par exemple.</p>
</blockquote><p>Les changements d'opacité ou autres apportés à la définition originale seront reflétés dans les clones.</p><p>Il n'y a pas que les éléments qui peuvent ainsi être clonés et référencés : nous pouvons également <a href="https://la-cascade.io/articles/les-bases-de-svg-groupes/">regrouper des éléments</a>, donner un <code>id</code> au groupe et l'utiliser autant de fois que nous le voulons.</p><pre>&lt;svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100"&gt;
&lt;defs&gt;
    &lt;g id="primgroup"&gt;
        &lt;circle cx="50" cy="50" r="10" fill="red" /&gt;
        &lt;circle cx="70" cy="70" r="10" fill="blue" /&gt;
    &lt;/g&gt;
&lt;/defs&gt;
    &lt;use xlink:href="#primgroup" /&gt;
&lt;/svg&gt;</pre><p>J'utilise les <a href="https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses/">éléments circle</a> pour la simplicité de la démonstration, mais les sources peuvent être à peu près ce que vous voulez. Il est également possible de générer des références <code>use</code> avec JavaScript, mais ce sera pour un autre article.</p></div>]]></description>
      <link>https://la-cascade.io/articles/utiliser-svg-use</link>
      <guid>https://la-cascade.io/articles/utiliser-svg-use</guid>
      <pubDate>Mon, 26 Dec 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Initial, Inherit, Unset et Revert]]></title>
      <description><![CDATA[<p><em>Il existe quatre valeurs applicables (en théorie) à n'importe quelle propriété CSS, ce sont les valeurs explicites par défaut. Avec Ire Aderinokun apprenez à les connaître et à les différencier.</em></p><div class="articleContent"><p>Il existe quatre valeurs applicables (en théorie) à n’importe quelle propriété CSS. Ce sont les valeurs explicites par défaut — <code>initial</code>, <code>inherit</code>, <code>unset</code> et <code>revert</code>. Ces valeurs nous permettent de donner des valeurs par défaut avec nuance. Même si elles ne sont pas universellement supportées, il est utile de les connaître et de comprendre leurs différences.</p><h2>Initial</h2><p>La valeur <code>initial</code> est la valeur par défaut de la propriété, telle qu’elle est définie par la <a href="https://www.w3.org/TR/CSS/">spécification CSS officielle</a>. Par exemple pour un élément <code>&lt;p&gt;</code>, <code>text-align</code> est <code>left</code> et <code>display</code> est <code>inline</code>.</p><pre>//HTML
&lt;p style="text-align: initial;
          display: initial;
          background-color: rgba(255,219,58, 0.3)"&gt;
  Hello, world!
&lt;/p&gt;</pre><figure><img src="https://la-cascade.io/images/initial-compressor.png" alt="" /></figure><p>Compatibilité navigateurs : <a href="http://caniuse.com/#feat=css-initial-value">La compatibilité</a> est excellente, à l’exception d’IE et Opera Mini.</p><h2>Inherit</h2><p>La valeur <code>inherit</code> représente la valeur prise par le parent immédiat de l’élément HTML pour la même propriété.</p><pre>&lt;div style="border: 2px solid plum;"&gt;
  &lt;div style="border: inherit; background-color: rgba(255,219,58, 0.3);"&gt;
      Hello, world!
  &lt;/div&gt;
&lt;/div&gt;</pre><figure><img src="https://la-cascade.io/images/inherit-1-compressor.png" alt="La div intérieure hérite du style de la div parent" /></figure><p>Si la propriété n’est pas explicitement définie pour l’élément parent, c’est le comportement de <code>revert</code> qui se produira. CSS ne remontera pas dans l’arbre des éléments parents pour trouver une valeur explicitement définie pour cette propriété.</p><pre>&lt;div style="border: 2px solid plum;"&gt;
  &lt;div&gt;
    &lt;div style="border: inherit; background-color: rgba(255,219,58, 0.3);"&gt;
           Hello, world!
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><figure><img src="https://la-cascade.io/images/inherit-2-compressor.png" alt="La div enfant n’hérite pas de son grand-parent" /></figure><h2>Unset</h2><p>La valeur <code>unset</code> est une sorte de mélange de <code>initial</code> et <code>inherit</code>.</p><p>Certaines propriétés, si elles ne sont pas définies explicitement, prendront pour valeur par défaut <code>inherit</code>. Par exemple, si nous définissons la <code>color</code> d’un élément, elle s’applique à tous les éléments enfants par défaut. Par contre, d’autres propriétés, telles que <code>border</code>, n’héritent pas par défaut.</p><pre>&lt;div style="border: 2px solid plum; color: cornflowerblue;"&gt;
  &lt;div style="background-color: rgb(200, 200, 200)"&gt;
    Hello, world
  &lt;/div&gt;
&lt;/div&gt;</pre><figure role="group"><img src="https://la-cascade.io/images/unset-compressor.png" alt="" /><figcaption>La propriété color est héritée, mais pas la propriété border</figcaption></figure><p>Compatibilité navigateurs : <a href="http://caniuse.com/#feat=css-unset-value">La compatibilité</a> est bonne, à l’exception d’IE, iOS Safari et Opera Mini.</p><h2>Revert</h2><p>La valeur <code>revert</code>, autrefois appelée <code>default</code>, représente toute valeur que prendrait la propriété si aucune valeur ne lui était donnée.</p><p>Si aucune valeur n’est donnée à une propriété dans la feuille de style de l’auteur (les styles que nous appliquons en tant qu’auteurs), voici les étapes suivies par le navigateur pour trouver une valeur :</p><ol><li>Vérifier s’il existe des <a href="http://www.kloh.ch/le-pouvoir-des-feuilles-de-style-utilisateur-143">styles définis par l’utilisateur</a></li>
<li>Si rien n’est trouvé, vérifier la feuille de style user agent (styles définis par le navigateur)</li>
<li>Si rien n’est trouvé, appliquer l’équivalent de <code>unset</code></li>
</ol><p>Par exemple, un style fréquemment ajouté aux éléments <code>&lt;div&gt;</code> par les feuilles de style user agent est <code>display: block;</code> même si la valeur initiale de <code>display</code> est <code>inline</code>. Voici ce qui se passe quand <code>revert</code> est utilisé — et la comparaison avec <code>initial</code>.</p><pre>&lt;div style="display: revert;
            background-color: rgba(255,219,58, 0.3)"&gt;
  Hello, world! (revert)
&lt;/div&gt;
&lt;div style="display: initial;
            background-color: rgba(255,219,58, 0.3)"&gt;
  Hello, world! (initial)
&lt;/div&gt;</pre><figure><img src="https://la-cascade.io/images/revert-compressor.png" alt="la div revert est affichée en mode bloc, la div initial est affichée en mode inline" /></figure><p>Compatibilité : pour une information à jour à la lecture de cet article, <a href="http://caniuse.com/#feat=css-revert-value">consultez Can I Use</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-initial-inherit-unset-et-revert</link>
      <guid>https://la-cascade.io/articles/css-initial-inherit-unset-et-revert</guid>
      <pubDate>Sun, 08 May 2016 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Grid Layout, guide complet]]></title>
      <description><![CDATA[<p><em>Avec Flexbox, le module CSS Grid Layout représente l'avenir de la mise page CSS. Chris House a conçu un guide complet et plein d'exemples pour enfin comprendre cette spécification complexe.</em></p><div class="articleContent"><h2>Introduction</h2><p>CSS Grid Layout (aka “Grid”) est un système de layout bi-dimensionnel basé sur les grilles qui a pour ambition ni plus ni moins que de révolutionner la façon dont nous concevons les interfaces utilisateurs basées sur des grilles.</p><p>CSS a toujours été utilisé pour la mise en page web, mais il n’a jamais été très bon pour cela. Nous avons d’abord utilisé des tables, puis des <em>floats</em>, divers positionnements et inline-block, mais toutes ces méthodes s’apparentaient fondamentalement à des rustines, et ne permettaient pas de résoudre certains problèmes récurrents comme le centrage vertical. Flexbox nous a bien aidés, mais il est conçu pour des layouts plus simples et uni-dimensionnels, et non pour des layouts bi-dimensionnels. En fait, Flexbox et Grid se complètent bien et <a href="https://la-cascade.io/articles/grid-et-flexbox-le-duo-gagnant/">sont faits pour travailler ensemble</a>. Grid est le premier module CSS créé spécifiquement pour résoudre les problèmes de layout que nous avons contournés par des tripatouillages depuis que nous réalisons des sites web.</p><p>Ce guide et tutoriel puise son inspiration d’une part dans le formidable livre de <a href="https://la-cascade.io/auteurs/rachel-andrew/">Rachel Andrew</a>, <a href="https://abookapart.com/products/get-ready-for-css-grid-layout">Get Ready for CSS Grid Layout</a>, une introduction très claire à CSS Grid que je vous recommande chaudement, et d’autre part dans l’article fameux de Chris Coyier <a href="https://la-cascade.io/articles/flexbox-guide-complet/">Flexbox, Guide Complet</a>, qui est depuis le début mon article de chevet pour tout ce qui concerne Flexbox. Il a aidé des tas de gens et c’est la raison pour laquelle il est le premier résultat que vous trouvez quand vous cherchez “Flexbox” dans Google. Vous remarquerez de nombreuses similarités entre son article et le mien parce que... pourquoi ne pas emprunter chez les maîtres ?</p><p>Mon intention est de vous présenter les concepts Grid tels qu’ils existent dans la dernière version de la spécification. Je ne passerai donc pas en revue la syntaxe IE obsolète et je veillerai à mettre à jour ce guide au fur et à mesure de l’évolution de la spécification.</p><h2>Les bases et la compatibilité</h2><p>Il est facile de se lancer dans Grid. Il suffit de définir un élément container comme une grille, via la propriété <code>display:grid</code>, de régler les dimensions des colonnes et des rangées avec <code>grid-template-columns</code> et <code>grid-template-rows</code> et de placer ses éléments enfants dans la grille avec <code>grid-column</code> et <code>grid-row</code>. Comme pour Flexbox, l’ordre des items de la grille tel qu’il apparaît dans la source n’a pas d’importance. Votre CSS peut les placer dans n’importe quel ordre, ce qui facilite la réorganisation de votre grille avec les media queries. Vous pouvez ainsi définir le layout de votre page et le réorganiser entièrement pour l’adapter à différentes tailles d’écrans, et tout cela avec juste quelques lignes de CSS. Grid est un des modules CSS les plus puissants jamais proposés.</p><p> <em>Note du traducteur : depuis mars 2017 CSS Grid est supporté par Firefox, Chrome, Opera et Safari. Pour les détails complets et à jour de la compatibilité, voir <a href="http://caniuse.com/#feat=css-grid">Can I Use</a></em>.</p><h2>Terminologie importante</h2><p>Avant de plonger dans les concepts de Grid, il est important de bien comprendre la terminologie. Dans la mesure où les termes utilisés sont assez similaires, il est facile de les confondre si vous n’avez pas bien mémorisé leur signification telle qu’elle est définie par la spécification. Mais ne vous inquiétez pas, il n’y en a pas beaucoup.</p><h3 id="gridcontainer">Container Grid</h3><p>C’est l’élément sur lequel s’applique <code>display: grid</code>. C’est donc le parent direct de tous les items grid. Dans cet exemple, <code>container</code> est le container grid.</p><pre>/HTML
&lt;div class="container"&gt;
  &lt;div class="item item-1"&gt;&lt;/div&gt;
  &lt;div class="item item-2"&gt;&lt;/div&gt;
  &lt;div class="item item-3"&gt;&lt;/div&gt;
&lt;/div&gt;</pre><h3 id="griditem">Item Grid</h3><p>L’enfant (c’est à dire le descendant direct) du container grid. Ici, les éléments <code>item</code> sont des items grid, mais ce n’est pas le cas de <code>sub-item</code>.</p><pre>/HTML
&lt;div class="container"&gt;
  &lt;div class="item"&gt;&lt;/div&gt;
  &lt;div class="item"&gt;
        &lt;p class="sub-item"&gt;&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class="item"&gt;&lt;/div&gt;
&lt;/div&gt;</pre><h3 id="gridline">Ligne de Grille</h3><p>Les lignes qui divisent et constituent la structure de la grille. Elles peuvent être verticales (“lignes de grille de colonnes”) ou horizontales (“lignes de grille de rangées”) et sont situées d’un côté ou de l’autre d’une rangée ou d’une colonne. Ici, la ligne jaune est un exemple de ligne de grille de colonne (<em>column grid line</em>).</p><figure role="group"><img src="https://la-cascade.io/images/grid-line.png" alt="" /></figure><h3 id="gridtrack">Piste de Grille</h3><p>La piste (ou plage) de grille (<em>grid track</em>) est l’espace situé entre deux lignes de grille adjacentes, en d’autres termes ce sont les colonnes ou les rangées de la grille. Ci-dessous, la piste de grille est située entre les deuxième et troisième lignes de rangée.</p><figure role="group"><img src="https://la-cascade.io/images/grid-track.png" alt="" /></figure><h3 id="gridcell">Cellule de Grille</h3><p>La cellule de grille (<em>grid cell</em>) est l’espace situé entre deux lignes de grille adjacentes de rangée et deux lignes de grille adjacentes de colonne. C’est une “unité” de la grille. Ci-dessous, la cellule de grille est entre les lignes de grille de rangée 1 &amp; 2, et les lignes de grille de colonne 2 &amp; 3. Dit autrement, une cellule est l’intersection d’une rangée et d’une colonne.</p><figure role="group"><img src="https://la-cascade.io/images/grid-cell.png" alt="" /></figure><h3 id="gridarea">Zone de Grille</h3><p>La zone de grille (<em>grid area</em>) est l’espace entouré par quatre lignes de grille. Une zone de grille peut comprendre n’importe quel nombre de cellules. Voici la zone de grille entre les lignes de grille de rangée 1 &amp; 3 et les lignes de grille de colonne 1 &amp; 3.</p><figure role="group"><img src="https://la-cascade.io/images/grid-area.png" alt="" /></figure><h2>Les Propriétés Grid</h2><p>Nous allons voir d'abord les propriétés du parent (le grid container), puis celles des enfants (les grid items).</p><ul><li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#parent">Propriétés du Parent (Grid Container)</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#children">Propriétés des Enfants (Grid Items)</a></li>
</ul><h3 id="parent">Propriétés du Parent (Grid Container)</h3><h4>Table des matières</h4><ul><li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#display">display</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gtc">grid-template-columns</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gtc">grid-template-rows</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gta">grid-template-areas</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcg">grid-column-gap</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcg">grid-row-gap</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gg">grid-gap</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ji">justify-items</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ai">align-items</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#jc">justify-content</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ac">align-content</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gac">grid-auto-columns</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gac">grid-auto-rows</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gaf">grid-auto-flow</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#grid">grid</a></li>
</ul><h3 class="softTitleBlue" id="display">display</h3><p>Définit l’élément en tant que container grid et établit un <em>nouveau contexte de formatage</em> de son contenu.</p><p><strong>Valeurs</strong> :</p><ul><li><code>grid</code> - génère une grille de niveau bloc</li>
<li><code>inline grid</code> - génère une grille de niveau inline.</li>
</ul><pre>.container{
  display: grid | inline-grid
}</pre><p>Remarque : <code>column</code>, <code>float</code>, <code>clear</code> et <code>vertical-align</code> n’ont aucun effet sur un container grid.</p><h3 id="gtc">grid-template columns, grid-template-rows</h3><p>Définissent les colonnes et rangées de la grille via une liste de valeurs séparées par un espace. Les valeurs représentent la dimension de la piste (<em>track</em>) et l’espace entre les pistes représente la ligne de grille.</p><p><strong>Valeurs</strong> :</p><ul><li><code>&lt;track-size&gt;</code> - peut être une longueur, un pourcentage, ou une fraction de l’espace libre dans la grille (via l’unité <code>fr</code>)</li>
<li><code>&lt;line-name&gt;</code> - un nom arbitraire choisi par vous</li>
<li><code>subgrid</code> - si votre container grid est lui-même un item grid (autrement dit, nous avons des grilles imbriquées), vous pouvez utiliser cette propriété pour indiquer que vous voulez que les dimensions de ses rangées et colonnes soient héritées de l’élément parent plutôt que d’en donner des spécifiques.</li>
</ul><pre>.container{
  grid-template-columns: &lt;track-size&gt; ... | &lt;line-name&gt; &lt;track-size&gt; ... | subgrid;
  grid-template-rows: &lt;track-size&gt; ... | &lt;line-name&gt; &lt;track-size&gt; ... | subgrid;
}</pre><p>Exemples : Lorsque vous laissez un espace vide entre les valeurs de pistes (<em>track</em>), les lignes de grille se voient automatiquement attribuer des numéros :</p><pre>.container{
  grid-template-columns: 40px 50px auto 50px 40px;
  grid-template-rows: 25% 100px auto;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-numbers.png" alt="" /></figure><p>Mais vous pouvez choisir de nommer explicitement les lignes. Remarquez la syntaxe entre crochets pour les noms de lignes :</p><pre>.container{
  grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
  grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}</pre><figure role="group"><img itemprop="url" src="https://la-cascade.io/images/grid-names.png" alt="" /></figure><p>Notez bien qu’une même ligne peut avoir plus d’un nom. Par exemple ci-dessous la deuxième ligne a deux noms, row1-end et row2-start :</p><pre>.container{
  grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}</pre><p>Si votre définition contient des parties qui se répètent, vous pouvez utiliser la notation <code>repeat()</code> pour alléger le code :</p><pre>.container{
  grid-template-columns: repeat(3, 20px [col-start]) 5%;
}</pre><p>...ce qui est équivalent à :</p><pre>.container{
  grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%;
}</pre><p>L’unité <code>fr</code> vous permet de spécifier la dimension d’une piste comme une fraction de l’espace libre du container grid. Par exemple, ce code donnera à chaque item la dimension d’1/3 du container :</p><pre>.container{
  grid-template-columns: 1fr 1fr 1fr;
}</pre><p>L’espace libre est calculé après prise en compte des items non-flexibles. Dans l’exemple qui suit, la quantité d’espace libre disponible pour les unités <code>fr</code> est l’espace total déduction faite des 50px.</p><pre>.container{
  grid-template-columns: 1fr 50px 1fr 1fr;
}</pre><h3 id="gta">grid-template-areas</h3><p>Définit un template de grille en référençant les noms des zones de grille (<em>grid areas</em>) spécifiées par la propriété <code>grid-area</code>. Si l’on répète le nom d’une zone de grille, cela étend la surface couverte par ces cellules. Un point (<code>.</code>) signifie que la cellule est vide. La syntaxe elle-même fournit une visualisation de la structure de la grille.</p><p><strong>Valeurs</strong> :</p><ul><li><code>&lt;grid-area-name&gt;</code> - le nom de la zone de grille spécifié avec <code>grid-area</code></li>
<li><code>.</code> - un point indique une cellule vide</li>
<li><code>none</code> - aucune zone de grille n’est définie</li>
</ul><pre>.container{
  grid-template-areas: "&lt;grid-area-name&gt; | . | none | ..."
                       "..."
}</pre><p>Exemple :</p><pre>.item-a{
  grid-area: header;
}
.item-b{
  grid-area: main;
}
.item-c{
  grid-area: sidebar;
}
.item-d{
  grid-area: footer;
}
.container{
  grid-template-columns: 50px 50px 50px 50px;
  grid-template-rows: auto;
  grid-template-areas: "header header header header"
                       "main main . sidebar"
                       "footer footer footer footer"
}</pre><p>On crée ainsi une grille de quatre colonnes sur trois rangées. La rangée supérieure tout entière constitue le header, la rangée du milieu comprend deux zones principales, une cellule vide et une zone de sidebar. La dernière rangée est le footer.</p><figure role="group"><img src="https://la-cascade.io/images/grid-template-areas.png" alt="" /></figure><p>Chaque rangée de notre déclaration doit avoir le même nombre de cellules.</p><p>Vous pouvez utiliser autant de <code>.</code> points que vous voulez pour déclarer une cellule vide. Du moment que les points ne sont pas séparés par un espace, ils représentent une cellule unique.</p><p>Remarquez qu’avec cette syntaxe vous ne nommez pas les lignes mais les zones. Quand vous utilisez cette syntaxe, les lignes de chaque côté des zones sont nommées automatiquement. Si le nom de votre zone de grille est <code>foo</code>, alors le nom de la ligne de rangée (et de colonne) au début de la zone sera <code>foo-start</code> et à l’autre bout <code>foo-end</code>. En conséquence, certaines lignes pourront avoir plusieurs noms, par exemple dans notre illustration précédente, la ligne verticale tout à gauche aura trois noms : header-start, main-start et footer-start.</p><h3 id="gcg">grid-column-gap et grid-row-gap</h3><p>Spécifie la dimension des lignes de grille. On peut les voir comme des largeurs de gouttières entre les colonnes ou les rangées.</p><p><strong>Valeurs</strong> :</p><ul><li><code>&lt;line-size&gt;</code> - une longueur</li>
</ul><pre>.container{
  grid-column-gap: &lt;line-size&gt;;
  grid-row-gap: &lt;line-size&gt;;
}</pre><p>Exemple :</p><pre>.container{
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;
  grid-column-gap: 10px;
  grid-row-gap: 15px;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-column-row-gap.png" alt="" /></figure><p>Les gouttières sont créées <em>uniquement</em> entre les colonnes ou les rangées, pas autour.</p><h3 id="gg">grid-gap</h3><p>C’est un raccourci de <code>grid-column-gap</code> et <code>grid-row-gap</code>.</p><p><strong>Valeurs</strong> :</p><ul><li><code>&lt;grid-column-gap&gt;&lt;grid-row-gap&gt;</code> - longueur</li>
</ul><pre>.container{
  grid-gap: &lt;grid-column-gap&gt; &lt;grid-row-gap&gt;;
}</pre><p>Exemple :</p><pre>.container{
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px;
  grid-gap: 10px 15px;
}</pre><p>Si aucun <code>grid-row-gap</code> n’est spécifié, il prend la même valeur que <code>grid-column-gap</code>.</p><h3 id="ji">justify-items</h3><p>Aligne le contenu à l’intérieur d’un item grille, le long de l’axe des colonnes (par opposition à <code>align-items</code> qui les aligne le long de l’axe des rangées). Cette valeur s’applique à tous les items grid à l’intérieur du container.</p><p><strong>Valeurs</strong> :</p><ul><li><code>start</code> - aligne le contenu à partir de la gauche de la zone de grille.</li>
<li><code>end</code> - aligne le contenu en partant de la droite de la zone de grille</li>
<li><code>center</code> - aligne le contenu au centre de la zone de grille</li>
<li><code>stretch</code> - remplit toute la largeur de la zone de grille (c’est la valeur par défaut).</li>
</ul><pre>.container{
  justify-items: start | end | center | stretch;
}</pre><p>Exemples :</p><pre>.container{
  justify-items: start;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-items-start.png" alt="" /></figure><pre>.container{
  justify-items: end;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-items-end.png" alt="" /></figure><pre>.container{
  justify-items: center;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-items-center.png" alt="" /></figure><pre>.container{
  justify-items: stretch;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-items-stretch.png" alt="" /></figure><p>On peut également spécifier ce comportement pour des items de grille <em>individuels</em> <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#js">via la propriété <code>justify-self</code></a>.</p><h3 id="ai">align-items</h3><p>Aligne le contenu situé à l’intérieur d’un item de grille le long de l’axe des rangées (par opposition à <code>justify-items</code> qui l’aligne le long de l’axe des colonnes). Cette valeur s’applique à tous les items grid à l’intérieur du container.</p><p><strong>Valeurs</strong> :</p><ul><li><code>start</code> - aligne le contenu à partir du sommet de la zone de grille.</li>
<li><code>end</code> - aligne le contenu en partant du bas de la zone de grille</li>
<li><code>center</code> - aligne le contenu au centre de la zone de grille</li>
<li><code>stretch</code> - remplit toute la hauteur de la zone de grille (c’est la valeur par défaut).</li>
</ul><pre>.container{
  align-items: start | end | center | stretch;
}</pre><p>Exemples :</p><pre>.container{
  align-items: start;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-items-start.png" alt="" /></figure><pre>.container{
  align-items: end;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-items-end.png" alt="" /></figure><pre>.container{
  align-items: center;
}
</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-items-center.png" alt="" /></figure><pre>.container{
  align-items: stretch;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-items-stretch.png" alt="" /></figure><p>On peut également spécifier ce comportement pour des items de grille <em>individuels</em> <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#as">via la propriété <code>align-self</code></a>.</p><h3 id="jc">justif-content</h3><p>Parfois la dimension totale de votre grille semblera inférieure à la dimension de son container grid. Cela peut arriver si tous les items grid sont dimensionnés avec des unités non-flexibles comme <code>px</code>. Dans ce cas, vous pouvez régler l’alignement de la grille à l’intérieur du container. Cette propriété aligne la grille le long de l’axe des colonnes (<a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ac">par opposition à <code>align-content</code></a> qui aligne la grille le long de l’axe des rangées).</p><p><strong>Valeurs</strong> :</p><ul><li><code>start</code> - aligne la grille à partir de la gauche de la grille container (<em>container grid</em>).</li>
<li><code>end</code> - aligne la grille à partir de la droite de la grille container.</li>
<li><code>center</code> - aligne la grille au centre de la grille container</li>
<li><code>stretch</code> - redimensionne les items pour permettre à la grille de remplir toute la largeur de la grille container.</li>
<li><code>space-around</code> - place un espace égal entre chaque item de grille, et un demi-espace aux extrémités.</li>
<li><code>space-between</code> - place un espace égal entre chaque item de grille, et aucun espace aux extrémités.</li>
<li><code>space-evenly</code> - place un espace égal entre chaque item de grille, y compris aux extrémités.</li>
</ul><pre>.container{
  justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
}</pre><p>Exemples :</p><pre>.container{
  justify-content: start;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-content-start.png" alt="" /></figure><pre>.container{
  justify-content: end;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-content-end.png" alt="" /></figure><pre>.container{
  justify-content: center;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-content-center.png" alt="" /></figure><pre>.container{
  justify-content: stretch;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-content-stretch.png" alt="" /></figure><pre>.container{
  justify-content: space-around;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-content-space-around.png" alt="" /></figure><pre>.container{
  justify-content: space-between;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-content-space-between.png" alt="" /></figure><pre>.container{
  justify-content: space-evenly;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-content-space-evenly.png" alt="" /></figure><h3 id="ac">align-content</h3><p>Parfois la dimension totale de votre grille semblera inférieure à la dimension de son container grid. Cela peut arriver si tous les items grid sont dimensionnés avec des unités non-flexibles comme <code>px</code>. Dans ce cas, vous pouvez régler l’alignement de la grille à l’intérieur du container. Cette propriété aligne la grille le long de l’axe des rangées (<a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#jc">par opposition à <code>justify-content</code></a> qui aligne la grille le long de l’axe des colonnes).</p><p><strong>Valeurs</strong> :</p><ul><li><code>start</code> - aligne la grille à partir du sommet de la grille container (<em>container grid</em>).</li>
<li><code>end</code> - aligne la grille à partir du bas de la grille container.</li>
<li><code>center</code> - aligne la grille au centre de la grille container</li>
<li><code>stretch</code> - redimensionne les items pour permettre à la grille de remplir toute la hauteur de la grille container.</li>
<li><code>space-around</code> - place un espace égal entre chaque item de grille, et un demi-espace aux extrémités.</li>
<li><code>space-between</code> - place un espace égal entre chaque item de grille, et aucun espace aux extrémités.</li>
<li><code>space-evenly</code> - place un espace égal entre chaque item de grille, y compris aux extrémités.</li>
</ul><pre>.container{
  align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}</pre><p>Exemples :</p><pre>.container{
  align-content: start;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-content-start.png" alt="" /></figure><pre>.container{
  align-content: end;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-content-end.png" alt="" /></figure><pre>.container{
  align-content: center;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-content-center.png" alt="" /></figure><pre>.container{
  align-content: stretch;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-content-stretch.png" alt="" /></figure><pre>.container{
  align-content: space-around;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-content-space-around.png" alt="" /></figure><pre>.container{
  align-content: space-between;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-content-space-between.png" alt="" /></figure><pre>.container{
  align-content: space-evenly;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-content-space-evenly.png" alt="" /></figure><h3 id="gac">grid-auto-colums, grid-auto-rows</h3><p>Spécifie la dimension de toute piste auto-générée (également appelée piste implicite — <em>implicit grid track</em>). Les pistes implicites sont créées lorsque vous positionnez explicitement des rangées ou des colonnes (via <code>grid-template-rows</code> ou <code>grid-template-column</code>) qui se trouvent en dehors de la grille définie.</p><p><strong>Valeurs</strong> :</p><ul><li><code>&lt;track-size&gt;</code> - peut être une longueur, un pourcentage, ou une fraction de l’espace libre dans la grille (via l’unité <code>fr</code>)</li>
</ul><pre>.container{
  grid-auto-columns: &lt;track-size&gt; ...;
  grid-auto-rows: &lt;track-size&gt; ...;
}</pre><p>Pour illustrer la façon dont les pistes implicites sont créées, imaginons ce cas :</p><pre>.container{
  grid-template-columns: 60px 60px;
  grid-template-rows: 90px 90px
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-auto.png" alt="Exemple de grid-template-columns et grid-template-rows" /></figure><p>On crée ainsi une grille de 2 × 2.</p><p>Mais imaginons maintenant que vous utilisiez <code>grid-column</code> et <code>grid-row</code> pour positionner vos items de grille comme ceci :</p><pre>.item-a{
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}
.item-b{
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}</pre><figure role="group"><img src="https://la-cascade.io/images/implicit-tracks.png" alt="" /></figure><p>Nous avons dit à <code>.item-b</code> de commencer à la ligne de colonne 5 et de se terminer à la ligne de colonne 6, <em>mais nous n’avons jamais défini de lignes de colonne 5 ou 6</em>.</p><p>Nous avons référencé des lignes qui n’existent pas, en conséquence de quoi des pistes implicites de largeur 0 sont créées pour remplir l’espace. Nous pouvons utiliser <code>grid-auto-columns</code> et <code>grid-auto-rows</code> pour spécifier la largeur de ces pistes implicites :</p><pre>.container{
  grid-auto-columns: 60px;
}</pre><figure role="group"><img src="https://la-cascade.io/images/implicit-tracks-with-widths.png" alt="" /></figure><h3 id="gaf">grid-auto-flow</h3><p>Si vous avez des items de grille que vous ne placez pas explicitement sur la grille, l’algorithme de placement automatique intervient pour placer automatiquement les items. Cette propriété contrôle la façon dont l’algorithme de placement automatique fonctionne.</p><p><strong>Valeurs</strong> :</p><ul><li><code>row</code> - indique à l’algorithme de remplir chaque rangée tout à tour, en ajoutant de nouvelles rangées si nécessaire.</li>
<li><code>column</code> - indique à l’algorithme de remplir chaque colonne tout à tour, en ajoutant de nouvelles colonnes si nécessaire.</li>
<li><code>dense</code> - indique à l’algorithme d’essayer de remplir les trous le plus tôt possible dans la grille au cas où de plus petits items devaient apparaître plus tard.</li>
</ul><pre>.container{
  grid-auto-flow: row | column | row dense | column dense
}</pre><p>Attention : <code>dense</code> pourrait faire apparaître vos items dans le désordre.</p><p>Exemples :</p><p>Considérons ce HTML :</p><pre>&lt;section class="container"&gt;
    &lt;div class="item-a"&gt;item-a&lt;/div&gt;
    &lt;div class="item-b"&gt;item-b&lt;/div&gt;
    &lt;div class="item-c"&gt;item-c&lt;/div&gt;
    &lt;div class="item-d"&gt;item-d&lt;/div&gt;
    &lt;div class="item-e"&gt;item-e&lt;/div&gt;
&lt;/section&gt;</pre><p>Définissons une grille de cinq colonnes sur deux rangées et réglons <code>grid-auto-flow</code> sur <code>row</code> (qui est également la valeur par défaut) :</p><pre>.container{
    display: grid;
    grid-template-columns: 60px 60px 60px 60px 60px;
    grid-template-rows: 30px 30px;
    grid-auto-flow: row;
}</pre><p>Quand nous plaçons les items sur la grille, nous spécifions seulement le placement de deux d’entre eux, les <code>item-a</code> et <code>item-e</code> :</p><pre>.item-a{
    grid-column: 1;
    grid-row: 1 / 3;
}
.item-e{
    grid-column: 5;
    grid-row: 1 / 3;
}</pre><p>Comme nous avons réglé <code>grid-auto-flow</code> sur <code>row</code>, notre grille va ressembler à ceci. Remarquez que les trois items que nous n’avons pas placés (<code>item-b</code>, <code>item-c</code> et <code>item-d</code>) se répartissent sur les rangées disponibles :</p><figure role="group"><img src="https://la-cascade.io/images/grid-auto-flow-row.png" alt="" /></figure><p>Mais si au lieu de cela nous avions réglé <code>grid-auto-flow</code> sur <code>column</code>, les <code>item-b</code>, <code>item-c</code> et <code>item-d</code> se seraient répartis sur les colonnes :</p><pre>.container{
    display: grid;
    grid-template-columns: 60px 60px 60px 60px 60px;
    grid-template-rows: 30px 30px;
    grid-auto-flow: column;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-auto-flow-column.png" alt="" /></figure><h3 id="grid">grid</h3><p><code>grid</code> est un raccourci permettant de définir toutes les propriétés suivantes en une seule déclaration : <code>grid-template-rows</code>, <code>grid-template-columns</code>, <code>grid-template-areas</code>, <code>grid-auto-rows</code>, <code>grid-auto-columns</code>, et <code>grid-auto-flow</code>. Il donne également à <code>grid-column-gap</code> et <code>grid-row-gap</code> leur valeur initiale, même si elles ne peuvent pas être explicitement définies par cette propriété.</p><p><strong>Valeurs</strong> :</p><ul><li><code>none</code> - règle toutes les sous-propriétés à leur valeur initiale.</li>
<li><code>subgrid</code> - règle <code>grid-template-rows</code> et <code>grid-template-columns</code> sur <code>subgrid</code> et toutes les autres sous-propriétés à leur valeur initiale.</li>
<li><code>&lt;grid-template-rows&gt; / &lt;grid-template-columns&gt;</code> - règle <code>grid-template-rows</code> et <code>grid-template-columns</code> à leur valeur spécifiée, respectivement, et toutes les autres sous-propriétés à leur valeur initiale.</li>
<li><code>&lt;grid-auto-flow&gt; [&lt;grid-auto-rows&gt; [ / &lt;grid-auto-columns&gt;] ]</code> - accepte toutes les valeurs de <code>grid-auto-flow</code>, <code>grid-auto-rows</code> et <code>grid-auto-columns</code>, respectivement. Si <code>grid-auto-columns</code> est omis, il prend la valeur donnée à <code>grid-auto-rows</code>. Si les deux sont omis, ils sont réglés sur leur valeur initiale.</li>
</ul><pre>.container{
    grid: none | subgrid | &lt;grid-template-rows&gt; / &lt;grid-template-columns&gt; |
    &lt;grid-auto-flow&gt; [&lt;grid-auto-rows&gt; [/ &lt;grid-auto-columns&gt;]];
}</pre><p>Exemples :</p><p>Les deux blocs de code suivants sont équivalents :</p><pre>.container{
    grid: 200px auto / 1fr auto 1fr;
}</pre><p>est l’équivalent de :</p><pre>.container{
    grid-template-rows: 200px auto;
    grid-template-columns: 1fr auto 1fr;
    grid-template-areas: none;
}</pre><p>De même, les deux blocs de code suivants sont équivalents :</p><pre>.container{
    grid: column 1fr / auto;
}
</pre><p>est l’équivalent de :</p><pre>.container{
    grid-auto-flow: column;
    grid-auto-rows: 1fr;
    grid-auto-columns: auto;
}</pre><p><code>grid</code> accepte également une syntaxe plus complexe mais très pratique pour régler toutes les propriétés en une seule fois. Vous spécifiez <code>grid-template-areas</code>, <code>grid-auto-rows</code> et <code>grid-auto-columns</code>, et toutes les autres sous-propriétés sont réglées sur leur valeur initiale. Vous spécifiez les noms de lignes et les dimensions de pistes en ligne avec leur zones de grille respective. C’est plus facile à décrire avec un exemple :</p><pre>.container{
    grid: [row1-start] "header header header" 1fr [row1-end]
          [row2-start] "footer footer footer" 25px [row2-end]
          / auto 50px auto;
}</pre><p>C’est l’équivalent de :</p><pre>.container{
    grid-template-areas: "header header header"
                         "footer footer footer";
    grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end];
    grid-template-columns: auto 50px auto;
}</pre><h3 id="children">Propriétés des Enfants (Grid Items)</h3><h4>Table des matières</h4><ul><li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcs">grid-column-start</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcs">grid-column-end</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcs">grid-row-start</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gcs">grid-row-end</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gc">grid-column</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#gc">grid-row</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ga">grid-area</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#js">justify-self</a></li>
<li><a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#as">align-self</a></li>
</ul><h3 id="gcs">grid column-start, grid-column-end, grid-row-start, grid-row-end</h3><p>Déterminent l’endroit où se trouve un item de grille en référence à des lignes de grille spécifiques. <code>grid-column-start</code> / <code>grid-row-start</code> est la ligne où commence l’item, <code>grid-column-end</code>/ <code>grid-row-end</code> est la ligne où il finit.</p><p><strong>Valeurs</strong> :</p><ul><li><code>&lt;line&gt;</code> - peut être un numéro pour se référer à une ligne de grille numérotée, ou un nom pour se référer à une ligne de grille nommée.</li>
<li><code>span &lt;number&gt;</code> - l’item s’étendra (<em>span</em>) sur le nombre spécifié de pistes de grille.</li>
<li><code>span &lt;name&gt;</code> - l’item s’étendra jusqu’à rencontrer le ligne contenant le nom fourni.</li>
<li><code>auto</code> - indique un auto-placement, une extension (<em>span</em>) automatique, ou le span par défaut</li>
</ul><pre>.item{
  grid-column-start: &lt;number&gt; | &lt;name&gt; | span &lt;number&gt; | span &lt;name&gt; | auto
  grid-column-end: &lt;number&gt; | &lt;name&gt; | span &lt;number&gt; | span &lt;name&gt; | auto
  grid-row-start: &lt;number&gt; | &lt;name&gt; | span &lt;number&gt; | span &lt;name&gt; | auto
  grid-row-end: &lt;number&gt; | &lt;name&gt; | span &lt;number&gt; | span &lt;name&gt; | auto
}</pre><p>Exemples :</p><pre>.item-a{
  grid-column-start: 2;
  grid-column-end: five;
  grid-row-start: row1-start
  grid-row-end: 3
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-start-end-a.png" alt="" /></figure><pre>.item-b{
  grid-column-start: 1;
  grid-column-end: span col4-start;
  grid-row-start: 2
  grid-row-end: span 2
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-start-end-b.png" alt="" /></figure><p>Si aucune <code>grid-column-end</code>/ <code>grid-row-end</code>n’est déclarée, l’item s’étendra sur 1 piste par défaut.</p><p>Les items peuvent se recouvrir. Vous pouvez utiliser <a href="https://la-cascade.io/articles/comment-fonctionne-z-index/">z-index</a> pour contrôler leur empilement.</p><h3 id="gc">grid-column, grid-row</h3>Raccourci pour `grid-column-start` + `grid-column-end`, et `grid-row-start` + `grid-row-end`, respectivement.<p><strong>Valeurs</strong> :</p><ul><li><code>&lt;start-line&gt; / &lt;end-line&gt;</code> - chacun accepte les mêmes valeurs que la version longue, y compris span.</li>
</ul><pre>.item{
  grid-column: &lt;start-line&gt; / &lt;end-line&gt; | &lt;start-line&gt; / span &lt;value&gt;;
  grid-row: &lt;start-line&gt; / &lt;end-line&gt; | &lt;start-line&gt; / span &lt;value&gt;;
}</pre><p>Exemple :</p><pre>.item-c{
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-start-end-c.png" alt="" /></figure><p>Si aucune valeur de fin de ligne n’est déclarée, l’item s’étendra sur 1 piste par défaut.</p><h3 id="ga">grid-area</h3><p>Donne un nom à un item pour qu’il puisse être référencé par un template créé avec la propriété <code>grid-template-areas</code>. Par ailleurs, cette propriété peut être utilisée comme raccourci encore plus court pour <code>grid-row-start</code> + <code>grid-column-start</code> + <code>grid-row-end</code> + <code>grid-column-end</code>.</p><p><strong>Valeurs</strong> :</p><ul><li><code>&lt;name&gt;</code> - un nom, choisi par vous.</li>
<li><code>&lt;row-start&gt; / &lt;column-start&gt; / &lt;row-end&gt; / &lt;column-end&gt;</code> - peuvent être des nombres ou des lingnes nommées.</li>
</ul><pre>.item{
  grid-area: &lt;name&gt; | &lt;row-start&gt; / &lt;column-start&gt; / &lt;row-end&gt; / &lt;column-end&gt;;
}</pre><p>Exemples :</p><p><code>grid-area</code> pour attribuer un nom à l’item :</p><pre>.item-d{
  grid-area: header
}</pre><p><code>grid-area</code> comme raccourci de <code>grid-row-start</code> + <code>grid-column-start</code> + <code>grid-row-end</code> + <code>grid-column-end</code> :</p><pre>.item-d{
  grid-area: 1 / col4-start / last-line / 6
}</pre><figure role="group"><img itemprop="url" src="https://la-cascade.io/images/grid-start-end-d.png" alt="" /></figure><h3 id="js">justify-self</h3><p>Aligne le contenu d’un item de grille sur l’axe des colonnes (par opposition à <code>align-self</code> qui l’aligne le long de l’axe des rangées). Cette propriété s’applique au contenu d’un item de grille et uniquement à lui.</p><p><strong>Valeurs</strong> :</p><ul><li><code>start</code> - aligne le contenu sur la gauche de la zone de grille</li>
<li><code>end</code> - aligne le contenu sur la droite de la zone de grille</li>
<li><code>center</code> - aligne le contenu au centre de la zone de grille</li>
<li><code>stretch</code> - Remplit toute la largeur de la zone de grille (c’est la valeur par défaut).</li>
</ul><pre>.item{
  justify-self: start | end | center | stretch;
}</pre><p>Exemples :</p><pre>.item-a{
  justify-self: start;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-self-start.png" alt="" /></figure><pre>.item-a{
  justify-self: end;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-self-end.png" alt="" /></figure><pre>.item-a{
  justify-self: center;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-self-center.png" alt="" /></figure><pre>.item-a{
  justify-self: stretch;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-justify-self-stretch.png" alt="" /></figure><p>Pour régler l’alignement de <em>tous</em> les items dans une grille, ce comportement peut être défini sur le container grid <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ji">via la propriété <code>justify-items</code></a>.</p><h3 id="as">align-self</h3><p>Aligne le contenu d’un item de grille sur l’axe des rangées (par opposition à <code>justify-self</code> qui l’aligne le long de l’axe des colonnes). Cette propriété s’applique au contenu d’un item de grille et uniquement à lui.</p><p><strong>Valeurs</strong> :</p><ul><li><code>start</code> - aligne le contenu sur le sommet de la zone de grille</li>
<li><code>end</code> - aligne le contenu sur le bas de la zone de grille</li>
<li><code>center</code> - aligne le contenu au centre de la zone de grille</li>
<li><code>stretch</code> - Remplit toute la hauteur de la zone de grille (c’est la valeur par défaut).</li>
</ul><pre>.item{
  align-self: start | end | center | stretch;
}</pre><p>Exemples :</p><pre>.item-a{
  align-self: start;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-self-start.png" alt="" /></figure><pre>.item-a{
  align-self: end;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-self-end.png" alt="" /></figure><pre>.item-a{
  align-self: center;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-self-center.png" alt="" /></figure><pre>.item-a{
  align-self: stretch;
}</pre><figure role="group"><img src="https://la-cascade.io/images/grid-align-self-stretch.png" alt="" /></figure><p>Pour régler l’alignement de <em>tous</em> les items dans une grille, ce comportement peut être défini sur le container grid <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet#ai">via la propriété <code>align-items</code></a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-grid-layout-guide-complet</link>
      <guid>https://la-cascade.io/articles/css-grid-layout-guide-complet</guid>
      <pubDate>Mon, 18 Apr 2016 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Sur :not et la spécifité]]></title>
      <description><![CDATA[<p><em>Ire Aderinokun revisite ici la pseudo-classe de négation, nous montre l'envers du décor et nous offre un crash course sur la spécificité!</em></p><div class="articleContent"><p><a href="https://la-cascade.io/articles/la-pseudo-classe-de-negation/">La pseudo-classe de négation</a> <code>:not</code> peut être extrêmement utile. Elle nous permet de cibler des éléments en fonction d’attributs qu’<em>ils n’ont pas</em>. Ce faisant, elle nous évite le recours à des règles supplémentaires et toujours plus spécifiques.</p><p>Un exemple assez courant serait celui d’une liste à laquelle nous voulons appliquer un style — sauf au dernier item :</p><pre>/* Sans :not */
li { border-right: 1px solid #000; }
li:last-child { border-right: none; }
/* Avec :not */
li:not(:last-child) { border-right: 1px solid #000; }</pre><p><a href="https://developer.mozilla.org/fr/docs/Web/CSS/:not">La pseudo classe :not</a> fait partie de mes préférées. Cependant, je me suis parfois trouvée dans des situations où la déclaration <code>:not</code> n’écrasait pas la déclaration initiale. Par exemple :</p><pre>a:not(.ul) { text-decoration: none; }
nav a { text-decoration: underline; }</pre><p>Dans ce cas précis, je me suis aperçue que les éléments <code>nav a</code> n'étaient toujours pas soulignés. Après un moment de confusion, j’ai approfondi ma recherche sur le fonctionnement de la règle <code>:not</code> et son effet sur la spécificité.</p><h2>La spécificité en 5 sec</h2><p>La spécificité en CSS peut être compliquée à comprendre, le mieux est de commencer par un exemple. Prenons l’élément HTML suivant :</p><pre>&lt;p class="foo" id="bar"&gt;Lorem ipsum dolor sit amet.&lt;/p&gt;</pre><p>et les styles que voici :</p><pre>p { color: red; }
.foo { color: green; }
#bar { color: blue; }
p.foo#bar { color: yellow; }</pre><p>Dans les cas comme celui-ci, où plusieurs sélecteurs ciblent le même élément, c’est la <strong>spécificité du sélecteur</strong> qui déterminera les règles qui prévaudront.</p><p>La spécificité d’un sélecteur dépend de deux facteurs :</p><ol><li><strong>De quels types de sélecteur s’agit-il ?</strong> Il y a trois types de sélecteurs :a. les ID, par exemple <code>#bar</code>b. les classes (dont les pseudo-classes), par exemple <code>.foo</code> ou <code>:last-child</code>c. les types, par exemple <code>p</code></li>
<li><strong>Le nombre de chacun des sélecteurs</strong>. Par exemple s’il y a 2 IDs et 3 classes.</li>
</ol><p>Ces deux facteurs combinés déterminent le niveau de spécificité d’un sélecteur. Si nous revenons à notre exemple, voici comment est calculée la spécificité de chaque sélecteur.</p><table class="specificTable"><tbody><tr class="odd"><td align="left"><code>p</code></td>
<td align="left">0</td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">0-0-1</td>
<td align="left"> </td>
</tr><tr class="even"><td align="left"><code>.foo</code></td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">0</td>
<td align="left">0-1-0</td>
<td align="left"> </td>
</tr><tr class="odd"><td align="left"><code>#bar</code></td>
<td align="left">1</td>
<td align="left">0</td>
<td align="left">0</td>
<td align="left">1-0-0</td>
<td align="left"> </td>
</tr><tr class="even"><td align="left"><code>p.foo#bar</code></td>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">1-1-1</td>
<td align="left">✓</td>
</tr></tbody></table><p>Pour lire le résultat figurant dans la colonne “Spécificité”, on ne prend pas le nombre global, mais chaque unité qui le compose, de gauche à droite.</p><p>Quand on compare deux sélécteurs, on prend la première valeur (qui représente le nombre de sélecteurs ID) et on les compare. Si un sélecteur a une valeur ID plus élevée, il gagne automatiquement la bataille. Si, et seulement si, les deux sélecteurs ont la même valeur ID, on passe à la suivante (dans ce cas, c’est le nombre de classes) et ainsi de suite.</p><p>Prenons l’exemple suivant :</p><table class="specificTable"><tbody><tr><td align="left"><code>p</code></td>
<td align="left">0</td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">0-0-1</td>
<td align="left"> </td>
</tr><tr><td align="left"><code>p:last-child</code></td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">0-1-1</td>
<td align="left"> </td>
</tr><tr><td align="left"><code>p.foo.bar.baz</code></td>
<td align="left">0</td>
<td align="left">3</td>
<td align="left">1</td>
<td align="left">0-3-1</td>
<td align="left"> </td>
</tr><tr><td align="left"><code>#bar</code></td>
<td align="left">1</td>
<td align="left">0</td>
<td align="left">0</td>
<td align="left">1-0-0</td>
<td align="left">✓</td>
</tr></tbody></table><p>Un seul ID l’emportera toujours sur 100 classes, parce que le nombre de classes est sans importance s’il existe un ID.</p><p>Remarque : ces calculs ne s’appliquent qu’aux styles définis en CSS. Les styles définis en ligne auront la priorité.</p><p>?? <em>NdT : Pour approfondir ce sujet, vous pouvez consulter <a href="http://openweb.eu.org/articles/cascade_css">Cascade CSS et priorité des sélecteurs</a> de Laurent Denis</em>.</p><h2>Et :not là-dedans ?</h2><p>La pseudo-classe de négation n’ajoute rien à la quantité de spécificité contrairement aux autres pseudo-classes. Cependant, les sélecteurs situés à l’intérieur de <code>:not</code>, oui.</p><blockquote>
<p>Relativement à la spécificité, ajouter <code>p:not(.foo)</code> revient au même qu’ajouter <code>.notFoo</code> à tous les <code>p</code> n’ayant pas la classe <code>.foo</code>.</p>
</blockquote><p>Par exemple :</p><pre>p.bar { color: red; }
p:not(.foo) { color: green; }</pre><p>De quelle couleur pensez-vous que sera <code>&lt;p class="bar"&gt;</code> ? La bonne réponse est vert, pas rouge. Ceci parce qu’en ajoutant la règle <code>:not</code> nous avons fait l’équivalent d’un ajout de classe <code>.notFoo</code> à notre élément <code>&lt;p class="bar"&gt;</code>.</p><table class="specificTable"><tbody><tr><td align="left"><code>p.bar</code></td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">0-1-1</td>
<td align="left">Égalité</td>
</tr><tr><td align="left"><code>p:not(.foo)</code></td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">0-1-1</td>
<td align="left">Égalité</td>
</tr></tbody></table><p>La règle <code>:not</code> est maintenant au même niveau de spécificité que les éléments ayant une “vraie” classe. Mais comme elle est définie après dans le CSS, c’est elle qui prévaut.Cela explique aussi pourquoi, dans notre exemple de <code>nav</code>, la règle <code>:not</code> l’emportait sur les sélecteurs de types imbriqués.</p><table class="specificTable"><tbody><tr><td align="left"><code>a:not(.ul)</code></td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">0-1-1</td>
<td align="left">✓</td>
</tr><tr><td align="left"><code>nav a</code></td>
<td align="left">0</td>
<td align="left">0</td>
<td align="left">2</td>
<td align="left">0-0-2</td>
<td align="left"> </td>
</tr></tbody></table><p><strong>Les choses deviennent encore plus complexes quand on introduit des IDs</strong>. De même que <code>p:not(.foo)</code> revient à peu près à ajouter <code>.notFoo</code> à tous les éléments <code>&lt;p&gt;</code>, de même <code>p:not(#bar)</code> revient à ajouter <code>#notBar</code> à tous les éléments <code>&lt;p&gt;</code>. Par exemple si nous avons :</p><pre>p:not(#foo) { color: green; }
p.bar { color: red; }</pre><p>...de quelle couleur pensez-vous que sera <code>&lt;p class="bar"&gt;</code>? La bonne réponse est vert, pas rouge.</p><table class="specificTable"><tbody><tr><td align="left"><code>p.bar</code></td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">1</td>
<td align="left">0-1-1</td>
<td align="left"> </td>
</tr><tr><td align="left"><code>p:not(#foo)</code></td>
<td align="left">1</td>
<td align="left">0</td>
<td align="left">1</td>
<td align="left">1-0-1</td>
<td align="left">✓</td>
</tr></tbody></table><p>Bien que notre élément positif et sa classe soient déclarés après dans le CSS, nous avons ajouté pour ainsi dire un ID à l’élément à partir de la règle <code>:not</code> !</p><h2>Utiliser :not</h2><p>Cet effet de <code>:not</code> m’a amenée à repensé la façon dont je l’utilisais. Nous croyons contourner le besoin d’écrire des règles spécifiques pour en écraser d’autres, comme dans notre premier exemple, mais en réalité <code>:not</code> nous amène à faire quelque chose qui y ressemble, sans que nous nous en apercevions.</p><p>Je vais continuer à utiliser <code>:not</code> parce que bien souvent c’est la façon la plus propre d’écrire, mais je le ferai en tenant compte de quelques avertissements :</p><ul><li>Ne <strong>jamais</strong> l’utiliser avec des IDs, par exemple : <code>:not(#bar)</code></li>
<li>Limiter son utilisation aux sélecteurs de type génériques, par exemple <code>div</code> dans <code>div:not(.foo)</code></li>
<li>Définir les règles <code>:not</code> le plus en amont possible dans mon CSS de façon à pouvoir les écraser si nécessaire.</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/sur-not-et-la-specifite</link>
      <guid>https://la-cascade.io/articles/sur-not-et-la-specifite</guid>
      <pubDate>Sun, 20 Mar 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Backgrounds SVG : hexagones et écailles]]></title>
      <description><![CDATA[<p><em>Dudley Storey poursuit sa passionnante série sur les backgrounds SVG, ici avec des motifs en tuiles hexagonales et en écailles. On y apprend quelques petites astuces relatives à l'encodage base64.</em></p><div class="articleContent"><p>Un récent <a href="http://tyler-mackenzie.ca/">dossier de travail réalisé par un de mes étudiants</a> utilisait une image de background “en écailles”, très intéressante, encodée en base64. J’ai <a href="https://www.base64decode.org/">décodé la texture</a> puis j’ai apporté quelques améliorations au SVG. Pour compléter, j’ai créé un background hexagonal simple que je partage ici.</p><h2>Motif en écailles</h2><p>Pour les écailles, le balisage est assez simple :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%"&gt;
&lt;defs&gt;
    &lt;pattern id="scales" width="30" height="30"
    patternUnits="userSpaceOnUse"  patternTransform="scale(2)"&gt;
            &lt;g id="curves"&gt;
                &lt;path id="inner" d="M0 0c0,30, 30,30 30,0" /&gt;
                &lt;path id="outer" d="M0 0c0,30, 30,30 30,0" /&gt;
            &lt;/g&gt;
            &lt;use x="15" y="15" xlink:href="#curves" /&gt;
            &lt;use x="-15" y="15" xlink:href="#curves" /&gt;
            &lt;use x="0" y="0" xlink:href="#curves" /&gt;
            &lt;use x="15" y="-15" xlink:href="#curves" /&gt;
            &lt;use x="-15" y="-15" xlink:href="#curves" /&gt;
        &lt;/pattern&gt;
    &lt;/defs&gt;
    &lt;rect width="100%" height="100%" fill="url(#scales)" /&gt;
&lt;/svg&gt;</pre><p>Le SVG utilise la technique standard du <code>&lt;pattern&gt;</code> que j’ai déjà illustrée dans de précédents articles (par exemple : <a href="https://la-cascade.io/articles/motifs-svg-japonais">motifs japonais</a>, <a href="https://la-cascade.io/articles/diagonales-et-motifs-svg-en-background">diagonales et motifs SVG en background</a>) . Moins habituel, le motif utilisé dans le pattern est <a href="https://la-cascade.io/articles/les-bases-de-svg-groupes/">un élément “groupe”</a>.</p><p>L’arrière-plan SVG est associé aux styles suivants :</p><pre>svg {
  background: #0F7173;
}
#scales {
  fill: #0F7173;
}
#inner {
    stroke: #0c4c4d;
    stroke-width: 3.1;
}
#outer {
  stroke: #098f92;
  stroke-width: 0.9;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/dudleystorey/pen/xZyKVp">écailles SVG</a>de dudleystorey dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez que l’élément SVG et les écailles utilisent la même couleur pour leur <code>background</code> et <code>fill</code>. Cette technique est répétée dans l’exemple de motifs hexagonaux qui va suivre.</p><blockquote>
<p>Le pattern pourait être amélioré en définissant le <code>stroke</code> des chemins (<em>path</em>) en rgba plutôt qu’en valeurs hexadécimales. On pourrait ainsi les corriger automatiquement si les couleurs de background et de fill des écailles étaient modifiées.</p>
</blockquote><h2>Motifs hexagonaux</h2><p>Le code comprend un balisage minimal pour créer un background hexagonal lié :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  width="100%" height="100%"&gt;
     &lt;defs&gt;
        &lt;pattern id="hexagons" width="50" height="43.4"
        patternUnits="userSpaceOnUse"
        patternTransform="scale(5) translate(2) rotate(45)"&gt;
            &lt;polygon
            points="24.8,22 37.3,29.2 37.3,43.7 24.8,50.9 12.3,43.7 12.3,29.2"
            id="hex" /&gt;
            &lt;use xlink:href="#hex" x="25" /&gt;
            &lt;use xlink:href="#hex" x="-25" /&gt;
            &lt;use xlink:href="#hex" x="12.5" y="-21.7" /&gt;
            &lt;use xlink:href="#hex" x="-12.5" y="-21.7" /&gt;
        &lt;/pattern&gt;
     &lt;/defs&gt;
&lt;rect width="100%" height="100%" fill="url(#hexagons)" /&gt;
&lt;/svg&gt;</pre><p>Le pattern utilise le CSS suivant :</p><pre>svg {
  background: rgb(125,155,132);
}
polygon {
  fill: rgb(125,155,132);
  stroke-width: 2;
  stroke: #000;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/dudleystorey/pen/YwdYxq">background SVG hexagones</a>de dudleystorey dans<a href="https://codepen.io">CodePen</a></div><p>Là encore, le SVG utilise la même technique consistant à s’appuyer sur les mêmes <code>background</code> et <code>fill</code> pour l’élément SVG et ses polygones pour “remplir” l’espace vide. Dans cet exemple, j’ai utilisé une série de transformations du pattern pour le placé légèrement “en dehors” de la page.</p><blockquote>
<p>Le <code>translate</code> est particulièrement important car un hexagone ayant un bord placé contre une bordure du viewport semblera avoir un côté plus long que l’autre.</p>
</blockquote><p>Les traits (<em>stroke</em>) SVG s’étendent de manière égale de chaque côté d’une ligne interne représentant le chemin, par conséquent une augmentation de la valeur <code>stroke-width</code> (“épaisseur du trait”) aura pour conséquence de réduire la taille des hexagones.</p><h3>Exemples CodePen</h3><p>Les exemples CodePen qui précèdent utilisent le code SVG directement dans le HTML pour plus de clarté. En production, le CSS serait intégré au SVG et l’ensemble serait transformé en code base64 qui serait utilisé comme valeur de la propriété <code>background-image</code>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/backgrounds-svg-hexagones-et-ecailles</link>
      <guid>https://la-cascade.io/articles/backgrounds-svg-hexagones-et-ecailles</guid>
      <pubDate>Sun, 14 Feb 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Cacher des éléments avec CSS]]></title>
      <description><![CDATA[<p><em>Encore un article d'Ire Aderinokun, qu'on aime beaucoup ici pour ses analyses en profondeur et la clarté de ses explications. Avez-vous bien tout considéré lorsque vous cachez un élément HTML?</em></p><div class="articleContent"><p>La possibilité de faire disparaître et apparaître des éléments sur une page fait partie intégrante du design responsif. Selon ce que vous voulez obtenir, il existe plusieurs façons de masquer un élément avec CSS. Dans cet article, je vais explorer les propriétés à notre disposition et les avantages et désavantages de chacune.</p><h3>Display</h3><p><a href="https://la-cascade.io/articles/controler-le-modele-de-boite/">Comme je l’ai déjà mentionné</a>, à l’intérieur d’un document HTML chaque élément est une boîte rectangulaire. Cacher un élément HTML à l’aide de la propriété <code>display</code> signifie que cette boîte rectangulaire n’est pas générée du tout.</p><p>Bien que l’élément soit toujours dans notre markup (comme vous pouvez le voir en inspectant la page), il n’existe pour ainsi dire pas dans la page. Aucune partie du modèle de boîte — la surface du contenu, celles du padding, de la bordure ou de la marge — n’est générée ou n’apparaît sur la page.</p><p>Tout contenu situé à l’intérieur de l’élément ou de ses enfants est fonctionnellement inexistant. S’il s’agit d’un élément actionnable, par exemple un bouton ou une ancre, on ne peut pas l’activer. L’élément, et tout ce qu’il contient, est également ignoré par les lecteurs d’écran.</p><pre>.foo {
  display: none;
}</pre><figure role="group"><img src="https://la-cascade.io/images/display-position-compressor.png" alt="L’élément foo disparaît et les autres éléments prennent sa place" /></figure><h3>Visibility</h3><p>Avec la propriété <code>visibility</code>, la “boîte rectangulaire” est générée, mais elle n’est pas rendue à l’écran. Du fait que la boîte est générée, les quatre surfaces constituant la boîte affectent toujours la disposition du reste de la page, cependant sans que les quatre surfaces soient visibles à l’écran.</p><p>Mis à part le fait que la boîte soit générée, l’utilisation de la propriété visibility pour cacher un élément est semblable à la propriété display.</p><pre>.foo {
  visibility: hidden;
}</pre><figure role="group"><img src="https://la-cascade.io/images/visibility-opacity-compressor.png" alt="L’élément foo disparaît mais les autres éléments restent à leur place" /></figure><h3>Opacity</h3><p>La propriété opacity n’a d’impact que sur la façon dont un élément apparaît visuellement — plus exactement sur sa transparence.</p><p>Lorsque l’opacité d’un élément est à sa valeur minimum, bien qu’il soit invisible à l’écran ses fonctionnalités demeurent, comme s’il avait une couleur solide. Par conséquent, l’élément occupe toujours son espace, il est lu par les lecteurs d’écran et on peut interagir avec lui.</p><pre>.foo {
  opacity: 0;
}</pre><figure role="group"><img src="https://la-cascade.io/images/visibility-opacity-compressor.png" alt="L’élément foo disparaît, les autres éléments restent à leur place et sont actionnables" /></figure><h3>Position</h3><p>La propriété <code>position</code> n’est pas faite a priori pour masquer ou afficher les éléments d’une page. On l’a utilisée à cet effet parce qu’on avait besoin de cacher un élément et de le soustraire de la disposition de la page <em>tout en conservant la possibilité qu’il soit lu par les lecteurs d’écran et qu’il soit actionnable si besoin</em>.</p><p>Il y a deux manières de combiner la propriété position avec d’autres propriétés pour parvenir à cet effet.</p><p>Combiné avec les propriétés <code>top</code> et <code>left</code>, l’élément est déplacé en dehors du viewport et il est donc hors de vue.</p><pre>.foo {
  position: absolute;
  top: -9999px;
  left: -9999px;
}</pre><p>Une autre façon de faire, imaginée par <a href="http://adaptivethemes.com/using-css-clip-as-an-accessible-method-of-hiding-content">Jeff Burnz</a>, consiste à utiliser la propriété <code>clip</code> pour redimensionner la boîte rectangulaire à une taille insignifiante, ce qui la l’escamote fonctionnellement.</p><pre>.foo {
  position: absolute;
  clip: rect(1px 1px 1px 1px); /* syntaxe pour IE6 &amp; IE7 */
  clip: rect(1px, 1px, 1px, 1px);
}</pre><p>Avec les deux méthodes, le résultat est identique :</p><figure role="group"><img src="https://la-cascade.io/images/display-position-compressor.png" alt="L’élément foo disparaît et les autres éléments prennent sa place" /></figure><p>Bien que ces solutions relèvent un peu du bidouillage, elles sont actuellement la meilleure manière de faire disparaître un élément de l’écran tout en conservant ses fonctions.</p><h3>En résumé</h3><table class="specificTable"><thead><tr><th> </th>
<th>display</th>
<th>visibility</th>
<th>opacity</th>
<th>position</th>
</tr></thead><tbody><tr><td>Le modèle de boîte est-il généré ?</td>
<td>✗</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
</tr><tr><td>La boîte affecte-t-elle le layout ?</td>
<td>✗</td>
<td>✓</td>
<td>✓</td>
<td>✗</td>
</tr><tr><td>La boîte est-elle visible ?</td>
<td>✗</td>
<td>✗</td>
<td>✗</td>
<td>✗</td>
</tr><tr><td>L’élément est-il lu par les lecteurs d’écran ?</td>
<td>✗</td>
<td>✗</td>
<td>✓</td>
<td>✓</td>
</tr><tr><td>L’élément est-il actionnable (cliquable, focusable) ?</td>
<td>✗</td>
<td>✗</td>
<td>✓</td>
<td>✓</td>
</tr></tbody></table><p>?? <em>Note complémentaire du traducteur (d'après un <a href="https://davidwalsh.name/html5-hidden">article de David Walsh</a>)</em></p><p>HTML5 a ajouté quelques attributs intéressants comme placeholder, download et autofocus. Un autre attribut nouveau est <code>hidden</code>. Appliqué à un élément, il se comporte comme CSS <code>display: none;</code> l'élément disparaît et son espace avec, il sort du flux. Il suffit pour cela d'écrire :</p><pre>&lt;div hidden&gt;
        Tu ne me vois plus !
&lt;/div&gt;</pre><p>Si un navigateur ne supporte pas cet attribut, on peut le styler via:</p><pre>*[hidden] { display: none; }</pre><p>Pourquoi utiliser l'attribut <code>hidden</code> ? Il est plus sémantiquement correct et devrait aider plus efficacement les lecteurs d'écran.</p><p>Pour faire réapparaître l'élément, il suffit d'utiliser la propriété <code>display</code> avec n'importe laquelle des valeurs acceptées, sauf <code>none</code>.</p><p>?? NdT : <a href="https://codepen.io/vincent-valentin/">Vincent Valentin</a> a créé dans Codepen <a href="https://codepen.io/vincent-valentin/full/JjGmxzV">un tableau hyper complet</a> des techniques d'escamotage (cacher, supprimer, désactiver...) et de leurs implications, à lire absolument !</p></div>]]></description>
      <link>https://la-cascade.io/articles/cacher-des-elements-avec-css</link>
      <guid>https://la-cascade.io/articles/cacher-des-elements-avec-css</guid>
      <pubDate>Sun, 24 Jan 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Contrôler le modèle de boîte]]></title>
      <description><![CDATA[<p><em>Dans cet article simple et complet, Ire Aderinokun rappelle les bases du modèle de boîte CSS et montre pourquoi vous devriez utiliser box-sizing.</em></p><div class="articleContent"><p>Dans l’arbre qui représente notre document, <a href="http://www.w3.org/TR/CSS2/box.html">chaque élément est une boîte rectangulaire</a>. Le modèle de boîte CSS décrit ces boîtes et leurs composants.</p><h2>Les bases du modèle de boîte</h2><p>Dans un document HTML, chaque boîte rectangulaire est constituée de quatre zones : la zone du contenu, celle du padding, celle de la bordure et celle de la marge.</p><p>Prenons un exemple.</p><pre>//HTML
&lt;div class="box"&gt;
  &lt;!-- start content area --&gt;
  Lorem ipsum dolor sit amet.
  &lt;!-- end content area --&gt;
&lt;/div&gt;</pre><p>Donnons un style à cette boîte :</p><pre>//CSS
.box {
  width: 300px;
  height: 300px;
  padding: 50px; /* padding area */
  margin: 50px; /* margin area */
  border: 50px solid grey; /* border area */
}</pre><h3>La zone du contenu</h3><p>La zone du contenu est la partie occupée par le contenu de l’élément HTML. Cela peut être du texte, une image ou tout autre media. Le contour est appelé “contour du contenu” ou “contour intérieur”.</p><figure role="group"><img src="https://la-cascade.io/images/1-content-compressor.jpeg" alt="texte dans une boîte rectangulaire délimitée par un contour" /><figcaption>Content edge, le contour du contenu</figcaption></figure><h3>La zone du padding</h3><p>La zone du padding est l’espace que nous spécifions entre le contenu et la bordure. Son contour est appelé “contour de padding”.</p><figure role="group"><img src="https://la-cascade.io/images/1-padding-compressor.jpeg" alt="texte dans une boîte rectangulaire délimitée par un contour et entourée par un padding lui-même délimité par un contour" /><figcaption>Padding edge, le contour de padding</figcaption></figure><h3>La zone de bordure</h3><p>La zone de bordure est constituée par l’épaisseur de la bordure. Son contour est appelé “contour de bordure”.</p><figure role="group"><img src="https://la-cascade.io/images/1-border-compressor.jpeg" alt="" /><figcaption>Border edge, le contour de bordure</figcaption></figure><h3>La zone de marge</h3><p>La zone de marge est l’espace situé en dehors de la bordure. Bien que ne faisant pas strictement partie de l’élément lui-même, elle est prise en compte lorsque nous considérons l’espace occupé par l’élément dans la page. Son contour est appelé “contour de marge” ou “contour extérieur”.</p><figure role="group"><img src="https://la-cascade.io/images/1-margin-compressor.jpeg" alt="" /><figcaption>Margin edge, le contour de marge</figcaption></figure><p>Pour <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline/">les éléments de niveau block</a>, nous pouvons contrôler la hauteur et la largeur des boîtes rectangulaires avec les propriétés CSS <code>height</code> et <code>width</code>. Cependant, vu le nombre de zones pour chaque élément, nous devons spécifier (ou calculer) ce que nous entendons par “largeur” et “hauteur” de l’élement. C’est ici qu’intervient la propriété <code>box-sizing</code>.</p><h2>La propriété box-sizing</h2><p>La propriété box-sizing définit lequel parmi les quatre contours nous utilisons pour déterminer la largeur et la hauteur de notre élément. Selon la zone que nous spécifions, la zone de contenu pourra être ajustée.</p><p>La propriété <code>box-sizing</code> accepte quatre valeurs, <code>content-box</code>, <code>padding-box</code>, <code>border-box</code> et <code>inherit</code>. Pour illustrer les différences entre chacune, appliquons-les à notre exemple de <code>.box</code>.</p><h3>content-box</h3><p><mark>largeur = zone du contenu</mark></p><p>C’est la valeur par défaut. Elle définit la largeur de l’élément, dans notre cas 300px, comme étant égale à la largeur de la zone de contenu. L’épaisseur du padding et de la bordure font que l’élément est globalement plus large que 300px. La largeur de l’élément (au sens strict) est maintenant de 500px et l’espace occupé total est de 600px en comptant la marge.</p><figure role="group"><img src="https://la-cascade.io/images/2-content-compressor.jpeg" alt="" /></figure><h3>padding-box</h3><p><mark>largeur = zone du contenu + zone de padding</mark></p><p>Cette valeur intègre l’épaisseur du padding dans le calcul de la largeur de l’élément. La zone de contenu est ajustée à 200px de large pour y arriver.</p><figure role="group"><img src="https://la-cascade.io/images/2-padding-compressor.jpeg" alt="" /></figure><p>Remarque : Cette valeur est <a href="http://caniuse.com/#feat=css3-boxsizing">uniquement supportée par Firefox</a>, car elle a été supprimée de la spécification. Les autres navigateurs utiliseront la valeur par défaut, content-box, si vous utilisez padding-box.</p><h3>border-box</h3><p><mark>largeur = zone du contenu + zone de padding + zone de bordure</mark></p><p>Cette valeur intègre à la fois la bordure et le padding dans le calcul de la largeur de l’élément. Dans notre exemple, la largeur de la zone de contenu est maintenant réduite à 100px.</p><figure role="group"><img src="https://la-cascade.io/images/2-border-compressor.jpeg" alt="" /></figure><h3>inherit</h3><p>Cette valeur donne au box-sizing de l’élément la valeur du box-sizing de son élément parent.</p><h2>Contrôler le modèle de boîte</h2><p>La méthode de dimensionnement de la boîte que vous utiliserez dépendra de la façon dont vous préférez concevoir votre élément. La plupart des gens, y compris moi-même, préfèrent utiliser la valeur <code>border-box</code> qui est la façon la plus logique de définir les dimensions de l’élément.</p><p>Pour écraser la valeur par défaut <code>content-box</code>, j’utilise ce reset recommandé par <a href="http://www.paulirish.com/2012/box-sizing-border-box-ftw/">Paul Irish</a> dans mon fichier reset.css.</p><pre>html {
  /* Set border-box as the global default */
  box-sizing: border-box;
}
*, *:before, *:after {
  /* Allow each element to override */
  box-sizing: inherit;
}</pre></div>]]></description>
      <link>https://la-cascade.io/articles/controler-le-modele-de-boite</link>
      <guid>https://la-cascade.io/articles/controler-le-modele-de-boite</guid>
      <pubDate>Sat, 23 Jan 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Créer un cube en CSS]]></title>
      <description><![CDATA[<p><em>David Walsh s’amuse à créer un cube 3D en CSS. En chemin, on suit la logique de construction, on apprend ou on révise la 3D CSS et les animations.</em></p><div class="articleContent"><p>Les cubes CSS sont une bonne démonstration de l’évolution de CSS ces dernières années, depuis les simples directives relatives aux couleurs et aux dimensions du début jusqu’au langage actuel nous permettant de créer des visuels profonds et créatifs. Ajoutez-y l’animation et vous avez un travail abouti.</p><p>Jusqu’à présent, les tutoriels que j’ai trouvés pour créer des cubes en CSS sont longs et mélangent un peu tout, alors j’ai décidé d’écrire cet article qui vous donnera les infos basiques pour créer ce cube. Pour l’idée, je me suis basé sur cette belle réalisation de Mircea Georgescu :</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/mirceageorgescu/pen/roblc/">CSS only spinning cubes</a>by Mircea Georgescu<a href="https://codepen.io">CodePen</a></div><p><strong><a href="https://davidwalsh.name/demo/css-cube.php">Voir la démo de David Walsh</a></strong></p><h2>Le HTML</h2><p>L’élément cube, qui est un container, sera lui-même enveloppé dans une autre <code>div</code>.</p><pre>//HTML
&lt;div class="wrap"&gt;
        &lt;div class="cube"&gt;
                &lt;div class="front"&gt;front&lt;/div&gt;
                &lt;div class="back"&gt;back&lt;/div&gt;
                &lt;div class="top"&gt;top&lt;/div&gt;
                &lt;div class="bottom"&gt;bottom&lt;/div&gt;
                &lt;div class="left"&gt;left&lt;/div&gt;
                &lt;div class="right"&gt;right&lt;/div&gt;
        &lt;/div&gt;
&lt;/div&gt;</pre><p>Chaque face du cube aura son propre élément. Comme vous pouvez l’imaginer, CSS va faire un travail de fou pour le disposer comme il faut.</p><h2>Le CSS</h2><p>Procédons pas à pas, en prenant chaque élément significatif. Le premier élément à avoir du sens est le container de l’animation — il fournira une <a href="https://developer.mozilla.org/fr/docs/Web/CSS/perspective">perspective CSS</a> pour l’élément en 3D :</p><pre>.wrap {
        perspective: 800px;
        perspective-origin: 50% 100px;
}</pre><p>La perspective en CSS est <a href="https://developer.mozilla.org/fr/docs/Web/CSS/perspective">très bien expliquée par MDN</a>, je ne répèterai pas leur présentation, mais pour mieux comprendre la perspective, je vous recommande de jouer avec les valeurs de la propriété <code>perspective</code> et de voir comment cela affecte la démo. Passons maintenant au container du cube qui contiendra toutes les faces :</p><pre>.cube {
        position: relative;
        width: 200px;
        transform-style: preserve-3d;
}</pre><p>Le cube aura 200px de large, il aura un positionnement relatif de façon à ce que les faces positionnées absolument restent dans les limites. Nous allons aussi utiliser <code>preserve-3d</code> pour que notre élément reste en 3D. Avant d’entrer dans le détail des règles relatives aux faces, nous appliquons quelques styles généraux à chaque face :</p><pre>.cube div {
        position: absolute;
        width: 200px;
        height: 200px;
}</pre><p>Maintenant que nous avons déterminé la position et les dimensions des faces, nous pouvons ajouter les transformations des faces individuelles :</p><pre>.back {
        transform: translateZ(-100px) rotateY(180deg);
}
.right {
        transform: rotateY(-270deg) translateX(100px);
        transform-origin: top right;
}
.left {
        transform: rotateY(270deg) translateX(-100px);
        transform-origin: center left;
}
.top {
        transform: rotateX(-90deg) translateY(-100px);
        transform-origin: top center;
}
.bottom {
        transform: rotateX(90deg) translateY(100px);
        transform-origin: bottom center;
}
.front {
        transform: translateZ(100px);
}</pre><p>Les valeurs de <code>rotateY</code> font pivoter les faces pour montrer le texte à l’angle voulu, tandis que le <code>translateZ</code> déplace les éléments d’avant en arrière à l’intérieur de l’empilement. <code>translateY</code> est peut-être encore confus pour vous, mais considérez qu’il permet d’élever ou d’abaisser une face pour montrer l’effet 3D à travers les panneaux transparents. Chaque face a ses propres réglages de translation qui la place au bon endroit, là encore je vous conseille de jouer avec ces valeurs pour voir à quoi cela correspond pour chacune.</p><p><strong><a href="https://davidwalsh.name/demo/css-cube.php">Voir la démo</a></strong></p><h2>Rotation horizontale du cube</h2><p>Évidemment, à quoi servent tous ces éléments 3D s’il n’y a pas d’animation ? Réponse : à rien. Alors, voici les étapes qu’il nous reste à franchir pour animer notre cube horizontalement :</p><pre>@keyframes spin {
        from { transform: rotateY(0); }
        to { transform: rotateY(360deg); }
}
.cube {
        animation: spin 5s infinite linear;
}</pre><p>Sans doute plus simple que vous ne l’imaginiez, pas vrai ? Le texte apparaît comme il faut grâce à la rotation que nous avons implémentée au départ, et j’ai utilisé une animation keyframe au cas où nous voudrions ajouter des choses plus sexy à l’avenir.</p><h2>Rotation verticale du cube</h2><p>Pour faire tourner le cube verticalement, il suffit de changer l’animation en prenant l’axe des Y, pas vrai ? Eh bien, malheureusement non. Les panneaux, tels qu’ils sont actuellement, montreraient le texte à l’envers dans certains cas, donc il nous faut revoir la rotation de certains éléments.</p><pre>@keyframes spin-vertical {
        from { transform: rotateX(0); }
        to { transform: rotateX(-360deg); }
}
.cube-wrap.vertical .cube {
        margin: 0 auto; /* keeps the cube centered */
        transform-origin: 0 100px;
        animation: spin-vertical 5s infinite linear;
}
.cube-wrap.vertical .top {
        transform: rotateX(-270deg) translateY(-100px);
}
.cube-wrap.vertical .back {
        transform: translateZ(-100px) rotateX(180deg);
}
.cube-wrap.vertical .bottom {
        transform: rotateX(-90deg) translateY(100px);
}</pre><p>...et il nous faut bien sûr changer l’animation.</p><h2>Aplatir le cube</h2><p>Pour supprimer l’aspect 3D du cube et simplement afficher un bloc à chaque fois, supprimez la perspective et l’origine du container :</p><pre>.wrap {
        /* suppression de la perspective */
        perspective: none;
        perspective-origin: 0 0;
}</pre><p>Maintenant, seule une face s’affiche.</p><p><strong><a href="https://davidwalsh.name/demo/css-cube.php">Voir la démo</a></strong></p><p>J’espère que cet article a suffisamment simplifié la façon dont un cube 3D est constitué en CSS et qu’il vous aura donné envie de créer les vôtres. Et ne vous découragez pas si vous rencontrez des problèmes, ça m’est arrivé également ! J’espère voir bientôt ce que vous aurez inventé !</p></div>]]></description>
      <link>https://la-cascade.io/articles/creer-un-cube-en-css</link>
      <guid>https://la-cascade.io/articles/creer-un-cube-en-css</guid>
      <pubDate>Thu, 07 Jan 2016 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre SVG preserveAspectRatio]]></title>
      <description><![CDATA[<p><em>Après SVG viewport et viewBox, Joni Trythall présente le complément logique, l'attribut preserveAspectRatio. Là aussi, les choses sont d'abord un peu complexes, mais présentées par Joni elles deviennent très claires.</em></p><div class="articleContent"><p>J’ai écrit dernièrement un article sur <a href="https://la-cascade.io/articles/comprendre-svg-viewbox-et-viewport/">Comprendre SVG viewport et viewBox</a> et je me suis dit que celui-ci ferait une suite idéale pour approfondir le sujet.</p><p>Comprendre l’espace de travail SVG est parfois compliqué. La qualité de notre SVG dépend fortement du système de coordonnées que nous aurons défini.</p><h2>Résumé de viewport et viewBox</h2><p>La largeur <code>width</code> et la hauteur <code>height</code> de notre SVG établissent la surface visible (le viewport). Si nous définissons une <code>viewBox</code>, nous pouvons spécifier la façon dont notre élément graphique peut s’étendre pour remplir un container (habituellement le viewport). Lorsque les valeurs de chacun des deux sont identiques, l’image est visible dans son entièreté et se redimensionne lorsque la taille du viewport est modifiée. C’est magnifique.</p><p>Si la <code>viewBox</code> SVG et le viewport n’ont pas le même ratio largeur et hauteur, <code>preserveAspectRatio</code> indique si l’on doit ou non forcer un redimensionnement uniforme.</p><p>Dans les exemples qui suivent, nous allons passer des poires aux cerises et nous verrons l’effet que les diverses valeurs de <code>preserveAspectRatio</code> auront sur le rendu visuel. Dans ce premier exemple, les cerises sont définies de façon à se redimensionner uniformément grâce à des valeurs de viewport et de <code>viewBox</code> identiques.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/avxQPo/">viewport et viewBox</a>dans<a href="https://codepen.io">CodePen</a></div><h2>Valeurs de preserveAspectRatio</h2><p><code>preserveAspectRatio</code> accepte deux paramètres, <code>&lt;align&gt;</code> et <code>&lt;meetOrSlice&gt;</code>. Le premier paramètre comporte deux parties et régit l’alignement de la <code>viewBox</code> à l’intérieur du viewport. Le second paramètre est optionnel et indique la façon dont le ratio d’aspect doit être préservé.</p><p><code>preserveAspectRatio=“xMaxYMax meet”</code></p><p>Ces valeurs vont aligner le coin inférieur droit de la <code>viewBox</code> avec le coin inférieur droit du viewport. La valeur <code>meet</code> préserve le ratio d’aspect en redimensionnant la <code>viewBox</code> de façon à ce qu’elle s’adapte autant que possible au viewport.</p><p>Il existe trois options <code>&lt;meetOrSlice&gt;</code> : <code>meet</code> (par défaut), <code>slice</code> et <code>none</code>. La première option <code>meet</code> assure une complète visibilité du graphique (autant que possible), alors que <code>slice</code> essaie de remplir le viewport avec la <code>viewBox</code> et découpe (<em>slice off</em>) tout ce qui dépasse. La troisième option <code>none</code> a pour résultat la perte du ratio d’aspect et donc une image potentiellement déformée.</p><p>Vous pourrez trouver une liste complète des combinaisons de valeurs et leur description <a href="http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute">sur W3C</a>.</p><h3>Ratio d’aspect et cerises</h3><p>La valeur la plus simple est <code>none</code>, elle établit qu’aucun redimensionnement uniforme ne doit être appliqué. Si nous augmentons les valeurs en pixel du viewport, les cerises vont s’étirer de manière non uniforme et seront déformées (et pas très appétissantes...)</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/qOwQgd/">Ratio d’aspect</a>dans<a href="https://codepen.io">CodePen</a></div><h3>Valeurs Min, Max et Mid modifiées</h3><p>Jetons un coup d’oeil à ce que donnent les différentes combinaisons.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/jbRQdp/">preserveAspectRatio à xMinYMax</a>dans<a href="https://codepen.io">CodePen</a></div><p>Le <code>preserveAspectRatio</code> est fixé à <code>xMinYMax</code> ce qui aligne le coin inférieur gauche de la <code>viewBox</code> au coin inférieur gauche du viewport, qui est maintenant visualisé par son contour. <code>meet</code> assure que l’image est redimensionnée de façon à entrer dans le viewport autant que possible.</p><p>Si on change <code>xMin</code> en <code>xMax</code> ou en <code>xMid</code>, les cerises seront positionnées à droite ou au centre du viewport.</p><p>Voici ce qui se passe si nous changeons <code>meet</code> en <code>slice</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/dYLQrX/">meet en slice</a>dans<a href="https://codepen.io">CodePen</a></div><p>Les cerises ne sont plus forcées de rester à l’intérieur du viewport, et l’excédent graphique est éliminé : tout le contenu de la <code>viewBox</code> qui n’entre pas dans le viewport est supprimé.</p><p>Les valeurs d’alignement ne sont pas obligées d’être liées.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/XmQyGL/">preserveAspectRatio à xMinYMid slice</a>dans<a href="https://codepen.io">CodePen</a></div><p>L’exemple ci-dessus a un <code>preserveAspectRatio</code> égal à <code>xMinYMid slice</code>. Nous voyons maintenant les cerises alignées sur le milieu de l’axe des y du viewport.</p><p>?? Le livre de Joni, “Pocket Guide to Writing SVG” est open source, vous pouvez le <a href="http://svgpocketguide.com/">télécharger gratuitement ici</a> ou le lire en ligne en suivant le même lien.</p><h3><small>Ressources complémentaires en anglais</small></h3><ul><li><a href="http://tutorials.jenkov.com/svg/svg-viewport-view-box.html">SVG Viewport and viewBox</a>, par Jakob Jenkov</li>
</ul><h3><small>Ressources complémentaires en français</small></h3><ul><li><a href="http://tecfa.unige.ch/guides/tie/html/svg-intro/svg-intro-8.html">Système de coordonnées, transformations et unités</a>, par Tecfa</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-svg-preserveaspectratio</link>
      <guid>https://la-cascade.io/articles/comprendre-svg-preserveaspectratio</guid>
      <pubDate>Sun, 22 Nov 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre SVG viewBox et viewport]]></title>
      <description><![CDATA[<p><em>SVG viewport et viewBox peuvent sembler compliqués et intimidants lorsqu’on débute avec SVG. Excellente introduction agrémentée d'illustrations fruitées.</em></p><div class="articleContent"><p>Quand nous utilisons l’élément <code>&lt;svg&gt;</code>, nous créons un fragment constitué de détails multiples, imbriqué dans notre document. Ce fragment a son propre viewport et son propre système de coordonnées, ce qui peut semble compliqué et intimidant lorsqu’on débute avec SVG.</p><p>Si vous voulez que votre travail s’affiche correctement, il est utile de comprendre l’espace dans lequel se situe votre SVG, mais cela devient réellement crucial dès lors que vous vous lancez dans un SVG un peu plus complexe, comme <a href="https://la-cascade.io/articles/les-degrades-svg/">les dégradés</a> et les motifs, où les détails sont fortement liés à un système de coordonnées.</p><p>Le sujet est riche, mais je donnerai ici les bases, en indiquant l’objectif et le comportement de SVG viewport et viewBox. J’espère que cette introduction vous donnera des fondations solides pour avancer dans vos créations SVG.</p><p>?? <em>NdT : Vous pouvez également consulter l'article de Dudley Storey traduit dans la Cascade "<a href="https://la-cascade.io/articles/comprendre-svg-viewbox/">Comprendre SVG viewBox</a>"</em>.</p><h2>Le viewport</h2><p>Le viewport est la partie visible d’un SVG. Un SVG est par nature extensible, il peut être aussi haut et large que nous le voulons, et nous pouvons également déterminer qu’une partie seulement soit visible.</p><p><strong>Le viewport est défini grâce aux attributs <code>height</code> et <code>width</code> à l’intérieur de l’élément <code>&lt;svg&gt;</code>.</strong></p><p>Si nous choisissons de ne pas définir de viewport, les dimensions du viewport seront déterminées par tout autre indicateur présent dans le SVG, par exemple la largeur de l’élément SVG contenant. Cependant, si vous laissez cet information non définie, le risque est que votre SVG soit coupé à l’affichage.</p><p>De mon point de vue, plus on donne de détails à l’intérieur de SVG, et mieux notre image se comportera sur tous les navigateurs.</p><h2>preserveAspectRatio</h2><p>Si le viewport et la <code>viewBox</code> n’ont pas le même ration de hauteur et de largeur, l’attribut <code>preserveAspectRatio</code> indique au navigateur comment afficher l’image (<em>NdT : Voir <a href="https://la-cascade.io/articles/comprendre-svg-preserveaspectratio/">l'article sur preserveAspectRatio</a> qui fait suite à celui-ci</em>).</p><p>Les valeurs de cet attribut sont nombreuses, <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio">Mozilla Developer Network les liste clairement</a>.</p><p>Si nous ne spécifions pas de valeur, le réglage par défaut impose une mise à l’échelle uniforme et la viewBox entière est visible dans le viewport.</p><h2>Poire exemple</h2><p>Prenons une image de poire. Dans ce premier exemple, le viewport et la <code>viewBox</code> sont définis avec des valeurs correspondantes, une <code>width</code> de 155px et une <code>height</code> de 190px. La <code>viewBox</code> est définie de façon à couvrir entièrement l’image de la poire et cette image est définie de façon à entrer dans les limites de son container.</p><p>Dans l’exemple ci-dessous, vous pourrez constater en jouant avec Codepen que l’élément <code>&lt;svg&gt;</code> est défini ainsi :</p><pre>//HTML
...
&lt;svg width="115" height="190" viewBox="0 0 115 190"&gt;
...</pre><p>Les <code>width</code>et <code>height</code> définissent le viewport.</p><h3>1 - Dimensions concordantes</h3><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/RWOeLO/">Dimensions concordantes</a>dans<a href="https://codepen.io">CodePen</a></div><h3>2 - viewBox réduite</h3><p>Si nous réduisons de 50px la hauteur et la largeur de la <code>viewBox</code> de notre image, nous réduisons la dimension de la portion de notre poire que nous souhaitons afficher, mais du coup ce qui reste visible est redimensionné de façon à remplir le container.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/RWOexO/">viewBox réduite</a>dans<a href="https://codepen.io">CodePen</a></div><h3>3 - viewport agrandi</h3><p>Ajoutons maintenant 200px aux <code>width</code> et <code>height</code> de notre viewport. L’image se redimensionne pour correspondre à ces dimensions. La <code>viewBox</code> couvre l’image entière, la poire est entièrement visible. Le viewport contient toute l’image et définit les limites que doit remplir notre poire.</p><p>Voici ce que donne notre viewport agrandi :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/LpvgQg/">viewport agrandi</a>dans<a href="https://codepen.io">CodePen</a></div><h3>4 - Changer les valeurs `min`</h3><p>À l’intérieur de la <code>viewBox</code>, les valeurs <code>min</code> définissent l’origine de la <code>viewBox</code> dans l’élément parent. En d’autres termes, à quel point, dans la <code>viewBox</code>, nous voulons que commence la correspondance avec le viewport. Dans les exemples qui précèdent, les valeurs <code>min</code> sont définies comme <code>0, 0</code> (c’est à dire en haut à gauche). Modifions-les en <code>50, 30</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/pierrechoffe/pen/XmQxEV/">Changer les valeurs `min`</a>dans<a href="https://codepen.io">CodePen</a></div><p>La <code>viewBox</code> (ce qui sera visible) commence maintenant à 50px sur l’axe des x et à 30px sur celui des y. En changeant ces valeurs, nous avons simplement changé la partie de la poire sur laquelle nous voulons nous concentrer.</p><h2>Conclusion</h2><p>Comprendre et mettre en oeuvre un bon système de coordonnées pour SVG est vraiment utile pour créer et afficher vos réalisations graphiques.</p><p>Nous avons passé en revue quelques modifications basiques de SVG viewport et <code>viewBox</code> qui je l’espère ont montré toute la puissance et l’utilité d’une bonne définition de l’espace de travail SVG.</p><p>?? Le livre de Joni, “Pocket Guide to Writing SVG” est open source, vous pouvez le <a href="https://svgpocketguide.com/">télécharger gratuitement ici</a> ou le lire en ligne en suivant le même lien.</p><h3><small>Ressources complémentaires en anglais</small></h3><ul><li><a href="http://tutorials.jenkov.com/svg/svg-viewport-view-box.html">SVG Viewport and viewBox</a>, par Jakob Jenkov</li>
</ul><h3><small>Ressources complémentaires en français</small></h3><ul><li><a href="http://tecfa.unige.ch/guides/tie/html/svg-intro/svg-intro-8.html">Système de coordonnées, transformations et unités</a>, par Tecfa</li>
<li><a href="https://webdesign.tutsplus.com/fr/tutorials/svg-viewport-and-viewbox-for-beginners--cms-30844">SVG viewport et viewBox (pour les débutants complets)</a>, par Kezz Bracey</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-svg-viewbox-et-viewport</link>
      <guid>https://la-cascade.io/articles/comprendre-svg-viewbox-et-viewport</guid>
      <pubDate>Sat, 21 Nov 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Comment fonctionne z-index]]></title>
      <description><![CDATA[<p><em>Ça n'est pas évident à première vue, mais les éléments HTML sont générés en 3D. La propriété CSS z-index spécifie le niveau et le contexte d'empilement.</em></p><div class="articleContent"><p>Ça n’a pas l’air évident à première vue, mais les éléments HTML sont générés en 3D. Alignés sur les axes des x et des y, les éléments peuvent en outre reposer sur l’axe des z, qui contrôle leur CSS dans la troisième dimension.</p><figure role="group"><img src="https://la-cascade.io/images/les_3_dimensions-compressor.jpeg" alt="les trois axes x, y et z" /></figure><p>Les marges, les float et autres propriétés permettant de décaler un élément contrôlent la façon dont un élément est positionné sur les axes des x et des y. Mais seule la propriété CSS <code>z-index</code> permet de contrôler la façon dont il repose sur l’axe des z.</p><h2>La propriété z-index</h2><p>La propriété <code>z-index</code> spécifie deux choses :</p><ul><li>le <a href="https://la-cascade.io/articles/comment-fonctionne-z-index/#niveau">niveau d’empilement</a> de l’élément courant</li>
<li>et si l’élément courant établit un nouveau <a href="https://la-cascade.io/articles/comment-fonctionne-z-index/#contexte">contexte d’empilement</a></li>
</ul><p><strong>La propriété ne s’applique qu’aux <a href="https://la-cascade.io/articles/le-positionnement-css/">éléments positionnés</a>. Autrement dit, les éléments qui ont une <code>position</code> soit <code>relative</code>, soit <code>absolute</code>, soit <code>fixed</code></strong>.</p><p>La propriété <code>z-index</code> peut prendre trois valeurs :</p><table class="specificTable"><thead><tr><th>Valeur</th>
<th>Description</th>
</tr></thead><tbody><tr><td><code>auto</code></td>
<td>Fixe le niveau d’empilement à 0 et ne crée pas de nouveau contexte d’empilement</td>
</tr><tr><td><code>&lt;integer&gt;</code></td>
<td>Le niveau d’empilement est un nombre entier <strong>et</strong> un nouveau contexte d’empilement est créé</td>
</tr><tr><td><code>inherit</code></td>
<td>Le niveau d’empilement est hérité de l’élément parent, ce qui ne crée pas de nouveau contexte d’empilement</td>
</tr></tbody></table><pre>z-index: auto | &lt;integer&gt; | inherit</pre><h2 id="niveau">Niveau d’empilement</h2><p>Le niveau d’empilement est la valeur attribuée à l’élément courant sur l’axe des z. Plus le nombre est élevé, plus l’élément se situe haut dans l’empilement et donc plus près de la surface de l’écran.</p><figure role="group"><img src="https://la-cascade.io/images/stacking_level-compressor.png" alt="4 niveaux d’empilement, de 1 en bas à 4 en haut" /></figure><p>S’il n’est pas spécifié par la propriété <code>z-index</code>, le niveau d’empilement d’un élément est établi <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Comprendre_z-index/Empilement_sans_z-index">en fonction de sa place dans le document</a>. Les éléments déclarés plus tard dans le document ont un niveau d’empilement plus élevé par défaut.</p><h2>Calculer le niveau d’empilement</h2><p>En plus du z-index spécifié, le niveau d’empilement est contrôlé par un certain nombre de facteurs. Les éléments sont empilés dans l’ordre suivant.</p><table class="specificTable"><thead><tr><th>Position</th>
<th>Description</th>
<th>CSS</th>
</tr></thead><tbody><tr><td>1 (en bas)</td>
<td>L’élément qui crée le contexte d’empilement</td>
<td><code>z-index: &lt;integer&gt;</code></td>
</tr><tr><td>2</td>
<td>Éléments enfants ayant des niveaux d’empilement négatifs</td>
<td><code>z-index: &lt;negative integer&gt;</code><code>position: relative | absolute | fixed</code></td>
</tr><tr><td>3</td>
<td>Élément enfants dans le flux, pas en ligne, non positionnés</td>
<td><code>display: /* not inline */</code><code>position: static</code></td>
</tr><tr><td>4</td>
<td>Éléments enfants flottants non positionnés</td>
<td><code>float: left | right</code><code>position: static</code></td>
</tr><tr><td>5</td>
<td>Éléments enfants dans le flux, en ligne, non positionnés</td>
<td><code>display: /* inline */</code><code>position: static</code></td>
</tr><tr><td>6</td>
<td>Éléments enfants avec niveau d’empilement égal à 0</td>
<td><code>z-index: auto | 0</code><code>position: relative | absolute | fixed</code></td>
</tr><tr><td>7 (en haut)</td>
<td>Éléments enfants avec des niveaux d’empilement positifs</td>
<td><code>z-index: &lt;positive integer&gt;</code><code>position: relative | absolute | fixed</code></td>
</tr></tbody></table><h2 id="contexte">Contexte d’empilement</h2><p>Lorsque nous spécifions le niveau d’empilement d’un élément à l’aide de la propriété <code>z-index</code>, nous ne spécifions pas toujours le niveau d’empilement de l’élément par rapport à chaque autre élément de la page. <strong>Le niveau d’empilement de l’élément est seulement défini par rapport à son contexte d’empilement</strong>.</p><p>Cela peut conduire à des situations bizarres où un élément ayant un z-index plus élevé ne se retrouve pas au-dessus d’un élément ayant un z-index plus bas.</p><p>Le contexte d’empilement peut être expliqué à l’aide des règles suivantes.</p><h3>1 - Le contexte d’empilement par défaut est l’élément racine</h3><p>Le contexte d’empilement par défaut pour tout document HTML est l’élément racine <code>&lt;html&gt;</code>. C’est pourquoi, à moins qu’un nouveau contexte d’empilement ne soit créé, le niveau d’empilement d’un élément est par défaut en relation avec celui de tous les autres éléments de la page.</p><h3>2 - Créez un nouveau contexte d’empilement avec la propriété z-index</h3><p>Nous créons un nouveau contexte d’empilement en donnant une valeur au z-index d’un élément. Cela a pour effet, d’une part de donner ce niveau d’empilement à cet élément, d’autre part de créer un nouveau contexte d’empilement.</p><p>Le nouveau contexte d’empilement s’applique à tous les enfants de cet élément. Leurs niveaux d’empilement sont maintenant situés à l’intérieur de ce contexte d’empilement et non dans le contexte racine.</p><p>Dans l’exemple qui suit, <code>.foo</code> appartient au contexte d’empilement 1, alors que <code>.bar</code> appartient au contexte d’empilement 2.</p><figure role="group"><img src="https://la-cascade.io/images/stacking-context-compressor.png" alt="l’élément foo est dans le contexte racine, bar est au-dessus" /></figure><h3>3 - Les éléments ne peuvent pas être empilés au-dessus (ou en-dessous) du niveau de leur élément parent</h3><p>Lorsque le niveau d’empilement de l’élément parent est défini, ses enfants ne peuvent pas être empilés au-dessus ou en-dessous de ce niveau (par rapport au contexte d’empilement de l’élément parent).</p><p>Dans l’exemple ci-dessous, même si <code>.bar</code> a un z-index plus élevé que <code>.baz</code>, il est toujours affiché en-dessous. Cela est dû au fait que dans le contexte d’empilement 1, <code>.bar</code> ne peut pas dépasser le niveau d’empilement 1.</p><pre>.foo { z-index: 1; }
.bar { z-index: 1000; }
.baz { z-index: 2; }</pre><figure role="group"><img itemprop="url" src="https://la-cascade.io/images/stacking-context-2-compressor.png" alt="" /></figure><pre>//HTML
&lt;div class="foo"&gt;
  .foo
  &lt;div class="bar"&gt;
    .bar
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class="baz"&gt;
  .baz
&lt;/div&gt;</pre><p>et le CSS :</p><pre>body {
  background-color: rgb(230, 230, 230);
}
.foo {
  background-color: green;
  height: 300px;
  width: 500px;
  position: relative;
  z-index: 1;
}
.bar {
  background-color: blue;
  height: 200px;
  width: 200px;
  position: absolute;
  bottom: 20px;
  right: 20px;
  z-index: 1000;
}
.baz {
  background-color: red;
  height: 250px;
  width: 300px;
  position: absolute;
  top: 150px;
  left: 400px;
  z-index: 2;
}
.foo,
.bar,
.baz {
  box-sizing: border-box;
  padding: 20px;
  color: #fff;
}</pre><p>Voir également :</p><ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context">Le contexte d'empilement</a> sur MDN</li>
<li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/isolation">CSS isolation property</a></li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/comment-fonctionne-z-index</link>
      <guid>https://la-cascade.io/articles/comment-fonctionne-z-index</guid>
      <pubDate>Mon, 02 Nov 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Les bases de SVG : Groupes]]></title>
      <description><![CDATA[<p><em>Suite des bases de SVG par Dudley Storey : les groupes SVG ressemblent aux éléments div des pages web mais il existe des différences qu’il est important de bien comprendre.</em></p><div class="articleContent"><p>Les groupes — la balise <code>&lt;g&gt;</code> en SVG — ressemblent un peu aux éléments <code>&lt;div&gt;</code> de nos pages web en ce sens qu’ils permettent de contenir et de contrôler des éléments ayant une relation les uns avec les autres.</p><p>Toutefois, il existe des différences entre <code>&lt;g&gt;</code> et <code>&lt;div&gt;</code> qu’il est important de bien comprendre.</p><ul><li>De même que les éléments <code>&lt;div&gt;</code>, les éléments <code>&lt;g&gt;</code> <strong>permettent à leurs éléments descendants d’hériter de leurs styles</strong> :</li>
</ul><pre>&lt;svg viewBox="0 0 400 160"&gt;
    &lt;g fill="#33E" stroke="#000" stroke-width="10px"&gt;
        &lt;circle  cx="88" cy="80" r="62"/&gt;
        &lt;rect x="246" y="17" width="123" height="123"/&gt;
    &lt;/g&gt;
&lt;/svg&gt;</pre><p>Ce qui nous donne :</p><ul><li>De même, <strong>les transformations appliquées à des groupes sont héritées</strong> par les éléments situés à l’intérieur du groupe.</li>
<li>Cependant, contrairement aux éléments <code>&lt;div&gt;</code>, <strong>les groupes SVG ne peuvent pas être positionnés</strong>. Ils peuvent être déplacés vers une nouvelle position, <em>via</em> <code>transform</code>, mais du fait qu’ils n’ont pas d’attributs x ou y, ils ne peuvent être <em>positionnés</em> dans le document SVG. On peut contourner le problème en imbriquant les éléments <code>&lt;svg&gt;</code> à l’intérieur de groupes, puisque les éléments <code>&lt;svg&gt;</code> ont des attributs x et y. Je reviendrai là-dessus dans un article à venir.</li>
<li>Tout comme les éléments <code>&lt;div&gt;</code>, les éléments <code>&lt;g&gt;</code> peuvent avoir un attribut <code>id</code> (et également des classes, même si c’est moins courant), pour les styles ou les scripts :</li>
</ul><pre>&lt;svg viewBox="0 0 400 163"&gt;
&lt;style type="text/css"&gt;
    #svg-container {
        fill: hsl(45,80%,80%);
        stroke: rgba(0,0,0,0.3);
        stroke-width: 10px;
    }
&lt;/style&gt;
    &lt;g id="svg-container"&gt;
        &lt;circle  cx="88" cy="80" r="62"/&gt;
        &lt;rect x="246" y="17" width="123" height="123"/&gt;
    &lt;/g&gt;
&lt;/svg&gt;</pre><p>Ce qui crée :</p><p>Tout comme en CSS, les règles de présentation appliquées directement aux éléments écraseront les règles héritées de leurs éléments parents si les deux entrent en conflit.</p><ul><li>Enfin, contrairement aux éléments <code>&lt;div&gt;</code>, les éléments <code>&lt;g&gt;</code> peuvent avoir leurs propres éléments <code>&lt;title&gt;</code> (<em>titre</em>) et <code>&lt;desc&gt;</code> (<em>description</em>) imbriqués pour ajouter des informations supplémentaires et améliorer l’accessibilité.</li>
</ul><p>Attention : <a href="http://thenewcode.com/821/Adobe-Illustrator-Workflow-For-SVG-Production">Adobe Illustrator</a> et d’autres éditeurs graphiques surchargent de code leurs exports SVG en utilisant de nombreux éléments <code>&lt;g&gt;</code> souvent inutiles (et en général liés à des calques multiples). Pour éviter cela, il est conseillé de fusionner les calques <em>avant</em> de sauvegarder le fichier en format SVG. Une autre solution est d’utiliser un outil comme <a href="https://jakearchibald.github.io/svgomg/">SVGoMG</a> de <a href="https://twitter.com/jaffathecake">Jake Archibald</a> qui pourra supprimer les éléments groupes redondants lors du processus de minification.</p><p><small>Photo par <a href="https://500px.com/arken">Dina Belenko</a> reproduite avec sa permission.</small></p></div>]]></description>
      <link>https://la-cascade.io/articles/les-bases-de-svg-groupes</link>
      <guid>https://la-cascade.io/articles/les-bases-de-svg-groupes</guid>
      <pubDate>Sat, 17 Oct 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Bien utiliser l'attribut alt]]></title>
      <description><![CDATA[<p><em>Dudley Storey fait le point sur les règles à connaître concernant l'attribut alt d'alternative textuelle pour les images, indispensable pour l'accessibilité et le SEO.</em></p><div class="articleContent"><p>Le web est plus fort lorsqu’il est divers : plus il est accessible, meilleur est ce qu’il nous offre. L’attribut <code>alt</code> est un exemple déjà ancien de ce que nous pouvons faire pour améliorer l’accessibilité, mais pour bien écrire un texte alternatif pour vos images il est utile de connaître quelques règles.</p><p>Qu'est-ce que l'attribut <code>alt</code> ? c'est la <strong>représentation alternative d’une image sous forme de texte</strong>. Si une image ne se charge pas ou si elle est bloquée, la valeur de l’attribut <code>alt</code> s’affichera à la place. Les utilisateurs d’outils pour l'accessibilité pourront entendre le texte lu à haute voix ou lire sa transcription en braille. Optimiser <code>alt</code> est également utile pour le SEO, car il fait partie des informations permettant aux moteurs de recherche de déterminer le contenu d’une image et d’associer votre site aux termes de recherche.</p><p>L’attribut <code>alt</code> (souvent appelé par erreur la “balise tag”) est obligatoire pour tous les éléments <code>&lt;img&gt;</code> de votre site. La plupart du temps, la façon la plus simple de rédiger un texte alternatif est <strong>d’écrire ce que vous diriez si vous faisiez le description de l’image à quelqu’un</strong>. Par exemple la photographie en tête de cet article pourrait être décrite ainsi :</p><pre>&lt;img src="singel.jpg" alt="Crépuscule à Jordaan, Amsterdam, Hollande"&gt;</pre><p>Ou encore (et mieux) :</p><pre>&lt;img src="singel.jpg" alt="Une rangée de maisons aux fenêtres illuminées le long d’un canal à Amsterdam"&gt;</pre><p>D’une manière générale, plus le texte est descriptif, meilleur il est.</p><h3>Exceptions à alt : les logos</h3><p><strong>Si le contenu principal d’une image est un texte, les règles changent</strong>. Les images bitmap présentant un texte intégré, comme celle-ci :</p><figure role="group"><img src="https://la-cascade.io/images/festa-del-rederentore.png" alt="Festa Del Rederentore, Venezia ~ Dal 1577" /></figure><p>…devrait avoir <strong>une valeur d’attribut <code>alt</code> reflétant directement le texte de l’image</strong>.</p><pre>&lt;img src="festa-del-rederentore.png" alt="Festa Del Rederentore, Venezia ~ Dal 1577"&gt;</pre><p>La raison en est simple : la plupart des lecteurs d’écran ne savent pas bien reconnaître et traduire le texte d’une image, celui-ci est donc impénétrable à la fois pour les moteurs de recherche et pour les personnes malvoyantes. En plaçant le texte dans <code>alt</code>, vous faites la traduction pour eux.</p><p><em>NB : vous verrez souvent ce genre de balisage pauvre, Ne faites pas cela </em>:</p><pre>&lt;img src="logo.gif" alt="Logo"&gt;</pre><p>C’est aussi une excellente raison d’utiliser le <a href="https://la-cascade.io/tags/svg/">SVG</a> en ligne pour les logos. Correctement construit, un logo SVG sera un vrai texte, lisible par tous. Il est important de noter que si le texte est dispersé en plusieurs chemins SVG, sa valeur sémantique est perdue. Une solution alternative (et peut-être meilleure) est de conserver la partie graphique du logo en SVG et d’écrire le reste dans le balisage auquel on appliquera un style. Bien sûr les deux options doivent être examinées en tenant compte du temps que prendra le chargement d’une police de caractères embarquée.</p><h3>alt vide</h3><p>Il y a deux cas dans lesquels on peut laisser vide l’attribut <code>alt</code> :</p><ul><li>l’image est purement décorative, c’est à dire qu’elle n’a pas de valeur informative;</li>
<li>l’image est décrite de manière appropriée par un élément sémantique qui la suit immédiatement, généralement une légende <code>&lt;figcaption&gt;</code>.</li>
</ul><p>Si vous voulez que votre page reste valide, <code>alt</code> doit malgré tout être présent dans <code>&lt;img&gt;</code>, et pour indiquer qu’il est vide on lui donne la valeur <code>""</code> (guillemets ouvrant et fermant sans espace entre les deux).</p><pre>&lt;img src="flourish.png" alt=""&gt;</pre><p>Une autre solution en HTML5 est de laisser l’attribut <code>alt</code> sans valeur :</p><pre>&lt;img src="flourish.png" alt&gt;</pre><p>Dans certaines occasions rares, la valeur de <code>alt</code> peut être très proche du <a href="http://thenewcode.com/413/Captioning-images-in-HTML5">texte en légende (<code>&lt;figcaption&gt;</code>)</a>, dans ce cas le texte alternatif est redondant et peut être laissé vide.</p><pre>&lt;figure&gt;
        &lt;img src="rio-di-san-barnaba.jpg" alt&gt;
        &lt;figcaption&gt;Photograph down the canal of the Rio di San Barnaba, Venice&lt;/figcaption&gt;
&lt;/figure&gt;</pre><p>Les différences peuvent être subtiles : <code>alt</code> <strong>décrit</strong> une image, alors que <code>&lt;figcaption&gt;</code> <strong>intitule</strong> le contenu de l’élément <code>&lt;figure&gt;</code>. Dans la plupart des cas, les deux seront différents et devraient donc être conservés :</p><pre>&lt;figure&gt;
        &lt;img src="doge-portrait.jpg" alt="Peinture à l'huile représentant un homme âgé portant un couvre-chef et un manteau brodé"&gt;
        &lt;figcaption&gt;Portrait du Doge Leonardo Loredan par Giovanni Bellini&lt;/figcaption&gt;
&lt;/figure&gt;</pre><figure role="group"><img src="https://la-cascade.io/images/Giovanni_Bellini-_portrait_of_Doge_Leonardo_Loredan.jpeg" alt="Peinture à l'huile représentant le doge Loredan dans des vêtements formels sur un fond bleu clair. Il porte un couvre-chef typique des doges de Venise. La dignité du caractère est suggérée par la fixité, le détachement solennel par le contact non-visuel avec le spectateur." /><figcaption>Portrait du Doge Leonardo Loredan par Giovanni Bellini</figcaption></figure><h3>Ne confondez pas alt et title</h3><p>On trouve parfois des balisages qui appliquent la même valeur à <code>alt</code> et à <code>title</code>. En général, c’est une mauvaise idée. Le texte de title, qui apparaît en pop-up, est rarement vu par les utilisateurs car il faut quelques secondes avant qu’il ne surgisse, et il ne sera pas lu par les outils d’accessibilité sauf si l’élément est en focus.</p><h3>Positionnement de alt</h3><p>Les lecteurs d’écran lisent le texte de <code>alt</code> en ligne avec le reste du contenu, par conséquent il est souhaitable d’écrire le texte descriptif dans un flux contextuel, en particulier si l’image est flottée.</p><h3>Ne négligez pas les autres media</h3><p><code>alt</code> est presque exclusivement associé aux images, mais cela ne signifie pas que le texte descriptif des autres formats de media doive être négligé : les vidéos et les audios devraient par exemple utiliser <a href="http://thenewcode.com/580/Make-Online-Video-Accessible-And-Searchable-With-WebVTT">les sous-titres WebVTT</a>.</p><p><em>Photo par <a href="https://www.flickr.com/people/bcnbits">MorBCN</a>, sous licence Creative Commons</em>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/bien-utiliser-lattribut-alt</link>
      <guid>https://la-cascade.io/articles/bien-utiliser-lattribut-alt</guid>
      <pubDate>Sat, 03 Oct 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS :root, le retour aux racines]]></title>
      <description><![CDATA[<p><em>La cascade CSS est la meilleure et la pire des choses. Dans cet article limpide, Simurai donne quelques astuces simples pour réduire les problèmes de spécificité et mieux comprendre CSS.</em></p><div class="articleContent"><p>CSS est comme la langue d’Ésope, la meilleure et la pire des choses. Elle fonctionne généralement bien, mais elle présente des inconvénients qui amènent parfois certains à se demander <a href="https://css-tricks.com/the-debate-around-do-we-even-need-css-anymore/">si nous avons vraiment encore besoin de CSS</a>. Je les rejoins quelquefois — mais je pense également que la cascade n’est pas la seule responsable et que nous devons souvent nous battre contre la spécifité. Il est difficile de ne pas rencontrer de problèmes de spécificité, à peu près aussi difficile que de prononcer le mot.</p><p>Dans cet article, je vais essayer de montrer que la cascade peut être votre amie et nous allons voir quelques façons de réduire le besoin d’écraser des styles et donc de réduire les problèmes de spécificité.</p><h2>Astuce 1 :</h2><blockquote>
<p><em>Pour chaque propriété CSS que vous écrivez, essayez de la remonter aussi haut que possible vers la racine de l’arbre. En d’autres termes :</em> back to the :root.</p>
</blockquote><p>Par exemple, si notre site a une side bar et que nous voulons y insérer une petite bio. Le balisage ressemblerait à ceci :</p><pre class="language-HTML">  &lt;body&gt;
    &lt;main class=“Posts”&gt;
    &lt;aside class=“SideBar”&gt;
      &lt;nav class=“Nav”&gt;
      &lt;p class=“Bio”&gt;</pre><p>...et le CSS :</p><pre class="language-CSS">  Bio {
    font-size: .8em;
    line-height: 1.5;
    color: #888;
  }</pre><p>Ça pourrait marcher. Mais si nous regardons la <code>nav</code> qui est déjà dans la side bar, il y a des chances que certains des styles soient identiques, dans notre cas, ce serait <code>font-size</code> et <code>color</code>. Donc, retirons ces propriétés de <code>nav</code> et de <code>.Bio</code> et ajoutons-les à l’élément parent, la side bar.</p><pre class="language-CSS">  .SideBar {
    font-size: .8em;
    color: #888;
  }</pre><p>De plus, il se trouve que cette <code>line-height: 1.5;</code> est déjà définie pour nos articles. Donc, puisqu’il semble que toute la page utilise la même hauteur de ligne, retirons-la des éléments Bio et Post et remontons-la au niveau du nœud racine.</p><pre class="language-CSS">  :root {
    line-height: 1.5;
  }</pre><p>C’est du simple bon sens direz-vous, mais il est souvent tentant de styler un nouvel élément sans même regarder si les éléments frères définissent la même chose. Cela se produit également lorsqu’on fait un copier/coller de styles d’une autre section ou lorsqu’on récupère des bouts de code trouvés sur le web. La refactorisation prendra un tout petit peu plus de temps mais votre CSS sera bien plus sain.</p><figure role="group"><img src="https://la-cascade.io/images/roots-1.png" alt="image d’un arbre divisé en deux, d’un côté chaque feuille est stylée, de l’autre uniquement les branches, pour le même effet" /><figcaption>Stylez les branches, pas chaque feuille !</figcaption></figure><h2>Astuce 2 :</h2><blockquote>
<p><em>Certaines propriétés doivent être stylées de manière combinée</em>.</p>
</blockquote><p>Un bon exemple de cela est le combo <code>color</code> et <code>background-color</code>. Sauf s’il ne s’agit que d’ajustements mineurs, c’est généralement une bonne idée de les modifier ensemble. Lorsqu’on ajoute une couleur d’arrière-plan à un élément HTML, il peut ne contenir aucun texte, toutefois il est très probable qu’un élément enfant en contiendra. Par conséquent, si nous définissons les couleurs d’arrière-plan et de premier plan ensemble, nous pouvons être sûrs que nous n’aurons jamais de problèmes de lisibilité ou de contraste. De plus, si nous changeons la couleur d’arrière-plan, nous n’avons pas à faire la chasse à toutes les couleurs de texte qui doivent être modifiées, elles sont là, au même endroit.</p><figure role="group"><img src="https://la-cascade.io/images/roots-2.png" alt="" /><figcaption>Capture d’écran de <a href="http://jxnblk.com/colorable/demos/text/">Colorable</a></figcaption></figure><h2>Astuce 3 :</h2><blockquote>
<p><em>Utilisez des valeurs “dynamiques”, comme <code>currentColor</code> et <code>em</code></em>.</p>
</blockquote><p>Parfois il est plus malin d’utiliser la <code>color</code> du texte pour d’autre propriétés. Par exemple, pour <code>border</code>, pour <code>bow-shadow</code> ou pour le <code>fill</code> des icônes <a href="https://la-cascade.io/tags/svg/">SVG</a>. Au lieu de les définir directement, vous pouvez <a href="https://la-cascade.io/articles/la-premiere-variable-css-currentcolor">utiliser currentColor</a> et ce sera la même propriété <code>color</code>. Et comme <code>color</code> hérite par défaut, vous pourriez même n’avoir à le changer qu’à un seul endroit.</p><p>De la même manière, les <code>em</code> sont mappés à <code>font-size</code> et vous permettent de redimensionner ce que vous voulez, simplement en modifiant la font size de :root.</p><figure><img src="https://la-cascade.io/images/cssconf-size.gif" alt="" /></figure><h2>Astuce 4 :</h2><blockquote>
<p><em>Écrasez les styles user-agent pour qu’ils héritent de leurs parents</em>.</p>
</blockquote><p>Des contrôles de formulaires comme les boutons, ou les inputs sont stylés par le navigateur d’une certaine façon. On peut les écraser avec <code>inherit</code> pour qu’ils s’adaptent à votre style.</p><pre class="language-CSS">  button,
  input,
  select,
  textarea {
    color: inherit;
    font-family: inherit;
    font-style: inherit;
    font-weight: inherit;
  }</pre><p>L’exemple ci-dessus est repris de <a href="https://github.com/csstools/sanitize.css/">sanitize.css</a>. <a href="https://necolas.github.io/normalize.css/">normalize.css</a> fait la même chose, donc si vous avez l’un des deux, vous êtes couverts.</p><p>Vous pouvez également essayer de restyler d’autres inputs comme des curseurs, des boutons radio, des cases à cocher, etc. Et comme nous l’avons vu ci-dessus, en utilisant <code>currentColor</code> on leur donne automatiquement la propriété <code>color</code>. On peut les faire passer d’un thème lumineux à un thème sombre sans avoir rien d’autre à changer.</p><figure><img src="https://la-cascade.io/images/cssconf-color3.gif" alt="" /></figure><h2>Conclusion</h2><p>Tout cela est très cool, mais à qui est-ce que cela s’adresse ? Bien sûr, ce n’est pas adapté à toutes les situations. Je dirais que les sites web simples en seront les premiers bénéficiaires. Mais même lorsqu’on utilise un préprocesseur, ça ne fait pas de mal de réduire encore un peu la quantité de CSS produite, voire d’éviter de créer certaines variables.</p><p>Cela s’accorde bien aussi à l’approche “une classe pour chaque objectif” de <a href="http://tachyons.io/">Tachyons</a>. Cela peut aider à réduire la complexité et le nombre de classes nécessaires.</p><p>Un autre intérêt pourrait apparaître avec les propriétés personnalisés, autrement dit les variables CSS. Contrairement aux variables utilisées dans les préprocesseur, lorsqu’on écrase une propriété personnalisée cela n’affecte que la portée (<em>scope</em>) du sélecteur courant. Donc, dans un certain sens ce seront des “variables en cascade”. Mais il faut que je voie ça de plus près en pratique.</p><p>PS : il est possible que cet article ait été inspiré par <a href="https://twitter.com/kaelig/status/616902099457175552">ce tweet</a> de <a href="https://twitter.com/kaelig">Kaelig</a>.</p><p>NdT: voyez également (comme toujours) <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:root">la page MDN</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-roots-le-retour-aux-racines</link>
      <guid>https://la-cascade.io/articles/css-roots-le-retour-aux-racines</guid>
      <pubDate>Mon, 14 Sep 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[:nth-last-of-type]]></title>
      <description><![CDATA[<article><p>par <a href="https://la-cascade.io/auteurs/sara-cope">Sara Cope</a>, 10 septembre 2015, <a href="https://la-cascade.io/tags/css">css</a>, <a href="https://la-cascade.io/tags/pseudo-classes">pseudo-classes</a>, <a href="https://la-cascade.io/tags/dico">dico</a>, <a href="https://css-tricks.com/almanac/selectors/n/nth-last-of-type/">article original</a> paru le 6 septembre 2011 dans <a href="https://css-tricks.com/">CSS-Tricks</a></p></article><p><a href="https://la-cascade.io/auteurs/sara-cope">Voir la liste des articles</a> de Sara Cope traduits dans La Cascade.</p><h3 class="autresRessources">Autres ressources</h3>
<ul><li><a href="https://developer.mozilla.org/fr/docs/Web/CSS/:nth-last-of-type">:nth-last-of-type</a></li>
</ul><p><a href="https://css-tricks.com/almanac/selectors/n/nth-last-of-type/">Article original</a> paru le 6 septembre 2011 dans <a href="https://css-tricks.com/">CSS-Tricks</a>Traduit avec l'aimable autorisation de CSS-Tricks et de Sara Cope.Copyright CSS-Tricks © 2011</p>]]></description>
      <link>https://la-cascade.io/articles/nth-last-of-type</link>
      <guid>https://la-cascade.io/articles/nth-last-of-type</guid>
      <pubDate>Thu, 10 Sep 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[:nth-last-child]]></title>
      <description><![CDATA[<p>Le sélecteur <code>:nth-last-child</code> nous permet de sélectionner un ou plusieurs éléments en fonction de leur ordre d'origine, selon une formule. Il est défini dans la spécification CSS Selectors Level 3 comme une "pseudo-classe structurelle", ce qui signifie qu'il est utilisé pour styliser le contenu en fonction de sa relation avec les éléments parents et frères et sœurs. Il fonctionne de la même manière que <code>:nth-child</code>, sauf qu'il sélectionne les éléments en commençant par le bas de l'ordre de la source, et non par le haut.</p><p>Supposons que nous ayons une liste avec un nombre inconnu d'éléments et que nous souhaitions mettre en évidence l'avant-dernier élément, dans cet exemple précis, le quatrième élément ("Fourth Item") :</p><pre class="language-html">&lt;ul&gt;
  &lt;li&gt;First Item&lt;/li&gt;
  &lt;li&gt;Second Item&lt;/li&gt;
  &lt;li&gt;Third Item&lt;/li&gt;
  &lt;li&gt;Fourth Item&lt;/li&gt;
  &lt;li&gt;Fifth Item&lt;/li&gt;
&lt;/ul&gt;</pre><p>Plutôt que d'ajouter une classe à l'élément de la liste (par exemple, <code>.highlight</code>), nous pouvons utiliser <code>:nth-last-child</code> :</p><pre class="language-css">li {
  background: slategrey;
}
/* select the second-last item */
li:nth-last-child(2) {
  background: lightslategrey;
}</pre><p>Comme vous pouvez le voir, <code>:nth-last-child</code> prend un argument : il peut s'agir d'un seul nombre entier, des mots-clés "even" (pair) ou "odd" (impair), ou d'une formule. Si un nombre entier est spécifié, un seul élément est sélectionné — mais les mots-clés ou une formule vont itérer à travers tous les enfants de l'élément parent et sélectionner les éléments correspondants — ce qui est similaire à la navigation dans un tableau en JavaScript. Les mots-clés "even" et "odd" sont simples (2, 4, 6 etc. ou 1, 3, 5 respectivement). La formule est construite à l'aide de la syntaxe <code>an+b</code>, où :</p><ul><li>"a" est une valeur entière</li>
<li>"n" est la lettre "n" littérale</li>
<li>"+" est un opérateur et peut être soit "+", soit "-".</li>
<li>"b" est un nombre entier et est requis si un opérateur est inclus dans la formule</li>
</ul><p>Il est important de noter que cette formule est une équation, et itère à travers chaque élément frère, déterminant celui qui sera sélectionné. La partie "n" de la formule, si elle est incluse, représente un ensemble d'entiers positifs croissants (tout comme l'itération dans un tableau). Dans notre exemple ci-dessus, nous avons sélectionné un élément sur deux avec la formule 2n, ce qui a fonctionné car à chaque fois qu'un élément était vérifié, "n" augmentait d'une unité (2×0, 2×1, 2×2, 2×3, etc.). Si l'ordre d'un élément correspond au résultat de l'équation, il est sélectionné (2, 4, 6, etc.). Pour une explication plus approfondie des mathématiques impliquées, veuillez lire cet article.</p><p>Pour illustrer davantage, voici quelques exemples de sélecteurs :nth-last-of-type valides :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/zakkain/pen/nORPOZ">CSS-Tricks: :nth-last-child</a>de zakkain dans<a href="https://codepen.io">CodePen</a></div><p>Heureusement, vous ne devez pas toujours faire les calculs vous-même. Il existe plusieurs testeurs et générateurs de type <code>:nth-of</code> :</p><ul><li><a href="https://css-tricks.com/examples/nth-child-tester/">Testeur CSS-Tricks</a></li>
<li><a href="https://lea.verou.me/demos/nth.html">Testeur de Léa Verou</a></li>
</ul><ul><li><code>:nth-last-child</code> itère à travers les éléments en commençant par le bas de l'ordre source. La seule différence entre lui et <code>:nth-child</code> est que ce dernier parcourt les éléments en commençant par le haut de l'ordre des sources.</li>
<li>Le sélecteur <code>:nth-last-child</code> est très similaire à <code>:nth-last-of-type</code> mais avec une différence essentielle : il est moins spécifique. Dans notre exemple ci-dessus, ils produiraient le même résultat car nous n'itérons que sur les éléments <code>li</code>, mais si nous itérions sur un groupe plus complexe de frères et sœurs, <code>:nth-last-child</code> essaierait de faire correspondre tous les frères et sœurs, et pas seulement les frères et sœurs du même type d'élément. Ceci révèle la puissance de <code>:nth-last-child</code> : il peut sélectionner n'importe quel élément frère dans un arrangement, et <em>pas seulement les éléments spécifiés avant les deux points</em>.</li>
</ul>]]></description>
      <link>https://la-cascade.io/articles/nth-last-child</link>
      <guid>https://la-cascade.io/articles/nth-last-child</guid>
      <pubDate>Wed, 09 Sep 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[:nth-of-type]]></title>
      <description><![CDATA[<p>Le sélecteur <code>:nth-of-type</code> nous permet de sélectionner un ou plusieurs éléments en fonction de leur ordre d'origine, selon une formule. Il est défini dans la spécification <a href="https://www.w3.org/TR/selectors/">CSS Selectors Level 4</a> comme une "pseudo-classe structurelle", ce qui signifie qu'il est utilisé pour styliser le contenu en fonction de sa relation avec les éléments parents et frères.</p><p>Supposons que nous ayons une liste non ordonnée et que nous souhaitions "zébrer" les éléments de la liste en alternance :</p><pre class="language-html">&lt;ul&gt;
  &lt;li&gt;First Item&lt;/li&gt;
  &lt;li&gt;Second Item&lt;/li&gt;
  &lt;li&gt;Third Item&lt;/li&gt;
  &lt;li&gt;Fourth Item&lt;/li&gt;
  &lt;li&gt;Fifth Item&lt;/li&gt;
&lt;/ul&gt;</pre><p>Plutôt que d'ajouter des classes à chaque élément de la liste (par exemple <code>.even</code> (<em>pair</em>) &amp; <code>.odd</code> (<em>impair</em>)), nous pouvons utiliser <code>:nth-of-type</code> :</p><pre class="language-css">li {
  background: slategrey;
}
/* select alternating items starting with the second item */
li:nth-of-type(2n) {
  background: lightslategrey;
}</pre><p>Comme vous pouvez le voir, <code>:nth-of-type</code> prend un argument : il peut s'agir d'un seul nombre entier, des mots-clés <code>even</code> ou <code>odd</code>, ou d'une formule comme indiqué ci-dessus. Si un nombre entier est spécifié, un seul élément est sélectionné, mais les mots-clés ou une formule itéreront à travers tous les enfants de l'élément parent et sélectionneront les éléments correspondants — ce qui est similaire à la navigation dans un tableau en JavaScript. Les mots-clés <code>even</code> et <code>odd</code> sont simples, mais la formule est construite à l'aide de la syntaxe <code>an+b</code>, où :</p><ul><li>"a" est une valeur entière</li>
<li>"n" est la lettre "n" littérale</li>
<li>"+" est un opérateur et peut être soit "+", soit "-".</li>
<li>"b" est un nombre entier et est requis si un opérateur est inclus dans la formule</li>
</ul><p>Il est important de noter que cette formule est une équation, et itère à travers chaque élément frère, déterminant celui qui sera sélectionné. La partie "n" de la formule, si elle est incluse, représente un ensemble d'entiers positifs croissants (tout comme l'itération dans un tableau). Dans notre exemple ci-dessus, nous avons sélectionné un élément sur deux avec la formule 2n, ce qui a fonctionné car à chaque fois qu'un élément était vérifié, "n" augmentait d'une unité (2×0, 2×1, 2×2, 2×3, etc.). Si l'ordre d'un élément correspond au résultat de l'équation, il est sélectionné (2, 4, 6, etc.). Pour une explication plus approfondie des mathématiques impliquées, veuillez lire cet article.</p><p>Pour illustrer davantage, voici quelques exemples de sélecteurs <code>:nth-of-type</code> valides :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/zakkain/pen/AwWGpa">CSS-Tricks: :nth-of-type</a>de zakkain dans<a href="https://codepen.io">CodePen</a></div><p>Heureusement, vous ne devez pas toujours faire les calculs vous-même. Il existe plusieurs testeurs et générateurs de type <code>:nth-of</code> :</p><ul><li><a href="https://css-tricks.com/examples/nth-child-tester/">Testeur CSS-Tricks</a></li>
<li><a href="https://lea.verou.me/demos/nth.html">Testeur de Léa Verou</a></li>
</ul><ul><li><code>:nth-of-type</code> itère à travers les éléments en commençant par le haut de l'ordre des sources. La seule différence entre ce sélecteur et <code>:nth-last-of-type</code> est que ce dernier parcourt les éléments en commençant par le bas de l'ordre des sources.</li>
<li>Le sélecteur <code>:nth-of-type</code> est très similaire à <code>:nth-child</code> mais avec une différence essentielle : il est plus spécifique. Dans notre exemple ci-dessus, ils produiraient le même résultat car nous n'itérons que sur les éléments <code>li</code>, mais si nous itérions sur un groupe plus complexe de frères et sœurs, <code>:nth-child</code> essaierait de correspondre à tous les frères et sœurs, et pas seulement aux frères et sœurs du même type d'élément. Cela révèle la puissance de <code>:nth-of-type</code> : il cible un type d'élément particulier dans un arrangement <em>par rapport à des frères et sœurs similaires, et non pas tous les frères et sœurs</em>.</li>
</ul>]]></description>
      <link>https://la-cascade.io/articles/nth-of-type</link>
      <guid>https://la-cascade.io/articles/nth-of-type</guid>
      <pubDate>Mon, 07 Sep 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[:nth-child]]></title>
      <description><![CDATA[<p><em>Le sélecteur :nth-child (“n-ième enfant”) permet de sélectionner un ou plusieurs éléments en fonction de leur ordre dans la source et selon des critères que vous déterminez.</em></p><div class="articleContent"><p>Le sélecteur <code>:nth-child</code> (“n-ième enfant”) permet de sélectionner un ou plusieurs éléments en fonction de leur ordre dans la source et selon des critères que vous déterminez. La spécification W3C le range parmi les “pseudo-classes structurelles”, ce qui signifie qu'il est utilisé pour appliquer un style au contenu en fonction de ses relations avec les éléments parents et enfants.</p><p>Supposons que nous ayons une grille CSS et que nous voulions retirer la marge sur chaque quatrième module :</p><pre>//HTML
&lt;section class="grid"&gt;
  &lt;article class="module"&gt;One&lt;/article&gt;
  &lt;article class="module"&gt;Two&lt;/article&gt;
  &lt;article class="module"&gt;Three&lt;/article&gt;
  &lt;article class="module"&gt;Four&lt;/article&gt;
  &lt;article class="module"&gt;Five&lt;/article&gt;
&lt;/section&gt;</pre><p>Plutôt que d'ajouter une classe à chaque quatrième item, nous pouvons utiliser <code>:nth-child</code> :</p><pre>//CSS
.module:nth-child(4n) {
  margin-right: 0;
}</pre><p>Comme vous le voyez, <code>:nth-child</code> prend un argument (c'est le n-ième enfant, mais il faut bien préciser comment on détermine ce <em>n</em>). Cela peut être un simple chiffre, les mots-clés <code>even</code> (pair) ou <code>odd</code> (impair), ou bien une formule.</p><p>Si un chiffre est spécifié, seul <em>un</em> élément sera sélectionné, par exemple <code>:nth-child(2)</code> sélectionnerait le deuxième module dans notre HTML ci-dessus.</p><p>Si c'est un mot-clé ou une formule, une itération permettra de sélectionner le ou les éléments correspondants. Par exemple, <code>:nth-child(even)</code> sélectionnerait les modules 2 et 4. <code>:nth-child(3n+1)</code> séléctionnerait les modules 1 et 4.</p><p>Au passage, on voit ici que <code>:nth-child(even)</code> est l'équivalent de <code>:nth-child(2n)</code> et <code>:nth-child(odd)</code> est l'équivalent de <code>:nth-child(2n+1)</code> - sachant que lorsque la valeur de l'argument est inférieure ou égale à zéro, il n'y a pas de sélection. Inférieure à zéro ? Oui, car on pourrait très bien utiliser une formule du type <code>:nth-child(2n-1)</code> et pour n=0 on aurait un argument égal à -1. Dans ce cas, aucun élément ne serait sélectionné.</p><p>Pour illustrer tout ceci, voici quelques exemples de sélecteurs <code>:nth-child</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/zakkain/pen/ALiBx/">CSS-Tricks: :nth-child</a>by Zachary Kain<a href="https://codepen.io">CodePen</a></div><p><strong>À noter</strong></p><ul><li><code>:nth-child</code> procède par itération en commençant par le début de la liste. C'est la seule différence avec <code>:nth-last-child</code> qui commence par la fin de la liste.</li>
<li>le sélecteur <code>:nth-child</code> est très proche de <code>:nth-of-type</code> mais avec une différence essentielle : il est <a href="https://la-cascade.io/nth-of-type">moins spécifique</a>. Dans notre premier exemple, il donnerait le même résultat parce que nous ne faisons d'itérations que sur les éléments <code>.module</code>, mais si nous avions un groupe plus complexe, <code>:nth-child</code> essaierait de cibler <em>tous</em> les éléments frères (siblings) et non pas les éléments frères limités au même type. C'est un point important à retenir concernant la puissance de <code>:nth-child</code> : il sélectionne tous les éléments frères et non pas seulement ceux qui sont spécifiés avant les deux-points <code>:</code>. Vous pouvez consulter <a href="https://la-cascade.io/nth-of-type">l'article <code>:nth-of-type</code></a> pour plus de détails sur la différence entre les deux.</li>
</ul><p><strong>Allons plus loin sur la différence entre les deux</strong></p><p>Prenons le HTML suivant :</p><pre>//HTML
&lt;section&gt;
   &lt;p&gt;Petit&lt;/p&gt;
   &lt;p&gt;Cochon&lt;/p&gt;    &lt;!-- Celui que je veux --&gt;
&lt;/section&gt;</pre><p>Les deux CSS qui suivent parviendraient au même résultat :</p><pre>//CSS
p:nth-child(2) { color: red; }
p:nth-of-type(2) { color: red; }</pre><p>Et pourtant il y a une différence. En bon français, le sélecteur <code>:nth-child</code> nous dit de sélectionner un élément <em>si</em> :</p><ol><li>c'est un élément paragraphe</li>
<li>c'est le second enfant d'un parent (quel qu'il soit)</li>
</ol><p>Le sélecteur <code>:nth-of-type</code>, lui, dit ceci :</p><ol><li>sélectionner le second paragraphe enfant d'un parent (quel qu'il soit)</li>
</ol><p><code>:nth-of-type</code> est… comment dire… <em>moins conditionnel</em>.</p><p>Admettons que notre balisage soit maintenant :</p><pre>//HTML
&lt;section&gt;
   &lt;h1&gt;Mots&lt;/h1&gt;
   &lt;p&gt;Petit&lt;/p&gt;
   &lt;p&gt;Cochon&lt;/p&gt;    &lt;!-- Celui que je veux --&gt;
&lt;/section&gt;</pre><p>Ce CSS ne fonctionne plus :</p><pre>//CSS
p:nth-child(2) { color: red; }</pre><p>Celui-ci fonctionne encore :</p><pre>//CSS
p:nth-of-type(2) { color: red; }</pre><p>Quand je dis qu'il ne fonctionne plus, je veux dire que le sélecteur <code>:nth-child</code> sélectionne maintenant <em>Petit</em> au lieu de <em>Cochon</em>, parce que cet élément répond à la fois à la condition (1) être le deuxième enfant (de <code>&lt;section&gt;</code>) et (2) être un élément paragraphe.</p><p>Et quand je dis que le deuxième fonctionne encore, je veux dire que c'est bien <em>Cochon</em> qui est sélectionné, parce que c'est le deuxième paragraphe à l'intérieur de cet élément parent <code>&lt;section&gt;</code>.</p><p>Si nous ajoutions un <code>&lt;h2&gt;</code> après le <code>&lt;h1&gt;</code>, le sélecteur <code>:nth-child</code> ne sélectionnerait plus rien du tout parce que maintenant le deuxième enfant n'est plus un paragraphe. Le sélecteur <code>:nth-of-type</code> quant à lui fonctionnerait toujours.</p><p>Mon sentiment est que le sélecteur <code>:nth-of-type</code> est moins fragile et plus utile en règle générale, même si <code>:nth-child</code> est plus courant apparemment. Vous vous dites sans doute parfois “je veux sélectionner le second enfant d'un parent si c'est un paragraphe”, mais il y a des chances que vous vouliez plutôt “sélectionner le deuxième paragraphe” ou “sélectionner une ligne sur trois dans le tableau”, et ce sont là des cas où <code>:nth-of-type</code> (à mon avis) est un meilleur choix.</p><p>Dernière chose : je me suis rendu compte que la plupart de mes moments de “<em>mais pourquoi ce #@/$!!! de :nth-child ne marche pas ??</em>” venaient du fait que j'avais qualifié le sélecteur avec la balise. Donc lorsque j'utilise <code>:nth-child</code> je préfère en général spécifier le parent et ne pas qualifier <code>:nth-child</code> :</p><pre>//CSS
dl :nth-child(2) {  } /* est préférable à */
dd:nth-child(2) {  } /* ceci */</pre><p>Mais bien sûr, tout dépend de la situation exacte.</p><p><strong>Quelques recettes</strong></p><p>Il existe quelques "testeurs" de <code>:nth-child</code> que vous pouvez vous amuser à utiliser :</p><p><a href="http://css-tricks.com/examples/nth-child-tester/#">CSS-Tricks nth-child tester</a><br /><a href="http://lea.verou.me/demos/nth.html">Le testeur de Lea Verou</a><br /><a href="http://nth-test.com/">Nth-Test</a> de Paul Maloney</p><p>Vous pouvez tester les <strong>recettes</strong> suivantes :</p><p> Sélectionner uniquement le cinquième élément :</p><pre>//CSS
li:nth-child(5) {
    color: green;
}</pre><p> Sélectionner tous les éléments sauf les 5 premiers :</p><pre>//CSS
li:nth-child(n+6) {
    color: green;
}</pre><p> Sélectionner seulement les 5 premiers éléments :</p><pre>//CSS
li:nth-child(-n+5) {
    color: green;
}</pre><p> Sélectionner un élément sur quatre, en commençant par le premier :</p><pre>//CSS
li:nth-child(4n-7) {  /* or 4n+1 */
    color: green;
}</pre><hr /><p>Autres ressources à consulter sur ce sujet :</p><ul><li>MDN : <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:nth-child">:nth-child</a></li>
<li><a href="http://www.sitepoint.com/web-foundations/nth-childn-css-selector/">Référence SitePoint</a> (en anglais)</li>
<li><a href="http://tympanus.net/codrops/css_reference/nth-child/">CSS Reference Codrops</a> (en anglais)</li>
<li><a href="http://www.w3.org/wiki/CSS/Selectors/pseudo-classes/:nth-child">Wiki W3C</a> (en anglais)</li>
<li><a href="http://dev.w3.org/csswg/selectors3/#structural-pseudos">Spécification W3C</a> (en anglais)</li>
</ul><p>Autres articles intéressants :</p><p><strong>articles en français</strong> :</p><ul><li><a href="http://www.grafikart.fr/tutoriels/html-css/css-nth-child-168">Le sélecteur :nth-child</a>, vidéo par Grafikart</li>
</ul><p><strong>articles en anglais</strong> :</p><ul><li><a href="http://nthmaster.com/">nthmaster</a>, quelques exemples complexes d'utilisation des pseudo-classes structurelles <strong>:nth</strong></li>
<li><a href="https://css-tricks.com/useful-nth-child-recipies/">Usefil :nth-child recipes</a>, de Chris Coyier, quelques recette utiles</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/nth-child</link>
      <guid>https://la-cascade.io/articles/nth-child</guid>
      <pubDate>Sun, 06 Sep 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Motifs SVG japonais]]></title>
      <description><![CDATA[<p><em>Pour le plaisir, Dudley Storey a réalisé deux nouveaux backgrounds SVG dérivés des motifs géométriques traditionnels japonais. Un approfondissement de la série sur SVG, mine de rien, ça devient sérieux!</em></p><div class="articleContent"><p>Juste pour le plaisir (et de manière fortuite pour le <a href="http://codepen.io/collection/Dmrpwb/">week end des tuiles rétro sur CodePen</a>), j'ai réalisé deux nouveaux backgrounds SVG dérivés des motifs géométriques traditionnels japonais.</p><h2>Seigaiha</h2><p>La traduction littérale de <a href="https://www.jhinparis.com/tissusjaponaisgeometriques/k2ke5csnq9c1nwyxd48xr7gl24c3a2">seigaiha</a> est “mer bleue et vagues”. À l'origine, ce motif était utilisé dans les cartes chinoises pour représenter l'océan. Importé au Japon un peu avant le 6e siècle de notre ère, il apparaît sur des figurines funéraires <a href="https://fr.wikipedia.org/wiki/Haniwa">haniwa</a>. Il existe de nombreuses variantes du motif qui sont utilisées partout : impressions géométriques, incrustations, ou dessiné au rateau dans les jardins japonais.</p><h3>Le SVG</h3><pre>&lt;svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%"&gt;
  &lt;defs&gt;
    &lt;pattern id="waves" patternUnits="userSpaceOnUse" width="230.4" height="221.7" patternTransform="scale(.5)"&gt;
    &lt;defs&gt;
      &lt;g id="wave" stroke="#000080" fill="none"&gt;
        &lt;circle fill="#FFF" stroke-width="8" r="106.7" /&gt;
        &lt;circle stroke-width="9" r="81" /&gt;
        &lt;circle stroke-width="8" r="55.3" /&gt;
        &lt;circle stroke-width="7" r="32.5" /&gt;
        &lt;circle stroke-width="7" r="13.2" /&gt;
      &lt;/g&gt;
    &lt;/defs&gt;
    &lt;use x="229.9" y="0.7" xlink:href="#wave" /&gt;
    &lt;use x="114.9" y="55.3" xlink:href="#wave" /&gt;
    &lt;use x="-114.9" y="55.3" xlink:href="#wave" /&gt;
    &lt;use x="0" y="111.3" xlink:href="#wave" /&gt;
    &lt;use x="229.9" y="111.3" xlink:href="#wave" /&gt;
    &lt;use x="114.9" y="166.4" xlink:href="#wave" /&gt;
    &lt;use x="-114.9" y="166.4" xlink:href="#wave" /&gt;
    &lt;use x="0" y="222.2" xlink:href="#wave" /&gt;
    &lt;use x="345.1" y="166.4" xlink:href="#wave" /&gt;
    &lt;use x="229.9" y="222.2" xlink:href="#wave" /&gt;
    &lt;use x="114.9" y="277.2" xlink:href="#wave" /&gt;
    &lt;use x="-114.9" y="277.2" xlink:href="#wave" /&gt;
    &lt;use x="345.1" y="277.2" xlink:href="#wave" /&gt;
    &lt;/pattern&gt;
  &lt;/defs&gt;
 &lt;rect width="100%" height="100%" fill="url(#waves)" /&gt;
&lt;/svg&gt;</pre><p>Le balisage utilise pour l'essentiel la même idée que mon <a href="https://la-cascade.io/articles/diagonales-et-motifs-svg-en-background/">design de lignes SVG</a>, mais il va un peu plus loin : dans ce cas, j'utilise <code>defs</code> à l'intérieur de <code>defs</code> pour créer le motif initial. Ce qu'il faut retenir :</p><ol><li>Le <code>fill</code> et le <code>stroke</code> par défaut des <a href="https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses/">cercles</a> ont été déplacés dans un élément groupe pour l'efficacité.</li>
<li>Les <code>cx</code> et <code>cy</code> des cercles n'ont pas besoin d'être définis car le motif lui-même n'est jamais rendu directement ; les cercles sont supposés être centrés sur <code>0,0</code>.</li>
<li>Le plus grand cercle extérieur du motif a un background blanc, qui sert à le remplir et à créer un effet de recouvrement.</li>
<li>Le <code>use</code> du motif du cercle est disposé en couches allant du dessus vers le dessous à l'intérieur de la surface définie par les <code>width</code> et <code>height</code> du motif.</li>
<li>L'échelle du motif, et donc le nombre de fois qu'il se répète sur la page, est contrôlée par la valeur <code>scale</code> de <code>patternTransform</code>.</li>
</ol><h2>Asanoha</h2><p>Un dessin géométrique régulier tracé à partir d'un motif de feuilles de chanvre qui se recouvrent. Il est utilisé pour les kimono de tous les jours et (traditionnellement) pour les langes des bébés. On le comprend plus aisément si on le voit comme un motif d'étoile à 6 pointes, chacune étant reliée au centre de l'étoile adjacente.</p><figure role="group"><img src="https://la-cascade.io/images/asanoha-visualisation-compressor.jpeg" alt="" /><figcaption>Visualisation du motif asanoha comme des étoiles à 6 pointes qui se recouvrent les unes les autres.</figcaption></figure><h3>Le SVG</h3><p>Le motif de cet exemple consiste en un simple <a href="https://la-cascade.io/articles/les-bases-de-svg-polygones/">polygone</a> couplé à des <a href="https://la-cascade.io/articles/les-bases-de-svg-lignes-simples-et-multiples/">lignes et polylignes</a> :</p><pre>&lt;svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%"&gt;
&lt;defs&gt;
  &lt;pattern id="ashano" patternUnits="userSpaceOnUse" width="119" height="103" patternTransform="scale(1)"&gt;
  &lt;g stroke="#231F20" fill="none"&gt;
    &lt;polygon points="89.3,0 89.3,34.4 119,51.6 89.3,68.7 89.3,103.1 59.5,85.9 29.8,103.1 29.8,68.7 0,51.5 29.8,34.4 29.8,0 59.5,17.2"/&gt;
    &lt;line x1="59.5" y1="17.2" x2="59.5" y2="85.9"/&gt;
    &lt;line x1="29.8" y1="103.1" x2="89.3" y2="0"/&gt;
    &lt;line x1="29.8" y1="0" x2="89.3" y2="103.1"/&gt;
    &lt;line x1="0" y1="51.5" x2="119" y2="51.5"/&gt;
    &lt;line x1="29.8" y1="68.7" x2="89.3" y2="34.4"/&gt;
    &lt;line x1="89.3" y1="68.7" x2="29.8" y2="34.4"/&gt;
    &lt;line x1="29.8" y1="0" x2="89.3" y2="0"/&gt;
    &lt;line x1="89.3" y1="0" x2="119" y2="51.6"/&gt;
    &lt;line x1="119" y1="51.6" x2="89.3" y2="103.1"/&gt;
    &lt;line x1="89.3" y1="103.1" x2="29.8" y2="103.1"/&gt;
    &lt;polyline points="89.3,103.1 119,85.9 119,51.5"/&gt;
    &lt;line x1="89.3" y1="103.1" x2="119" y2="103.1"/&gt;
    &lt;polyline points="119,51.5 119,17.2 89.3,0"/&gt;
    &lt;line x1="89.3" y1="0" x2="119" y2="0"/&gt;
    &lt;line x1="119" y1="51.5" x2="89.3" y2="0"/&gt;
    &lt;polyline points="29.8,0.1 0,17.2 0,51.6"/&gt;
    &lt;line x1="0" y1="0" x2="29.8" y2="0.1"/&gt;
    &lt;line x1="29.8" y1="0.1" x2="0" y2="51.6"/&gt;
    &lt;polyline points="0.1,51.5 0.1,85.9 29.8,103.1"/&gt;
    &lt;line x1="0" y1="103" x2="29.8" y2="103.1"/&gt;
    &lt;line x1="0.1" y1="51.5" x2="29.8" y2="103.1"/&gt;
  &lt;/g&gt;
  &lt;/pattern&gt;
&lt;/defs&gt;
&lt;rect width="100%" height="100%" fill="url(#ashano)" /&gt;
&lt;/svg&gt;</pre><p>Dans de prochains articles j'espère passer plus de temps à recréer des motifs japonais et arabes en SVG.</p></div>]]></description>
      <link>https://la-cascade.io/articles/motifs-svg-japonais</link>
      <guid>https://la-cascade.io/articles/motifs-svg-japonais</guid>
      <pubDate>Mon, 03 Aug 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Créer de superbes diagrammes avec SVG et Blend Modes]]></title>
      <description><![CDATA[<p><em>Une nouvelle association de SVG et CSS Blend Modes pour de nouveaux effets créatifs. De quoi vous faire regretter le bureau, les graphiques et les diagrammes en camembert. Merci Dudley!</em></p><div class="articleContent"><p>Un cas intéressant d’utilisation de CSS Blend Mode est l’amélioration du design des diagrammes et des graphes.</p><h2>Diagrammes de Venn améliorés</h2><p>Prenez par exemple le diagramme de Venn classique illustrant <a href="https://en.wikipedia.org/wiki/Project_management_triangle">la règle "Fast, Cheap, Good"</a> : Le markup <a href="https://la-cascade.io/tags/svg/">SVG</a> du diagramme de base pourrait être :</p><pre class="language-xml">  &lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500"&gt;
      &lt;title&gt;Project Triangle&lt;/title&gt;
      &lt;desc&gt;Three overlapping circles, labelled "Good", "Fast" and "Cheap"&lt;/desc&gt;
      &lt;style type="text/css"&gt;
        svg {
          background: #1c1c38;
          }
        circle {
          opacity: 0.76;
          }
        text {
          font-family: Avenir Black, Avenir, sans-serif;
          font-weight: 700;
          font-size: 36px;
          }
      &lt;/style&gt;
      &lt;circle fill="#ED1F24" cx="163" cy="165" r="141" aria-labelledby="#fast" /&gt; &lt;circle fill="#55C6D9" cx="250" cy="306" r="141" aria-labelledby="#good" /&gt; &lt;circle fill="#FEE600" cx="337" cy="165" r="141" aria-labelledby="#cheap"&gt;      &lt;text x="100" y="165" id="fast"&gt;FAST&lt;/text&gt;
      &lt;text x="310" y="165" id="good"&gt;GOOD&lt;/text&gt;
      &lt;text x="190" y="340" id="cheap"&gt;CHEAP&lt;/text&gt;
  &lt;/svg&gt;</pre><p>Le résultat :</p><p>Project TriangleThree overlapping circles, labelled &amp;quot;Good&amp;quot;, &amp;quot;Fast&amp;quot; and &amp;quot;Cheap&amp;quot;FASTGOODCHEAP</p><p>Remarquez que nous aurions pu laisser l’opacité en ligne pour chacun des cercles, puisque c’est également un attribut de présentation SVG. Je les ai intégrés comme des styles pour économiser de l’espace et éviter des répétitions inutiles. J’ai utilisé <code>aria-labelledby</code> pour l’accessibilité afin d’associer chaque cercle avec le texte approprié.</p><p>C’est un bon début, mais nous pouvons améliorer l’apparence du diagramme en ajoutant <code>mix-blend-mode</code> aux éléments <code>circle</code> :</p><pre class="language-css">circle {
  opacity: 0.76;
  mix-blend-mode: color-dodge;
}</pre><p>Ce qui nous donne :</p><figure role="group"><img src="https://la-cascade.io/images/venn.svg" alt="diagramme amélioré" /></figure><p> <em>Nota Bene</em> : pour parvenir au résultat espéré, les éléments auxquels on applique <code>mix-blend-mode</code> <em>ne doivent pas être</em> sur un fond blanc ou noir purs. C’est une bonne règle pour tester vos blend modes en général.\n\nTout comme <code>opacity</code>, nous aurions pu appliquer la version SVG native de <code>blend-mode</code>, les filtres <code>&lt;feBlend&gt;</code>. Comme beaucoup d’aspects récents de CSS, les blend modes ont leurs racines dans la syntaxe SVG. J’ai utilisé la version CSS dans la mesure où il s’agit d’une <em>amélioration</em> de la présentation, et non une obligation, et la syntaxe CSS est plus simple à écrire et à utiliser.</p><h2>Graphiques à barres améliorés</h2><p>Comme dans mon article sur les <a href="http://thenewcode.com/1032/Easy-Cross-Browser-Text-Masks-with-Blend-Modes">textes avec effets blend modes</a>, nous pouvons utiliser les blend modes pour donner un background aux barres verticales d’un diagramme en barres. Pour cet exemple, j’ai laissé de côté les aspects liés à l’accessibilité ainsi que les légendes, pour plus de clarté. L’effet principal ici est obtenu par le fait que le SVG qui contient le diagramme en barres est lui-même inclus dans une div qui a une image de background :</p><pre class="language-css">div {
  background-image: url(new-york-city-skyline.jpg);
  background-size: cover;
  font-size: 0;
}
svg {
  background: #fff;
  mix-blend-mode: lighten;
}
rect {
  fill: #202020;
  width: 42.4px;
}</pre><p>Nous pourrions donner un aspect plus propre à l’effet en redimensionnant l’image de background. Telles quelles, les axes des abscisses et des ordonnées prennent également l’effet. Une autre manière de faire serait d’entourer les rectangles représentant les barres avec des <a href="http://thenewcode.com/1007/Combining-CSS-clip-path-and-Shapes-for-New-Layout-Possibilities">éléments clip-path</a>, ce qui fonctionnerait assez comme notre effet blend-mode.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/dudleystorey/pen/eNQbjz/">Better SVG Diagrams &amp; Graphs with Blend Modes</a>de Dudley Storey dans<a href="https://codepen.io">CodePen</a></div><p><em>(Photo par <a href="https://www.flickr.com/photos/jliba/8067975235">Josh Liba</a>, sous licence <a href="https://creativecommons.org/licenses/by-nc-nd/2.0/">CC-BY-NC-ND 2.0</a>)</em></p></div>]]></description>
      <link>https://la-cascade.io/articles/creer-de-superbes-diagrammes-avec-svg-et-blend-modes</link>
      <guid>https://la-cascade.io/articles/creer-de-superbes-diagrammes-avec-svg-et-blend-modes</guid>
      <pubDate>Thu, 30 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Backgrounds Pop-Art avec SVG et Blend Modes]]></title>
      <description><![CDATA[<p><em>Dudley Storey nous a appris à dessiner avec SVG. Ces lignes peuvent devenir complexes, on peut les mélanger à des images via Blend Modes pour créer des backgrounds “pop art</em></p><div class="articleContent"><p><a href="https://la-cascade.io/articles/backgrounds-svg-les-rayures/">Dans un précédent article</a>, j’ai présenté l’utilisation de <a href="https://la-cascade.io/tags/svg/">SVG</a> dans des backgrounds “carrelés”. Ces simples lignes et rayures peuvent devenir des formes complexes, et on peut les mélanger à des images bitmap via CSS Blend Modes pour créer des backgrounds “pop art”. Ces techniques permettent de créer des effets visuels plus riches avec un code plus simple et plus de flexibilité que <a href="http://thenewcode.com/307/Pop-Art-Web-Page-Backgrounds-Via-CSS3-Gradients-Merged-With-Images">mon essai précédent</a> qui faisait appel aux dégradés CSS.</p><h2>Motif en échiquier</h2><p>Pour créer un échiquier avec SVG, il suffit d’utiliser deux <a href="https://la-cascade.io/les-bases-de-svg-rectangles-et-carres/">éléments carrés</a> disposés diagonalement :</p><pre class="language-xml">&lt;svg xmlns="http://www.w3.org/2000/svg" width="50" height="50"&gt;
  &lt;g fill="#ccc"&gt;
    &lt;rect width="25" height="25" /&gt;
    &lt;rect x="25" y="25" width="25" height="25" /&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><p>Ce qui produit :</p><br />Appliqué par-dessus une image bitmap :<pre class="language-css">section#grid {
  background-image: url(checkerboard.svg), url(grace-kelly.jpg);
  background-size: 100px 100px, cover;
  background-blend-mode: overlay;
}</pre><p>Cela nous donne ce bel effet :</p><p>L’image bitmap est dimensionnée pour couvrir la surface de l’élément. Le motif en échiquier se répète tous les 100px à la fois horizontalement et verticalement. Mais plutôt que de recouvrir l’image, il se mélange avec elle dans le mode <code>overlay</code> ( <em>NdT : en fait ici dans le mode <code>multiply</code> qui est plus doux</em>.)</p><h2>Motif à pois</h2><p>La même idée peut être utilisée pour recouvrir une image d’un motif à pois, à l’aide de cinq <a href="https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses/">cercles SVG</a> : un au centre exact de la <a href="https://la-cascade.io/articles/comprendre-svg-viewbox/">viewbox</a> et les quatre autres ayant leur centre à chaque coin.</p><pre class="language-xml">&lt;svg xmlns="http://www.w3.org/2000/svg" width="300" height="300"&gt;
&lt;style type="text/css"&gt;
  circle { fill: #f99; }
&lt;/style&gt;
&lt;circle cx="0" cy="0" r="100"/&gt;
&lt;circle cx="300" cy="0" r="100"/&gt;
&lt;circle cx="0" cy="300" r="100" /&gt;
&lt;circle cx="300" cy="300" r="100"/&gt;
&lt;circle cx="150" cy="150" r="100"/&gt;&lt;/svg&gt;</pre><p>Ce qui crée ce pattern :</p><p>On sauvegarde ce code comme <code>circle-grid.svg</code> et on applique le SVG sur l’image bitmap dans le background de l’élément :</p><pre class="language-CSS">section#circles {
  background-image: url(kelly-brook-as-gilda.jpg), url(circle-grid.svg);
  background-size: cover, 100px 100px;
  background-blend-mode: multiply;
  }</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/dudleystorey/pen/PqQmxM/">Pop Art Backgrounds with SVG &amp; Blend Modes</a>de Dudley Storey dans<a href="https://codepen.io">CodePen</a></div><h2>Conclusion</h2><p>J’espère que cela vous a donné une idée de la façon dont vous pouvez mettre en œuvre vos propres idées. Il y a bien d’autres possibilités de designs de ce genre, nous les verrons dans de futurs articles.</p></div>]]></description>
      <link>https://la-cascade.io/articles/backgrounds-pop-art-avec-svg-et-blend-modes</link>
      <guid>https://la-cascade.io/articles/backgrounds-pop-art-avec-svg-et-blend-modes</guid>
      <pubDate>Wed, 22 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Backgrounds SVG : les rayures]]></title>
      <description><![CDATA[<p><em>Dans la continuité des articles sur les bases de SVG, Dudley Storey commence une série sur les motifs et les backgrounds. SVG permet de réaliser des choses impossibles en CSS.</em></p><div class="articleContent"><p>Indépendantes de la résolution, légères, faciles à éditer, les images vectorielles ont de nombreux avantages sur les <a href="https://la-cascade.io/articles/les-degrades-css/">dégradés css</a> :</p><ol><li>La syntaxe SVG pour les rayures est plus simple et moins verbeuse que celle des dégradés CSS.</li>
<li>Les backgrounds SVG sont mieux supportés par les navigateurs (SVG est compatible avec IE9 mais les dégradés CSS ne sont supportés qu’à partir de IE10).</li>
<li>On peut réaliser des backgrounds bien plus complexes avec SVG qu’avec CSS.</li>
</ol><p>Mais pour être efficaces, les illustrations vectorielles doivent suivre quelques règles :</p><h2>Règles générales</h2><ul><li>Tout comme les <a href="http://thenewcode.com/991/Cross-Fading-Background-Images">backgrounds répétés en bitmap</a>, vous avez seulement besoin d’une “tuile” ou d’un “carreau” pour réaliser un carrelage. Un seul <code>&lt;pattern&gt;</code> suffit pour construire l’ensemble.</li>
<li>Votre fichier SVG doit être aussi petit, “léger” et éditable que possible : cela impliquera un peu de travail manuel.</li>
<li>En général, il est bon de garder au moins une composante couleur de votre background dans votre CSS, pour une meilleure flexibilité.</li>
</ul><p>Nous allons commencer par quelques exemples. Remarquez bien que je me suis concentré sur les backgrounds répétés, les backgrounds simples en SVG sont traités à peu près de la même façon que leurs équivalents en bitmap.</p><h2>Rayures simples en SVG</h2><p>Un effet de “rayures” simple n’est rien d’autre qu’une surface remplie à côté d’une surface vide, le tout répété à l’infini. Dans le cas de SVG, la manière la plus simple de réaliser cette surface pleine est d’utiliser <a href="https://la-cascade.io/articles/les-bases-de-svg-rectangles-et-carres/">un élément rectangle</a>. Sauvegardez le code suivant dans un fichier <code>stripe.svg</code> :</p><pre>&lt;svg viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg"&gt; &lt;rect width="0.5" height="1" /&gt; &lt;/svg&gt;</pre><p>Remarquez que <code>viewBox</code> <strong>ou</strong> les attributs équivalents <code>width</code> et <code>height</code> peuvent être utilisés pour dimensionner l’élément <code>&lt;svg&gt;</code> lorsqu’on crée des images de background.</p><p>Ce fichier SVG peut être appliqué au background d’une page web via :</p><pre>//CSS
body { background-image: url(stripe.svg); }</pre><p>Par défaut, le SVG s’étendra pour couvrir la surface entière de l’élément. Il en résultera une division de la page, moitié noire (le remplissage par défaut du rectangle SVG) et moitié blanche (la couleur de background par défaut de la page web, puisque toute surface non explicitement colorée en SVG est automatiquement transparente).</p><p>Pour que ce motif SVG se répète plus d’une fois, nous pouvons modifier la <code>background-size</code> dans notre déclaration CSS : une largeur x suivie d’une hauteur y.</p><pre> //CSS
body {
  background-image: url(stripe.svg);
  background-size: 20px 20px;
}</pre><p>Ce qui donne :</p><figure role="group"><img src="https://la-cascade.io/images/bw-vertical-stripes.png" alt="rayures verticales noires et blanches" /></figure><p>Un aspect sympa et pratique de cette concision de notre illustration SVG c’est qu’elle est très simple à modifier. par exemple, pour la transformer de verticale en horizontale, il suffit de modifier <code>background-size</code> :</p><p>Rayures horizontales : <code>body { background-size: 1px 10px; }</code><br />Rayures verticales : <code>body { background-size: 10px 1px; }</code></p><p>Pour plus de versatilité, vous pouvez colorer les rayures grâce à <code>rgba</code> ou <a href="https://la-cascade.io/articles/utiliser-hsl-pour-vos-couleurs/">HSL</a> et renvoyer la question du <code>background-color</code> de la page à CSS :</p><pre>&lt;svg viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg"&gt;
  &lt;rect width="0.5" height="1" fill="hsla(32, 42%, 50%, .5)" /&gt;
&lt;/svg&gt;</pre><p>Le CSS :</p><pre>body {
  background-image: url(stripe.svg);
  background-size: 20px 20px;
  background-color: #669;
}</pre><p>Ce fichier SVG est suffisamment petit pour être inséré en ligne dans le CSS lui-même, ce qui évite une requête HTTP :</p><pre>body {
  background-image: url(’data:image/svg+xml;utf8,&lt;svg viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;rect width="0.5" height="1" fill="hsla(32, 42%, 50%, .5)" /&gt;&lt;/svg&gt;’);
  background-size: 20px 20px;
}</pre><p>Faites bien attention aux guillemets ! Ce SVG utilise des doubles guillemets en interne, ce qui signifie que nous devons utiliser des guillemets simples à l’extérieur pour éviter que notre navigateur s’embrouille.</p><p>Vous pouvez également encoder le fichier SVG en base64 et utiliser ce code dans le CSS :</p><pre>body { background-image: url(’data:image/svg+xml;base64,
PHN2ZyB2aWV3Qm94PSIwIDAgMiAxIiB4bWxucz0iaHR0cDovL3d3dy53
My5vcmcvMjAwMC9zdmciIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5Z
TWluIG1lZXQiPjxyZWN0IHdpZHRoPSIxIiBoZWlnaHQ9IjIiIGZpbGw
9ImhzbGEoMzIsIDQyJSwgNTAlLCAuNSkiIC8+PC9zdmc+’); }</pre><p>C’est évidemment une option, mais elle présente trois désavantages :</p><ul><li>La version Data URI occupe plus d’espace que la version SVG en ligne.</li>
<li>Le fait de convertir l’image en base64 la rend non éditable. Pour faire un changement, il vous faudra retrouver le fichier SVG original, le modifier, le convertir en base64 et l’ajouter à votre CSS.</li>
<li>le désencodage de base64 est plus lent sur les plateformes mobiles.</li>
</ul><p>Toutefois, l’utilisation de base64 vous donne un peu plus de compatibilité navigateurs. Au final, c’est à vous de décider.</p><h2>Séparer les lignes</h2>Il est facile de rendre les lignes plus fines ou plus épaisses dans notre exemple, via `background-size`, mais une chose que cela ne changera pas c’est le *ratio* entre l’épaisseur des lignes et l’espace alentour. Pour changer cela, nous retournons à notre SVG et nous rendons notre rectangle plus large ou plus étroit :<pre>&lt;svg viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg"&gt;
  &lt;rect width=".25" height="1" /&gt;
&lt;/svg&gt;</pre><p>Ce qui produit :</p><figure role="group"><img src="https://la-cascade.io/images/yv-vertical-stripes.png" alt="rayures fines jaunes sur fond violet" /></figure><h2>Réaliser des motifs plus complexes</h2><p>Une fois les bases intégrées, il est aisé de réaliser des variations plus complexes de rayures horizontales et verticales en SVG. Par exemple, un motif guingan (Vichy) serait réalisé via un rectangle de ⅓ de large recouvrant un élément de ⅓ de hauteur.</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"&gt;
  &lt;g fill="rgba(0,0,0,0.3)"&gt;
    &lt;rect width="100" height="33" /&gt;
    &lt;rect width="33" height="100" x="67" /&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><p>Les mêmes concepts peuvent être utilisés pour créer des plaids et des tartans, mais les plus complexes d’entre eux devraient plutôt utiliser la syntaxe <code>&lt;pattern&gt;</code> de SVG que nous pouvons retrouver dans l’article <a href="https://la-cascade.io/articles/diagonales-et-motifs-svg-en-background/">Diagonales et motifs SVG en background</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/backgrounds-svg-les-rayures</link>
      <guid>https://la-cascade.io/articles/backgrounds-svg-les-rayures</guid>
      <pubDate>Tue, 21 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Diagonales et motifs SVG en background]]></title>
      <description><![CDATA[<p><em>Lorsque nous comprenons les bases des motifs SVG, c'est un monde de créativité qui s'ouvre. Après les bases de SVG, Dudley Storey nous montre comment créer des backgrounds en SVG.</em></p><div class="articleContent"><p>Quand on se lance dans un design de background avec motifs en diagonale, on utilise habituellement nos connaissances en trigonométrie (pour des motifs (<em>patterns</em>) qui se répètent à l’intérieur d’un carré et se suivent sans rupture) ou bien des dégradés linéaires CSS. Ces deux méthodes ont leurs limites et leurs complications, que résout le pattern SVG.</p><h2>Tuiles SVG</h2><p>Un motif SVG est exactement ce que son nom indique : une surface qui comporte des informations de tracé, lesquelles sont ensuite reprises sur une surface plus large — un peu comme un carrelage à partir d’un carreau.</p><p>Dans la plupart des cas, il est plus facile de dessiner le motif <em>d’abord</em>, c’est à dire de créer de SVG de l’intérieur. Le template de base est le suivant :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"&gt;
  &lt;defs&gt;
    &lt;pattern id="pinstripe" patternUnits="userSpaceOnUse" width="50" height="50"&gt;
      &lt;line x1="25" y1="0" x2="25" y2="50" stroke="goldenrod" stroke-width="25" /&gt;
    &lt;/pattern&gt;
  &lt;/defs&gt;
&lt;/svg&gt;</pre><p>Plusieurs choses sont à noter ici :</p><ol><li>Le SVG ne comporte pas de <code>viewBox</code> mais utilise <code>width</code> et <code>height</code> à la place, les deux attributs ayant pour valeur 100%.</li>
<li>Le <code>&lt;pattern&gt;</code> a ses <em>propres</em> <code>width</code> et <code>height</code>. Le <code>patternUnits="userSpaceOnUse"</code> signifie que ces limites sont utilisées <em>à l’intérieur du motif</em> lui-même : elles deviennent les limites du monde occupé par le motif.</li>
<li>Le <code>&lt;pattern&gt;</code> est défini à l’intérieur d’un élément <code>&lt;defs&gt;</code> et il faut se rappeler que les <code>&lt;defs&gt;</code> ne sont pas affichés tant qu’ils ne sont pas référencés. C’est pourquoi il peut être préférable de dessiner votre motif SVG dans un autre document, comme un dessin vectoriel normal, idéalement à l’intérieur d’une <a href="https://la-cascade.io/articles/comprendre-svg-viewbox/">viewBox</a> de mêmes dimensions que le pattern (50 × 50 dans notre cas), ce qui vous permet de visualiser les composants du motif — et de les modifier le cas échéant — avant de les placer à l’intérieur du contexte du <code>&lt;pattern&gt;</code> lui-même.</li>
<li>Dans notre exemple, le motif est constitué d’une ligne verticale qui occupe exactement la moitié de la surface du motif.</li>
</ol><p>Nous n’avons pas tout à fait terminé. Pour voir le résultat, notre motif doit être utilisé pour remplir un élément SVG. Un rectangle est ce qui paraît le plus logique :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"&gt;
  &lt;defs&gt;
    &lt;pattern id="pinstripe" patternUnits="userSpaceOnUse" width="50" height="50"&gt;
      &lt;line x1="25" y1="0" x2="25" y2="50" stroke="goldenrod" stroke-width="25" /&gt;
    &lt;/pattern&gt;
  &lt;/defs&gt;
  &lt;rect width="100%" height="100%" fill="url(#pinstripe)" /&gt;
&lt;/svg&gt;</pre><p>Le <code>&lt;rect&gt;</code> occupe tout l’espace du SVG. Peu importe qu’il soit déclaré avant ou après l’élément <code>&lt;defs&gt;</code> : le <code>fill</code> trouvera l’<code>id</code> du motif de toute façon :</p><p>Sauvegardé sous le nom <code>pinstripe.svg</code>, le résultat est appliqué comme image de background à une page HTML, de la même façon qu’habituellement :</p><pre>body { background-color: darkblue; background-image: url(’pinstripe.svg’); }</pre><p>Le motif se reproduit sur toute la page. Arrivé ici, vous pourriez vous dire “eh, mais on peut faire la même chose avec moins de markup” et en effet c’est que nous avons vu dans l’article sur <a href="https://la-cascade.io/articles/backgrounds-svg-les-rayures/">Backgrounds SVG : les rayures</a>. Mais c’est ici que ça devient intéressant. Du fait que <code>&lt;pattern&gt;</code> est un petit monde en soi, nous pouvons faire ce que nous voulons avec lui et voir ces changements appliqués dans le contexte plus large de la page. Revenons à <code>pinstripes.svg</code> et modifions la balise <code>&lt;pattern&gt;</code> :</p><pre>&lt;pattern id="pinstripe" patternTransform="rotate(45)" patternUnits="userSpaceOnUse" width="50" height="50"&gt;</pre><p>Sauvegardons le fichier, on rafraîchit la page HTML et on voit maintenant que notre motif de background est à 45°, sans que nous ayons besoin de rien faire d’autre.</p><p>La rotation peut prendre n’importe quelle valeur avec le même résultat :</p><pre>&lt;pattern id="pinstripe" patternTransform="rotate(33)" patternUnits="userSpaceOnUse" width="50" height="50"&gt;</pre><p>Là encore, le tuilage est parfait. Vous voulez des lignes plus fines ? Il suffit de diminuer le <code>stroke-width</code> sur l’élément <code>line</code>. Moins de lignes sur la page ? Ajoutez une déclaration <code>background-size</code> à votre CSS.</p><p>Voyez aussi <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternTransform">patternTransform</a> dans MDN.</p><h2>Conclusion</h2><p>Lorsque nous comprenons les bases des motifs SVG, c’est un monde de créativité qui s’ouvre : dans vos backgrounds, vous pouvez superposer des motifs multiples, créer des tuilages parfait à partir de formes vectorielles. J’en montrerai quelques-uns dans les prochains articles.</p><p><em>Tous mes remerciements à <a href="https://twitter.com/AmeliasBrain">Amelia Bellamy-Royds</a> qui a attiré mon attention sur cette technique et dont j’ai eu plaisir à lire et critiquer les livres récemment. C’est dans ses ouvrages que j’ai trouvé l’inspiration pour cet article</em>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/diagonales-et-motifs-svg-en-background</link>
      <guid>https://la-cascade.io/articles/diagonales-et-motifs-svg-en-background</guid>
      <pubDate>Mon, 20 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Pourquoi height: 100% ne marche pas]]></title>
      <description><![CDATA[<p><em>Le blog que Maujor consacre à CSS depuis 2006 est bien connu au Brésil pour ses articles spécialisés ou de vulgarisation. Celui-ci fait le point sur le problème height:100%.</em></p><div class="articleContent"><p>Une des déclarations CSS championnes des réclamations chez les débutants (et même chez ceux qui ont déjà une bonne pratique de CSS) est la déclaration <code>height: 100%;</code>. Il est courant de trouver sur les forums de discussion des questions ou remarques du genre :</p><blockquote>
<p>J’ai déjà déclaré <code>height: 100%</code> dans mon CSS et cette <code>div</code> ne s’étire pas verticalement comme on pouvait l’espérer, un conseil ?</p>
</blockquote><p>ou des réponses du genre :</p><blockquote>
<p>Déclare <code>height: 100%</code> et ta div sera responsive dans le sens vertical</p>
</blockquote><p>Le problème ne vient pas du fonctionnement de la propriété, car elle a été créée pour étirer la hauteur d’une boîte de 100%, exactement en effet <em>comme on pouvait l’espérer</em>. Alors, où est le problème ? Eh bien en fait il n’y a pas de problème, ce qu’il faut c’est <em>bien comprendre comment fonctionne la propriété</em> <code>height</code>.</p><p>Une mesure CSS (comme n’importe quelle mesure) exprimée en pourcentage est une mesure relative, elle doit donc être rapportée à autre chose.</p><h2>Width: 100%</h2><p>Dans le modèle de boîte CSS, la boîte a une largeur (<em>width</em>) initiale définie comme égale à <code>auto</code> qui par défaut est considérée comme couvrant toute la largeur du viewport. Si l’utilisateur redimensionne la fenêtre du navigateur, il modifie de manière dynamique la largeur du viewport et par conséquent la largeur <code>auto</code> de la boîte pour lui donner la valeur actuelle du viewport.</p><p>La largeur à laquelle se réfère le navigateur pour calculer celle, exprimée en pourcentage, d’une boîte est la largeur de son élément parent. Ainsi, une boîte ayant une largeur <code>width: 50%</code> qui est enfant d’un container de largeur égale à 200px aura une largeur de 50% de 200px, c’est à dire 100px. Élémentaire.</p><p>Et si la largeur de l’élément parent n’est pas définie, comment s’effectue le calcul ?</p><p>Eh bien dans ce cas, elle est par défaut considérée comme <code>auto</code>.</p><p>Et s’il n’y a pas d’élément parent ayant une largeur définie ?</p><p>Dans ce cas, on considère implicitement que la largeur de tous les éléments parents est <code>auto</code>, en d’autres termes la largeur est calculée par rapport à celle du viewport, comme nous venons de le voir. Dans ces conditions, une boîte ayant une largeur de 25% occupera toujours 1/4 de la largeur du viewport. Si l’utilisateur redimensionne la fenêtre du navigateur, la largeur s’ajuste automatiquement.</p><h2>Height: 100%</h2><p>Dans le modèle de boîte CSS, une boîte a une hauteur initiale définie comme <code>auto</code> mais, contrairement à width, <strong>cette valeur par défaut n’est pas égale à la hauteur du viewport</strong>. Pour la propriété <code>height</code>, la valeur <code>auto</code> par défaut est celle qui permet de faire rentrer le contenu verticalement dans la boîte — et elle dépend d’autres facteurs, comme par exemple la largeur de la boîte.</p><p>Pour le calcul de la hauteur exprimée en pourcentage, la référence est la hauteur de l’élément parent. Ainsi, une boîte de hauteur <code>height: 50%</code> qui est l’enfant d’une boîte de hauteur égale à 200px aura une hauteur de 50% de 200px, soit 100px. Élémentaire à nouveau.</p><p>Et si la hauteur de l’élément parent n’est pas définie ? Comment se fait le calcul ?</p><p>Dans ce cas, il est implicite que la hauteur de l’élément parent est <code>auto</code> (indéfini) et n’importe quel pourcentage d’<em>indéfini</em> donnera <em>indéfini</em>.</p><p>La déclaration CSS n’est donc pas appliquée, et ce qui détermine la hauteur est alors <em>le contenu</em>. Voilà pourquoi <code>height: 100%</code> ne fonctionne pas.</p><h2>Faire fonctionner height: 100%</h2><p>Reprenons ce que nous venons d’exposer et n’oublions pas que les éléments <code>html</code> et <code>body</code> sont les ancêtres les plus distants de n’importe quel élément de notre document.</p><p>Dans toute structure HTML, lorsque nous définissons la hauteur d’un élément en pourcentage il est nécessaire que son élément parent ait une hauteur définie. Si cette hauteur est définie de manière absolue, on calcule le pourcentage sur la valeur en question et c’est bon.</p><p>Si par contre la hauteur de l’élément parent est définie en pourcentage, il faut alors examiner la définition de la hauteur de l’ancêtre (l’élément parent de l’élément parent) et répéter le processus jusqu’à arriver à l’élément racine <code>html</code>.</p><p>Si dans cette chaîne d’ancêtres l’un n’a pas de hauteur définie, les définitions de hauteur en pourcentage pour tous ses descendants ne sont pas prises en compte, puisque comme nous l’avons vu ne pas définir de hauteur revient à donner la valeur <code>auto</code> (qui est indéfinie).</p><h2>Exemples</h2><p>Pour démontrer le fonctionnement de la déclaration <code>height: 100%</code> j’ai créé ces quelques démos.</p><p>Les démos montrent un élément <code>div</code> ayant une classe de <code>um</code> (“un” en portugais) et son contenu : un petit texte et le code correspondant à la démo. Nous souhaitons que la div prenne toute la hauteur de la page.</p><p>La première tentative consiste simplement à déclarer la règle de style :</p><pre>.um { height: 100%; }</pre><p>Cela ne va pas fonctionner car l’élément parent de <code>div.um</code> (<code>body</code>) n’a pas de hauteur déclarée. Voir <a href="http://maujor.com/blog/pg_apoio/height100/exemplo1.html">la démo 1</a>.</p><p>Pour que cela fonctionne, nous devons déclarer la hauteur de <strong>tous</strong> les éléments ancêtres de <code>div.um</code>. Ce sont <code>body</code> et <code>html</code>. Voir <a href="http://maujor.com/blog/pg_apoio/height100/exemplo2.html">la démo 2</a>.</p><p>Vous aurez peut-être la tentation de déclarer <code>* { height: 100%; }</code> dans l’espoir de normer les hauteurs. Ou encore de déclarer <code>height: 100%;</code> pour tous les éléments d’une partie du DOM où vous aurez besoin de cette extension. Attention : procéder de la sorte peut résulter en une belle confusion dans votre mise en page.</p><p>Si un élément sur lequel vous déclarez <code>height: 100%</code> comporte des marges ou du padding verticaux, des barres de défilement apparaîtront dans le rendu final car le calcul du pourcentage est effectué avant ajout des marges et/ou padding. Voir <a href="http://maujor.com/blog/pg_apoio/height100/exemplo3.html">la démo 3</a> (observez la barre de défilement)</p><p>Pour éliminer les barres de défilement, nous devons soustraire la valeur des marges et/ou padding verticaux de nos 100%. Si ces espacements sont eux-mêmes définis en pourcentages, c’est simple, il suffit de les déduire de nos 100%, sinon utilisez la fonction <code>calc()</code> de CSS. Voir <a href="http://maujor.com/blog/pg_apoio/height100/exemplo4.html">la démo 4</a>.</p><p>NB : on peut également utiliser la propriété <a href="https://la-cascade.io/articles/controler-le-modele-de-boite/">box-sizing</a> à la place de la fonction <code>calc()</code>.</p><p>NdT : Voir également cet article interactif génial (en anglais) : <a href="https://2019.wattenberger.com/blog/css-percents">What does 100% mean in CSS?</a></p><h3>Conclusion</h3><p>Pour faire fonctionner <code>height: 100%</code> il suffit de déclarer explicitement la valeur de hauteur de tous les éléments ancêtres. La difficulté est de savoir quelles implications cela peut avoir sur le reste de la mise en page.</p><p>Par conséquent, la déclaration <code>height: 100%</code> est finalement d’usage restreint, et n’est certainement pas la solution à tous nos problèmes de hauteur.</p><p>Tout n’est pas perdu cependant, <a href="https://la-cascade.io/tags/flexbox/">Flexbox</a> est là ! Parmi les fonctionnalités de cette nouvelle spécification, celles qui permettent un plus grand contrôle des dimensions de nos boîtes, sans dépendre des éléments liés dans le markup, sont particulièrement intéressantes.</p><p><strong>Mise à jour</strong> du 24 juillet 2015, via <a href="https://twitter.com/johnnybegood_21">jon begood</a> : la spécification du W3C <a href="http://www.w3.org/TR/css3-values/#viewport-relative-lengths">CSS Values and Units Module Level 3</a> est actuellement dans la phase de candidate à recommandation. Parmi les fonctionnalités proposées, on trouve les unités de mesure dont la valeur est un pourcentage de la largeur ou de la hauteur du viewport (unités ‘vw’, ‘vh’, ‘vmin’, ‘vmax’). Cette unité de mesure est <a href="http://caniuse.com/#feat=viewport-units">bien supportée par les navigateurs actuels</a>, voir l'<a href="http://maujor.com/blog/pg_apoio/height100/exemplo5.html">exemple 5</a>.</p><p> <em>NdT : un bel exemple de</em> cascade de la connaissance : <em>un article brésilien traduit en français, mis à jour par un lecteur français. Merci Johnny B Good !</em></p></div>]]></description>
      <link>https://la-cascade.io/articles/pourquoi-height-100-ne-marche-pas</link>
      <guid>https://la-cascade.io/articles/pourquoi-height-100-ne-marche-pas</guid>
      <pubDate>Sun, 19 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Mécanique des polices de caractères, 2]]></title>
      <description><![CDATA[<p><em>Deuxième article de la brillante série de Tobias Frere-Jones. Après les questions de dimensions, Tobias aborde celles de l’épaisseur du trait et des graisses.</em></p><div class="articleContent"><p>Dans l’<a href="https://la-cascade.io/articles/fonctionnement-des-polices-de-caracteres-1/">article précédent</a>, nous avons vu avec surprise à quel point il était difficile de retrouver une équivalence visuelle entre dimensions et alignements. Notre prochain défi — qui lui non plus ne semble pas en être un au départ — est de gérer les <a href="http://fr.wikipedia.org/wiki/Graisse_%28typographie%29">graisses</a> différentes, à la fois au niveau d’une lettre et au niveau d’un groupe de lettres.</p><p>Imaginons que nous voulions dessiner quelque chose de simple : une police de caractères sans <a href="http://fr.wikipedia.org/wiki/Empattement_%28typographie%29">empattement</a> (<em>sans serif</em>) avec une graisse identique dans tous les cas de figure. Nous choisissons les dimensions et nous commençons à construire les formes.</p><figure role="group"><img src="https://la-cascade.io/images/Horiz-Vert01-compressor.gif" alt="" /><figcaption>Les graissses, égalité mathématique ou visuelle ?</figcaption></figure><p>Mais après les deux premières, une base verticale et une barre horizontale, tout s’écroule. L’horizontale semble plus lourde que la verticale, notre beau plan tombe à l’eau. Nous voulions appliquer les mêmes mesures de manière uniforme, et voilà que nous en avons (apparemment) deux. Pourtant, nous venons de les mesurer et nous savons qu’elles sont égales. Ou plutôt “égales”.</p><p>Nos yeux ne voient pas toutes les formes de la même façon, par exemple ils voient les formes horizontales plus lourdes qu’elles ne sont. Ce phénomène a fait l’objet de descriptions multiples, depuis la théorie de “<a href="https://en.wikipedia.org/wiki/Unconscious_inference">l’inférence inconsciente</a>” de la perception visuelle, jusqu’à la sagesse populaire sur les vêtements rayés nous faisant paraître plus minces ou plus grands. Dans ces exemples et dans bien d’autres, nous sommes trompés par les changements d’orientation. Pour contrecarrer cette mauvaise interprétation, nous devons alléger la graisse des horizontales jusqu’à ce qu’elles aient l’air égales aux verticales. En d’autres termes, nous avons besoin de graisses multiples pour donner l’illusion d’une graisse unique.</p><figure role="group"><img src="https://la-cascade.io/images/Futura-O-anim-compressor.gif" alt="" /><figcaption>Vues verticale et horizontale : Futura Medium par Paul Renner, Bauer 1927</figcaption></figure><p>Dans cette vaste entreprise de traficotage, nous nous retrouvons malgré tout en bonne compagnie. <a href="https://en.wikipedia.org/wiki/Futura_(typeface)">Futura</a>, l’exemple ultime de la stricte géométrie, fait les mêmes concessions sous ses airs de pureté. Nous jurerions que ce <em>O</em> est un cercle parfait dessiné par un compas impartial. Mais si nous basculons la forme d’un quart de tour, nous faisons apparaître la supercherie optique et nous voyons la forme telle qu’elle est : une ellipse à l’intérieur d’un cercle.</p><p>(Il m’a fallu du temps pour l’accepter après m’en être aperçu. “<em>Bien sûr</em> que ces formes géométriques sont pures. Elles <em>doivent</em> l’être, n’est-ce pas ? Oui ? Sil vous plaît…” C’était comme d’apprendre que la petite souris n’existe pas.)</p><figure role="group"><img src="https://la-cascade.io/images/Futura-Bruce101-compressor.jpeg" alt="" /><figcaption>Futura Medium par Paul Renner, Bauer 1927 &amp; Roman n° 1, Bruce Type Foundry, vers 1815</figcaption></figure><p>Cette relation déséquilibrée des verticales et des horizontales se retrouve dans tous les styles. Les deux designs ci-dessus, bien que d’apparence très différente, fonctionnent selon le même principe de contraste des graisses. L’une est recherchée et subtile, l’autre est bruyante et mélodramatique. Sur les plans culturel, émotionnel et pratique, ces designs de l’Europe moderniste et de l’Amérique victorienne n’ont rien à voir. Mais sur le plan optique, ils sont construits selon le même schéma, avec une simple différence d’intensité. Le contraste ne disparaît jamais complètement.</p><figure role="group"><img src="https://la-cascade.io/images/InitialesLabeur01-compressor.jpeg" alt="" /><figcaption>“Initiales Labeur” par La Fonderie Typographique Française, spécimen, vers 1930</figcaption></figure><p>Ce design nous montre un autre conflit fréquent, cette fois-ci entre les formes droites et incurvées. Si nous nous approchons et que nous mesurons les éléments droits et courbes, nous constatons que ce bel ordonnancement précis est fait de disparités.</p><figure><img src="https://la-cascade.io/images/InitialesLabeur02-compressor.jpeg" alt="" /></figure><p>Un poids supplémentaire a été ajouté aux formes incurvées qui, à leur maximum, sont 12% plus larges que les verticales. Le problème sous-jacent et sa solution correspondent en grande partie à ce que nous avons vu avec les alignements dans l’article précédent.</p><p>Une courbe atteint son épaisseur maximale en un seul point à son centre, alors que les autres parties deviennent progressivement plus légères. La colonne droite quant à elle conserve son épaisseur du sommet jusqu’en bas. La seule façon de leur donner un air égal est de donner plus d’épaisseur aux parties incurvées, de la même façon que nous avions dû <a href="https://la-cascade.io/articles/fonctionnement-des-polices-de-caracteres-1/">les étendre vers le haut et vers le bas</a>.</p><figure><img src="https://la-cascade.io/images/InitialesLabeur03-compressor.jpeg" alt="" /></figure><p>Si le travail est bien fait, cette différence sera à peine perceptible. Mais si nous superposons les formes, nous pouvons voir à quel point les fonderies trichent avec l’épaisseur des courbes pour leur donner un air correct.</p><figure role="group"><img src="https://la-cascade.io/images/CandidaMemphis01-compressor.jpeg" alt="" /><figcaption>Candida Mager de Jakob Erbar, Ludwig &amp; Mayer 1936 &amp; Memphis Halbfett de Rudolf Wolf, Stempel 1929</figcaption></figure><p>Nous avons vu précédemment que le “dépassement” (<em><a href="http://en.wikipedia.org/wiki/Overshoot_%28typography%29">overshoot</a></em>) est fonction du type de courbe : moindre lorsque la courbe tend vers une forme carrée, maximum lorsqu’elle est plus ronde. Ici, nous avons les mêmes conditions et conséquences, avec cette masse supplémentaire nécessitée par le contraste. Ci-dessus, Candida offre certains contrastes remarquables, bien que moins accentués que dans le style néoclassique que nous venons de voir. Au-dessous, Memphis est une égyptienne (_<a href="https://en.wikipedia.org/wiki/Slab_serif">slab serif</a>_) sans contraste apparent.</p><p>À mesure que le contraste diminue, l’écart entre épaisseur maximum et minimum se réduit. Lorsque l’épaisseur du trait varie moins, on a moins besoin d’ajouter une masse supplémentaire.</p><figure role="group"><img src="https://la-cascade.io/images/CandidaMemphis04-compressor.jpeg" alt="" /><figcaption>Masse supplémentaire dans Candida &amp; Memphis</figcaption></figure><p>Si nous reprenons nos mesures, nous nous apercevons qu’un contraste moindre nécessite moins de masse supplémentaire. Candida augmente l’épaisseur de son trait de 9% alors que le faible contraste de Memphis ne nécessite que 1%. Par conséquent, si vous avez noté comme règle 12% à partir de l’exemple précédent, vous pouvez le rayer : il n’y a pas de formule universelle, mais uniquement des situations particulières, parfois au niveau d’une seule lettre, parfois au niveau de l’alphabet ou de la famille tout entière.</p><p>Au bout du compte, tout revient à ajouter du noir lorsqu’il y a trop de blanc. Mais ailleurs dans notre design — voire dans la même lettre — nous pouvons avoir le problème inverse, où nous devons supprimer du noir parce qu’il n’y a pas assez de blanc.</p><figure role="group"><img src="https://la-cascade.io/images/B-Wratios-1b-compressor.gif" alt="" /><figcaption>Suppression de blanc à droite</figcaption></figure><p>Pour prendre à nouveau un exemple simplifié, nous avons ici un ensemble de lignes séparées par un espace constant. Admettons que nous voulions les rapprocher — les condenser si vous voulez.</p><p>Si nous modifions l’intervalle blanc, sans rien changer d’autre, cela aboutit à un résultat inattendu (du moins si nous pensions conserver la même luminosité). La proportion de noir et de blanc a changé, et c’est <em>de là</em> que nous percevons la lumière, pas des dimensions de tel ou tel élément. Alors, si moins de blanc donne l’impression de plus de noir, pouvons-nous redimensionner les éléments de façon à ce que le ratio noir-blanc reste intact ?</p><figure role="group"><img src="https://la-cascade.io/images/B-Wratios-2b-compressor.gif" alt="" /><figcaption>Noir et blanc, redimensionnés pour conserver le même ratio</figcaption></figure><p>Hélas, ça ne marche pas. Tout devient trop léger à droite car nous voyons que l’épaisseur des traits ne correspond pas. Au passage, c’est la raison pour laquelle les fausses <a href="https://fr.wikipedia.org/wiki/Petite_capitale">petites capitales</a> (<em>small caps</em>) ont l’air maigrichonnes. En redimensionnant les lettres capitales on crée des caractères dont le poids est différent comme dans l’exemple précédent.</p><figure role="group"><img src="https://la-cascade.io/images/B-Wratios-3b-compressor.gif" alt="" /><figcaption>Noir et blanc, rééquilibrés optiquement</figcaption></figure><p>Donc, quand nous rééquilibrons les choses en mettant une épaisseur de trait et un espacement qui ont l’air corrects, nous créons une relation qui n’est ni arithmétique ni géométrique, mais quelque part entre les deux. Nos yeux sont exigeants, ils acceptent rarement la solution la plus simple.</p><figure role="group"><img src="https://la-cascade.io/images/Intersections-anim-compressor.gif" alt="" /><figcaption>Intersection de traits, avec et sans amincissement (Interstate Bold, Font Bureau 1994)</figcaption></figure><p>Ce problème de ratio noir/blanc apparaît à l’intérieur même des lettres. Lorsque les bordures des traits sont conservées mécaniquement parallèles, nous constatons un empilement de graisses à l’endroit où ils se croisent. Le centre du <em>x</em> semble vouloir se gonfler, tandis que le <em>v</em> a l’air d’être en caractère gras au sommet et extra-gras en bas. Nous pouvons corriger tout cela en amincissant les traits à l’approche de leur intersection, ce qui stabilise partiellement le ratio de noir et de blanc.</p><p>Les graisses s’accumulent en fonction de l’angle de l’intersection, le problème devenant plus aigu à mesure que l’angle est plus pointu. Voilà pourquoi les designers de polices de caractères respirent profondément avant de se lancer dans une version <em>Compressed Extra Bold</em> d’une police, et c’est aussi la raison pour laquelle ils lancent des jurons au <em>W</em> majuscule (ça c’est moi !).</p><figure role="group"><img src="https://la-cascade.io/images/Intersections-3-compressor.jpeg" alt="" /><figcaption>Mapping de l’amincissement</figcaption></figure><p>Pour en avoir une vue différente (et en couleur), j’ai demandé à ma collègue Nina Stössinger d’écrire un petit programme en Python qui repère ces changements de graisses et modifie la couleur en fonction. Cela illumine littéralement l’amincissement des traits, dont on voit qu’il s’accélère aux intersections. Il fait également apparaître que la partie gauche du <em>v</em> est plus lourde que la partie droite — mais c’est tout une autre histoire que je vous raconterai la prochaine fois.</p></div>]]></description>
      <link>https://la-cascade.io/articles/mecanique-des-polices-de-caracteres-2-2</link>
      <guid>https://la-cascade.io/articles/mecanique-des-polices-de-caracteres-2-2</guid>
      <pubDate>Sat, 18 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Guide de Flexbox : space-between, l'oublié]]></title>
      <description><![CDATA[<p><em>Tout comprendre sur space-between, le héros oublié de Flexbox. Noah Blon propose un cas pratique d'utilisation de cette valeur de justify-content dans Flexbox, super pratique pour vos mises en page.</em></p><div class="articleContent"><p>Plus j’utilise <a href="https://la-cascade.io/tags/flexbox/">flexbox</a>, plus revient la même règle : <code>justify-content: space-between</code>. Dans cet article, je vais vous montrer mon approche des questions de mise en page avec flexbox et l’utilité de <code>space-between</code> pour résoudre efficacement quelques difficultés épineuses.</p><p><code>space-between</code> est une des valeurs possibles de la propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/justify-content">justify-content</a>. Elle dispose tous les items flex de manière régulière le long de l’axe principal. L’espace résiduel éventuel est distribué de manière égale <em>entre</em> les items. Un peu comme des items flottants à gauche et à droite, mais vous n’avez pas besoin de <em>clear</em> et vous pouvez le faire horizontalement ou verticalement. C’est un pattern qu’on retrouve à peu près tout le temps.</p><p>Ce qui est cool avec <code>space-between</code> c’est que les items que vous disposez conservent leur dimension intrinsèque. Cela vous permet d’avoir un balisage vraiment efficace, qui ne requiert pas d’utiliser des éléments contenants — en fait, la plupart du temps vous pouvez simplement positionner vos items avec flex et c’est bon.</p><p>Comme pour tout, à mon avis rien ne vaut une bonne démo. Imaginons que nous avons un super projet d’appli de tournoi Super Smash Bros et un designer nous remet ceci :</p><figure><img src="https://la-cascade.io/images/super-smash-bros-1-compressor.png" alt="tableau de scores" /></figure><p>Voici comment je m’y prendrais pour construire la section header — la partie avec les images des combattants, les icônes, leurs noms, le score, etc. — avec flexbox et <code>space-between</code>.</p><h3>Figure 1 - Décomposer le problème de layout</h3><figure><img src="https://la-cascade.io/images/super-smash-bros-2-compressor.jpeg" alt="décomposition de l'image en ses éléments, une section en haut, une section en bas" /></figure><p>La première chose que je fais lorsque je m’attaque à un problème de mise en page, c’est de décomposer tous ses éléments. On a l’image de background, que nous pouvons traiter avec un positionnement absolu et sortir du flow.</p><p>Il nous reste à positionner le contenu supérieur par-dessus l’image. Nous avons deux régions :</p><ol><li>une section en haut avec quelques boutons icônes, l’un à gauche, l’autre à droite.</li>
<li>une section en bas comportant le nom du combattant , le score final, des icônes, etc.</li>
</ol><p>Pour ces deux sections, l’axe principal est vertical. Avec <code>display: flex</code> et <code>flex-direction: column</code> puis <code>justify-content: space-between</code>, on fixe les items flex en haut et en bas du header.</p><p>Pour illustrer la façon dont ça marche, j’ai indiqué une hauteur donnée pour les sections, mais normalement on peut simplement laisser la dimension du contenu situé à l’intérieur d’un item flex déterminer sa taille. Plus tard dans ces exemples je retirerai la hauteur fixe. Voici une démo.</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/noahblon/pen/EjVjJV/">Figure 1</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div><p><em>Note : Nous devons laisser le background en dehors du contexte flex, car il y a un <a href="https://github.com/philipwalton/flexbugs/issues/18">bug dans Firefox</a> qui fait que <code>space-between</code> applique de l’espace à des éléments positionnés absolument. Pour éviter ce bug, j’ai enveloppé le contenu dans un élément positionné absolument — .header-content — et indiqué le contexte flex à l’intérieur</em></p><h3>Figure 2 - Flexibiliser et grouper les items</h3><figure><img src="https://la-cascade.io/images/super-smash-bros-3-compressor.jpeg" alt="icônes de navigation, partage, menu" /></figure><p>Maintenant, attaquons-nous à la section du haut. Cette fois-ci, les items sont fixés sur les côtés du header, mais selon un axe horizontal. Indiquons <code>display: flex</code> dans cette section pour créer notre contexte flex. Nous n’avons pas besoin de définir explicitement la <code>flex-direction</code> parce que la valeur est <code>row</code>, ou horizontal, par défaut. On utilise à nouveau <code>justify-content: space-between</code> pour fixer les items sur les côtés. Les deux icônes sur la droite sont enveloppées dans un élément pour les fixer ensemble sur le côté droit. C’est une façon commode et efficace de grouper des items flex. Dans l’enveloppe de droite, nous pouvons utiliser une autre astuce sympa de flexbox, <code>display: inline-flex</code>. Tout se passe comme si on mettait <code>display: inline-block</code> sur chacun des items pour leur permettre d’être les uns à côté des autres, mais contrairement à <code>inline-block</code>, nous n’avons pas besoin de le définir sur chaque item et il ne nous reste pas d’espace à éliminer entre les items.</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/noahblon/pen/YXyXbQ/">Figure 2</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div><h3>Figure 3 - L’efficacité de space-between</h3><figure><img src="https://la-cascade.io/images/super-smash-bros-4-compressor.jpeg" alt="partie du bas" /></figure><p>Et maintenant, la partie du bas. Ce sont juste deux boîtes superposées. Comme avec les enveloppes de la partie du haut, nous n’avons rien de particulier à faire avec ces items. À nouveau, je donnerai une hauteur déterminée pour la démonstration, mais on pourrait tout aussi bien laisser cette section prendre les dimensions de son contenu.</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/noahblon/pen/doYoxW/">Figure 3</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div><h3>Figure 4</h3><figure><img src="https://la-cascade.io/images/super-smash-bros-5-compressor.jpeg" alt="" /></figure><p>La partie du haut de la section inférieure est semblable au header. Les items sont fixés de chaque côté de l’axe horizontal. Est-ce que vous trouvez qu’on se répète ? J’espère bien que oui !</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/noahblon/pen/bdVVbm/">Figure 4</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div><h3>Figure 5</h3><figure><img src="https://la-cascade.io/images/super-smash-bros-6-compressor.jpeg" alt="" /></figure><p>La partie du bas de la section inférieure comporte des items fixés de chaque côté et un item au milieu. Là encore, <code>space-between</code> est l’outil qu’il nous faut : un troisième item à l’intérieur d’un contexte flex est positionné au milieu. Trop fort !</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/noahblon/pen/waKKBY/">Figure 5</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div><h3>Figure 6 - Tous ensemble maintenant !</h3>Et voici tous les éléments réunis et stylés.<div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/noahblon/pen/GJppMX/">le résultat final</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div><p>Et voici les mêmes, avec l’image de background, un SVG que j’ai créé pour avoir des couleurs qui se mélangent dynamiquement. Restez branché pour en savoir plus à ce sujet !</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/noahblon/pen/MwabGx/">le résultat vraiment final</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div></div>]]></description>
      <link>https://la-cascade.io/articles/guide-de-flexbox-space-between-loublie</link>
      <guid>https://la-cascade.io/articles/guide-de-flexbox-space-between-loublie</guid>
      <pubDate>Sun, 05 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Les bases de SVG : Lignes simples et multiples]]></title>
      <description><![CDATA[<p><em>Après les formes de base de SVG, Dudley Storey présente les lignes, simples et multiples et... ce n’est pas si simple.</em></p><div class="articleContent"><p>Si vous souhaitez dessiner des lignes ou une forme ouverte, plutôt qu’un <a href="https://la-cascade.io/articles/les-bases-de-svg-polygones/">polygone</a> ou un <a href="https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses/">cercle</a>, <a href="https://la-cascade.io/tags/svg/">SVG</a> vous offre deux options : les lignes et les polylignes.</p><h2>Les lignes</h2><p>La syntaxe SVG pour les lignes peut paraître intimidante de prime abord, mais c’est parce qu’elle est précise : une ligne peut être décrite simplement en deux points, chacun spécifié par ses coordonnées <code>x</code> et <code>y</code>.</p><p>À la différence des formes que nous avons vues jusqu’ici, <strong>les lignes sont entièrement invisibles par défaut</strong>, et le resteront tant qu’on n’aura pas spécifié au moins une couleur de trait (<em>stroke</em>). Une fois colorées, elles auront l’épaisseur d’un cheveu tant qu’on n’aura pas spécifié une épaisseur via <code>stroke-width</code>.</p><pre>&lt;svg width="300" height="300" viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg"&gt;
  &lt;line x1="0" y1="0" x2="300" y2="200" stroke-width="20" stroke="black" /&gt;
&lt;/svg&gt;</pre><p>Le lecteur à l’oeil exercé aura remarqué que l’extrémité du trait est coupé par les coins de la <code>viewBox</code>. Pour s’assurer que le trait apparaisse dans son intégrité, il faut lui donner des coordonnées qui dépassent la viewBox — ou bien utiliser <code>stroke-linecap: square</code> (dont nous allons parler plus bas) afin d’étendre l’extrémité des lignes.</p><p>Le résultat avec <code>stroke-linecap: square</code> :</p><h2>Les polylignes</h2><p>Les polylignes sont simplement des lignes SVG qui se rejoignent en des points multiples :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 414.3 231.4"&gt;
  &lt;polyline stroke="#000" stroke-width="6" fill="none" points="15.7,127.9 112.1,15 294.3,205 75,167.9 364.3,36.4 392.1,212.9 "/&gt;
&lt;/svg&gt;</pre><p>Ce qui donne :</p><p>Remarquez que contrairement à ce qui se passe avec les outils graphiques, le fait de placer le dernier point d’une polyligne au même endroit que le point de départ n’aura pas pour résultat de “fermer” la forme. Cependant, vous pouvez appliquer un remplissage couleur (<em>fill</em>) à la forme :</p><p>Je vous en dirai plus sur les <code>fill</code> dans un article à venir, mais pour l’instant, il suffira de dire que même si nous pouvons appliquer un remplissage couleur à une polyligne, et en général il marchera comme souhaité, il ne donnera qu’une <em>apparence</em> de polygone fermé, mais ce ne sera pas la même chose.</p><h2>Caps &amp; corners</h2><p>Lorsqu’une ligne SVG change de direction, on n’est pas obligé de rendre l’angle qui en résulte sous la forme d’un angle “dur” : il existe deux autres options, grâce à la propriété <code>stroke-linejoin</code>. Celle-ci prend deux valeurs, <code>round</code> (arrondi) et <code>bevel</code> (biseauté), qui font exactement ce qu’on attend d’elles (vous aurez peut-être besoin d’augmenter l’épaisseur du trait pour bien voir l’effet). Une troisième valeur, <code>miter</code>, est la valeur par défaut.</p><p>Ci-dessous, nos polylignes avec une valeur de <code>stroke-linejoin="bevel"</code> :</p><p>De la même manière, les fins de lignes peuvent se terminer par des sortes de capuchons, via la propriété <code>stroke-linecap</code>, qui prend trois valeurs, <code>round</code> (arrondi en demi cercle), <code>square</code> (la ligne prend un capuchon carré, comme le bout d’un lacet de chaussure), ou <code>butt</code> par défaut. Ci-dessous les trois options, où l’on voit que le capuchon allonge légèrement la ligne, comme on le voyait déjà dans le deuxième exemple de cet article :</p><p>S’agissant de propriétés liées à l’apparence, <code>stroke-linejoin</code> et <code>stroke-linecap</code> peuvent être appliquées soit comme attributs, soit comme propriétés CSS.</p><p>Un dernier point : Les traits (<em>stroke</em>) et les remplissages couleur (<em>fill</em>) peuvent être appliqués à d’autres objets que les lignes, polylignes et polygones ; par exemple, ils peuvent être utilisés pour <a href="http://thenewcode.com/439/Introduction-to-SVG-Text">tracer un texte</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/les-bases-de-svg-lignes-simples-et-multiples</link>
      <guid>https://la-cascade.io/articles/les-bases-de-svg-lignes-simples-et-multiples</guid>
      <pubDate>Sat, 04 Jul 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Le $Path vers la lumière]]></title>
      <description><![CDATA[<p><em>L'installation de logiciels sur notre machine est souvent un processus pénible et semé d'embûches. Mieux connaître $PATH facilitera notre vie et nous évitera quelques crises</em></p><div class="articleContent"><p>L’installation des logiciels open source est souvent pénible, mais un processus d'installation un peu compliqué — même lorsqu'il semble nous éloigner du but (résoudre des problèmes au moyen dudit logiciel) — constitue une bonne opportunité d’apprivoiser l’un de nos principaux outils de travail : la ligne de commande.</p><p>La <a href="https://fr.wikipedia.org/wiki/Interface_en_ligne_de_commande">ligne de commande</a> (<em>command line</em>) repousse pas mal de gens — elle est souvent considérée comme la technologie des hackers et des “sorciers de l’informatique”. La réalité n’est pas aussi cool, il s’agit en fait d’un ensemble d’outils ridiculement simples créés dans les années 70 par les employés de Bell (aujourd’hui AT&amp;T) pour réaliser les tâches les plus basiques. C’est à peu près aussi “space-age” que votre four à micro-ondes.</p><p>Mais la ligne de commande est extrêmement utile et puissante, et vous donnera parfois l’impression de passer de la construction manuelle à la construction industrielle. Avec quelques concepts et quelques métaphores, nous allons essayer de jeter un peu de lumière dans les recoins les plus sombres de notre ligne de commande.</p><p><strong>Parmi ces concepts, l’un des plus importants est le Chemin d'Accès (<em>Path</em>)</strong>.</p><p>De nombreux frameworks, préprocesseur CSS, bibliothèques JavaScript et autres outils de développement reposent sur Ruby ou sur Node.js pour leur installation sur votre machine. Bower est l’un de ces outils. Invariablement, ces outils vous conduiront à interagir avec le PATH — parce que le Chemin doit connaître l’ensemble des outils que vous installez pour votre environnement de développement, afin que votre ligne de commande fonctionne convenablement.</p><p>Plus vous utiliserez la ligne de commande et plus il y a de chances que vous rencontriez des problèmes avec le Chemin. Avant que vous ne perdiez trop de temps ou que vous ne vous en preniez à votre machine, passons en revue les bases de l’utilisation du Chemin.</p><h2>Une humble petite variable</h2><p><code>$PATH</code>, comme le dénotent son préfixe $ et ses majuscules criardes, est une <a href="https://fr.wikipedia.org/wiki/Variable_d%27environnement#.3CPATH.3E_pour_l.27emplacement_des_ex.C3.A9cutables">variable d’environnement</a> Unix. À l’intérieur de cette variable est enregistrée une liste de chemins de dossiers, séparés par des <code>:</code>, qui ressemble à ceci :</p><pre>/root/directory/binary:/root/other_directory/other_binary</pre><p>Si vous êtes curieux de savoir quelles autres variables d’environnement existent dans votre système, vous pouvez taper <code>env</code> dans la ligne de commande. Faites <em>Enter</em> et vous verrez la liste de toutes les variables d’environnement présentes.</p><p>Puisque <code>$PATH</code> est une variable, elle peut être modifiée comme vous le souhaitez, à la volée. Par exemple, vous pouvez taper ceci dans votre ligne de commande :</p><pre>$ export PATH=banana</pre><p>Que fait cette commande ? Eh bien, après l’avoir tapée, essayez de lancer n’importe quelle commande basique (par exemple <code>ls</code> pour lister le contenu d’un dossier) et vous obtiendrez un message <code>-bash: ls: command not found</code> alors que <code>ls</code> fonctionnait jusqu’ici sans problème…</p><p>Ce sabotage sournois nous aide à comprendre que sans contenu dans notre <code>$PATH</code> nous nous retrouvons… comme des bananes.</p><p>Mais pourquoi ? Eh bien parce que comme le font de nombreux chemins de chargement (y compris dans les langages de programmation et dans les frameworks comme Rails), ce Path détermine ce qui peut être exécuté dans votre ligne de commande. Si cette dernière ne peut rien trouver qui corresponde au nom que vous avez entré, elle ne peut pas l’exécuter.</p><p>Ah ! à propos : il suffit de quitter votre application de ligne de commande pour restaurer toutes vos commandes. C’était un sabotage temporaire. Mais faites attention de ne jamais sauvegarder ce genre de blagues dans votre <code>~/.bash_profile</code>, ça pourrait mal se terminer.</p><h2>Le conte des mille et un binaires</h2><p>Dans Unix, certains programmes exécutables sont appelés binaires (<em>binaries</em>). Honnêtement, ce n’est pas un nom génial, il se focalise sur leur format plutôt que sur leur fonction. Quand vous écrivez un programme Unix, vous avez parfois besoin de compiler la source avant de pouvoir l’exécuter. Ce processus de compilation est ce qui crée le binaire. Plutôt que d’utiliser du texte (comme votre code source), ces fichiers utilisent un format binaire pour faciliter le traitement des instructions par les ordinateurs.</p><p>Unix comporte de nombreux dossiers dans lesquels enregistrer les binaires. Vous pouvez voir quel dossier est le dossier par défaut de stockage des binaires dans le fichier <code>/etc/paths</code>, pour cela il suffit d’utiliser la commande <code>cat</code> qui permet d’imprimer le contenu d’un fichier :</p><pre>$ cat /etc/paths
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin</pre><p>Ce fichier contient un dossier par ligne. Les chemins sont listés dans un ordre signifiant. Lorsqu’un binaire est trouvé dans un chemin, il est chargé. Si un binaire portant le même nom est trouvé par la suite dans un autre chemin, il est ignoré. Autrement dit, les chemins listés les premiers prennent le pas sur ceux qui les suivent.</p><p>Voilà pourquoi il est si commun de rencontrer des problèmes lorsqu’on essaie d’installer un binaire pour quelque chose qui existe déjà dans notre système. Dans le cas d’OS X, si vous essayez d’installer une version de Git différente de celle déjà présente dans le système, vous serez confronté à ce genre de problème. Et c’est bien dommage, parce que Git 2.0 est vraiment super.</p><p>Si je fais <code>cd</code> (<em>change directory</em>) dans <code>/usr/bin</code> — un dossier courant pour stocker les binaires — et que je fais <code>ls</code> j’aurai plus de 1.000 résultats. Ça ne m’aide pas beaucoup. Ceci dit, si j’utilise <a href="http://fr.wikipedia.org/wiki/Grep">grep</a> avec <code>ls | grep git</code>, je peux filtrer les résultats de la commande <code>ls</code> en ne conservant que ceux qui contiennent “git”.</p><pre>$ ls | grep git
git
git-cvsserver
git-receive-pack
git-shell
git-upload-archive
git-upload-pack</pre><p>...et bien sûr il y a un binaire pour Git à l’intérieur de <code>/usr/bin</code>. Une installation propre d’OS X devrait retourner <code>/usr/bin/git</code> lorsque vous faites <code>which git</code> :</p><pre>$ which git
/usr/local/bin/git</pre><p>Alors pourquoi mon résultat est-il différent ? En utilisant l’option <code>-a</code>, nous pouvons avoir une idée de ce qui se passe :</p><pre>$ which -a git
/usr/bin/git
/usr/local/bin/git</pre><p>Ceci me dit qu’il y a <em>deux</em> versions de Git sur mon système. Mais seule la première version est utilisée quant j’exécute les commandes <code>git</code> dans ma ligne de commande, la seconde est ignorée.</p><h2>Changer de chemins</h2><p>J’ai installé ma propre version de Git à l’aide d’un package manager pour OS X appelé <a href="http://brew.sh/">Homebrew</a>, parce que j’aime bien pouvoir contrôler les outils que j’utilise au quotidien et les mettre à jour quand je le veux. Je pourrais certes mettre à jour le Git installé dans le système, mais je n’ai aucune idée des applications ou des autres binaires qui en dépendent.</p><p>Nous avons vu que les fichiers binaires sont sélectionnés dans l’ordre où ils apparaissent, alors pourquoi ne changerions-nous pas cet ordre ?</p><p>À l’intérieur du fichier <code>/etc/paths</code>, je peux voir que le dossier <code>/usr/local/bin</code>, dans lequel se trouve ma version de Git installée avec Homebrew, arrive en dernier. Cela signifie que le binaire git qui se trouve dans <code>/usr/bin</code> aura la priorité et mon git sera ignoré. Il faut changer cela.</p><p>Pour ce faire, vous pourriez essayer de modifier l’ordre dans <code>/etc/paths</code> de façon à ce qu’il corresponde à vos besoins, en mettant <code>/usr/local/bin</code> tout en haut, et la version Homebrew serait chargée en premier. Mais malgré le nombre de fois où vous verrez ce conseil répété dans les discussions sur <a href="http://stackoverflow.com/">Stack Overflow</a>, ne le faites pas. <em>Jamais</em>. Les configurations enregistrées dans <code>/etc/</code> affectent le système tout entier. Elles ne sont pas censées être modifiées par les utilisateurs individuels (même si vous êtes le seul utilisateur de la machine), et vous pourriez créer des problèmes inattendus en bricolant de la sorte. Par exemple, certains services utilisés par OS X pourraient reposer sur l’ordre original de <code>/etc/paths</code>.</p><p>C’est le <code>$PATH</code> que vous devez modifier, dans <em>votre</em> environnement, en utilisant <em>votre</em> <code>.bash_profile</code> — celui qui est enregistré dans <code>/Users/votrenomdutilisateur/.bash_profile</code>.</p><p>Pour vous assurer que <code>/usr/local/bin</code> soit recherché en premier, il suffit d’inclure ce qui suit dans votre <code>.bash_profile</code> (par exemple pour moi dans <code>/Users/olivierlacan/.bash_profile</code>) :</p><pre>export PATH=/usr/local/bin:$PATH</pre><p>Cette ligne exporte une nouvelle variable d’environnement <code>$PATH</code> en imprimant celle qui existe actuellement et en plaçant juste avant le chemin <code>/usr/local/bin</code>. Après avoir enregistré votre <code>~/.bash_profile</code> et redémarré votre ligne de commande, voici ce que vous devriez voir lorsque vous faite <code>echo</code> sur le <code>$PATH</code> :</p><pre>$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin</pre><p>Comme vous pouvez le voir, <code>/usr/local/bin</code> est mentionné deux fois dans le <code>$PATH</code>, et ce n’est pas un problème. Comme il est mentionné en premier, tous les binaires chargés à ce moment seront ignorés lorsqu’ils sont rencontrés par la suite. Honnêtement, j’aimerais qu’il existe une façon simple et sûre de changer l’ordre des chemins, mais la plupart des solutions que je connais sont un peu trop complexes.</p><p>Maintenant que vous avez changé le <code>$PATH</code>, vous pouvez vérifier que le bon binaire est appelé quand vous utilisez la commande <code>git</code> :</p><pre>$ which git
/usr/local/bin/git
$ git --version
git version 2.0.0
/usr/bin/git --version git version 1.8.5.2 (Apple Git-48)</pre><p>Et voilà. Git 2.0.0 (la version installée par Homebrew) répond maintenant à la commande <code>git</code>, et la version installée par Apple est reléguée à l’arrière. Si vous préférez ne pas utiliser git 2.0.0, il suffit de le désinstaller et la version par défaut prendra le relais.</p><h2>Protégez votre chemin</h2><p>Tout un tas de services pour les développeurs et les designers injecteront automatiquement du code dans votre <code>.bash_profile</code> lors de leur installation, souvent sans même le mentionner. Si vous trouvez des chemins bizarres listés dans votre profil, cela peut expliquer que le chargement d’une nouvelle session (ce qui arrive lorsque vous ouvrez une nouvelle fenêtre ou onglet de la ligne de commande) prenne plus de temps que prévu : un <code>$PATH</code> boursoufflé peut prendre du temps à se charger.</p><p>Voici mon chemin aujourd’hui :</p><pre>/Users/olivierlacan/.rbenv/shims:/Users/olivierlacan/.rbenv/bin:
/usr/local/bin:/usr/local/heroku/bin:/usr/bin:/bin:/usr/sbin:
/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/MacGPG2/bin</pre><p>C’est un peu dur à lire, alors j’ai tendance à subdiviser l’affichage en lignes distinctes. C’est facile à faire avec la commande <code>tr</code> (<em>traduire</em> les caractères : les <code>:</code> sont traduits en <code>\n</code>, c’est à dire en retour à la ligne) :</p><pre>$ echo $PATH | tr ':' '\n'
/Users/olivierlacan/.rbenv/shims
/Users/olivierlacan/.rbenv/bin
/usr/local/bin
/usr/local/heroku/bin
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin
/opt/X11/bin
/usr/local/MacGPG2/bin</pre><p>Cela fait beaucoup en effet, et c’est bien plus simple à lire verticalement. Essayez sur votre machine, et si vous ne savez pas pourquoi une de ces lignes est dans votre <code>$PATH</code>, tentez de savoir pourquoi.</p><p>Maintenant que vous connaissez votre Chemin, à quoi il ressemble lorsqu’il est propre, comment le modifier comme il faut, et comment vérifier qu’il correspond à vos outils, il y a des chances que vous ne passerez plus des heures à retrouver votre chemin : celui que vous utilisez pour construire des choses pour les autres.</p></div>]]></description>
      <link>https://la-cascade.io/articles/le-path-vers-la-lumiere</link>
      <guid>https://la-cascade.io/articles/le-path-vers-la-lumiere</guid>
      <pubDate>Sun, 07 Jun 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Les bases de SVG : Polygones]]></title>
      <description><![CDATA[<p><em>Dudley Storey termine la série d'articles sur les formes de bases SVG avec les polygones : triangles, étoiles et autres formes plus complexes.</em></p><div class="articleContent"><p>Si vous voulez créer une forme SVG plus complexe qu’un <a href="https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses/">cercle</a> ou un <a href="https://la-cascade.io/articles/les-bases-de-svg-rectangles-et-carres/">rectangle</a>, vous pouvez essayer le polygone.</p><p>En <a href="https://la-cascade.io/tags/svg/">SVG</a>, un polygone est une forme fermée constituée de lignes droites ; SVG ne propose pas (encore) d’éléments pour les polygones réguliers (comme <em>étoile</em> ou <em>hexagone</em> par exemple), mais il vous permet de créer n’importe quelle forme en indiquant les points qui la définissent. Des formes constituées de trois ou quatre pointes sont faciles à coder manuellement, mais vous aurez sans doute besoin d’un logiciel de création graphique comme <a href="http://demosthenes.info/blog/823/SVG-Export-Settings-For-Adobe-Illustrator">Adobe Illustrator</a>, Inkscape, Sketch ou Photoshop pour réaliser des designs plus complexes, que vous pourrez <a href="http://webdesign.tutsplus.com/fr/tutorials/understanding-sketchs-export-options--cms-22207">exporter au format SVG</a>. Cependant, il est vraiment utile de comprendre les bases des polygones SVG car cela vous permettra de “bidouiller” et de modifier les formes directement dans le code sans avoir à repasser par l’éditeur graphique.</p><h2>Le plus simple des polygones SVG : le triangle</h2><p>Commençons par la plus simple des formes, en utilisant trois points pour créer un triangle rectangle :</p><pre>&lt;svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"&gt;
  &lt;polygon points="0 0, 100 100, 0 100"/&gt;
&lt;/svg&gt;</pre><p>Ce qui nous donne :</p><figure role="group" class="ds-small-svg"></figure><p>Quelques petites choses à noter :</p><ul><li>comme <a href="https://la-cascade.io/articles/les-bases-de-svg-rectangles-et-carres/">précédemment</a>, les axes x et y ont leur origine dans le coin supérieur gauche de <a href="https://la-cascade.io/articles/comprendre-svg-viewbox/">la viewBox</a> : X est l’axe horizontal, la valeur de x augmente lorsque le point se déplace vers la droite, et Y est l’axe vertical, la valeur de y augmente lorsque le point se déplace vers le bas.</li>
<li>les points constituant le polygone sont définis comme des paires de coordonnées x et y.</li>
<li>ces coordonnées sont séparées par une virgule.</li>
<li>il n’y a pas de direction requise dans l’ordre des points : vous pouvez commencer par n’importe quel point et continuer dans la direction que vous voulez. Dans l’exemple qui précède, le point “sommet” du polygone est défini le premier, suivi des deux autres dans le sens des aiguilles d’une montre — on aurait tout aussi bien pu commencer par le point inférieur gauche et continuer ensuite dans le sens inverse des aiguilles d’une montre.</li>
<li>il est inutile de répéter le premier point à la fin, SVG sait comment fermer le polygone tout seul comme un grand.</li>
<li>on peut appliquer <code>stroke</code>, <code>fill</code> et <code>stroke-width</code> aux polygones, comme nous l’avions fait pour les cercles, ellipses, rectangles et carrés.</li>
</ul><p>Et si nous voulions créer un triangle équilatéral ? il suffit pour cela de repositionner un seul point :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"&gt;
  &lt;polygon points="50 15, 100 100, 0 100"/&gt;
&lt;/svg&gt;</pre><figure role="group" class="ds-small-svg"></figure><h2>Le problème du remplissage croisé</h2><p>Avec trois points reliés par des lignes droites, il est impossible d’avoir des intersections. Mais à partir de quatre points, c’est parfaitement possible :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"&gt;
  &lt;polygon points="0 20, 100 20, 100 0, 0 100 "/&gt;
&lt;/svg&gt;</pre><p>SVG (comme la plupart des logiciels de création graphique) ne voit pas d’inconvénient à retourner ce résultat — qui n’est peut-être pas celui que vous attendiez :</p><figure role="group" class="ds-small-svg"></figure><p>Selon ce que vous voulez obtenir, il vous faudra peut-être repositionner le troisième point ou en ajouter un cinquième de manière à régler le problème.</p><h2>Une petite bibliothèque de polygones réguliers</h2><p>Même s’il est probable que vous créerez vos éléments SVG à l’aide d’un outil graphique, il est utile de voir la manière dont est construit le code des polygones réguliers. Vous pouvez bien évidemment copier ce code et l’utiliser dans vos créations, chaque polygone tient à l’intérieur d’une viewBox de 100 × 100.</p><h3>Pentagone</h3><figure role="group" class="ds-small-svg"></figure><pre>&lt;polygon points="26,86 11.2,40.4 50,12.2 88.8,40.4 74,86 " fill="hsl(56,80%,50%)"/&gt;</pre><h3>Étoile</h3><figure role="group" class="ds-small-svg"></figure><pre>&lt;polygon points="50,9 60.5,39.5 92.7,40.1 67,59.5 76.4,90.3 50,71.9 23.6,90.3 32.9,59.5 7.2,40.1 39.4,39.5" fill="hsl(106,80%,50%)"/&gt;</pre><h2>Hexagone</h2><figure role="group" class="ds-small-svg"></figure><pre>&lt;polygon points="30.1,84.5 10.2,50 30.1,15.5 69.9,15.5 89.8,50 69.9,84.5" fill="hsl(156,80%,50%)"/&gt;</pre><h2>Octogone</h2><figure role="group" class="ds-small-svg"></figure><pre>&lt;polygon points="34.2,87.4 12.3,65.5 12.3,34.5 34.2,12.6 65.2,12.6 87.1,34.5 87.1,65.5 65.2,87.4" fill="hsl(216,80%,50%)"/&gt;</pre><p>Et voilà ! Maintenant que nous avons passé en revue les formes de base, nous allons revenir aux lignes dans notre prochain article, en nous intéressant plus précisément aux lignes SVG, aux lignes multiples et aux chemins.</p></div>]]></description>
      <link>https://la-cascade.io/articles/les-bases-de-svg-polygones</link>
      <guid>https://la-cascade.io/articles/les-bases-de-svg-polygones</guid>
      <pubDate>Sat, 06 Jun 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[L'ajustement optique]]></title>
      <description><![CDATA[<p><em>Les designers ne doivent pas compter sur les seuls logiciels pour faire le travail d'ajustement, mais également sur leurs yeux et leur instinct. Preuves à l'appui.</em></p><div class="articleContent"><h2>Logique vs Design</h2><p>Quand j’étais tout jeune designer, je faisais confiance à Photoshop ou CSS pour me dire si quelque chose n’allait pas. Si Photoshop indiquait que deux formes étaient alignées, alors elles étaient alignées. Si elles avaient les mêmes dimensions, idem, et si deux couleurs avaient les mêmes valeurs hexadécimales, alors elles avaient le même rendu couleur.</p><p>Cette approche était logique, pourtant elle est incorrecte.</p><p>Les calculs de nos applications sont évidemment exacts, mais les softwares ne peuvent pas percevoir les formes, les couleurs, les dimensions de la même façon que les êtres humains — ils ne peuvent pas comprendre le <em>contexte</em> d’un objet en relation à d’autres, ou le contexte d’un langage visuel.</p><p>L’esprit humain juge et décide en fonction d’un contexte. Comprendre ces différences subtiles et savoir ajuster notre travail en fonction nous permet d’améliorer notre design — peu de gens le verront, mais par contre beaucoup s’en rendront compte si nous n’y avons pas fait suffisamment attention.</p><p>Voyons quelques exemples pratiques.</p><h2>Alignement et poids visuel</h2><p>Les ordinateurs ne peuvent savoir où se situe le poids d’un objet, ils ne connaissent que la largeur, la hauteur ou les positions x &amp; y. Notre travail de designer est de compenser cela par ce qu’on appelle l’ajustement optique.</p><p>Dans une icône <em>Play</em>, le triangle est centré dans le cercle, n’est-ce pas ? Eh bien non, si l’on trace un rectangle sur le triangle, on s’aperçoit qu’il est excentré.</p><figure role="group"><img src="https://la-cascade.io/images/play-icon-compressor.jpeg" alt="" /><figcaption>L’icône de gauche apparaît centrée, alors qu’en réalité on l’a décalée vers la droite.</figcaption></figure><p>À gauche, l’icône n’a pas l’air excentrée, et pourtant elle l’est (et <em>pas qu’un peu</em>…), pourquoi ? À cause du poids visuel. Le poids ou la masse du triangle se situe dans sa partie gauche, ce qui crée une illusion d’optique le tirant vers la gauche (comme on le voit dans le triangle “mathématiquement correct” à droite).</p><p>Pour résoudre ce problème, nous devons déplacer le triangle vers la droite jusqu’à ce qu’il ait <em>l'air</em> centré.</p><h2>La couleur</h2><p>Les ajustements optiques de couleurs sont plus subtils. Là encore, il s’agit du poids de l’objet et de la quantité de couleur qui apparaît.</p><p>En résumé : le même vert, selon qu’il est utilisé pour un texte ou pour un remplissage d’icône, paraîtra plus ou moins clair.</p><figure role="group"><img src="https://la-cascade.io/images/heart-recommend-compressor.jpeg" alt="" /><figcaption>La combinaison de gauche utilise la même valeur hexadécimale, celle de droite est ajustée en augmentant la quantité de noir dans le texte.</figcaption></figure><p>C’est subtil, mais vous pouvez observer que l’icône est plus “lourde” que le texte et que ce dernier semble d’un vert plus clair. Pour ajuster les deux, il convient soit d’éclaircir l’icône, soit d’assombrir le texte - le mieux étant de choisir la couleur qui respectera les critères d’accessibilité. Je recommande d’utiliser les valeurs de couleurs HSB (Photoshop, Sketch ou HSL (CSS) dans vos applications de design. Parmi tous leurs avantages, la possibilité d’ajuster facilement la valeur “B” ou “L” (luminosité).</p><p><em>NdT : <a href="https://la-cascade.io/auteurs/dudley-storey">Dudley Storey</a> a écrit deux articles instructifs sur HSL, dont “<a href="https://la-cascade.io/3-raisons-dutiliser-hsl-pour-vos-couleurs/">3 raisons d’utiliser HSL pour vos couleurs</a>”</em>.</p><figure role="group"><img itemprop="url" src="https://la-cascade.io/images/heart-recommend-2-compressor.jpeg" alt="" /><figcaption>L’ajustement se fait à vue, simplement en modifiant la valeur de “B”.</figcaption></figure><h2>L’échelle</h2><p>Par échelle, on entend la façon dont notre cerveau perçoit la taille des objects, texte y compris. Si nous traduisons cela en termes de cercles et de carrés, un carré de 120 × 120 pixels a une surface supérieure à celle d’un cercle de diamètre égal à 120 pixels, le cercle doit donc être légèrement plus grand pour pouvoir compenser.</p><figure role="group"><img src="https://la-cascade.io/images/cercle-and-rectangle.jpeg" alt="" /><figcaption>À gauche, les deux formes ont des dimensions de 120px, à droite le cercle a un diamètre de 126px.</figcaption></figure><p>Comme pour les autres ajustements, on fait dans la subtilité, mais ces modifications aident vraiment votre design à avoir l’air <em>juste</em>. C’est souvent un réglage fin d’éléments — comme de modifier des valeurs un pixel à la fois jusqu’à parvenir au bon <em>feeling</em>.</p><figure role="group"><img src="https://la-cascade.io/images/x-height-revealed-compressor.jpeg" alt="" /><figcaption>Le haut et le bas des formes incurvées de Didot dépassent la hauteur d’x et la ligne de base.</figcaption></figure><p>C’est également vrai pour la typographie, avec les dépassements (<em>overshoots</em>) des lettres arrondies (<em>NdT : Tobias Frere-Jones a écrit deux superbes articles à ce sujet, <a href="https://la-cascade.io/fonctionnement-des-polices-de-caracteres-1/">Mécanique des polices de caractères, 1</a> et <a href="https://la-cascade.io/mecanique-des-polices-de-caracteres-2-2/">Mécanique des polices de caractères, 2</a></em>). Si vous écrivez un texte en <a href="http://fr.wikipedia.org/wiki/Garamond_%28police_d%27%C3%A9criture%29">Garamond</a> et que vous représentez la <a href="http://fr.wikipedia.org/wiki/Ligne_de_base_%28typographie%29">ligne de base</a> et la <a href="http://fr.wikipedia.org/wiki/Hauteur_d%27x">hauteur d’x</a> du texte, vous verrez les dépassements des formes arrondies. Sans eux, les caractères donneraient l’impression d’être plus petits que leurs voisins.</p><h2>Lettres capitales</h2><p>Un dernier exemple rapide d’ajustement optique nécessaire : lorsqu’un texte en lettres capitales est placé à côté d’un texte en bas-de-casse. Le premier est proéminent et doit être ajusté pour équilibrer l’ensemble.</p><figure role="group"><img src="https://la-cascade.io/images/upper-case-compressor.jpeg" alt="" /><figcaption>Dans l’exemple du bas, le texte en capitales a été ajusté de 2px pour donner l’impression qu’il a la même taille.</figcaption></figure><p>Sauf si l’objectif de ce design est précisément de donner plus d’importance au texte en lettres capitales, celui-ci doit toujours être réduit de quelques pixels, par exemple en passant de 16 à 14 pixels ou de 12 à 11 pixels.</p><p>Lorsqu’on travaille sur une interface importante, chacun de ces petits détails s’accumule et affecte la sensation générale qui se dégage du site.</p><p>Une fois que vous l’aurez intégré à votre workflow, réduire un texte de 2 pixels ou déplacer un triangle de 10 pixels ne prendra que quelques instants, mais c’est ce qui rendra votre design proche de la perfection.</p><figure><img src="https://la-cascade.io/images/eye-compressor.jpeg" alt="un oeil" /></figure><p>Nous ne devons pas compter sur les seuls ordinateurs pour faire tout le travail pour nous, mais également sur nos yeux et notre instinct. Le regard des designers est plus aigu, leur instinct plus aiguisé à mesure qu’ils gagnent en expérience, c’est sur eux que doivent s’appuyer nos décisions.</p></div>]]></description>
      <link>https://la-cascade.io/articles/lajustement-optique</link>
      <guid>https://la-cascade.io/articles/lajustement-optique</guid>
      <pubDate>Sun, 31 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Astuces CSS avec checkbox]]></title>
      <description><![CDATA[<p><em>C'est incroyable ce qu'on peut faire avec un élément aussi modeste que les cases à cocher... du moins lorsqu'on s'appelle Will Boyd et qu'on a de la créativité à revendre !</em></p><div class="articleContent"><p>Les checkboxes (cases à cocher) sont épatantes, surtout quand vous les combinez avec un CSS astucieux. Cet article vise à montrer quelques petites choses créatives qu’on peut réaliser avec les checkboxes, et <em>sans JavaScript</em>.</p><h2>La formule de base</h2><p>Tout commence avec un peu de HTML :</p><pre>//HTML
&lt;input id="toggle" type="checkbox"&gt;
&lt;label for="toggle"&gt;</pre><p>Rien de bien spécial ici. L’attribut <code>for</code> sur le <code>&lt;label&gt;</code> correspond à l’<code>id</code> qu’on retrouve sur <code>&lt;input&gt;</code>, par conséquent lorsqu’on clique sur <code>&lt;label&gt;</code> on bascule l’état de la case à cocher <code>&lt;input&gt;</code>. C’est important parce que la prochaine étape va consister à cacher la case <code>&lt;input&gt;</code>.</p><pre>//CSS
input {
  position: absolute;
  left: -9999px;
}</pre><p>Pourquoi ne pas utiliser <code>display: none</code> ? Parce qu’il serait ignoré par les lecteurs d’écran et la navigation par tabulation. La méthode de décalage de la position permet de garder <code>&lt;input&gt;</code> dans le circuit, mais hors écran.</p><p>Cacher <code>&lt;input&gt;</code> nous facilite le travail. Nous devons toutefois transmettre l’état coché/non coché, ce que nous pouvons faire avec <code>&lt;label&gt;</code>. Et c’est ici qu’on commence à s’amuser.</p><pre>//CSS
input:checked + label {
  /* nos styles */
}</pre><p>Nous utilisons un mélange de <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:checked">pseudo-classe :checked</a> et de <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css/#combinateur-adjacent">combinateur adjacent</a> (<em>adjacent sibling</em>) pour dire ceci : “quand la checkbox est cochée (<em>checked</em>), trouver le <code>&lt;label&gt;</code> immédiatement consécutif et appliquer nos styles”. Vous pouvez même utiliser des pseudo-éléments (<a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after/">:before et :after</a>) à l’intérieur de <code>&lt;label&gt;</code> pour plus de créativité encore.</p><pre>//CSS
input:checked + label::before {
  /* styles pour un indicateur "on" */
}</pre><p>Très bien. Voyons tout cela en action. Cette démo utilise la formule basique dont nous venons de parler pour transformer les cases à cocher habituelles en quelque chose de plus impressionnant.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/RPZZPe/">Checkbox Trickery: Simple Toggle</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez que ce qu’il y a de bien, c’est que ça reste des checkboxes. Utilisez-les dans un formulaire et elles le soumettront exactement comme il faut : nous avons modifié leur apparence, pas leur comportement.</p><h2 class="softTitleBlue">Cacher et montrer du contenu</h2><p>Jusqu’ici, nous avons simplement appliqué quelques styles à <code>&lt;label&gt;</code> mais nous pouvons aller plus loin que cela. Cette démo cache et révèle dynamiquement des sections du formulaire en fonction des choix de l’utilisateur.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/NqvvGK/">Checkbox Trickery: Form Disclosure</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>La pseudo-classe <code>:checked</code> fonctionne avec les boutons radio de la même façon qu’avec les cases à cocher. Voici le code HTML correspondant aux boutons radio “Comment avez-vous entendu parler de nous ?” (<em>How did you hear about us?</em>) :</p><pre>//HTML
&lt;input id="how-friend" name="how" type="radio"&gt;
&lt;label for="how-friend" class="side-label"&gt;From a friend&lt;/label&gt;
&lt;input id="how-internet" name="how" type="radio"&gt;
&lt;label for="how-internet" class="side-label"&gt;Somewhere on the internet&lt;/label&gt;
&lt;input id="how-other" name="how" type="radio"&gt;
&lt;label for="how-other" class="side-label"&gt;Other...&lt;/label&gt;
&lt;div class="how-other-disclosure"&gt;
  &lt;label for="how-other-explain" class="top-label"&gt;Please explain&lt;/label&gt;
  &lt;textarea id="how-other-explain"&gt;&lt;/textarea&gt;
&lt;/div&gt;</pre><p>Le style des boutons radio est réalisé dans <code>&lt;label&gt;</code> via une combinaison de <code>:before</code> (pour le cercle externe) et <code>:after</code> (pour le point vert). Révéler ou cacher <code>:after</code> lorsqu’un bouton radio est coché ou décoché est très facile :</p><pre>//CSS
.side-label::after {
  display: none;
  /* autres styles */
}
input:checked + .side-label::after {
  display: block;
}</pre><p>La <code>&lt;div&gt;</code> est cachée jusqu’à ce que le bouton radio “Other...” soit coché. Cette fois-ci, la <code>&lt;div&gt;</code> est cachée via <code>display: none</code> car je veux que le contenu soit ignoré par les lecteurs d’écran jusqu’à ce qu’il soit effectivement révélé. Le CSS permettant de révéler le contenu de la <code>&lt;div&gt;</code> lorsque le bouton radio est coché est le suivant :</p><pre>//CSS
#how-other:checked ~ .how-other-disclosure {
  display: block;
}</pre><p>Jusqu’à présent, nous avons utilisé le combinateur adjacent <code>+</code> (plus), mais il est temps d’introduire <a href="https://la-cascade.io/combinateurs-et-pseudo-classes-css/#combinateur-general">le combinateur général</a> <code>~</code> (tilde). Il fonctionne un peu de la même manière, mais sur des frères (<em>siblings</em>) non adjacents, comme notre <code>&lt;div&gt;</code>.</p><h2>Arborescence de dossiers</h2><p>Nous pouvons réutiliser les techniques de la démo précédente pour créer un widget d’arborescence de dossiers.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/eNEEpB/">Checkbox Trickery: Folder Tree</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Le HTML d’un dossier individuel est donné ci-dessous. Le <code>&lt;label&gt;</code> est le dossier et les deux éléments <code>&lt;a&gt;</code> sont les “fichiers” à l’intérieur.</p><pre>//HTML
&lt;div&gt;
  &lt;input id="n-1" type="checkbox"&gt;
  &lt;label for="n-1"&gt;Blue&lt;/label&gt;
  &lt;div class="sub"&gt;
    &lt;a href="#link"&gt;Mana Leak&lt;/a&gt;
    &lt;a href="#link"&gt;Time Warp&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><p>Des icônes de <a href="http://fortawesome.github.io/Font-Awesome/">Font Awesome</a> sont utilisées pour indiquer l’état <em>checked</em> (ouvert) ou <em>unchecked</em> (fermé).</p><pre>//CSS
label::before, a::before {
  display: block;
  position: absolute;
  top: 6px;
  left: -25px;
  font-family: ’FontAwesome’;
}
label::before {
  content: ’\f07b’; /* closed folder */
}
input:checked + label::before {
  content: ’\f07c’; /* open folder */
}
a::before {
  content: ’\f068’; /* dash */
}</pre><p>Le contenu situé à l’intérieur d’un dossier est montré ou caché via le combinateur général <code>~</code>. C’est pourquoi on a une <code>&lt;div&gt;</code> supplémentaire pour envelopper chaque dossier, afin d’éviter que le combinateur ne se propage son effet et n’ouvre les autres dossiers.</p><pre>//CSS
input:checked ~ .sub {
  display: block;
}</pre><p>Évidemment, les dossiers peuvent être imbriqués. Cliquez sur le dossier “Multicolor” pour en voir un exemple.</p><p>Enfin, disons un mot sur notre bouton Reset.</p><pre>//HTML
&lt;input type="reset" value="Collapse All"&gt;</pre><p>Les boutons de Reset de formulaires ne sont plus vraiment utilisés de nos jours, mais nous avons ici un bon cas d’usage. Si nous cliquons dessus, toutes les cases à cocher retournent à leur état initial non-coché, ce qui ferme tous les dossiers. Cool !</p><h2>Listes scindées</h2><p>Cette démo partage les items en deux listes distinctes, selon qu’ils sont cochés ou non.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/xGLLwX/">Checkbox Trickery: To-Do List</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Le HTML ressemble à ceci :</p><pre>//HTML
&lt;div class="items"&gt;
  &lt;input id="item1" type="checkbox" checked&gt;
  &lt;label for="item1"&gt;Create a to-do list&lt;/label&gt;
  &lt;!-- more items --&gt;
  &lt;h2 class="done" aria-hidden="true"&gt;Done&lt;/h2&gt;
  &lt;h2 class="undone" aria-hidden="true"&gt;Not Done&lt;/h2&gt;
&lt;/div&gt;</pre><p>Le mécanisme de séparation des listes est obtenu via <a href="https://la-cascade.io/tags/flexbox/">Flexbox</a>. Voici le CSS correspondant :</p><pre>//CSS
.items {
  display: flex;
  flex-direction: column;
}
.done {
  order: 1;
}
input:checked + label {
  order: 2;
}
.undone {
  order: 3;
}
label {
  order: 4;
}</pre><p>CSS Flexbox nous permet de réordonner directement les éléments grâce à la propriété <code>order</code>. La valeur de la propriété passe de <code>4</code> à <code>2</code> lorsque la checkbox est cochée, ce qui la déplace de la partie inférieure “Not Done” vers la partie supérieure “Done”.</p><p>Malheureusement, la navigation via le clavier ainsi que <a href="http://sprungmarker.de/wp-content/uploads/css-a11y-group/css-a11y-flexbox.html">de nombreux lecteurs d’écran</a> suivront l’ordre des éléments dans le DOM, même s’ils ont été visuellement réordonnés avec flexbox. Du coup, les titres “Done” et “Not Done” sont sans utilité pour les lecteurs d’écran — c’est pourquoi j’ai ajouté <code>aria-hidden="true"</code> pour eux, mieux vaut qu’ils soient ignorés plutôt que de créer de la confusion. À part cela, la liste scindée est opérationnelle via le clavier et les lecteurs d’écran annonceront l’état d’un item (checked/unchecked).</p><p>Si vous êtes intrigués par les compteurs à droite de “Done” et “Not Done”, ils sont générés par des <a href="https://developer.mozilla.org/fr/docs/Web/CSS/Compteurs_CSS">CSS counters</a>, voyez <a href="http://codersblock.com/blog/fun-times-with-css-counters/">cet article</a> pour plus de détails.</p><h2>Filtrage de groupes</h2><p>C’est notre dernière démo. Nous allons voir comment mettre en valeur un tri croisé de données correspondant à un critère de sélection.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/lonekorean/pen/YXxxyj/">Checkbox Trickery: Group Filter</a>de Will Boyd dans<a href="https://codepen.io">CodePen</a></div><p>Voici le HTML abrégé. Remarquez que l’attribut <code>data-teams</code> est une liste d’attributs <code>id</code> de boutons radio séparés par un espace. C’est ainsi qu’on fait correspondre les personnages et les équipes.</p><pre>//HTML
&lt;input id="original" type="radio" name="team" checked&gt;
&lt;label for="original"&gt;Original X-Men&lt;/label&gt;
&lt;!-- autres équipes ici --&gt;
&lt;br&gt;
&lt;ul class="characters"&gt;
  &lt;li id="angel" data-teams="original force factor hellfire"&gt;
    &lt;h2&gt;Angel&lt;/h2&gt;
    &lt;img src="ct-angel.png" alt=""&gt;
  &lt;/li&gt;
  &lt;!-- autres personnages ici --&gt;
&lt;/ul&gt;</pre><p>En ce qui concerne l’accessibilité, j’utilise des attributs <code>alt</code> vides parce que les noms de personnages sont déjà dans les balises <code>&lt;h2&gt;</code> — il n’est donc pas nécessaire, ni souhaitable, de les répéter. De plus, puisque je ne cache pas les éléments <code>&lt;img&gt;</code> (ils sont seulement rétrécis et décolorés), cela permet aux lecteurs d’écrans de “sauter” les personnages non sélectionnés, il me suffit de cacher la balise <code>&lt;h2&gt;</code>.</p><p>Voici le CSS qui fait ressortir les personnages lorsque leur équipe est sélectionnée :</p><pre>//CSS
#original:checked ~ .characters [data-teams~="original"] h2,
#force:checked ~ .characters [data-teams~="force"] h2,
#factor:checked ~ .characters [data-teams~="factor"] h2,
#hellfire:checked ~ .characters [data-teams~="hellfire"] h2 {
  /* styles to show character name */
}
#original:checked ~ .characters [data-teams~="original"] img,
#force:checked ~ .characters [data-teams~="force"] img,
#factor:checked ~ .characters [data-teams~="factor"] img,
#hellfire:checked ~ .characters [data-teams~="hellfire"] img {
  /* styles to show character avatar */
}</pre><p>Ok, je reconnais que ces sélecteurs sont un peu touffus, mais en fait ce n’est pas si compliqué. Analysons la ligne 1 par exemple. Si on l’exprime en bon français, ça donne ceci : lorsque l’élément ayant une <code>id</code> ‘original’ est coché, chercher le ou les éléments frères (<em>general sibling</em>) ayant la classe de ‘personnages’ (<em>characters</em>) et contenant un attribut <code>data-teams</code> dans lequel se trouve ‘original’, puis aller chercher la balise <code>&lt;h2&gt;</code> située à l’intérieur. On répète avec ‘force’, ‘factor’ et ‘hellfire’ dans les lignes 2 à 4. Enfin, on reproduit le schéma dans le second bloc, mais cette fois-ci pour <code>&lt;img&gt;</code> à la place de <code>&lt;h2&gt;</code>.</p><h3>En guise de conclusion</h3><p>J’espère que vous avez eu autant de plaisir à jouer avec ces démos que j’en ai eu à les créer. C’était une expérience très intéressante de voir qu’on pouvait tirer quelque chose d’un élément aussi modeste que les cases à cocher. Je n’ai rien contre l’utilisation de JavaScript, lorsqu’elle est appropriée, mais c’est sympa de voir tout ce qu’on peut accomplir sans JS. Merci d’avoir lu cet article !</p></div>]]></description>
      <link>https://la-cascade.io/articles/astuces-css-avec-checkbox</link>
      <guid>https://la-cascade.io/articles/astuces-css-avec-checkbox</guid>
      <pubDate>Thu, 28 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Les bases de SVG : Rectangles et Carrés]]></title>
      <description><![CDATA[<p><em>Dudley Storey reconstitue un célèbre tableau de Mondrian et nous montre chemin faisant tout ce qu'il faut savoir pour créer des rectangles en SVG.</em></p><div class="articleContent"><p>Après <a href="https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses/">les cercles</a>, les rectangles sont sans doute l’élément le plus facile à réaliser en <a href="https://la-cascade.io/tags/svg/">SVG</a> puisqu’il suffit d’ajouter un attribut pour y parvenir. La syntaxe de base consiste en une position x, une position y, une largeur et une hauteur :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80"&gt;
  &lt;rect x="20" y="20" width="40" height="40"/&gt;
&lt;/svg&gt;</pre><p>Quelques petites choses à noter tout de suite :</p><ul><li>contrairement aux cercles, les rectangles sont dessinés à partir de leur coin supérieur gauche (déterminé par les coordonnées x et y).</li>
<li>comme la plupart des autres éléments, les rectangles sont noirs par défaut si aucun remplissage (<em>fill</em>) n’est indiqué.</li>
<li>l’élément rectangle est “auto-fermant”</li>
<li>comme tous les autres éléments, les rectangles qui apparaissent <em>après</em> dans le code seront positionnés au dessus des éléments qui les précèdent s’il y a chevauchement.</li>
<li>malgré l’impression trompeuse que pourrait donner le titre de cet article, il n’existe pas d’élément “carré” distinct du rectangle en SVG. Les carrés sont simplement des rectangles de côtés égaux.</li>
</ul><figure role="group" class="ds-big-svg">Composition in Color A, 1917, by Piet Mondrian<figcaption><a href="https://www.pinterest.fr/pin/91268329932353503/">Composition en couleur A, 1917</a>, de Piet Mondrian, reconstituée en SVG</figcaption></figure><h2>Bordures &amp; Coins</h2><p>Comme pour toutes les autres formes en SVG, on peut donner une bordure aux éléments <code>&lt;rect&gt;</code>, celle-ci étant un trait (<em>stroke</em>) dans le langage SVG :</p><pre>&lt;rect x="20" y="20" width="40" height="40" stroke="red" stroke-width="5" /&gt;</pre><p>Ce qui nous donne :</p><figure role="group" class="ds-small-svg"></figure><p>En CSS, on peut utiliser <code>border-radius</code> pour arrondir les angles visibles des éléments. Pour les rectangles SVG, on utilise les attributs <code>rx</code> et <code>ry</code> :</p><pre>&lt;rect x="20" y="20" width="40" height="40" stroke="red" stroke-width ="5" rx="5" ry="5" /&gt;</pre><p>Le résultat :</p><figure role="group" class="ds-small-svg"></figure><p>Cependant, contrairement à <code>border-radius</code>, <code>rx</code> et <code>ry</code> affectent simultanément et de manière égale tous les coins de l’élément — pas moyen de n’arrondir qu’un seul angle à la fois. On peut donner des valeurs différentes aux attributs <code>rx</code> et <code>ry</code> pour créer des effets spéciaux, par exemple pour donner une forme de de tonneau :</p><figure role="group" class="ds-small-svg"></figure><p>…mais la plupart du temps on donnera la même valeur aux deux attributs, et dans ce cas il existe un raccourci, il suffit d’indiquer uniquement <code>rx</code> :</p><pre>&lt;rect x="20" y="20" width="40" height="40" rx="5" /&gt;</pre><p>Note : <code>rx</code> et <code>ry</code> sont considérés comme des attributs <em>réguliers</em>, et non comme des attributs <em>de présentation</em>, par conséquent on ne peut pas les utiliser actuellement en CSS, pas plus d’ailleurs qu’on ne peut utiliser <code>border-radius</code> sur les éléments SVG (mais on peut l’utiliser sur l’élément SVG lui-même, comme on peut le voir sur le Mondrian ci-dessus).</p><h2>Le plus grand rectangle : styler le viewport</h2><p>Dans la plupart des éditeurs, le background d’un SVG apparaît blanc. En fait ce n’est pas le cas : il est transparent, son canal alpha est masqué, ce qui signifie que son rendu sera parfait lorsqu’on le placera comme image ou élément en ligne sur n’importe quel background de page HTML.</p><p>La première solution qui vient à l’esprit lorsqu’on a besoin d’un “canevas” de couleur différente dans un SVG est de dessiner un énorme rectangle qui couvre tout le viewport SVG. Mais en général c’est plutôt une mauvaise idée : non seulement cela ajoute un élément supplémentaire à la page, mais en plus cela complique le rendu de la page. À la place, il suffit d’appliquer un style à l’élément SVG lui-même, comme sur notre reproduction de Mondrian.</p><pre>svg { background: #fcedd6; }</pre><p>Il est même possible de placer un <code>border-radius</code> sur l’élément SVG, comme je l’ai fait dans <a href="http://codepen.io/dudleystorey/pen/ZGOKLJ">l’exemple de bouclier de Captain America</a>, créé pour l’article sur les cercles. C’est pratique si, par exemple, vous voulez donner une impression d’ombre portée sur le SVG entier.</p><p>Retrouvez <a href="http://codepen.io/dudleystorey/pen/MwbYaL">le code du tableau de Mondrian sur CodePen</a> !</p><p><em>La recréation de l'oeuvre de <a href="http://fr.wikipedia.org/wiki/Piet_Mondrian">Piet Mondrian</a> est en partie inspirée du travail de <a href="http://jennmoney.biz/">Jenn Schiffer</a>, qui a écrit une excellente série d'articles sur <a href="http://vart.institute/">la recréation d'oeuvres d'art au moyen des technologies du web</a></em>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/les-bases-de-svg-rectangles-et-carres</link>
      <guid>https://la-cascade.io/articles/les-bases-de-svg-rectangles-et-carres</guid>
      <pubDate>Tue, 26 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Les bases de SVG : Cercles et ellipses]]></title>
      <description><![CDATA[<p><em>Même lorsqu’on utilise un logiciel de création graphique pour créer des SVG, la connaissance de la syntaxe permet de créer plus rapidement et efficacement des formes simples.</em></p><div class="articleContent"><p>Même si la plupart des designers utilisent un logiciel de création graphique du type Adobe Illustrator ou Sketch pour créer des formes en</p><a href="https://la-cascade.io/tags/svg/">SVG</a>, le fait de connaître la syntaxe de base de SVG permet de créer plus facilement et plus précisément des éléments tels que lignes, cercles et rectangles — et parfois, encoder ces éléments à la main est plus rapide et plus efficace qu’un éditeur visuel.<h2>Cercles</h2><p>Regardons par exemple le tracé basique d’un cercle. Pour faire simple, je laisserai pour un prochain article les complications des unités et de leurs variations.</p><p>Vous pourriez écrire ce code à l’intérieur d’une balise <code>&lt;body&gt;</code> sur une page HTML, ou bien comme un document séparé, enregistré avec l’extension .svg — dans les deux cas le résultat serait visible dans un navigateur.</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200"&gt;
  &lt;circle cx="100" cy="100" r="80" fill="red" /&gt;
&lt;/svg&gt;</pre><p>…et le résultat est le suivant :</p><p>Quelques points à noter à ce stade :</p><ol><li>L’élément <code>circle</code> doit être “auto-fermant”</li>
<li>Le cercle est positionné à partir de son centre (cx pour “centre, axe des x”, cy pour “centre, axe des y”)</li>
<li>La position du centre du cercle est mesurée à partir du coin supérieur gauche de l’élément SVG</li>
<li>Le rayon (r) du cercle est, par défaut, mesuré dans la même unité que le reste</li>
<li>Si l’un de ces attributs n’est pas mentionné, il est supposé être égal à 0 (et noir pour les attributs de présentation impliquant la couleur)</li>
<li>le remplissage (<em>fill</em>) du cercle peut être spécifié via <a href="https://la-cascade.io/tags/couleur/">le système de couleur CSS</a> que vous préférez.</li>
</ol><p>Comme les rectangles et les autres éléments SVG, un cercle SVG est constitué de deux “parties”, un remplissage interne et un tracé (<em>stroke</em>) externe.</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200" height="200"&gt;
  &lt;circle cx="100" cy="100" r="80" fill="red" stroke-width="15" stroke="black" /&gt;
&lt;/svg&gt;</pre><p>Le code du cercle est un peu long et compliqué : nettoyons-le avec un sélecteur de classe :</p><pre>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"&gt;
  &lt;circle cx="100" cy="100" r="80" class="redcirc" /&gt;
&lt;/svg&gt;</pre><p>…et utilisons ce CSS :</p><pre>//CSS
svg {
  width: 200; height: 200;
}
.redcirc {
  fill: red;
  stroke: black;
  stroke-width: 15;
}</pre><p>Le résultat est le même que dans la version précédente :</p><p>Notes :</p><ul><li>Cela ne signifie pas que vous ayez tout d’un coup la possibilité d’appliquer <code>fill</code> aux éléments HTML. <code>fill</code>, <code>stroke</code> et <code>stroke-width</code> ne s’appliquent qu’aux éléments SVG. La plupart des attributs de présentation SVG ont un équivalent en propriété CSS, mais pas tous.</li>
<li>Si vous écrivez votre SVG dans le contexte d’une page HTML, la classe <code>.redcirc</code> peut se trouver dans la partie <code>&lt;head&gt;</code> de votre document ou dans une feuille de style externe.</li>
<li>La largeur du trait (<em>stroke-width</em>) est répartie de façon égale des deux côtés du contour de l’élément.</li>
</ul><p>Une fois que nous avons ceci, il est très facile de commencer à créer des tracés plus complexes. Je pense que vous voyez déjà où nous allons en venir :</p><pre>&lt;svg viewBox="0 0 500 500"&gt;
  &lt;title&gt;Captain America’s Shield&lt;/title&gt;
  &lt;circle cx="250" cy="250" r="250" fill="red" /&gt;
  &lt;circle cx="250" cy="250" r="200" fill="white" /&gt;
  &lt;circle cx="250" cy="250" r="150" fill="red" /&gt;
  &lt;circle cx="250" cy="250" r="50" fill="blue" /&gt;
  &lt;polygon fill="white" points="250,150 280,209 346,219 298,265 309,330 250,300 192,330 203,265 155,219 221,209" /&gt;
&lt;/svg&gt;</pre><p>Remarquez que les éléments SVG s’empilent <a href="http://demosthenes.info/blog/136/Stacking-order-and-z-index">comme les éléments HTML</a>.</p><p>Cependant, nous pouvons être plus malins ! D’une manière générale, moins il y a d’éléments dans un document SVG et mieux on se porte, donc nous pouvons simuler des sections du bouclier en utilisant <code>stroke</code> et seulement deux cercles :</p><pre>&lt;svg viewBox="0 0 500 500"&gt;
  &lt;title&gt;Captain America’s Shield&lt;/title&gt;
  &lt;circle cx="250" cy="250" r="220" fill="white" /&gt;
  &lt;circle cx="250" cy="250" r="125" fill="blue" /&gt;
  &lt;polygon fill="white" points="250,150 280,209 346,219 298,265 309,330 250,300 192,330 203,265 155,219 221,209" /&gt;
&lt;/svg&gt;</pre><p>combinés avec ce CSS :</p><pre>//CSS
circle {
  stroke-width: 50;
  stroke: red;
}</pre><p>Captain America’s Shield</p><p>Le résultat est le même que l’original. <a href="http://codepen.io/dudleystorey/pen/ZGOKLJ">La version complète</a> (ci-dessus) utilise également une variation intéressante de <a href="https://la-cascade.io/tags/flexbox/">flexbox</a> et de <code>box-shadow</code> pour positionner et ombrer le bouclier.</p><h2>Ellipses</h2><p>La syntaxe de l’ellipse est proche de celle du cercle :</p><pre>&lt;svg viewBox="0 0 120 120"&gt;
  &lt;ellipse cx="60" cy="60" rx="60" ry="30"/&gt;
&lt;/svg&gt;</pre><p>Ici, nous avons deux rayons représentant <a href="http://en.wikipedia.org/wiki/Semi-major_axis">le demi-grand-axe (<em>semi-major</em>) et le demi-petit-axe (<em>semi-minor</em>)</a> de l’ellipse.</p><p>Un trait utile des cercles et des ellipses (et des formes SVG en général) écrites en ligne dans une page est que, contrairement aux éléments HTML, leur “zone active” correspond exactement à leur forme. Donc si nous insérons un lien dans notre ellipse :</p><pre>&lt;svg viewBox="0 0 120 120"&gt;
  &lt;a xlink:href="http://www.cnn.com"&gt;
    &lt;ellipse cx="60" cy="60" rx="50" ry="25" /&gt;
  &lt;/a&gt;
&lt;/svg&gt;</pre><p>et que nous combinons ceci avec ce CSS :</p><pre>//CSS
ellipse:hover { fill: red; }</pre><p>nous obtenons exactement ceci : remarquez la réponse précise en fonction de la position de la souris.</p><p>Il est possible de reproduire cette forme en HTML via <code>border-radius</code> sur un élément, mais le défi devient insurmontable dès lors que les formes de boutons sont plus compliquées — et c’est l’une des raisons qui font de SVG un excellent format pour les éléments d’interface utilisateur.</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/dudleystorey/pen/ZGOKLJ">Le bouclier de Captain America</a>de dudleystorey dans<a href="https://codepen.io">CodePen</a></div></div>]]></description>
      <link>https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses</link>
      <guid>https://la-cascade.io/articles/les-bases-de-svg-cercles-et-ellipses</guid>
      <pubDate>Mon, 25 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Comprendre Clip Path]]></title>
      <description><![CDATA[<p><em>La propriété clip-path de CSS est un super outil pour réaliser des effets de style</em></p><div class="articleContent"><p>Ce qui est bien quand on enseigne, c’est que les étudiants arrivent toujours avec de nouvelles idées. L’un d’eux voulait reproduire un effet observé sur <a href="http://www.squarespace.com/about/values">Squarespace</a>, où une <code>div</code> semble entaillée :</p><figure role="group"><img src="https://la-cascade.io/images/navigation-compressor.jpeg" alt="navigation, l’onglet sélectionné semble porter une entaille" /></figure><p>Sachant que son niveau lui permettait de comprendre les HTML et CSS du site, je me suis lancé avec elle dans la réalisation de cet effet. Ce découpage de la <code>nav</code> n’est pas si facile, ma première idée était de créer une image aux dimensions de l’entaille et de l’intégrer avec <code>::after</code>, mais ce n’est pas très responsif et pas aisé à gérer.</p><h2>Clip Path entre en scène</h2><p>La propriété CSS clip-path permet de cacher des portions d’un élément via le masquage (<em>masking</em>) et le découpage, ou détourage (<em>clipping</em>).</p><figure role="group"><img src="https://la-cascade.io/images/ville-compressor.jpeg" alt="" /><figcaption>L’image qui nous servira de base pour nos découpages.</figcaption></figure><p>En bref, la façon dont la propriété fonctionne est simple : on fournit une série de valeurs X et Y pour créer un chemin. Ces valeurs, une fois un chemin complet créé, découpent l’image située à l’intérieur.</p><p>Nous pouvons créer de nombreuses formes différentes à partir de cercles, d’ellipses, de polygones. La créativité est la seule limite.</p><h3>Un triangle simple</h3><p>L’effet ci-dessus est obtenu en utilisant simplement un élément et en lui appliquant un clip-path.</p><pre>//CSS
.clipClass {
   clip-path: polygon(0 100%, 50% 0, 100% 100%);
}</pre><h3>Whoa, détaillons tout ça</h3><p>De la même façon que pour la propriété <code>position</code>, nous devons penser en termes de valeurs X et Y. X:0 et Y:0 sont situés dans le coin supérieur gauche de l’élément. X:100% signifie qu’on a atteint le côté droit et Y:100% le bas.</p><p>Ok, cool. Donc le chemin que nous venons de créer utilise les points suivants :</p><pre>x: 0, y:100%
x: 50%, y: 0
x: 100%, y: 100%</pre><p>Un chemin simple, qui part du bas à gauche, se déplace horizontalement jusqu’à la moitié de l’espace (50%), puis monte jusqu’en haut (0) pour atteindre le 2e point, puis va tout à fait à droite horizontalement et en bas, pour atteindre le 3e point : 3 points = un triangle !</p><p>Tout ce qui ne se trouve pas à l’intérieur de ces limites est simplement découpé et n’apparaît pas. L’élément lui-même garde ses dimensions, bien que le mode de présentation ait changé.</p><h3>Formes</h3><p>Dans ce premier exemple, nous avons utilisé un polygone pour créer une forme et définir un chemin en créant des paires x et y, séparées par des virgules. Mais nous pouvons travailler avec différentes formes, qui prennent des valeurs différentes.</p><h3>Cercles</h3><p>Pour créer des cercles, nous passons trois valeurs. L’axe des x et des y nous donne les coordonnées du centre du cercle, et le rayon définit sa taille. La syntaxe est la suivante : “dimension du rayon (at) coordonnées du centre” :</p><pre>//CSS
.clipClass {
  clip-path: circle(50% at 50% 50%);
}</pre><h3>Ellipses</h3><p>Si vous préférez une forme oblongue, vous pouvez choisir l’<a href="http://fr.wikipedia.org/wiki/Ellipse_%28math%C3%A9matiques%29">ellipse</a>. Pour celle-ci, vous devez fournir quatre valeurs, une valeur sur l’axe des x, une sur l’axe des y, et les deux valeurs correspondant au centre. Ici encore, les coordonnées du centre sont précédées du mot-clé “at” :</p><pre>//CSS
.clipClass {
  clip-path: ellipse(30% 20% at 50% 50%);
}</pre><h3>Inset</h3><p>Si les angles aigus des polygones ne vous plaisent pas et que vous souhaitez créer des rectangles arrondis, utilisez les valeurs “inset”. Inset prend quatre valeurs, correspondant aux positions haut, droit, bas, gauche et permet l’utilisation d’un rayon sur chacune de ces valeurs.</p><pre>//CSS
.clipClass {
  clip-path: inset(25% 0 25% 0 round 0 25% 0 25%);
}</pre><p>Ce qui se lit comme :</p><pre>inset(&lt;haut&gt; &lt;droit&gt; &lt;bas&gt; &lt;gauche&gt; round &lt;rayon-haut&gt; &lt;rayon-droit&gt; &lt;rayon-bas&gt; &lt;rayon-gauche&gt;)</pre><p>Un peu long ? Bonne nouvelle, il y a un raccourci :</p><pre>//CSS
.clipClass {
  clip-path: inset(25% 0 round 0 25%);
}</pre><h4>Références rapides :</h4><p><strong>Cercle</strong> : circle(rayon at x y)</p><p><strong>Ellipse</strong> : ellipse(rayon-x rayon-y at x y)</p><p><strong>Polygone</strong> : polygon(x y, x y, ...)</p><p><strong>Inset</strong> : inset(haut droit bas gauche round rayon-haut rayon-droit rayon-bas rayon-gauche)</p><h3>Créer des formes</h3><p>Les cercles et les formes utilisant les rayons sont limités à quelques valeurs, par conséquent les polygones sont souvent un meilleur choix pour créer des formes complexes. Comme nous pouvons définir autant de points que nous le voulons, nous pouvons découper notre élément dans des formes très variées.</p><h3>Bulle de bande dessinée</h3><pre>//CSS
.clipClass {
  clip-path: polygon(0% 0%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);
}</pre><h3>Étoile</h3><pre>//CSS
.clipClass {
  clip-path: polygon(50% 0%, 63% 38%, 100% 38%, 69% 59%, 82% 100%, 50% 75%, 18% 100%, 31% 59%, 0 38%, 37% 38%);
}</pre><h3>Animation</h3><p>Maintenant que nous maîtrisons mieux les formes et la façon de les produire, nous pouvons nous amuser à créer des effets.</p><p>Nous pouvons par exemple avoir une forme qui s’applique au survol, en utilisant une propriété <a href="https://la-cascade.io/transition/">transition</a> pour créer un effet en douceur. Cependant, nous devons garder à l’esprit qu’il nous faut créer un état initial par défaut, utilisant les mêmes points que ceux qui nous serviront pour notre état modifié.</p><pre>//CSS
.animateClass {
  clip-path: polygon(20% 0%, 0% 0%, 0% 50%, 0% 80%, 0% 100%, 50% 100%, 80% 100%, 100% 100%, 100% 50%, 100% 0, 80% 0, 50% 0);
  transition: clip-path 0.5s;
}
.animateClass:hover {
  clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
}</pre><h2>Utilisation en production</h2><p>Comme toujours, pour connaître les détails à jour de la compatibilité vous pouvez consulter <a href="http://caniuse.com/#search=css%20clip-path">Can I Use</a>.</p><h3>Retour à notre tâche initiale</h3><p>Tout ceci parce que nous voulions recréer la navigation Squarespace, vous vous rappelez ? Eh bien maintenant, si nous utilisons le positionnement pour recouvrir un élément par un autre, puis que nous utilisons clip-path pour masquer l’image, nous pouvons simplement montrer l’image de background sans avoir à appliquer de techniques complexes de remplacement d’images.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/rachelandrew/pen/vEZOeq/">Squarespace clip-path</a>de Drew Minns dans<a href="https://codepen.io">CodePen</a></div><p>Je ne sais pas ce que vous en pensez, mais je trouve que l’avenir est de plus en plus géométrique.</p></div>]]></description>
      <link>https://la-cascade.io/articles/comprendre-clip-path</link>
      <guid>https://la-cascade.io/articles/comprendre-clip-path</guid>
      <pubDate>Sat, 09 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[5 règles pour rendre SVG accessible]]></title>
      <description><![CDATA[<p><em>rendre SVG accessible demande encore du travail, simple avec ces 5 règles proposées par Dudley Storey</em></p><div class="articleContent"><p>Le SVG en ligne peut faire des miracles pour le design responsif tout en réduisant le temps de chargement des pages web et en produisant des icônes propres et à la netteté parfaite — mais il n’est pas sans poser quelques problèmes, parmi lesquels l’accessibilité. L’accessibilité n’était pas une priorité lorsque la spécification originale SVG 1.0 a été publiée il y a 15 ans. Cependant, SVG 1.1 a amélioré les choses et SVG 2.0 devrait à l’avenir mettre l’accessibilité au premier plan.</p><p>Pour l’instant, rendre les SVG accessibles demande un peu de travail, mais c’est un processus assez simple si vous suivez ces cinq règles :</p><h2>1 - Traitez les liens vers une image SVG comme les bitmaps</h2><p>Lorsque vous faites un lien vers un document SVG comme image, l’attribut <code>alt</code> est requis :</p><pre>//HTML
&lt;img src="coca-cola-logo.svg" alt="Coca-Cola"&gt;</pre><p>...comme pour n’importe quelle <a href="http://thenewcode.com/64/Bitmap-Images-for-the-Web-Formats-and-Optimisation-Options">image matricielle</a> (<em>bitmap</em>).</p><h2>2 - Pour SVG en ligne, donnez un titre</h2><p>Le <code>&lt;title&gt;</code> d’un élément SVG sert le même objectif que le <code>&lt;title&gt;</code> d’un document HTML : C’est une brève description du document, ou un conseil. On peut le voir comme le <code>&lt;alt&gt;</code> d’un SVG inline.</p><pre>//HTML
&lt;header&gt;
  &lt;svg&gt;
    &lt;title&gt;Coca-Cola&lt;/title&gt;
    &lt;polyline ... /&gt;
   &lt;/svg&gt;
&lt;/header&gt;</pre><p><code>&lt;title&gt;</code> peut également être utilisé pour les éléments individuels : plus spécifiquement <code>&lt;circle&gt;</code>, <code>&lt;ellipse&gt;</code>, <code>&lt;image&gt;</code>, <code>&lt;line&gt;</code>, <code>&lt;path&gt;</code>, <code>&lt;polygon&gt;</code>, <code>&lt;polyline&gt;</code>, <code>&lt;rect&gt;</code>, <code>&lt;text&gt;</code> et <code>&lt;use&gt;</code>, ainsi que les éléments container SVG tels que <code>&lt;a&gt;</code>, <code>&lt;defs&gt;</code>, <code>&lt;g&gt;</code> et <code>&lt;symbol&gt;</code>. <code>&lt;title&gt;</code> sera généralement le premier enfant de cet élément. Parfois, ce titre sera <em>visuellement</em> descriptif :</p><pre>&lt;title&gt;Yellow Five-Pointed Star&lt;/title&gt;
&lt;polygon fill="#ff0" points="509,19.6 534.7,71.7 592.1,80 550.5,120.5 560.4,177.7 509,150.7 457.6,177.7 467.5,120.5 425.9,80 483.3,71.7 "/&gt;</pre><p>...et parfois il sera <em>informationnel</em> (c’est à dire qu’il décrit la <em>finalité</em> d’un élément, ou son <em>sens</em>).</p><p><strong>Note</strong> : on remarquera que les éléments <code>&lt;text&gt;</code> de SVG inline sont dans la plupart des cas complètement accessibles, puisqu’ils contiennent du texte — quels que soient les effets graphiques qui leur sont appliqués — ils n’auront donc pas besoin de <code>&lt;title&gt;</code> dans ce cas. Toutefois, si transformez votre texte en pures formes vectorielles, il vous <em>faudra</em> fournir un <code>&lt;title&gt;</code>.</p><p>Comme pour les pages HTML, le texte situé à l’intérieur d’un élément SVG est lu par les outils d’accessibilité dans l’<em>ordre du document</em>, et non dans l’ordre de leur <em>position visuelle à l’écran</em>.</p><p>Si un SVG ne contient qu’un seul élément, un simple <code>&lt;title&gt;</code> après la balise ouvrante <code>&lt;svg&gt;</code> pourra s’avérer suffisant. Si le document contient plusieurs éléments, vous aurez probablement besoin d’un <code>&lt;title&gt;</code> pour chacun ou pour chaque groupe :</p><pre>&lt;svg&gt;
  &lt;g&gt;
    &lt;title&gt;Red Rectangle&lt;/title&gt;
    &lt;rect x="0" y="0" width="100" height="50" fill="red" /&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><p>Vous pouvez améliorer cette information en associant <code>&lt;title&gt;</code> à <code>aria-labelledby</code>. Dans le cas d’un élément simple, cela peut renvoyer à l’élément racine <code>&lt;svg&gt;</code> :</p><pre>&lt;svg aria-labelledby="title"&gt;
  &lt;g&gt;
    &lt;title id="title" lang="en"&gt;Red Rectangle&lt;/title&gt;
    &lt;rect x="0" y="0" width="100" height="50" fill="red" /&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><p>Tout comme <code>&lt;desc&gt;</code> et d’autres éléments HTML, <code>&lt;title&gt;</code> devrait également avoir <a href="http://thenewcode.com/474/Language-Support-In-HTML">un attribut <code>lang</code> indiquant la langue utilisée</a> (voir plus bas).</p><p><strong>Note</strong> : il est possible de naviguer vers les éléments SVG utilisés dans les balises <code>&lt;img&gt;</code> comme s’ils étaient des éléments autonomes, ils peuvent également être indexés par les moteurs de recherche en tant de documents séparés, et de ce fait ils devraient aussi contenir un <code>&lt;title&gt;</code> et une <code>&lt;desc&gt;</code> appropriés <em>dans le balisage du document SVG original</em>.</p><h2>3 - Donnez une description lorsque nécessaire</h2><p><code>&lt;desc&gt;</code> correspond à une description plus longue de votre élément SVG, spécifiant son intention. On peut le voir un peu comme l’équivalent SVG de <code>figcaption</code>.</p><pre>&lt;svg&gt;
  &lt;g&gt;
    &lt;title&gt;International sales by country&lt;/title&gt;
    &lt;title lang="fr"&gt;Les ventes internationales par pays&lt;/title&gt;
    &lt;desc&gt;Bar chart showing company sales by country, in millions of dollars (US).&lt;/desc&gt;
    &lt;desc lang="fr"&gt;Diagramme montrant les ventes de l’entreprise par pays, en millions de dollars (US).&lt;/desc&gt;
  &lt;g&gt;
    &lt;text x="20" y="70"&gt;US Sales&lt;/text&gt;
    &lt;title id="USamount"&gt;30 million&lt;/title&gt;
    &lt;rect x="0" y="0" width="100" height="50" fill="red" aria-labelledby="USamount" /&gt;
  &lt;/g&gt;
  &lt;g&gt;
    &lt;text x="20" y="70"&gt;French Sales&lt;/text&gt;
    &lt;title id="FRamount"&gt;50 million&lt;/title&gt;
    &lt;rect x="150" y="20" width="100" height="80" fill="red" aria-labelledby="FRamount" /&gt;
  &lt;/g&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><p>International sales by countryLes ventes internationales par paysBar chart showing company sales by country, in millions of dollars (US).Diagramme montrant les ventes de l’entreprise par pays, en millions de dollars (US).Ventes US30 millionVentes France50 million</p><p>Cet exemple suppose que vous fournirez également les axes graphiques et les informations chiffrées pour les utilisateurs n’ayant <em>pas</em> de problèmes d’accessibilité : quand c’est possible, exposer l’information sous forme de <code>&lt;text&gt;</code> rendra service à <em>tous</em>.</p><h2>4 - Vous n’avez rien à faire si le SVG est purement décoratif</h2><p>Si l’élément SVG est utilisé à des fins purement décoratives — un dégradé ou un motif de background par exemple — pas besoin de fournir <code>&lt;title&gt;</code>, <code>&lt;desc&gt;</code> ni <code>alt</code>. (Si vous voulez que votre page soit <a href="http://thenewcode.com/454/Climbing-Mount-Sinai-The-Importance-of-Web-Page-Validation">validée</a> par les outils de validation, vous devrez mettre un <code>alt</code> pour les SVG liés, mais vide pour les éléments décoratifs, c’est à dire <code>alt=""</code> ou simplement <code>alt</code>).</p><p>Par défaut, ni <code>&lt;desc&gt;</code> ni <code>&lt;title&gt;</code> ne sont rendus visuellement dans le navigateur (bien qu’on puisse leur appliquer un style pour qu’ils le soient) ; le texte de <code>&lt;title&gt;</code> apparaîtra au survol dans les navigateurs compatibles. ( <em>NdT : vous pouvez faire l’essai avec le diagramme ci-dessus</em>).</p><h2>5 - Ne comptez pas sur votre WYSIWYG pour le faire à votre place</h2><p>Malheureusement, Adobe Illustrator ne supporte que très peu l’accessibilité SVG. Il exporte les noms de calques comme des valeurs d’ <code>id</code> plutôt que comme une information <code>&lt;title&gt;</code>. Inkscape fait mieux en vous permettant d’ajouter et d’éditer <code>&lt;title&gt;</code> et <code>&lt;desc&gt;</code> pour chaque élément, avec l’inconvénient d’ajouter du code redondant à votre markup. Vous en viendrez sans doute à la conclusion qu’il est préférable d’ajouter un peu de code à la main pour ajouter une pleine accessibilité à un document SVG réalisé avec les outils vectoriels.</p></div>]]></description>
      <link>https://la-cascade.io/articles/rendre-svg-accessible</link>
      <guid>https://la-cascade.io/articles/rendre-svg-accessible</guid>
      <pubDate>Fri, 08 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[5 règles pour rendre SVG accessible]]></title>
      <description><![CDATA[<p><em>SVG est formidable pour le design responsif, la performance et la qualité vectorielle, mais rendre SVG accessible demande encore un peu de travail, rendu simple avec ces 5 règles proposées par Dudley Storey.</em></p><div class="articleContent"><p>Le <a href="https://la-cascade.io/tags/svg/">SVG</a> en ligne peut faire des miracles pour le design responsif tout en réduisant le temps de chargement des pages web et en produisant des icônes propres et à la netteté parfaite — mais il n’est pas sans poser quelques problèmes, parmi lesquels l’accessibilité. L’accessibilité n’était pas une priorité lorsque la spécification originale SVG 1.0 a été publiée il y a 15 ans. Cependant, SVG 1.1 a amélioré les choses et SVG 2.0 devrait à l’avenir mettre l’accessibilité au premier plan.</p><p>Pour l’instant, rendre les SVG accessibles demande un peu de travail, mais c’est un processus assez simple si vous suivez ces cinq règles :</p><h2>1 - Traitez les liens vers une image SVG comme les bitmaps</h2><p>Lorsque vous faites un lien vers un document SVG comme image, l’attribut <code>alt</code> est requis :</p><pre class="language-HTML">  &lt;img src="coca-cola-logo.svg" alt="Coca-Cola"&gt;</pre><p>...comme pour n’importe quelle <a href="http://thenewcode.com/64/Bitmap-Images-for-the-Web-Formats-and-Optimisation-Options">image matricielle</a> (<em>bitmap</em>).</p><h2>2 - Pour SVG en ligne, donnez un titre</h2><p>Le <code>&lt;title&gt;</code> d’un élément SVG sert le même objectif que le <code>&lt;title&gt;</code> d’un document HTML : C’est une brève description du document, ou un conseil. On peut le voir comme le <code>&lt;alt&gt;</code> d’un SVG inline.</p><pre class="language-HTML">  &lt;header&gt;
    &lt;svg&gt;
      &lt;title&gt;Coca-Cola&lt;/title&gt;
      &lt;polyline ... /&gt;
    &lt;/svg&gt;
  &lt;/header&gt;</pre><p><code>&lt;title&gt;</code> peut également être utilisé pour les éléments individuels : plus spécifiquement <code>&lt;circle&gt;</code>, <code>&lt;ellipse&gt;</code>, <code>&lt;image&gt;</code>, <code>&lt;line&gt;</code>, <code>&lt;path&gt;</code>, <code>&lt;polygon&gt;</code>, <code>&lt;polyline&gt;</code>, <code>&lt;rect&gt;</code>, <code>&lt;text&gt;</code> et <code>&lt;use&gt;</code>, ainsi que les éléments container SVG tels que <code>&lt;a&gt;</code>, <code>&lt;defs&gt;</code>, <code>&lt;g&gt;</code> et <code>&lt;symbol&gt;</code>. <code>&lt;title&gt;</code> sera généralement le premier enfant de cet élément. Parfois, ce titre sera <em>visuellement</em> descriptif :</p><pre class="language-xml">  &lt;title&gt;Yellow Five-Pointed Star&lt;/title&gt;
  &lt;polygon fill="#ff0" points="509,19.6 534.7,71.7 592.1,80 550.5,120.5 560.4,177.7 509,150.7 457.6,177.7 467.5,120.5 425.9,80 483.3,71.7 "/&gt;</pre><p>...et parfois il sera <em>informationnel</em> (c’est à dire qu’il décrit la <em>finalité</em> d’un élément, ou son <em>sens</em>).</p><p><strong>Note</strong> : on remarquera que les éléments <code>&lt;text&gt;</code> de SVG inline sont dans la plupart des cas complètement accessibles, puisqu’ils contiennent du texte — quels que soient les effets graphiques qui leur sont appliqués — ils n’auront donc pas besoin de <code>&lt;title&gt;</code> dans ce cas. Toutefois, si vous transformez votre texte en pures formes vectorielles, il vous <em>faudra</em> fournir un <code>&lt;title&gt;</code>.</p><p>Comme pour les pages HTML, le texte situé à l’intérieur d’un élément SVG est lu par les outils d’accessibilité dans l’<em>ordre du document</em>, et non dans l’ordre de leur <em>position visuelle à l’écran</em>.</p><p>Si un SVG ne contient qu’un seul élément, un simple <code>&lt;title&gt;</code> après la balise ouvrante <code>&lt;svg&gt;</code> pourra s’avérer suffisant. Si le document contient plusieurs éléments, vous aurez probablement besoin d’un <code>&lt;title&gt;</code> pour chacun ou pour chaque groupe :</p><pre class="language-xml">&lt;svg&gt;
  &lt;g&gt;
    &lt;title&gt;Red Rectangle&lt;/title&gt;
    &lt;rect x="0" y="0" width="100" height="50" fill="red" /&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><p>Vous pouvez améliorer cette information en associant <code>&lt;title&gt;</code> à <code>aria-labelledby</code>. Dans le cas d’un élément simple, cela peut renvoyer à l’élément racine <code>&lt;svg&gt;</code> :</p><pre class="language-xml">&lt;svg aria-labelledby="title"&gt;
  &lt;g&gt;
    &lt;title id="title" lang="en"&gt;Red Rectangle&lt;/title&gt;
    &lt;rect x="0" y="0" width="100" height="50" fill="red" /&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><p>Tout comme <code>&lt;desc&gt;</code> et d’autres éléments HTML, <code>&lt;title&gt;</code> devrait également avoir <a href="http://thenewcode.com/474/Language-Support-In-HTML">un attribut <code>lang</code> indiquant la langue utilisée</a> (voir plus bas).</p><p><strong>Note</strong> : il est possible de naviguer vers les éléments SVG utilisés dans les balises <code>&lt;img&gt;</code> comme s’ils étaient des éléments autonomes, ils peuvent également être indexés par les moteurs de recherche en tant de documents séparés, et de ce fait ils devraient aussi contenir un <code>&lt;title&gt;</code> et une <code>&lt;desc&gt;</code> appropriés <em>dans le balisage du document SVG original</em>.</p><h2>3 - Donnez une description lorsque nécessaire</h2><p><code>&lt;desc&gt;</code> correspond à une description plus longue de votre élément SVG, spécifiant son intention. On peut le voir un peu comme l’équivalent SVG de <code>figcaption</code>.</p><pre class="language-xml">&lt;svg&gt;
  &lt;g&gt;
    &lt;title&gt;International sales by country&lt;/title&gt;
    &lt;title lang="fr"&gt;Les ventes internationales par pays&lt;/title&gt;
    &lt;desc&gt;Bar chart showing company sales by country, in millions of dollars (US).&lt;/desc&gt;
    &lt;desc lang="fr"&gt;Diagramme montrant les ventes de l’entreprise par pays, en millions de dollars (US).&lt;/desc&gt;
    &lt;g&gt;
      &lt;text x="20" y="70"&gt;US Sales&lt;/text&gt;
      &lt;title id="USamount"&gt;30 million&lt;/title&gt;
      &lt;rect x="0" y="0" width="100" height="50" fill="red" aria-labelledby="USamount" /&gt;
    &lt;/g&gt;
  &lt;g&gt;
&lt;/svg&gt;</pre><p>French SalesInternational sales by countryLes ventes internationales par paysBar chart showing company sales by country, in millions of dollars (US).Diagramme montrant les ventes de l’entreprise par pays, en millions de dollars (US).US Sales30 millionFrench Sales50 million</p><p>Cet exemple suppose que vous fournirez également les axes graphiques et les informations chiffrées pour les utilisateurs n’ayant <em>pas</em> de problèmes d’accessibilité : quand c’est possible, exposer l’information sous forme de <code>&lt;text&gt;</code> rendra service à <em>tous</em> comme dans l'illustration qui précède.</p><h2>4 - Vous n’avez rien à faire si le SVG est purement décoratif</h2><p>Si l’élément SVG est utilisé à des fins purement décoratives — un dégradé ou un motif de background par exemple — pas besoin de fournir <code>&lt;title&gt;</code>, <code>&lt;desc&gt;</code> ni <code>alt</code>. (Si vous voulez que votre page soit <a href="http://thenewcode.com/454/Climbing-Mount-Sinai-The-Importance-of-Web-Page-Validation">validée</a> par les outils de validation, vous devrez mettre un <code>alt</code> pour les SVG liés, mais vide pour les éléments décoratifs, c’est à dire <code>alt=""</code> ou simplement <code>alt</code>).</p><p>Par défaut, ni <code>&lt;desc&gt;</code> ni <code>&lt;title&gt;</code> ne sont rendus visuellement dans le navigateur (bien qu’on puisse leur appliquer un style pour qu’ils le soient) ; le texte de <code>&lt;title&gt;</code> apparaîtra au survol dans les navigateurs compatibles.<br />( <em>NdT : vous pouvez faire l’essai avec le diagramme ci-dessus</em>).</p><h2>5 - Ne comptez pas sur votre WYSIWYG pour le faire à votre place</h2><p>Malheureusement, Adobe Illustrator ne supporte que très peu l’accessibilité SVG. Il exporte les noms de calques comme des valeurs d’ <code>id</code> plutôt que comme une information <code>&lt;title&gt;</code>. Inkscape fait mieux en vous permettant d’ajouter et d’éditer <code>&lt;title&gt;</code> et <code>&lt;desc&gt;</code> pour chaque élément, avec l’inconvénient d’ajouter du code redondant à votre markup. Vous en viendrez sans doute à la conclusion qu’il est préférable d’ajouter un peu de code à la main pour ajouter une pleine accessibilité à un document SVG réalisé avec les outils vectoriels.</p><p><strong>Ressources complémentaires en anglais</strong></p><ul><li><a href="http://www.sitepoint.com/tips-accessible-svg/">Tips for creating accessible SVG</a>, par Léonie Watson</li>
</ul><p><strong>Ressources complémentaires en français</strong></p><ul><li><a href="http://blog.atalan.fr/svg-liens-et-lecteurs-decran/">SVG, liens et lecteurs d’écran</a>, sur le blog d’Atalan</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/5-regles-pour-rendre-svg-accessible</link>
      <guid>https://la-cascade.io/articles/5-regles-pour-rendre-svg-accessible</guid>
      <pubDate>Thu, 07 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[3 raisons d'utiliser HSL pour vos couleurs]]></title>
      <description><![CDATA[<p><em>Pourquoi utiliser HSL ? Quelle différence entre HSL et RGB ? Dudley Storey passe en revue quelques situations où HSL peut vraiment vous changer la vie.</em></p><div class="articleContent"><p>Nous avons vu dans <a href="https://la-cascade.io/articles/utiliser-hsl-pour-vos-couleurs/">l’article précédent</a> tout l’intérêt qu’il y avait à utiliser HSL pour créer et manipuler les couleurs, mais il est des domaines où cela présente tellement d’avantages qu’il est presque surprenant que les développeurs n’en profitent pas plus.</p><figure role="group"><img src="https://la-cascade.io/images/holi-2x.jpeg" alt="jeune fille recouverte de peinture de toutes les couleurs et tirant la langue" /></figure><h2>Créer des prototypes rapides de schémas de couleurs</h2><p><a href="https://fr.wikipedia.org/wiki/Teinte_saturation_lumi%C3%A8re">HSL</a> est idéal pour la création rapide de <a href="http://en.wikipedia.org/wiki/Color_scheme">schémas de couleurs</a>, en particulier pour les développeurs qui ne maîtrisent pas parfaitement le design ou la théorie des couleurs. (<em>NdT : si c’est votre cas, pas d’inquiétude ! Vous retrouverez dans la Cascade tout un tas d’articles et de ressources pour maîtriser les couleurs comme un pro, voyez la liste dans la <a href="https://la-cascade.io/tags/couleur">page du tag "couleur"</a></em>). L’utilisation de quelques règles simples permet de créer des choix de couleurs harmonieux qui fonctionnent en toute situation.</p><p>Prenons un exemple, disons que vous avez une couleur principale et que vous voulez l’utiliser pour générer rapidement le schéma de couleurs d’un site. Admettons, par exemple, que vous ayez une couleur orange dérivée du logo du client, qui correspond à <code>hsl(30, 90%, 29%)</code>.</p><p>Pour générer instantanément une couleur complémentaire, il suffit d’ajouter 180 degrés à la valeur de la couleur : dans notre exemple, cela donne <code>hsl(210, 90%, 29%)</code>. Facile, non ? Et si votre première couleur a une valeur supérieure à 180 degrés, pas de souci, votre navigateur saura “faire le tour du cadran de l’horloge” et convertir les valeurs supérieures à 360 degrés. Il sait même gérer les valeurs négatives.</p><p>Pour créer en un tournemain un schéma de couleurs monochromatique : prenez la valeur de saturation et soustrayez un tiers. Notre base de couleur est <code>hsl(30, 90%, 29%)</code>, les couleurs additionnelles seront donc <code>hsl(30, 60%, 29%)</code> et <code>hsl(30, 30%, 29%)</code>.</p><p>Pour un schéma de couleurs neutre : soustrayez et/ou ajoutez à la couleur un nombre de degrés identiques à chaque fois, mais jamais supérieur à 90°. Par exemple, à partir d’une couleur de 30°, on obtiendra <code>hsl(0,90%,29%)</code> et <code>hsl(60,90%,29%)</code>.</p><p>Pour un schéma de couleurs triadique, ajoutez 120° à la valeur de la couleur principale.</p><p>Bien utilisé, ceci élimine le débat sur la question de savoir “ce qui irait bien avec ça ?” et vous aide à générer le design d’un site très rapidement.</p><h2>Ajustement rapide de couleurs</h2><p>Combien de fois un client vous a-t-il demandé “pourriez-vous éclaircir un peu le background ?” Si vous avez spécifié les couleurs en <a href="http://fr.wikipedia.org/wiki/Rouge_vert_bleu">RGB</a> ou en <a href="http://fr.wikipedia.org/wiki/Noms_de_couleur_du_Web">Hexadécimal</a>, il vous faudra ajuster trois composants simultanément, en faisant attention que l’un ne prenne pas plus d’importance que l’autre. Si votre schéma de couleurs est en HSL, rien de plus facile et sûr. Le background orange doit être plus sombre ? Vous prenez votre background :</p><pre>body { background: hsl(60,100%,50%); }</pre><p>...et vous réduisez la dernière composante (luminosité) :</p><pre>body { background: hsl(60,100%,40%); }</pre><p>Et voilà ! Et si vous avez utilisé les techniques de schémas de couleurs dont nous avons parlé ci-dessus, il suffit d’ajuster les autres couleurs — tout aussi facilement.</p><h2>Créer rapidement des variantes de couleurs</h2><p>J’ai travaillé sur un article qui utilise <a href="https://la-cascade.io/articles/les-degrades-css/#radial">un dégradé radial</a> pour créer une lumière témoin sur le bouton que vous voyez ici (le rendu est meilleur sur Webkit au moment où j’écris ceci), basé sur ce travail de simurai :</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/simurai/pen/rJwpz/">Animated Radio Inputs</a>de<a href="https://la-cascade.io/auteurs/simurai">simurai</a>dans<a href="https://codepen.io">CodePen</a></div><p>Si l’on fait abstraction des préfixes constructeurs, le code CSS3 ressemble à ceci :</p><pre>//CSS
input {
  background-image:
    radial-gradient( hsla(0,100%,90%,1) 0%,
    hsla(0,100%,70%,1) 15%,
    hsla(0,100%,60%,.3) 28%,
    hsla(0,100%,30%,0) 70% );
}</pre><figure role="group"><img src="https://la-cascade.io/images/red-button-compressor.jpeg" alt="" /><figcaption>Lumière témoin rouge, inspirée de simurai</figcaption></figure><p>Si je veux une lumière bleue, tout ce que j’ai à faire c’est de faire tourner la composante couleur du code HSL :</p><pre>//CSS
input {
  background-image:
    radial-gradient( hsla(200,100%,90%,1) 0%,
    hsla(200,100%,70%,1) 15%,
    hsla(200,100%,60%,.3) 28%,
    hsla(200,100%,30%,0) 70% );
}</pre><figure role="group"><img src="https://la-cascade.io/images/blue-button-compressor.jpeg" alt="" /><figcaption>Lumière témoin bleue, vite fait !</figcaption></figure><p>La nouvelle lumière a la même intensité et la même brillance, dans une couleur différente. Pas besoin de bricoler entre les rouges, les verts et les bleus.</p><h2>Quand ne faut-il  <em>pas</em>  utiliser HSL ?</h2><p>Réponse courte : quand votre site doit être visible sur IE8 et avant. Si vous avez besoin de la compatibilité IE, <a href="http://thenewcode.com/982/Learning-Sass-With-CodePen-Part-Four-Color">Sass peut automatiquement transférer les couleurs HSL en hexadécimal</a>... Donc vous pouvez commencer dès aujourd’hui à profiter de tout ce qu’HSL peut vous apporter !</p></div>]]></description>
      <link>https://la-cascade.io/articles/3-raisons-dutiliser-hsl-pour-vos-couleurs</link>
      <guid>https://la-cascade.io/articles/3-raisons-dutiliser-hsl-pour-vos-couleurs</guid>
      <pubDate>Mon, 04 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Utiliser HSL pour vos couleurs]]></title>
      <description><![CDATA[<p><em>La méthode HSL de création de couleurs est bien connue des designers mais négligée par les codeurs. Dudley Storey en montre ici tout l'intérêt.</em></p><div class="articleContent"><p>La <a href="http://fr.wikipedia.org/wiki/Teinte_saturation_lumi%C3%A8re">méthode HSL</a> de création de couleurs en CSS3 est très bien supportée par les navigateurs modernes mais quelque peu négligée par les codeurs, en raison sans doute de sa différence avec <a href="https://la-cascade.io/tags/couleur/">les autres modèles</a> :</p><ul><li>Il est facile de traduire d’<a href="http://fr.wikipedia.org/wiki/Noms_de_couleur_du_Web">hexadécimal</a> en <a href="http://fr.wikipedia.org/wiki/Rouge_vert_bleu">RGB</a>, mais plus difficile de traduire de ces modèles vers HSL.</li>
<li>Les valeurs Hex et RGB de Photoshop peuvent être transférées directement dans votre CSS, ce qui n’est pas le cas de HSB qui n’est <em>pas</em> la même chose que HSL.</li>
<li>HSL ne vous offre pas une plus grande palette de couleurs que Hex et RGB, on reste sur la même étendue.</li>
</ul><p>Et pourtant, malgré ces quelques restrictions, HSL est la méthode préférée des designers, voici pourquoi.</p><figure><img src="https://la-cascade.io/images/cercle-chromatique-hsl-compressor.jpeg" alt="le cercle chromatique" /></figure><p>Tout d’abord, il vous faut un nouveau modèle mental pour la couleur, focalisez-vous sur le cercle chromatique. Vous voyez le rouge, le vert et le bleu : au sommet, le rouge est à 0 degrés, le vert à 120 degrés et le bleu à 240 degrés, ensemble ils partagent le cercle en trois parties égales. À distance égale entre eux se trouvent le jaune, le cyan et le magenta (du système de couleurs CMYK) respectivement à 60, 180 et 300 degrés.</p><p><em>NdT : HSL signifie Hue, Saturation, Luminosity, c’est à dire <a href="https://fr.wikipedia.org/wiki/Teinte_saturation_luminosit%C3%A9">Teinte, Saturation, Luminosité</a>. Ce sont les trois composantes que nous retrouverons dans le code <code>hsl</code></em>.</p><p>En partant du sommet et en tournant dans le sens des aiguilles d’une montre, nous passons par toutes les couleurs de l’arc en ciel.</p><p>La première composante de HSL est donc très facile : c’est la position de la couleur (la “teinte") sur le cercle chromatique, exprimée en degrés.</p><p>Pour prendre un exemple, le violet se trouve à mi-chemin du bleu (240°) et du magenta (300°), son code serait donc <code>hsl(270, 100%, 50%)</code> (ne vous inquiétez pas pour les autres composantes du code, nous allons voir ça tout de suite). Pour obtenir un violet “plus bleu”, il suffit de revenir en arrière vers le bleu, par exemple en faisant <code>hsl(255, 100%, 50%)</code>.</p><p>La deuxième composante est la saturation, également décrite comme l’intensité. Plus on s’éloigne du centre, plus l’intensité de la couleur augmente, atteignant le maximum de saturation sur le bord extérieur du cercle. Au contraire, plus on va vers le centre, plus la couleur tend vers le gris. En d’autres termes, le degré de saturation dépend de la distance à laquelle on se trouve du gris. Toutes les couleurs HSL ayant une saturation de 0% ont la même ombre (<em>shade</em>) de gris, toutes choses étant égales par ailleurs.</p><p>Valeurs de saturation hsl(45, x%, 50%)</p><p>hsl(45,0%,50%) hsl(45,25%,50%) hsl(45,50%,50%) hsl(45,75%,50%) hsl(45,100%,50%)</p><p>Note : Pour la saturation et la luminosité, le signe % doit <em>toujours</em> être inclus, même si la valeur est égale à 0.</p><p>La luminosité, ou “brillance”, spécifie la distance à laquelle la couleur se trouve du blanc et du noir. Un niveau de luminosité de 50% signifie que la couleur est en équilibre parfait entre le clair et le sombre, et demeure inchangée. Si l’on réduit la luminosité, la couleur s’assombrit : toute couleur ayant un niveau de luminosité de 0 est un noir pur. Si l’on augmente la luminosité, la couleur s’éclaircit et à l’extrême (100%) elle est blanche. Entre les deux, vous avez de nombreuses possibilités, comme illustré ci-dessous :</p><p>Valeurs de luminosité hsl(90, 100%, x%)</p><p>hsl(90, 100%, 0%) hsl(90, 100%, 25%) hsl(90, 100%, 50%) hsl(90, 100%, 75%) hsl(90, 100%, 100%)</p><p>Avec un peu de pratique, cette carte mentale de la couleur deviendra instinctive et vous trouverez probablement qu’il est bien plus facile de créer et de manipuler les couleurs spécifiées en HSL. Même si vous choisissez de ne pas toujours l’utiliser, HSL présente quelques avantages spécifiques dans certaines circonstances — nous verrons cela dans <a href="https://la-cascade.io/articles/3-raisons-dutiliser-hsl-pour-vos-couleurs/">le prochain article</a>.</p><p><strong>Note</strong> :</p><p>Eric Meyer propose <a href="http://meyerweb.com/eric/css/colors/hsl-16.html">un diagramme bien utile</a> permettant de traduire les mots-clés de couleurs habituels en valeurs HSL, et Lars Gunther a construit un outil pédagogique intéressant pour <a href="http://itpastorn.github.io/webbteknik/future-stuff/svg/color-wheel.html">utiliser le cercle chromatique</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/utiliser-hsl-pour-vos-couleurs</link>
      <guid>https://la-cascade.io/articles/utiliser-hsl-pour-vos-couleurs</guid>
      <pubDate>Sun, 03 May 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Un carrousel responsif en pur CSS]]></title>
      <description><![CDATA[<p><em>De plus en plus les développeurs web ont besoin de solutions responsives et performantes. Dudley Storey propose ici un carrousel responsive en pur CSS qui répond parfaitement à ces objectifs.</em></p><div class="articleContent"><p>J’ai <a href="http://thenewcode.com/495/Make-A-CSS3-Animated-Image-Slider">déjà montré</a> comment réaliser un carrousel d’images de largeur fixe en CSS. De plus en plus, les développeurs web ont besoin de solutions qui non seulement se redimensionnent selon le viewport, mais aussi offrent de bonnes performances sur les mobiles. La solution responsive détaillée ici est particulièrement adaptée à ces objectifs, car elle se passe totalement de JavaScript et repose uniquement sur CSS.</p><p>L’idée est assez proche de mon tutoriel précédent : une “bande d’images” contenant toutes les photos de notre carrousel se déplace à l’intérieur d’une “fenêtre” dont le rôle est d’empêcher qu’on ne voie les éléments qui sont en dehors. Pour cet exemple, nous aurons besoin de quatre images, mais en pratique vous pouvez réaliser une bande contenant autant d’images que vous le souhaitez. La seule condition est que <strong>toutes les images doivent avoir la même taille</strong>.</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/dudleystorey/pen/ehKpi">Responsive CSS Image Slider</a>de Dudley Storey dans<a href="https://codepen.io">CodePen</a></div><h2>Créer un cadre responsif avec une bande d’images</h2><p>Tout d’abord nous avons besoin de rendre l’élément carrousel responsif. Pour cela, nous commençons avec le HTML suivant :</p><pre>//HTML
&lt;div id="slider"&gt;
  &lt;figure&gt;
    &lt;img src="austin-fireworks.jpg" alt&gt;
    &lt;img src="taj-mahal.jpg" alt&gt;
    &lt;img src="ibiza.jpg" alt&gt;
    &lt;img src="ankor-wat.jpg" alt&gt;
    &lt;img src="austin-fireworks.jpg" alt&gt;
  &lt;/figure&gt;
&lt;/div&gt;</pre><p>(Je laisse l’<a href="https://la-cascade.io/articles/articles/bien-utiliser-lattribut-alt/">attribut <code>alt</code></a> vide pour la clarté, il faudra le remplir pour l’<a href="https://la-cascade.io/tags/accessibilite/">accessibilité</a> et pour le SEO). Remarquez que la même image est placée au début et à la fin de la bande, pour permettre à l’animation de faire une boucle en douceur.</p><p>Nous donnons à la fenêtre une largeur de 80% pour la rendre responsive, et une largeur maximum (<code>max-width</code>) qui correspond à la largeur naturelle d’une image individuelle (1000px dans notre exemple), car nous ne souhaitons pas qu’une image soit agrandie :</p><pre>//CSS
div#slider { width: 80%; max-width: 1000px; }</pre><figure role="group"><img src="https://la-cascade.io/images/image-strip-compressor.jpeg" alt="" /><figcaption>La bande de 5 images, avec à gauche la “fenêtre” contenant une image. La bande fait 5 fois (500%) la largeur de la fenêtre.</figcaption></figure><p>Dans notre CSS, la largeur de l’élément <code>figure</code> est un pourcentage, qui est un multiple de la <code>div</code> qui le contient. Autrement dit, si la bande d’images contient cinq images, et que notre <code>div</code> n’en montre qu’une, la <code>figure</code> est 5x plus large, c’est à dire 500% la largeur de la <code>div</code> container :</p><pre>//CSS
div#slider figure {
  position: relative;
  width: 500%;
  margin: 0;
  padding: 0;
  font-size: 0;
  text-align: left;
}</pre><p>La <code>font-size: 0</code> aspire l’air autout de l’élément <code>figure</code> en retirant tout espace entre les images et autour. <code>position: relative</code> permet à la <code>figure</code> d’être déplacée facilement pendant l’animation. <code>text-align: left</code> est là en raison d’un bug de Safari 5 pour Windows.</p><p>Nous devons répartir les images de manière régulière à l’intérieur de la bande. Le calcul est très simple : Si nous considérons que l’élément <code>figure</code> fait 100% de large, chaque image doit prendre 1/5 de l’espace horizontal :</p><p>100% / 5 = 20%</p><p>Ce qui nous conduit à la déclaration CSS suivante :</p><pre>//CSS
div#slider figure img { width: 20%; height: auto; float: left; }</pre><p>(Ici aussi, <code>float: left</code> sert à corriger un bug de Win Safari 5).</p><p>Enfin, nous cachons ce qui dépasse (<em>overflow</em>) de la <code>div</code> :</p><pre>//CSS
div#slider { width: 80%; max-width: 1000px; overflow: hidden }</pre><h2>Animer la bande</h2><p>Il nous faut maintenant déplacer la bande de droite à gauche. Si on considère que la <code>div</code> container fait 100% de large, chaque mouvement de la bande vers la gauche sera mesuré en incréments de cette distance :</p><pre>//CSS
@keyframes slidy {
  0% { left: 0%; }
  20% { left: 0%; }
  25% { left: -100%; }
  45% { left: -100%; }
  50% { left: -200%; }
  70% { left: -200%; }
  75% { left: -300%; }
  95% { left: -300%; }
  100% { left: -400%; }
}</pre><p>Chaque image du carrousel sera affichée dans la <code>div</code> pour 20% de la durée totale de l’animation, le temps de déplacement étant de 5%.</p><p>Il ne nous reste plus qu’à appeler notre animation pour que les choses commencent (le code est indiqué ici sans préfixes constructeurs, pour la simplicité, mais il ne faudra pas les oublier, vous pouvez utiliser Autoprefixer pour cela).</p><pre>//CSS
div#slider figure {
  position: relative;
  width: 500%;
  margin: 0;
  padding: 0;
  font-size: 0;
  left: 0;
  text-align: left;
  animation: 30s slidy infinite;
}</pre><p>Comme vous le voyez, réaliser un <em>responsive carousel</em> est à maints égards plus facile qu’un carrousel fixe !</p><p><strong>Note</strong> : Si vous voulez une solution plus facile et plus rapide, <a href="http://thenewcode.com/871/CSS-Slidy-20-Captions--more">CSSslidy</a> est un petit JavaScript qui auto-génère des keyframes d’animation CSS3 pour n’importe quel ensemble d’images.</p><p>Les photos sont utilisées avec la permission de l’excellent <a href="http://www.stuckincustoms.com/">Trey Radcliff</a>.</p><p>Vous pouvez retrouver le code de cet article sur Codepen :</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/dudleystorey/pen/ehKpi">Responsive CSS Image Slider</a>de Dudley Storey dans<a href="https://codepen.io">CodePen</a></div></div>]]></description>
      <link>https://la-cascade.io/articles/un-carrousel-responsif-en-pur-css</link>
      <guid>https://la-cascade.io/articles/un-carrousel-responsif-en-pur-css</guid>
      <pubDate>Sat, 25 Apr 2015 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Mécanique des polices de caractères, 1]]></title>
      <description><![CDATA[<p><em>Notre esprit veut dessiner une forme, mais nos yeux veulent en voir une autre. Cette série d'articles de Tobias Frere-Jones explore le travail en coulisses permettant aux polices d'être fonctionnelles.</em></p><div class="articleContent"><p>Notre esprit veut dessiner une forme, mais nos yeux veulent en voir une autre. Le design de police de caractères consiste en partie à gérer cette éternelle friction entre la logique et l’optique. Elle est toujours présente, quel que soit le style.</p><p>Cette nouvelle série d’articles explorera ce que j’appelle la “mécanique des polices”, le travail en coulisses qui permet aux polices d’être visuellement fonctionnelles. C’est lui qui apaise les bizarreries de la perception humaine, qui aide ou gêne l’utilisateur, et façonne les vieilles conventions du design.</p><p>Le processus de design de polices de caractères comporte de nombreux moments contre-intuitifs. L’un des premiers concerne la position verticale et la taille, que nous souhaitons cohérentes entre toutes les lettres. Nous pourrions décider d’une mesure et l’appliquer partout, mais ce plan simple et logique échouerait une fois le résultat devant nos yeux et notre esprit.</p><p>Des formes telles que le <em>H</em> ont une relation simple et stable à la <a href="http://fr.wikipedia.org/wiki/Ligne_de_base_%28typographie%29">ligne de base</a> et la hauteur de capitale ( <em>NdT : voir l’article <a href="http://fr.wikipedia.org/wiki/Caract%C3%A8re_%28typographie%29">Caractères</a>, de wikipedia, pour les termes techniques</em>.). Leurs bords supérieur et inférieur coïncident avec ces limites et s’y maintiennent. Mais seul un tout petit bout d’un <em>O</em> est compris dans ces limites, le reste de la forme s’en éloigne et nous en concluons — faussement mais logiquement — que la forme arrondie est trop petite.</p><figure role="group"><img src="https://la-cascade.io/images/square-round-06-compressor.gif" alt="des formes mathématiquement égales ne le sont pas optiquement" /><figcaption>Des formes carrée et ronde : mathématiquement égales ou optiquement égales</figcaption></figure><p>Si la hauteur “correcte” semble inadéquate, alors “trop” paraîtra correct. C’est pourquoi on dessine le <em>O</em> plus grand que le <em>H</em> même si c’est mathématiquement incorrect. Mais nous lisons avec nos yeux, pas avec des règles, et l’oeil devrait toujours être vainqueur. Les polices de caractères de toutes les époques utilisent cette compensation, souvent appelée “dépassement” (_<a href="http://en.wikipedia.org/wiki/Overshoot_%28typography%29">overshoot</a>_).</p><figure role="group"><img src="https://la-cascade.io/images/Turlot-cropA2-compressor.jpeg" alt="une police &quot;antique&quot;" /><figcaption>Romaines Droites, par la Fonderie Turlot, 1880</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/Turlot-cropB1-compressor.jpeg" alt="le O dépasse les empattements du I et du U" /><figcaption>"Overshoot", Les formes arrondies dépassent les formes plates</figcaption></figure><p>Si les courbes ont besoin de dépasser parce que leur comportement est différent de celui des carrés, les formes pointues, elles, sont encore moins semblables aux carrés, et c’est pourquoi elles ont besoin de plus de dépassement. Mais si l’on fait bien attention, les lecteurs ne se rendront pas compte des tailles et positions multiples. Toutes <em>ont l’air</em> égales.</p><figure role="group"><img src="https://la-cascade.io/images/FutMedFASHIONS-compressor.jpeg" alt="une police &quot;moderne&quot;" /><figcaption>Futura Medium, par Paul Renner, Bauer 1928</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/FutMed-overlay-5a-compressor.gif" alt="dépassements différents selon la forme des lettres" /><figcaption>Dépassements progressifs, pour les formes arrondies et pointues</figcaption></figure><p>Mais comme de nombreux aspects de la mécanique des polices de caractères, le dépassement est affaire de gradation. Les courbes larges se comportent presque comme des formes plates, elles s’attardent plus longtemps sur la ligne de base qu’une forme ronde ou ovale. Ci-dessous, deux polices du même designer et de la même fonderie, à la même taille et à peu près les mêmes proportions. La différence de dépassement est liée à la différence de courbe. L’une est un arrondie (tendant vers l’ovale), l’autre tend vers le rectangle.</p><figure role="group"><img src="https://la-cascade.io/images/Recta-Metropole-words-02-compressor.jpeg" alt="deux polices" /><figcaption>Recta Nera Stretta (au-dessus) et Metropol Nera Compatta, par Aldo Novarese, Nebiolo vers 1960 et 1967</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/Recta-Metropole-overshoot-compressor.jpeg" alt="le design différent des polices entraîne des dépassements différents" /><figcaption>Différences de dépassement</figcaption></figure><p>Même à l’intérieur d’une famille, des variations de graisse et d’épaisseur peuvent altérer l’apparence de la forme et imposer un calibrage de son alignement. Par exemple un <em>V</em> peut avoir une pointe dans une <a href="http://fr.wikipedia.org/wiki/Graisse_%28typographie%29">graisse</a> légère, mais avoir une pointe émoussée et modifier sa profondeur apparente et son alignement pour s’accorder à une graisse supérieure.</p><figure role="group"><img src="https://la-cascade.io/images/Nobel-V2-compressor.jpeg" alt="la lettre V dans des graisses différentes" /><figcaption>Le dépassement diminue à mesure que la pointe s’émousse : FB Nobel Light, Book et Regular, par S.H. de Roos, Amsterdam 1928. Revisité par Font Bureau en 1992</figcaption></figure><p>Les alignements en <a href="https://fr.wikipedia.org/wiki/Bas_de_casse">bas de casse</a> sont souvent plus difficiles à obtenir du fait que de nombreuses lettres ont des formes aplaties immédiatement adjacentes à des formes arrondies et toutes deux doivent être optiquement correctes. Un alignement mixte devrait sembler “naturel” et ne montrer aucun signe de l’effort nécessaire.</p><figure role="group"><img src="https://la-cascade.io/images/HelvMedMainz4-compressor.jpeg" alt="le mot Mainz en helvetica medium" /><figcaption>Helvetica Medium par Eduard Hoffmann, Stempel 1956</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/HelvMed-lc-arch3-compressor.jpeg" alt="le I et le N de Mainz, le N dépasse" /><figcaption>Alignement mixte en bas de casse</figcaption></figure><p>Les polices avec <a href="http://fr.wikipedia.org/wiki/Empattement_%28typographie%29">empattement</a> (<em>serif</em>) inclinés peuvent encore compliquer les choses. Cette caractéristique est emblématique du style ancien en bas de casse, peu de lettres sont aplaties. Dans ce style, la hauteur théorique des lettres en bas de casse est très rarement respectée et la majorité des lettres — dont certaines parmi les plus communes — sont un mélange de courbes et d’angles capricieux.</p><figure role="group"><img src="https://la-cascade.io/images/Caslon540_nx0-compressor.jpeg" alt="le N dépasse, mais aussi le sérif supérieur du N, qui est incliné" /><figcaption>Carlson No. 540, American Type Founders 1906</figcaption></figure><p>Le <em>x</em> en bas de casse est un cas rare de quasi absence de changement entre un style et un autre. Quelle que soit l’épaisseur de ses empattements, le contraste de ses graisses, l’<a href="http://fr.wikipedia.org/wiki/Axe_%28typographie%29">inclinaison de son axe</a>, le <em>x</em> aura très certainement une partie supérieure et inférieure aplatie. C’est parce que le <em>x</em> est un repère fiable qu’on utilise l’expression “hauteur d’x” pour parler de la zone de bas-de-casse (W.A. Dwiggins a parfois utilisé le terme “hauteur de z” mais je n’ai pas retrouvé d’autre mention de cette convention).</p><figure role="group"><img src="https://la-cascade.io/images/Orpheo-serif-02-compressor.jpeg" alt="l'empattement inférieur d'un I, concave" /><figcaption>Orpheo (inachevé)</figcaption></figure><p>Les empattements marquent les limites supérieure et inférieure, mais de façon parfois imprécise. Des designs basés sur une dérivation calligraphique ou autre peuvent présenter des empattements concaves qui font que de nombreuses formes “plates” ne le sont plus. Le conflit est localisé de manière inhabituelle, le centre et les extrémités de l’empattement étant alignés différemment. La paix visuelle est souvent obtenue en établissant ces empattements concaves à mi-chemin de la ligne de base, une partie au-dessus, l’autre en-dessous.</p><p>L’établissement d’une taille optiquement cohérente est souvent une difficulté parmi bien d’autres. L’enchevêtrement de poids, de largeur, d’espacement en sont d’autres, ainsi que les difficultés liées à certaines lettres en particulier. Mais nous verrons cela dans les articles à suivre.</p></div>]]></description>
      <link>https://la-cascade.io/articles/fonctionnement-des-polices-de-caracteres-1</link>
      <guid>https://la-cascade.io/articles/fonctionnement-des-polices-de-caracteres-1</guid>
      <pubDate>Sat, 14 Feb 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Un surlignage simple en CSS]]></title>
      <description><![CDATA[<p><em>Surligner les rangées d'un tableau en CSS est très facile, mais les colonnes ? Les pseudo-éléments sont mis à contribution dans ce tutoriel court, facile et astucieux de l'indispensable Chris Coyier.</em></p><div class="articleContent"><p>Il est très facile de surligner les rangées d’un tableau en CSS. <code>tr:hover { background: yellow; }</code> fait ça très bien. Mais surligner les colonnes est déjà plus difficile, parce qu’il n’y a pas d’élément HTML unique qui serait le parent des cellules d’un tableau dans une colonne donnée. Une <a href="http://css-tricks.com/row-and-column-highlighting/">petite touche de JavaScript</a> pourrait faire l’affaire, mais Andrew Howe mais envoyé un mail dernièrement pour partager une astuce qu’il avait trouvée sur <a href="http://stackoverflow.com/questions/848840/cols-colgroups-and-css-hover-psuedoclass/11175979#11175979">StackOverflow</a>, envoyée par <a href="http://thinkingstiff.com/">Matt Walton</a>. Elle avait déjà quelques années, alors je me suis dit que je pourrais la mettre à jour et vous la livrer.</p><h2>L’astuce : des pseudo-éléments géants sur les td, et overflow hidden</h2><p>CSS ne nous permet pas vraiment de connaître les dimensions du tableau, donc on crée des <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css/#lespseudoelements">pseudo-éléments</a> super grands avec une valeur de <code>top</code> négative de la moitié, comme ceci :</p><pre>//CSS
table {
  overflow: hidden;
}
tr:hover {
  background-color: #ffa;
}
td:hover::after,
th:hover::after {
  content: "";
  position: absolute;
  background-color: #ffa;
  left: 0;
  top: -5000px;
  height: 10000px;
  width: 100%;
  z-index: -1;
}</pre><p>Le <code>z-index</code> négatif le cache en-dessous du contenu. Un <a href="https://la-cascade.io/articles/comment-fonctionne-z-index/">z-index</a> négatif est une astuce sympa, mais prenez garde de ne pas imbriquer ce tableau à l’intérieur d’autres éléments comportant un background, sinon le surlignage se trouvera caché en-dessous.</p><p>Vous pouvez le voir en action (survolez le tableau) :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/pvwmaR/">Row and Column Highlighting with CSS Only</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h2>Fonctionnement avec touch</h2><p>Les <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css/#lespseudoclasses">pseudo-classes</a> comme <code>:hover</code> fonctionnent plus ou moins sur les terminaux tactiles. Tout d’abord, l’élément doit être focusable, ce qui n’est pas le cas des cellules d’un tableau par défaut. On pourrait certainement ajouter un <a href="http://en.wikipedia.org/wiki/Event_%28computing%29#Event_handler">event handler</a> pour les clics sur les cellules du tableau, et tout faire en JavaScript, mais voici une méthode qui permet de faire l’essentiel du travail en CSS :</p><pre>//jQuery
// Whatever kind of mobile test you wanna do.
if (screen.width &lt; 500) {
  // :hover will trigger also once the cells are focusable
  // you can use this class to separate things
  $("body").addClass("nohover");
  // Make all the cells focusable
  $("td, th")
    .attr("tabindex", "1")
    // When they are tapped, focus them
    .on("touchstart", function() {
      $(this).focus();
    });
}</pre><p>Puis dans le CSS vous ajoutez des styles pour <code>:focus</code>.</p><pre>//CSS
td:focus::after,
th:focus::after {
  content: ’’;
  background-color: lightblue;
  position: absolute;
  left: 0;
  height: 10000px;
  top: -5000px;
  width: 100%;
  z-index: -1;
}
td:focus::before {
  background-color: lightblue;
  content: ’’;
  height: 100%;
  top: 0;
  left: -5000px;
  position: absolute;
  width: 10000px;
  z-index: -1;
}</pre><p>Dans la démo finale, je développe un peu les sélecteurs CSS pour m’assurer que les cellules vides ne déclenchent rien, que les titres de colonnes dans <code>&lt;thead&gt;</code> ne sélectionnent que les colonnes et que les titres de rangées dans <code>&lt;tbody&gt;</code> ne sélectionnent que les rangées.</p><p>Vous pouvez le voir dans la <a href="http://codepen.io/chriscoyier/pen/pvwmaR">démo finale</a>. Et ci-dessous un touch qui fonctionne :</p><figure role="group"><img itemprop="url" src="https://la-cascade.io/images/touch-cells-compressor.gif" width="637" height="483" alt="" /></figure></div>]]></description>
      <link>https://la-cascade.io/articles/un-surlignage-simple-en-css</link>
      <guid>https://la-cascade.io/articles/un-surlignage-simple-en-css</guid>
      <pubDate>Fri, 13 Feb 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Le morphing en SVG]]></title>
      <description><![CDATA[<p><em>Certaines propriétés SVG ne sont pas animables avec CSS. Chris Coyier montre ici comment réaliser simplement un morphing avec SMIL et Javascript.</em></p><div class="articleContent"><p>L’<a href="https://la-cascade.io/articles/animer-un-svg-avec-css/">animation d’un SVG au moyen de CSS</a> est facile, cependant CSS ne peut pas animer toutes les propriétés SVG animables. Par exemple, les propriétés qui définissent la forme présente d’un élément ne peuvent être modifiées ou animées en CSS. Il est toutefois possible de le faire grâce à SMIL. Sara Soueidan en parle dans son remarquable <a href="https://la-cascade.io/articles/guide-des-animations-svg/">Guide des animations SVG (SMIL)</a> ici-même, mais je voudrais éclairer ce point plus précisément ici.</p><p><strong>Le plus important à retenir : les formes doivent avoir le même nombre de points</strong><br />Autrement, l’animation ne marchera pas. La forme ne disparaîtra pas, rien de grave ne se produira, mais rien ne s’animera.</p><p>Il n’est pas toujours évident de savoir combien de points constituent une forme en regardant l’attribut <code>d</code> (dans le cas d’un <code>path</code>) ou <code>point</code> (dans le cas d’un polygone), le mieux est parfois de commencer avec une forme simple dans un programme d’édition vectorielle.</p><h3>1. Commencer avec la forme la plus complexe</h3><p>Dans cette démo, je vais partir d’une étoile, qui sera ma forme la plus compliquée, pour la morpher en <em>check</em> de case à cocher (une “hirondelle”).</p><figure><img src="https://la-cascade.io/images/star.png" alt="" /></figure><p>Gardez une copie de ce SVG, puis utilisez une autre version pour construire la forme suivante.</p><h3>2. Construire la forme suivante avec les mêmes points</h3><p>Déplacez les points pour obtenir la forme désirée.</p><figure><img src="https://la-cascade.io/images/star-illustrator-gif-compressor.gif" alt="dans illustrator, on déplace les points pour former une hirondelle" /></figure><figure><img src="https://la-cascade.io/images/check-illustrator-gif.png" alt="" /></figure><h3>3. Utiliser la forme de départ dans le SVG lui-même</h3><pre>//SVG
&lt;svg viewBox="0 0 194.6 185.1"&gt;
  &lt;polygon fill="#FFD41D" points=" ... les points de la forme 1 ... "&gt;
  &lt;/polygon&gt;
&lt;/svg&gt;</pre><h3>4. Ajouter un élément d’animation vers la forme suivante</h3><pre>//SVG
&lt;svg viewBox="0 0 194.6 185.1"&gt;
  &lt;polygon fill="#FFD41D" points=" ... les points de la forme 1 ... "&gt;
    &lt;animate attributeName="points" dur="500ms" to=" ... les points de la forme 2 ... " /&gt;
  &lt;/polygon&gt;
&lt;/svg&gt;</pre><p>Cette animation sera lancée immédiatement, il nous faut corriger cela.</p><h3>5. Déclencher l’animation quand on le veut</h3><p>SMIL permet de traiter les interactions telles que clics et hovers, tant que tout se passe à l’intérieur de SVG. Par exemple, vous pourriez lancer l’animation lorsqu’elle est cliquée :</p><pre>//SVG
&lt;polygon id="shape" points=" ... les points de la forme 1 ... "&gt;
  &lt;animate begin="shape.click" attributeName="points" dur="500ms" to=" ... les points de la forme 2 ... /&gt;
&lt;/polygon&gt;</pre><p>Pas mal, mais un peu limité car il ne permet de traiter que les clics sur ce SVG précisément. Mais quid si cet élément fait partie d’un bouton et qu’on veut lancer l’animation lorsque c’est le bouton qui est cliqué ?</p><p>Tout d’abord, donnons un ID à notre animation, afin de permettre à JavaScript de la retrouver, puis empêchons tout déclenchement intempestif :</p><pre>//SVG
&lt;animate id="animation-to-check" begin="indefinite" ... /&gt;</pre><p>Nous avons maintenant référencé cette animation et nous pouvons la déclencher comme nous l’entendons :</p><pre>//JavaScript
animationToCheck = document.getElementById("animation-to-check");
// Lancez ceci sur un clic, ou de la façon que vous voulez
// (voir démo ci-dessous)
animationToCheck.beginElement();</pre><h3>Démo</h3><p>Cette démo contient en fait quatre animations : une pour morpher l’étoile en hirondelle, une pour modifier la couleur de la forme, et les mêmes dans l’animation inverse. Lorsqu’on clique sur le bouton, on vérifie d’abord l’état présent du bouton, puis on déclenche les animations appropriées.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/DpFfE/">Shape Morph Button</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div></div>]]></description>
      <link>https://la-cascade.io/articles/le-morphing-en-svg</link>
      <guid>https://la-cascade.io/articles/le-morphing-en-svg</guid>
      <pubDate>Sat, 07 Feb 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Shape Blobbing]]></title>
      <description><![CDATA[<p><em>Le shape blobbing c'est cet effet d'aspiration d'une goutte par une autre, réalisable en CSS à partir de filtres pour le flou et le contraste. Tutoriel clair de Chris Coyier.</em></p><div class="articleContent"><p>Nous avons vu récemment <a href="https://la-cascade.io/articles/le-morphing-en-svg/">le morphing en SVG</a>, c’est à dire une forme qui se mue en une autre. Aujourd’hui, nous allons voir des formes qui se phagocytent entre elles ! C’est le <em>shape bobbling</em>, vous savez, cet effet d’aspiration qu’on peut voir par exemple dans <a href="https://www.youtube.com/watch?v=31CE2BYicyU#t=45">cette vidéo de gouttes de mercure</a> ou, de manière inverse, dans les images de <a href="http://fr.wikipedia.org/wiki/Division_cellulaire">division cellulaire</a>.</p><figure role="group"><img src="https://la-cascade.io/images/mercury-compressor.gif" alt="une goutte de mercure en aspire une autre" /></figure><p>Je ne sais pas qui a découvert le premier que cet effet était réalisable sur le web, mais <a href="http://codepen.io/lbebber/pen/lFdHu/">la première démo que j’en aie jamais vue</a> était de Lucas Bebber. Puis celle-ci, de <a href="http://codepen.io/felixhornoiu/pen/EjDwF/">Felix Hornoiu</a> (GIF ralenti pour mieux observer l’effet) :</p><figure role="group"><img src="https://la-cascade.io/images/bubbles-compressor.gif" alt="deux cercles fusionnent" /><figcaption><a href="http://codepen.io/chriscoyier/pen/lIBAg?editors=110">Démo visible ici</a>.</figcaption></figure><h3>Une astuce simple, à partir de filtres pour le flou et le contraste</h3><p>Le flou rend l’élément... flou, et le contraste lutte contre le flou. Si vous contrastez suffisamment, votre forme retrouve (à peu près) ses contours :</p><figure role="group"><img src="https://la-cascade.io/images/blur-vs-contrast-compressor.png" alt="tableau flou (en x) et contraste (en y)" /></figure><p>Là où ça devient intéressant, c’est que lorsque deux éléments floutés (mais forcés à ne pas apparaître comme tels) s’approchent l’un de l’autre, leurs flous “potentiels” créent suffisamment de contraste couleur “potentiel” pour que l’on ait l’impression que les formes se connectent et se mélangent.</p><figure role="group"><img src="https://la-cascade.io/images/blur-shape.png" alt="" /><figcaption><a href="http://codepen.io/chriscoyier/pen/lIBAg?editors=110">Démo visible ici</a>.</figcaption></figure><p>Je trouve qu’il est plus aisé de faire fonctionner l’effet en floutant la forme, mais en ajoutant le contraste sur le contexte, c’est à dire sur le container de l’effet (ci-dessous .stage).</p><pre>//CSS
.stage {
  /* doit être explicite, pour que le contraste fonctionne */
  background: white;
  /* des trucs bizarres arrivent au contact des bords, cachez
  éventuellement l’overflow */
  padding: 30px;
  -webkit-filter: contrast(20);
  filter: contrast(20);
}
.dot {
  border-radius: 50%;
  width: 50px;
  height: 50px;
  /* doit être une couleur très contrastante, p.ex. gris clair sur
  blanc ne marchera pas */
  background: black;
  -webkit-filter: blur(15px);
  filter: blur(15px);
}</pre><p>Et ça devient vraiment drôle quand on ajoute une animation pour déclencher la danse des phagocytes. Voici une démo dans laquelle vous pouvez jouer avec les valeurs de flou, de contraste et de luminosité (cette dernière a un effet sur le flou) :</p><p data-height="45" data-theme-id="5394" data-slug-hash="bopGc" data-default-tab="result" data-user="chriscoyier" class="codepen">See the Pen <a href="http://codepen.io/chriscoyier/pen/bopGc/">Blobbing Playground</a> by Chris Coyier (<a href="http://codepen.io/chriscoyier">@chriscoyier</a>) on <a href="http://codepen.io">CodePen</a>.</p><h3>Compatibilité navigateurs</h3><p>Aujourd’hui, à peu près tout le monde, WebKit/Blink, Firefox à partir de FF35, donc : Chrome / Safari / Opera / Firefox / iOS / Android. Pas mal. Le seul qui manque à l’appel est IE.</p><p><em>NdT : Pour voir une superbe application de cet effet, voyez</em> <a href="https://la-cascade.io/leffet-gluant-avec-svg/">l’effet Gooey</a> <em>de Lucas Bebber</em>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/shape-blobbing</link>
      <guid>https://la-cascade.io/articles/shape-blobbing</guid>
      <pubDate>Fri, 06 Feb 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Qu'est-ce qu'un élément remplacé ?]]></title>
      <description><![CDATA[<p><em>Avez-vous déjà entendu parler des éléments HTML remplacés ? Vous les utilisez pourtant tous les jours sans le savoir, et connaître leur nature peut vous éviter quelques soucis.</em></p><div class="articleContent"><p>On ne trouve pas beaucoup d’information en ligne sur les éléments remplacés HTML. Je n’ai rien trouvé à leur sujet dans les livres sur le développement web que je connais. C’est bien dommage... car si j’avais connu plus tôt les limites des éléments remplacés je me serais épargné bien du stress lorsque j’ai commencé mes expériences de CSS avancé.</p><p>Pour l’essentiel, les éléments remplacés sont <em>des éléments HTML ayant une largeur et une hauteur prédéterminées en l’absence de CSS précis</em>. Une autre façon de voir les choses est de penser aux éléments remplacés comme à <em>des balises ayant leur contenu remplacé par une source extérieure</em>. <code>&lt;img&gt;</code> et <code>&lt;video&gt;</code> en sont deux exemples évidents, mais on peut y ajouter de nombreux éléments de formulaires tels que <code>&lt;input&gt;</code>. Par exemple, lorsque vous insérez le code suivant dans une page :</p><pre>&lt;input type=“text”&gt;</pre><p>...l’<em>input</em> apparaît, sans que vous n’ayez rien à faire, aux dimensions qui conviennent à la saisie d’une ligne unique. Cela ne signifie pas que vous n’avez pas besoin d’ajouter des attributs et valeurs supplémentaires à l’élément, ou que vous ne pouvez pas lui appliquer de CSS, mais simplement que le navigateur <em>remplace</em> cette balise par un objet ayant des dimensions prédéterminées par défaut. La même chose se produit avec <code>&lt;img&gt;</code> :</p><pre>&lt;img src=“bison.jpg” alt=“Plains bison”&gt;</pre><p>Sans autre information, <code>bison.jpg</code> sera chargé dans la page et la balise <code>&lt;img&gt;</code> remplacée par le contenu de ce fichier, aux dimensions originales de l’image.</p><p><code>&lt;br&gt;</code>, <code>&lt;hr&gt;</code> et <code>&lt;object&gt;</code> sont des éléments remplacés, de même que <code>&lt;input&gt;</code>, <code>&lt;button&gt;</code> et <code>&lt;textarea&gt;</code>. En HTML5, <code>&lt;video&gt;</code> et <code>&lt;iframe&gt;</code> sont également des éléments remplacés, ainsi que (dans certaines circonstances) <code>&lt;audio&gt;</code> et <code>&lt;canvas&gt;</code>.</p><p>Mais puisque l’apparence de ces éléments peut être modifiée via CSS, en quoi le fait que ce soit des <em>éléments remplacés</em> pose-t-il problème ? En raison d’une règle essentielle :</p><blockquote>
<p>  On ne peut pas appliquer de contenu généré aux éléments remplacés. Autrement dit on ne peut pas leur appliquer les pseudo-éléments <code>:before</code> et <code>:after</code>.</p>
</blockquote><p>Pensons-y un instant. Est-ce que ce ne serait pas génial de pouvoir auto-générer des légendes pour nos images en CSS ? On a l’information disponible, on a les attributs <code>alt</code> et <code>title</code>, tout est là et il nous suffirait de faire :</p><pre>img:after { content: attr(alt); }</pre><p>Ce serait parfait ! On pourrait afficher la valeur <code>title</code> de l’image directement dans la page et on n’aurait pas à se soucier de <code>&lt;figcaption&gt;</code> ou des <a href="https://demosthenes.info/blog/55/CSS-and-Images-Captioned-Images">listes de définitions</a> (en XHTML)... Mais non, on ne peut pas. La balise <code>&lt;img&gt;</code> est <em>déjà</em> un contenu remplacé : on ne peut pas générer plus de contenu.</p><p>Un résultat utile en tout cas : si vous n’obtenez rien <a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after/">en appliquant <code>:before</code> ou <code>:after</code> à un élément</a>, il y a des chances que ce soit parce qu’il s’agit d’un élément remplacé !</p></div>]]></description>
      <link>https://la-cascade.io/articles/quest-ce-quun-element-remplace</link>
      <guid>https://la-cascade.io/articles/quest-ce-quun-element-remplace</guid>
      <pubDate>Tue, 13 Jan 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Utiliser CSS object-fit]]></title>
      <description><![CDATA[<p><em>La propriété object-fit de CSS offre des options de redimensionnement et de présentation des images qui faciliteront la vie des designers.</em></p><div class="articleContent"><p>Tout le monde sait que le format des films est redimensionné lorsqu’ils passent du cinéma à la télévision ou aux tablettes : format <em>letterbox</em>, changement de dimensions, image rognée... En tant que développeur web, vous connaissez également les diverses façons dont les images de background peuvent être rendues responsives, s’étirer pour couvrir le viewport ou être recadrées à mesure que la fenêtre du navigateur est redimensionnée.</p><p>Il manquait jusqu’à présent une règle intelligente de traitement du redimensionnement des images, similaire à celle qui existe pour la vidéo. C’est chose faite avec CSS <code>object-fit</code>.</p><p>Les images en format vignette sont un bon cas d’utilisation. Actuellement, les images de produits d’une boutique en ligne sont généralement traitées par un éditeur bitmap de façon à avoir toutes la même taille et le même ratio d'aspect. Cependant, même avec des instructions précises et des vérifications côté-serveur, si le client peut uploader tout seul ses images sur son site il y a un risque d’avoir des images étirées ou des ratios d’aspect différents. Par exemple, vous avez décidé que les vignettes suivront ce style :</p><pre>.product-thumb img {
  width: 150px;
  height: 150px;
  border: 1px solid;
}</pre><p>...ce qui impose que toutes les vignettes aient ces dimensions ou en tout cas qu’elles soient toutes carrées. Mais si le client uploade des images comme celle-ci :</p><figure role="group"><img src="https://la-cascade.io/images/1apex.jpeg" alt="image de robot" /><figcaption>Photographie par <a href="https://www.flickr.com/photos/tinkerbots">Tinkerbots</a>, sous licence CC</figcaption></figure><p>...ou celle-ci :</p><figure role="group"><img src="https://la-cascade.io/images/2le-helicron.jpeg" alt="image d'un autre robot" /><figcaption>Photographie par <a href="https://www.flickr.com/photos/tinkerbots">Tinkerbots</a>, sous licence CC</figcaption></figure><p>...lorsque les images sont affichées au format vignette, elles apparaissent "écrasées" par les règles CSS, dans un sens ou dans l’autre :</p><figure><img src="https://la-cascade.io/images/3thumbnails.jpeg" alt="les images sont déformées" /></figure><p>Évidemment, ce n’est pas idéal. Les solutions habituelles consistent à :</p><ul><li>obliger l’utilisateur à uploader des images à un format précis</li>
<li>traiter les images côté-serveur pour obtenir la taille souhaitée</li>
<li>afficher les images comme background, avec un positionnement soigné</li>
<li>utiliser des applications complexes de <code>position: fixed</code>.</li>
</ul><p>À présent, <code>object-fit</code> nous offre plusieurs options qui sont bien plus faciles à appliquer :</p><pre>.product-thumbs img {
  width: 150px;
  height: 150px;
  border: 1px solid;
  object-fit: contain;
}</pre><p>Le résultat avec les navigateurs compatibles (Chrome, Safari, et autres clients à base de Webkit/Blink) :</p><figure><img src="https://la-cascade.io/images/4compliantBrowsers.jpeg" alt="images non déformées" /></figure><p>On obtient un format <em>letterbox</em> qui préserve le ratio d’aspect en ajoutant un espace au-dessus ou au-dessous, ou bien à gauche ou à droite, pour leur donner la bonne taille sans les écraser ni les étirer.</p><p>Attention : pour qu’<code>object-fit</code> fonctionne, il faut définir les largeur et hauteur de l’élément. De plus il doit s’appliquer à un <a href="https://la-cascade.io/articles/quest-ce-quun-element-remplace/">élément remplacé</a>.</p><p>Une autre possibilité est de donner la valeur <code>cover</code> à <code>object-fit</code> :</p><pre>.product-thumbs img {
  width: 150px;
  height: 150px;
  border: 1px solid;
  object-fit: cover;
}</pre><p>Le résultat :</p><figure><img src="https://la-cascade.io/images/5cover.jpeg" alt="image non déformées, mais tronquées" /></figure><p>Comme vous pouvez le voir, cela fonctionne exactement comme <code>background-size: cover</code> pour les images de background. C’est l’équivalent du recadrage plein écran (<em>pan and scan</em>) d’un film originellement en écran large, où tout ce qui dépasse sur les côtés est éliminé.</p><p>Si vous préférez le bon vieux comportement par défaut, vous pouvez donner à <code>object-fit</code> la valeur <code>fill</code>, ce qui sera l’équivalent d’un <code>background-size: 100% 100%</code> pour une image de background.</p><p>Enfin, il y a <code>object-fit: none</code>, qui conserve à l’image ses dimensions originales et son ratio d’aspect, se focalise sur le centre de l’image et supprime tout ce qui dépasse :</p><pre>.product-thumbs img {
  width: 150px;
  height: 150px;
  border: 1px solid;
  object-fit: none;
}</pre><p>Le résultat :</p><figure><img src="https://la-cascade.io/images/6none.jpeg" alt="format original dans une vignette : on ne voit plus qu'un détail de l'image" /></figure><p>Si vous êtes en train de vous dire que ça pourrait être utile dans certains types de galeries d’images, vous avez raison. Des variations sur ce sujet peuvent également être utilisées pour corriger le ratio d’aspect de vidéos uploadées. Je vous montrerai tout cela dans des articles à venir.</p><p><em>NdT : Dudley Storey a ajouté un CodePen qui fait la synthèse de tout ce qui précède</em> :</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/dudleystorey/pen/myPZwN/">CSS object-fit</a>de Dudley Storey dans<a href="https://codepen.io">CodePen</a></div><h3>Compatibilité</h3><p>Pour connaître la compatibilité navigateurs, comme d'habitude il suffit de se reporter à <a href="https://caniuse.com/#feat=object-fit">CanIUse</a>, tous les navigateurs sont à ce jour compatibles, sauf... Internet Explorer, pour lequel la propriété est dans la liste des éléments “à l’étude”.</p><p>Si vous voulez vous assurer du bon fonctionnement d’<code>object-fit</code> avec tous les navigateurs, voici ce que vous pouvez faire :</p><p> Ajouter <code>overflow: hidden</code> aux éléments auxquels vous appliquez <code>object-fit</code>, pour garantir que les navigateurs incompatibles recadreront l’image à la taille voulue.</p><pre>.product-thumbs img {
  width: 150px;
  height: 150px;
  border: 1px solid;
  object-fit: cover;
  overflow: hidden;
}</pre><p> Utiliser le polyfill développé par Anselm Hannemann et Christian Schaefer qui vous donnera une compatibilité avec les navigateurs récalcitrants. Attention toutefois, ce polyfill a quelques problèmes avec <a href="https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS">CORS</a> dans Firefox qui interdisent son utilisation actuelle sur ce site.</p><h3>Conclusion</h3><p>Les algorithmes de mise en page automatique d’<code>object-fit</code> facilitent grandement la présentation cohérente d’images et de vidéos de dimensions variées, en particulier lorsqu’on les combine avec <a href="https://la-cascade.io/images-responsives-cas-dutilisation-et-snippets/">picture</a>. Nous avons même des options supplémentaires de positionnement lorsque nous utilisons <code>object-fit</code> avec <code>object-position</code> que nous verrons dans un prochain article.</p><p>Toutes ces nouvelles possibilités ne devraient toutefois pas être une excuse pour une utilisation paresseuse des tailles de fichiers media (n’oubliez pas de les optimiser !) mais <code>object-fit</code> nous permet de nous concentrer sur la création et la conception de contenu plutôt que sur le traitement des images.</p></div>]]></description>
      <link>https://la-cascade.io/articles/utiliser-css-object-fit</link>
      <guid>https://la-cascade.io/articles/utiliser-css-object-fit</guid>
      <pubDate>Mon, 12 Jan 2015 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[5 façons d'animer de manière responsable]]></title>
      <description><![CDATA[<p><em>Nous vivons une époque formidable de l'animation web. Mais tout à notre excitation, nous oublions parfois de nous poser la question du pourquoi ?</em></p><div class="articleContent"><p>Cela fait maintenant deux ans que j’ai écrit ici (<em>NdT: dans</em> <a href="http://24ways.org/">24Ways</a>) un article sur <a href="http://24ways.org/2012/flashless-animation/">les animations dans un monde sans Flash</a>. Depuis, les animations ont surgi un peu partout, aussi bien sur des interfaces au design épuré que sur des grilles de type magazine. C’est une époque formidable pour tous les mordus d’animation et d’interaction, les passionnés d’expérience utilisateur (UX), les designers d’interface utilisateur (UI) et toute une troupe d’autres acronymes !</p><p>Mais dans notre hâte à expérimenter toutes ces possibilités d’animation, il semble que nous nous posions de moins en moins la question de savoir si nous devrions vraiment les utiliser. Nous passons plus de temps à nous creuser les méninges sur la façon d’animer tous les éléments à 60fps qu’à réfléchir aux moyens d’éviter que les utilisateurs souffrant de <a href="http://a11yproject.com/posts/understanding-vestibular-disorders/">troubles vestibulaires</a> ne puissent utiliser notre site.</p><figure role="group"><img src="https://la-cascade.io/images/Rachel_Nabors_-_Google_1-compressor.jpeg" alt="vos designers ne se sont pas posé la question de savoir s'ils devaient utiliser des animations" /></figure><p>J’aime l’animation web. Je la vis, et j'en fais <a href="http://rachelnabors.com/alice-in-videoland/book/">d’adorables petites choses stupides</a> qui n’auraient pas leur place sur un site qui se respecte. Je sais qu’on peut en abuser. Nous nous sommes tous moqués de la <em>Flash-turbation</em>... mais comme nous oublions vite les leçons apprises de cette époque du design web ! Les effets de parallax scrolling sont peut-être le <em>skip intro</em> de cette génération. Nous avons certainement appris des choses plus intéressantes dans la période de sobriété <a href="http://www.smashingmagazine.com/2014/11/18/the-state-of-animation-2014/">entre Flash et l’API d’animation web</a>.</p><p>Alors voici cinq petits conseils pour nous permettre de prendre un peu de recul par rapport aux excès d’animations. Si nous les gardons bien à l’esprit, nous pouvons faire de 2015 l’année où l’animation web prendra son véritable essor.</p><h2>Animez délibérément</h2><p>Malheureusement, l’animation est considérée par la majorité des designers comme un élément décoratif. Les designers d’interfaces utilisateurs et les développeurs d’interaction comprennent mieux ces choses. Mais lorsque je donne un atelier sur l’<em>animation pour l’interaction</em>, je sais que mes étudiants devront mener une rude bataille contre des décideurs qui considèrent cela très joli, mais rangent rapidement le sujet au dernier rang de leurs priorités, quand ils ne l’éliminent pas tout simplement.</p><p>Difficile de se défaire de cette tare. Mais tout commence avec la qualité de nos choix : animer de manière délibérée, ou de ne pas animer du tout. Les animations de raccroc causeront toujours plus de mal que de bien. Les utilisateurs risquent de se plaindre qu’elles sont trop lentes ou trop rapides, ou de râler parce qu’ils ne comprennent pas ce qui se passe.</p><p>Au dernier Chrome Dev Summit cette année j’ai eu le privilège de m’entretenir avec <a href="https://www.youtube.com/watch?v=tfSiXRy1vEw">Roma Sha, responsable UX pour le design matériel de Polymer</a> (et la merveilleuse <a href="http://www.google.com/design/spec/animation/meaningful-transitions.html#">documentation d’animation</a>). Je lui ai demandé quel conseil elle donnerait aux personnes qui utilisent les animations et les transitions dans leur design. Elle m’a fait cette réponse très simple : <strong>animez de manière délibérée</strong>. Si vous ne pouvez pas vous poser un instant pour réfléchir à l’animation et pour prendre des décisions bien informées et bien articulées dans l’intérêt de l’utilisateur, alors mieux vaut ne même pas vous lancer là-dedans. Une animation prend de l’énergie, et une mauvaise animation est pire que pas d’animation du tout.</p><figure role="group"><img itemprop="url" src="https://la-cascade.io/images/Rachel_Nabors_-_Google_2.jpeg" alt="Oooh, quel rabat-joie ! Que pourrait-il arriver de mauvais ?" /></figure><h2>Il faut plus que 12 principes</h2><p>Nous essayons toujours de faire des corrélations entre des choses disparates qui suscitent notre intérêt. Depuis peu, il semble que de plus en plus de gens mettent <a href="http://www.amazon.com/gp/product/0786860707">The Illusion of Life</a> (<em>NdT: une histoire des animations Disney et des procédés utilisés</em>) dans leur bibliothèque à côté de <a href="http://www.scottmccloud.com/2-print/1-uc/index.html">Understanding Comics</a> (<em>NdT: le manuel de base pour comprendre la bande dessinée</em>). Ces livres nous donnent des aperçus utiles d’autres industries. Cependant, nous ne devrions jamais confondre un site web et un livre de bandes dessinées ou un dessin animé. Certains de ces concepts, s’ils nous aident à considérer notre travail sous un jour nouveau, sont plus ou moins appropriés au domaine qui est le nôtre.</p><p>Je pense en particulier aux <em>12 principes de l’animation</em>, mis en avant par les vétérans des studios Disney dans ce beau livre The Illusion of Life. Ces principes sont très utiles pour faire des animations réalistes et accrocheuses, comme une balle qui rebondit ou un écureuil qui trottine, mais ils ne nous orientent pas du tout pour savoir quand ou comment quelque chose doit être animé dans le cadre d’une expérience interactive améliorée, comme par exemple combien de temps un menu déroulant doit prendre pour se dérouler, ou bien si un groupe d’objets manipulables devrait être animé de manière séquentielle ou simultanée.</p><p>Les douze principes sont un excellent point de départ, mais nous avons tellement plus à apprendre. J’ai listé au moins <a href="http://alistapart.com/article/web-animation-at-work">six autres fonctions d’animation interactive</a> applicables à la conception web et d’applications. Lorsque nous pensons à l’animation, nous devrions envisager pourquoi et comment, et non pas seulement aux aspects esthétiques. Ceux-ci ne signifient rien si l’animation est superflue ou source de confusion.</p><h2>Utile et nécessaire, <em>puis</em> belle</h2><p>Chez les Shakers, il y a un proverbe qui dit : “Ne fais pas quelque chose si elle n’est pas à la fois nécessaire et utile; mais si elle est à la fois nécessaire et utile, n’hésite pas à la rendre belle”. S’agissant de l’animation et du web, il y a actuellement très peu de documentation sur ce qui la rend utile ou nécessaire. Nous avons tendance à nous concentrer davantage sur la beauté, l’agrément, l’esthétique. Mais même si l’esthétique est importante, elle occupe la banquette arrière par rapport à l’expérience globale de l’utilisateur.</p><p>La première fois que j’ai vu <a href="https://www.youtube.com/embed/m5MrbCGcaUI?rel=0">l’écran de chargement de Pokemon Yellow</a> sur ma GameBoy j’ai été captivée. À partir de la sixième fois, j’écrasais le bouton Start dès que le logo apparaissait à l’écran. Ce qui nous semble plein de charme et de sens lorsque nous travaillons sur un projet peut apparaître tout autrement à nos utilisateurs. Et même lorsqu’une animation adorable est très bien reçue, comme ce fut le cas de l’écran d’ouverture de Pokemon Yellow, trop de répétitions d’une animation jolie mais devenue inutile peut irriter l’utilisateur.</p><figure role="group"><img src="https://la-cascade.io/images/animation-ui-illos2.jpeg" alt="" /><figcaption>J’ai trouvé ça mignon la première fois, mais à la 70ème... c’est chiant !</figcaption></figure><p>Si une animation n’aide pas l’utilisateur d’une façon ou d’une autre, c’est une utilisation gratuite de la batterie et des cycles de processing. Plutôt que d’animer pour le seul plaisir d’animer, nous devrions être capables d’articuler deux choses que l’animation réalise pour l’utilisateur. Par exemple, prenons cette icône de menu de <a href="http://finethought.com/">Finethought.com</a> (trouvée grâce à <a href="http://useyourinterface.com/post/97576888941">Use Your Interface</a>). L’icône fait deux choses lorsqu’elle est cliquée :</p><ol><li>Elle donne un feedback à l’utilisateur en s’animant, ce qui permet à l’utilisateur de savoir qu’elle a bien été cliquée.</li>
<li>Elle montre que sa relation au contenu de la page a changé, en se transformant en bouton de fermeture.</li>
</ol><p>Si nous avons deux bonnes raisons d’animer quelque chose, rien ne s’oppose à ce qu’une troisième raison soit l’agrément de l’utilisateur.</p><h2>Aller 4 fois plus vite</h2><p>Il existe une règle générale dans le monde de l’animation traditionnelle qui s’applique très bien à l’animation web : quelle que soit la durée de ton animation, divise-la en deux. Puis divise-la encore en deux. Lorsque nous travaillons sur une animation pendant des heures, notre notion du temps se dilate, ce qui nous paraît rapide est en réalité insupportablement lent pour la plupart des utilisateurs. En fait, la critique la plus courante actuellement de la part des utilisateurs d’interfaces animées est “c’est trop lent !” Une bonne animation est non bloquante, et pour cela, elle doit aller vite.</p><p>Lorsque vos animations sont prêtes à être intégrées au site, réduisez leur durée à 25% de leur vitesse originale : un fade-out de 4 secondes sera parfait en 1 seconde.</p><h2>Installer un bouton stop</h2><p>Quel que soit l’intérêt ou la nécessité de votre animation, il y aura toujours des gens qu’elle rendra physiquement malades. Pour eux, il est important de prévoir une façon de désactiver les animations sur le site.</p><p>Heureusement, les designers web pensent déjà à divers moyens de permettre aux utilisateurs de choisir eux-mêmes leur expérience web. Par exemple, ce <a href="https://www.youtube.com/watch?v=2c3siLM1zlw">site de présentation du film d’animation Little from the Fish Shop</a> permet aux utilisateurs de désactiver la plupart des effets de parallaxe. Même si cela n’annule pas toutes les animations, c’est suffisant pour vous éviter la nausée.</p><p>L’animation est un outil puissant dans l’arsenal du web design. Mais la prudence s’impose : si nous abusons de l’animation, elle risque de finir par avoir mauvaise réputation. Si nous la sous-estimons, elle ne sera jamais une priorité. Mais si nous la manions avec sagacité, l’animation est un outil qui nous aidera à construire des sites et des applications plus faciles à utiliser et plus agréables, pour les années qui viennent.</p><p><strong>Faisons de 2015 l’année où les animations web se seront mises au service des utilisateurs</strong>.</p><figure role="group"><img src="https://la-cascade.io/images/Rachel_Nabors_-_Google_3-compressor.jpeg" alt="Un dinosaure qui pense 'ils ne créent jamais la même animation deux fois. Comme s'ils testaient les specs. Systématiquement. Ils se rappellent." /></figure><p>NdT : <em>Les illustrations détournées de</em> Jurassic Park <em>n'ont pas été retenues par l'éditeur de l'article original, Rachel Nabors les a amicalement communiquées à La Cascade</em>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/5-facons-danimer-de-maniere-responsable</link>
      <guid>https://la-cascade.io/articles/5-facons-danimer-de-maniere-responsable</guid>
      <pubDate>Tue, 23 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Guide des animations SVG (SMIL)]]></title>
      <description><![CDATA[<p><em>Pour tout savoir sur les animations SVG avec SMIL. Les animations SMIL permettent des choses impossibles avec CSS.</em></p><div class="articleContent"><p><strong>Introduction de Chris Coyier</strong> : Sara a le don de plonger au coeur des fonctionnalités du web et de nous les expliquer à nous autres, simples mortels. Ici, elle va creuser au plus profond de SMIL (et ses amis) et de la syntaxe d’animation de SVG pour nous donner ce guide <em>épique</em>.</p><p> <em>Note du traducteur épuisé : guide épique s’il en est, et qui peut paraître ardu, surtout dans ses premiers paragraphes. Mon conseil : regardez les animations (en commençant <a href="#morphing">ici par exemple</a>), lisez les paragraphes dans le désordre, puis relisez dans l’ordre</em>.</p><h2>Généralités</h2><p>Les graphiques SVG peuvent être animés au moyen d’<strong>éléments d’animation</strong>. Les éléments d’animation ont été définis à l’origine dans la <a href="http://www.w3.org/TR/2001/REC-smil-animation-20010904/">spécification d’animation SMIL</a> (<a href="http://fr.wikipedia.org/wiki/Synchronized_Multimedia_Integration_Language">Synchronized Multimedia Integration Language</a>). Ces éléments comprennent :</p><ul><li><code>&lt;animate&gt;</code> - qui vous permet d’animer des attributs et propriétés scalaires sur une période de temps donnée.</li>
<li><code>&lt;set&gt;</code> - qui est un raccourci pratique d’<code>&lt;animate&gt;</code>, utile pour assigner des valeurs d’animation à des attributs et propriétés non numériques, telles que la propriété visibilité.</li>
<li><code>&lt;animateMotion&gt;</code> - qui déplace un élément le long d’un chemin.</li>
<li><code>&lt;animateColor&gt;</code> - qui modifie la valeur de couleur d’attributs ou de propriétés dans le temps. Notez que l’élément <code>&lt;animateColor&gt;</code> est désormais obsolète, on utilise simplement l’élément <code>&lt;animate&gt;</code> en ciblant les propriétés qui peuvent prendre des valeurs de couleurs. Il est toujours présent dans la spécification SVG 1.1, mais il est clairement indiqué qu’il est obsolète — et il est absent de la spécification SVG 2.</li>
</ul><p>En plus des éléments d’animation définis dans la spec SMIL, SVG inclut des extensions compatibles avec ladite spécification. Ces extensions incluent les attributs étendant la fonctionnalité de l’élément <code>&lt;animateMotion&gt;</code> et des éléments d’animation supplémentaires. Les extensions SVG comprennent :</p><ul><li><code>&lt;animateTransform&gt;</code> - vous permet d’animer l’un des attributs de transformation SVG dans le temps, comme l’attribut <code>&lt;transform&gt;</code>.</li>
<li><code>&lt;path&gt;</code> (<em>attribut</em>) - permet à toute fonctionnalité de la syntaxe de chemin SVG d’être spécifiée dans un attribut de chemin de l’élément <code>&lt;animateMotion&gt;</code> (l’animation SMIL permet seulement un sous-ensemble de cette syntaxe à l’intérieur d’un attribut de chemin). Nous reviendrons sur <code>&lt;animateMotion&gt;</code> dans une section qui suit.</li>
<li><code>&lt;mpath&gt;</code> - utilisé en conjonction avec l’élément <code>&lt;animateMotion&gt;</code> pour référencer un chemin et indiquer qu’il servira de... chemin à une animation.L’élément <code>&lt;mpath&gt;</code> est inclu à l’intéreur de l’élément <code>&lt;animateMotion&gt;</code> avant la balise fermante.</li>
<li><code>&lt;keypoints&gt;</code> (<em>attribut</em>) - utilisé comme attribut pour <code>&lt;animateMotion&gt;</code> afin de fournir un contrôle précis de la vitesse des animations sur les chemins.</li>
<li><code>&lt;rotate&gt;</code> (<em>attribut</em>) - utilisé comme attribut pour <code>&lt;animateMotion&gt;</code> afin de contrôler si un objet est automatiquement pivoté de façon à ce que son axe des x pointe dans la même direction (ou la direction opposée) au vecteur tangent directionnel du chemin. Cet attribut est essentiel pour que le mouvement le long d’un chemin fonctionne comme le souhaitez. Nous verrons cela plus en détail dans la section <code>&lt;animateMotion&gt;</code>.</li>
</ul><p>Les animations SVG peuvent être de nature similaire aux animations et transitions CSS. On crée des keyframes, les objets se déplacent, les couleurs changent etc. Cependant, elles peuvent faire certaines choses que les animations CSS ne permettent pas de réaliser, ce que nous allons voir tout à l’heure.</p><h2>Pourquoi utiliser les animations SVG?</h2><p>Les SVG peuvent être <a href="http://slides.com/sarasoueidan/styling-animating-svgs-with-css--2#/">stylés et animés avec CSS (slides)</a>. À la base, toute animation de transformation ou de transition qui peut être appliquée à un élément HTML peut l’être à un élément SVG. Mais certaines propriétés SVG qui ne peuvent pas être animées avec CSS peuvent l’être avec SVG. Par exemple un chemin SVG vient avec un ensemble de <strong>données</strong> (un attribut <code>d=""</code>) qui définit la forme de ce chemin. Cette donnée peut être modifiée et animée avec SMIL, mais pas avec CSS. C’est pourquoi les éléments SVG sont décrits au travers d’un ensemble d’attributs appelés les <em>attributs de présentation</em> SVG. Certains d’entre eux peuvent être déterminés, modifiés et animés avec CSS, d’autres non.</p><p>Autrement dit, de nombreux effets et animations ne peuvent pas être obtenus avec CSS. Pour combler ces manques, on peut utiliser JavaScript ou les déclarations dérivées de SMIL.</p><p>Si vous préférez utiliser JavaScript, je recommande <a href="http://snapsvg.io/">snap.svg</a> de Dmitry Baranovskiy qui est décrit comme le “jQuery du SVG”. Voici <a href="http://codepen.io/collection/edpyJ/">quelques exemples</a> de ce qu’on peut faire.</p><p>Si vous préférez une approche plus déclarative, vous pouvez utiliser les éléments d’animation SVG, nous allons les passer en revue dans ce guide !</p><p>Un autre avantage de SMIL sur les animations JavaScript est que les animations JS ne fonctionnent pas lorsque le SVG est embarqué (<em>embedded</em>) en tant qu’<code>img</code> ou utilisé comme <code>background-image</code> dans CSS. Les animations SMIL fonctionnent, elles, dans les deux cas (ou le devraient, il faut aussi tenir compte des limitations des navigateurs). C’est un grand avantage à mon sens et vous pourriez choisir SMIL pour cette bonne raison. Cet article est conçu comme un guide pour vous aider à vous lancer dans SMIL dès maintenant.</p><h2>Compatibilité navigateurs et fallbacks</h2><p>La compatibilité navigateur des animations SMIL est tout à fait convenable. Elles fonctionnent dans tous les navigateurs à l’exception d’Internet Explorer et Opera Mini. Pour une étude complète de la compatibilité, vous pouvez vous référer au tableau de <a href="http://caniuse.com/#feat=svg-smil">Can I Use</a>.</p><p>Si vous avez besoin de solutions de repli (<em>fallback</em>) pour les animations SMIL, vous pouvez tester la compatibilité navigateurs à la volée avec <a href="http://modernizr.com/">Modernizr</a>. Lorsque SMIL n’est pas compatible, vous pouvez fournir une solution de repli (animations JavaScript, expérience utilisateur différente, etc.).</p><h2>Spécifier la cible de l’animation avec xlink:href</h2><p>Quel que soit celui des quatre éléments d’animations que vous choisissez, il vous faut spécifier la cible de l’animation définie par cet élément.</p><p>Pour spécifier une cible, vous pouvez utiliser l’attribut <code>xlink:href</code>. L’attribut prend une référence URI de l’élément cible de l’animation. <strong>L’élément cible doit faire partie du fragment de document SVG courant</strong>.</p><pre>//SVG
&lt;rect id="cool_shape" ... /&gt;
&lt;animation xlink:href="#cool_shape" ... /&gt;</pre><p>Si vous avez déjà rencontré des éléments d’animation SVG, vous les avez probablement vus imbriqués à l’intérieur de l’élément qu’ils sont supposés animer. C’est également possible selon la spécification :</p><blockquote>
<p>Si l’attribut <code>xlink:href</code> n’est pas fourni, l’élément cible sera l’élément immédiatement parent de l’élément d’animation courant</p>
</blockquote><pre>//SVG
&lt;rect id="cool_shape" ... &gt;
  &lt;animation ... /&gt;
&lt;/rect&gt;</pre><p>Donc si vous voulez “encapsuler” l’animation à l’intérieur de l’élément auquel elle s’applique, vous le pouvez. Et si vous préférez spécifier les animations ailleurs dans votre document, vous pouvez également le faire, et spécifier la cible de chaque animation en utilisant <code>xlink:href</code> — les deux façons de faire fonctionnent.</p><h2>Spécifier la propriété cible de l’animation avec attributeName et attributeType</h2><p>Tous les éléments d’animation partagent un autre attribut : <code>attributeName</code>, qu’on utilise pour spécifier le nom de l’attribut que vous animez.</p><p>Par exemple, si vous voulez animer la position du centre d’un cercle <code>circle</code> sur l’axe des x, vous pouvez le faire en spécifiant <code>cx</code> comme valeur de l’attribut <code>attributeName</code>.</p><p><code>attributeName</code> prend une valeur unique, il ne prend pas de liste de valeurs, par conséquent vous ne pouvez animer qu’un seul atribut à la fois. Si vous voulez animer plus d’un attribut, vous devez définir plus d’une animation pour l’élément. Sur ce point au moins, CSS a un avantage sur SMIL. Mais là encore, en raison des valeurs possibles pour les autres attributs d’animation (que nous allons voir ensuite), il est logique de ne définir qu’un seul nom d’attribut à la fois, sans quoi les autres valeurs d’attributs pourraient devenir trop complexes à gérer.</p><p>Lorsque vous spécifiez le nom d’attribut, vous pouvez ajouter un préfixe XMLNS (espace de nom XML) pour indiquer l’espace de nom de l’attribut. L’espace de nom peut également être spécifié en utilisant l’attribut <code>attributeType</code>. Par exemple, certains attributs font partie de l’espace de nom CSS (ce qui signifie que l’attribut peut être trouvé comme propriété CSS) et d’autres sont uniquement XML. Vous pouvez consulter <a href="http://slides.com/sarasoueidan/styling-animating-svgs-with-css#/10">une table de ces attributs ici</a>. Tous les attributs SVG ne figurent pas dans cette table, seulement ceux avec lesquels CSS fonctionne. Certains d’entre eux sont déjà disponibles comme propriétés CSS.</p><p>Si la valeur de <code>attributeType</code> n’est pas explicitement définie, ou si elle est définie comme <code>auto</code>, le navigateur doit d’abord chercher dans la liste des propriétés CSS un nom de propriété correspondant, et s’il n’en trouve pas, chercher le nom d’espace par défaut pour l’élément.</p><p>Par exemple, le code suivant anime l’<code>opacity</code> d’un rectangle SVG. Puisque l’attribut <code>opacity</code> existe aussi en tant que propriété CSS, l’<code>attributeType</code> est défini à partir de l’espace de nom CSS :</p><pre>//SVG
&lt;rect&gt;
  &lt;animate attributeType="CSS" attributeName="opacity"
           from="1" to="0" dur="5s" repeatCount="indefinite" /&gt;
&lt;/rect&gt;</pre><p>Nous allons voir les autres attributs d’animation dans les exemples qui suivent. Sauf indication contraire, tous les attributs d’animation sont communs à tous les éléments d’animation.</p><h2>Animer l’attribut d’un élément</h2><p>Commençons en déplaçant un cercle d’une position à une autre. Pour ce faire, nous allons modifier la valeur de son attribut <code>cx</code> qui spécifie la position de son centre sur l’axe des x.</p><p>Nous allons utiliser l’élément <code>animate</code>. Cet élément est utilisé pour animer un attribut à la fois. Les attributs peuvent prendre des valeurs numériques et les couleurs sont généralement animées avec <code>animate</code>. Pour une liste des attributs qui peuvent être animés, vous pouvez vous référer à <a href="http://www.w3.org/TR/SVG2/animate.html#AnimationAttributesAndProperties">cette table</a>.</p><p>Si l’on veut modifier une valeur sur une période de temps donnée, on utilise les attributs <code>from</code>, <code>to</code> et <code>dur</code>. Par ailleurs, si vous avez besoin de spécifier quand l’animation doit démarrer, vous utiliserez l’attribut <code>begin</code>.</p><pre>//SVG
&lt;circle id="my-circle" r="30" cx="50" cy="50" fill="orange" /&gt;
  &lt;animate
    xlink:href="#my-circle"
    attributeName="cx"
    from="50"
    to="450"
    dur="1s"
    begin="click"
    fill="freeze" /&gt;</pre><p>Dans l’exemple ci-dessus, nous avons défini un cercle, puis nous appelons une animation sur ce cercle. Le centre du cercle se déplace de sa position initiale (50 unités) vers sa position finale (450 unités) sur l’axe des x.</p><p>La valeur de <code>begin</code> est définie comme <code>click</code>. Cela signifie que le cercle se déplacera lorsqu’on cliquera dessus. Vous pouvez également définir cette valeur comme une unité de temps, par exemple <code>begin="0s"</code> démarrera l’animation dès que la page est chargée. Vous pouvez <strong>retarder l’animation</strong> en donnant une valeur de temps positive — par exemple <code>begin="2s"</code> qui démarrera l’animation deux secondes après le chargement de la page.</p><p>Ce qui est encore plus intéressant avec <code>begin</code>, c’est que vous pouvez définir des valeurs telles que <code>click + 1s</code> pour démarrer une animation <strong>une seconde après que l’élément ait été cliqué</strong>. De plus, vous pouvez utiliser d’autres valeurs qui vous permettent de synchroniser les animations sans avoir à calculer la durée et les retards des autres animations. Nous verrons cela tout à l’heure.</p><p>L’attribut <code>dur</code> est similaire à son équivalent CSS <code>animation-duration</code>.</p><p>Les attributs <code>from</code> et <code>to</code> sont similaires aux keyframes <code>from</code> et <code>to</code> dans un block d’animation CSS <code>@keyframe</code> :</p><pre>//CSS
@keyframes moveCircle {
  from { /* valeur de départ */ }
  to { /* valeur d’arrivée */ }
}</pre><p>L’attribut <code>fill</code> (qui porte malencontreusement le même nom que l’attribut <code>fill</code> définissant la couleur de remplissage d’un élément) est similaire à la propriété <code>animation-fill-mode</code> qui spécifie si l’élément devrait ou non revenir à son état initial à la fin de l’animation. Les valeurs en SVG sont similaires à leur équivalent CSS, à part deux noms :</p><ul><li><code>freeze</code> : on indique que l’effet doit rester dans son état final, l’effet d’animation est “gelé” (<em>freeze</em>) pour la durée d’existence de la page, ou jusqu’au moment où l’on redémarre l’animation.</li>
<li><code>remove</code> : l’effet d’animation est retiré (il ne s’applique plus) lorsque la durée de l’animation est passée. L’animation n’affecte plus la cible, sauf si elle est redémarrée.</li>
</ul><p>Cliquez sur le disque orange pour déclencher l'animation. Essayez de modifier les valeurs dans cette <a href="http://codepen.io/SaraSoueidan/pen/e883265849147a0a4b712c5960c448a8">démo CodePen</a> pour voir comment cela affecte l’animation (si vous ne pouvez le faire directement à l’écran, cliquez sur “Edit on CodePen”) :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/e883265849147a0a4b712c5960c448a8/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>L’attribut <code>by</code> est utilisé pour spécifier un décalage de l’animation. Comme son nom le suggère, vous pouvez spécifier le nombre ou la façon par (<em>by</em>) lequel vous voulez que l’animation progresse. L’effet de <code>by</code> est surtout visible lorsque vous progressez dans la durée de l’animation en étapes successives, un peu comme avec <a href="http://lea.verou.me/2011/09/pure-css3-typing-animation-with-steps/">la fonction CSS <code>steps()</code></a>. L’équivalent SVG de la fonction <code>steps()</code> est <code>calcMode="discrete"</code>. Nous verrons l’attribut <code>calcMode</code> un peu plus loin dans cet article.</p><p>Un autre cas où l’effet de <code>by</code> est plus visible est quand vous spécifiez uniquement l’attribut <code>to</code>. Un exemple serait de l’utiliser ave l’élément <code>set</code> que nous allons également voir tout à l’heure.</p><p>Et <em>last but not least</em>, <code>by</code> peut être utile quand vous travaillez avec des animations additives et accumulatives. Plus d’infos tout à l’heure.</p><h3>Redémarrer les animations avec restart</h3><p>Il peut être utile d’empêcher une animation d’être redémarrée tant qu’elle est active. Pour ce faire, SVG propose l’attribut <code>restart</code>. Vous pouvez lui donner l’une des trois valeurs suivantes :</p><ul><li><code>always</code> : l’animation peut être redémarrée n’importe quand. C’est la valeur par défaut.</li>
<li><code>whenNotActive</code> : l’animation peut être redémarrée seulement quand elle n’est pas active (c’est à dire lorsqu’elle est arrivée à son terme). Les tentatives de redémarrage pendant sa durée d’activité sont ignorées.</li>
<li><code>never</code> : l’élément ne peut pas être redémarré pour le reste de la durée courante du parent qui la contient. Dans le cas de SVG, puisque le conteneur de temps parent est le fragment de document, l’animation ne peut pas être redémarrée pour le reste de la durée du document.</li>
</ul><h3>Nommer les animations et les synchroniser</h3><p>Supposons que nous voulions animer la position <em>et</em> la couleur du cercle, afin que le changement de couleur se produise à la fin de l’animation de déplacement. Nous pouvons le faire en donnant à la valeur de <code>begin</code> de l’animation de changement de couleur la même valeur que la <code>dur</code>ée de l’animation de déplacement. C’est ce que nous ferions normalement en CSS.</p><p>Cependant, SMIL offre une fonctionnalité intéressante de traitement des événements. Nous avons mentionné précédemment que l’attribut <code>begin</code> acceptait des valeurs telles que <code>click + 5s</code>. Cette valeur est appelée “valeur d’événement”, et elle est constituée dans cet exemple d’une référence à l’événement (le clic) suivie d’une “valeur d’horloge”. Ce qui est intéressant ici, c’est le nom de la seconde partie: la “valeur d’horloge”. Pourquoi pas simplement une “valeur de temps” ? Eh bien la réponse est que vous pouvez littéralement utiliser <a href="http://www.w3.org/TR/SVG2/animate.html#ClockValueSyntax">une valeur d’horloge</a> comme “10min” ou “01:33” qui est l’équivalent de 1 minute et 33 secondes, ou même “02:30:03” (deux heures, trente minutes et trois secondes). À l’heure où nous écrivons, les valeurs d’horloge <em>ne sont implémentées complètement dans aucun navigateur</em>.</p><p>Donc, si nous revenons à la démo précédente et utilisons <code>click + 01:30</code>, si un navigateur s’avérait compatible, l’animation serait déclenchée 1 minute 30 après qu’on ait cliqué sur le cercle.</p><p>Un autre type de valeur acceptée est l’ID d’une autre animation suivi d’une référence d’événement. Si vous aviez deux animations (ou plus), qu’elles s’appliquent au même élément ou pas, et que vous vouliez les synchroniser de façon à ce que l’une démarre en fonction de l’autre, vous pourriez le faire sans avoir à connaître la durée de l’autre animation.</p><p>Par exemple, dans la démo suivante, le rectangle bleu commence à bouger 1 seconde après que l’animation du cercle ait démarré. On donne pour cela une ID à chaque animation, puis on utilise cette ID avec l’événement <code>begin</code> comme on le voit dans le code suivant :</p><pre>//SVG
&lt;circle id="orange-circle" r="30" cx="50" cy="50" fill="orange" /&gt;
&lt;rect id="blue-rectangle" width="50" height="50" x="25" y="200" fill="#0099cc"&gt;&lt;/rect&gt;
  &lt;animate
    xlink:href="#orange-circle"
    attributeName="cx"
    from="50"
    to="450"
    dur="5s"
    begin="click"
    fill="freeze"
    id="circ-anim" /&gt;
  &lt;animate
    xlink:href="#blue-rectangle"
    attributeName="x"
    from="50"
    to="425"
    dur="5s"
    begin="circ-anim.begin + 1s"
    fill="freeze"
    id="rect-anim" /&gt;</pre><p>La partie <code>begin="circ-anim.begin + 1s"</code> dit au navigateur de démarrer l’animation du rectangle 1 seconde après le début de celle du cercle. Vous pouvez voir l’effet dans cette démo :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/55195eee8647f438525b852000504c7a/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Vous pouvez également démarrer l’animation du rectangle après que celle du cercle soit arrivée à son terme, en utilisant l’événement <code>end</code> :</p><pre>//SVG
&lt;animate
  xlink:href="#blue-rectangle"
  attributeName="x"
  from="50"
  to="425"
  dur="5s"
  begin="circ-anim.end"
  fill="freeze"
  id="rect-anim"/&gt;</pre><p>Vous pourriez même la démarrer <em>avant</em> la fin de l’animation du cercle :</p><pre>//SVG
&lt;animate
  xlink:href="#blue-rectangle"
  attributeName="x"
  from="50"
  to="425"
  dur="5s"
  begin="circ-anim.end - 3s"
  fill="freeze"
  id="rect-anim"/&gt;</pre><h3>Répéter les animations</h3><p>Si vous voulez qu’une animation se produise plus d’une fois, vous pouvez utiliser l’attribut <code>repeatCount</code> en spécifiant le nombre de fois que vous voulez répéter l’animation, ou bien utiliser le mot-clé <code>indefinite</code> pour qu’elle se répète indéfiniment. Ainsi, si nous voulions que l’animation du cercle se produise deux fois, le code serait :</p><pre>//SVG
&lt;animate
  xlink:href="#orange-circle"
  attributeName="cx"
  from="50"
  to="450"
  dur="5s"
  begin="click"
  repeatCount="2"
  fill="freeze"
  id="circ-anim" /&gt;</pre><p>Dans la démo ci-dessous, j’ai donné une valeur de 2 à <code>repeatCount</code> sur le cercle, et <code>indefinite</code> sur le carré :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/d8e38406a5a90f4392a4bb85f6aadd78/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez que l’animation redémarre à partir de la valeur initiale <code>from</code> plutôt qu’à partir du point où elle est arrivée. à la fin de l’animation. Malheureusement, SMIL n’offre pas de manière d’aller et venir entre les valeurs de départ et d’arrivée, contrairement à CSS. La propriété <code>animation-direction</code> de CSS spécifie si une animation doit repartir en sens inverse sur tous les cycles ou sur certains d’entre eux. La valeur <code>animate-direction: alternate</code> indique que les cycles d’animation impairs se produisent dans la direction normale et que les cycles pairs se produisent en sens inverse. Le premier cycle va du début à la fin, le second va de la fin au début, etc.</p><p>Dans SMIL, il faudrait utiliser JavaScript pour changer explicitement les valeurs des attributs <code>from</code> et <code>to</code>. Jon McPartland de Big bite Creative a écrit <a href="http://bigbitecreative.com/introduction-svg-animation/">un article</a> à ce sujet pour expliquer comment il a créé <a href="http://jsfiddle.net/unhw/kk5CG/3/">une animation d’icône de menu</a>.</p><p>Une autre façon de contourner le problème serait de spécifier la valeur d’arrivée comme étant une valeur intermédiaire et de faire que la valeur finale soit identique à la valeur initiale. Par exemple, vous pouvez définir une animation commençant <code>from</code> une certaine valeur et se terminant à la même valeur, mais en donnant comme valeur intermédiaire entre <code>from</code> et <code>to</code> la valeur que vous <em>auriez utilisé</em> comme valeur finale.</p><p>En CSS, on ferait quelque chose comme cela :</p><pre>//CSS
@keyframes example {
  from, to {
    left: 0;
  }
  50% {
    left: 300px;
  }
}</pre><p>L’équivalent dans SMIL est d’utiliser l’attribut <code>values</code> que nous expliquerons sous peu.</p><p>Ceci étant dit, la solution contournée ci-dessus peut fonctionner ou non pour vous selon le type d’animation que vous cherchez et selon que vous enchaîniez ou non des animations, que vous les répétiez ou que vous les ajoutiez.</p><p>Voci une jolie animation infinie qui utilise des retards dans les débuts d’animation, par Miles Elam :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/mileselam/pen/kprKm/">Hexagon Ripple</a>de @mileselam dans<a href="https://codepen.io">CodePen</a></div><h3>Restreindre le temps de répétition avec <code>repeatDur</code></h3><p>Une répétition indéfinie peut s’avérer ennuyeuse ou peu <em>user-friendly</em> à la longue, réduire le temps de répétition est donc parfois une bonne solution. C’est ce qu’on appelle le <em>temps de présentation</em>.</p><p>Le temps de présentation est spécifié à l’aide de l’attribut <code>repeatDur</code> dont la syntaxe est similaire à celle de la valeur d’horloge, à ceci près qu’au lieu d’être relatif à un autre événement d’animation ou d’interaction, il est relatif au début du document.</p><p>Par exemple, le code suivant stoppera la répétition de l’animation 1 minute et 30 secondes après le début du document :</p><pre>//SVG
&lt;animate
  xlink:href="#orange-circle"
  attributeName="cx"
  from="50"
  to="450"
  dur="2s"
  begin="0s"
  repeatCount="indefinite"
  repeatDur="01:30"
  fill="freeze"
  id="circ-anim" /&gt;</pre><p>et voici la démo :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/366b9fba478e7ac1de2188f5a2594c3c/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><h3>Synchroniser en fonction du nombre de répétitions</h3><p>Revenons un peu en arrière pour reprendre le sujet de la synchronisation de deux animations. Avec SMIL vous pouvez synchroniser des animations de manière à ce qu’une animation commence en fonction du nombre de répétitions d’une autre. Par exemple, vous pouvez commencer une animation après la n-ième répétition d’une autre animation, plus ou moins une durée que vous pouvez ajouter.</p><p>L’exemple qui suit fait débuter l’animation du rectangle à la deuxième répétition de l’animation du cercle :</p><pre>//SVG
&lt;animate
  xlink:href="#blue-rectangle"
  attributeName="x"
  from="50"
  to="425"
  dur="5s"
  begin="circ-anim.repeat(2)"
  fill="freeze"
  id="rect-anim" /&gt;</pre><p>Et voici une démo dans laquelle l’animation du rectangle commence 1 seconde après la deuxième répétition de l’animation du cercle.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/pierrechoffe/pen/LEZbdz/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Et voici <a href="http://oreillymedia.github.io/svg-essentials-examples/ch12/sync_repetition.html">un autre exemple</a>, que David Eisenberg a créé pour son livre <a href="http://shop.oreilly.com/product/9780596002237.do?sortby=bestSellers">SVG Essentials, 2e édition</a>.</p><h3>Contrôler les valeurs de keyframe avec keyTimes et values</h3><p>En CSS, nous pouvons spécifier les valeurs que nous voulons donner à notre propriété animée pendant le cours de l’animation. Par exemple, si nous animons le décalage à gauche d’un élément, au lieu de l’animer de 0 à 300 directement, nous pouvons l’animer de façon à ce qu’il prenne certaines valeurs pendant certaines périodes de temps :</p><pre>//CSS
@keyframes example {
  0% {
    left: 0;
  }
  50% {
    left: 320px;
  }
  80% {
    left: 270px;
  }
  100% {
    left: 300px;
  }
}</pre><p>0%, 50%, 80% et 100% sont les keyframes (étapes) de l’animation et les valeurs comprises dans chaque bloc sont celles de chaque keyframe. L’effet décrit ci-dessus est celui d’un élément qui rebondit contre un mur et revient à la position finale.</p><p>Dans SMIL, vous pouvez contrôler les valeurs par étape de la même façon, mais la syntaxe est différente.</p><p>Pour spécifier les keyframes, on utilise l’attribut <code>keyTimes</code>. Puis pour spécifier la valeur de la propriété animée à chaque étape, on utilise les attributs <code>values</code>. Les conventions de nommage de SMIL sont très pratiques.</p><p>Si je reviens à notre cercle et que j’utilise des valeurs similaires à celles de l’exemple CSS précédent, le code ressemblera à ceci :</p><pre>//SVG
&lt;animate
  xlink:href="#orange-circle"
  attributeName="cx"
  from="50"
  to="450"
  dur="2s"
  begin="click"
  values="50; 490; 350; 450"
  keyTimes="0; 0.5; 0.8; 1"
  fill="freeze"
  id="circ-anim" /&gt;</pre><p>Qu’avons-nous fait ici ?</p><p>La première chose à remarquer est que les temps et valeurs intermédiaires des keyframes sont spécifiés sous forme de liste. L’attribut <code>keyTimes</code> est une liste de valeurs temporelles séparées par des points-virgules, utilisée pour contrôler l’avancée de l’animation. Chaque temps dans la liste correspond à une valeur dans la liste de l’attribut <code>values</code> et définit le moment où la valeur est utilisée dans la fonction d’animation. Chaque valeur temporelle dans la liste <code>keyTimes</code> est comprise entre 0 et 1 (compris), la différence avec CSS est donc qu’au lieu d’être indiquée en pourcentage, elle l’est sous forme de fraction.</p><p>Voici la démo du code précédent. Cliquez sur le cercle pour démarrer l’animation.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/ab87fd834cdf0af7ec27850e81b1c08a/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez que si on utilise une liste de valeurs, l’animation appliquera les valeurs dans l’ordre pendant le cours de l’animation. De plus, si une liste de <code>values</code> est spécifiée, toute valeur d’attributs <code>from</code>, <code>to</code> et <code>by</code> est ignorée.</p><p>Autre chose à savoir : vous pouvez utiliser l’attribut <code>values</code> sans l’attribut <code>keyTimes</code> — les valeurs sont automatiquement espacées de manière régulière dans le temps (pour chaque valeur <code>calcMode</code> différente de <code>paced</code>, voir section suivante).</p><p>###Contrôler la vitesse d’animation avec un easing personnalisé, <code>calcMode</code> et <code>keySplines</code></p><p>Je vais comparer à nouveau SMIL et CSS parce qu’il est plus facile de comparer les syntaxes et les concepts lorsqu’on connaît déjà les animations CSS.</p><p>En CSS, vous pouvez choisir de modifier le rythme de l’animation, uniforme par défaut, et de spécifier une fonction d’easing personnalisée qui contrôle l’animation, grâce à la propriété <code>animation-timing-function</code>. La fonction timing peut être l’un des mots-clés prédéfinis ou une <a href="http://fr.wikipedia.org/wiki/Courbe_de_B%C3%A9zier">courbe de Bézier</a> cubique. Cette dernière peut être créée via un outil tel que <a href="http://cubic-bezier.com/#.17,.67,.85,.06">celui proposé par Lea Verou</a>.</p><p>Dans SMIL, le rythme de l’animation est spécifié avec l’attribut <code>calcMode</code>. Par défaut, l’animation est linéaire pour tous les éléments, à l’exception de <code>animateMotion</code> (que nous verrons tout à l’heure). Outre la valeur <code>linear</code>, vous pouvez donner une valeur de <code>discrete</code>, <code>paced</code> ou <code>spline</code>.</p><ul><li><code>discrete</code> spécifie que l’animation sautera d’une valeur à l’autre sans interpolation. C’est la même chose que la fonction <code>steps()</code> en CSS.</li>
<li><code>paced</code> est similaire à <code>linear</code>, mais il ignorera tout les temps intermédiaires définis par <code>keyTimes</code>. Il calcule la distance entre les valeurs consécutives et divise le temps en fonction. Si vos valeurs sont toutes en ordre linéaire, vous ne remarquerez pas la différence. Mais si elles vont en avant et en arrière, ou si ce sont des couleurs (qui sont traitées comme des valeurs vectorielles tri-dimensionnelles), vous verrez les valeurs intermédiaires. Ci-dessous, voici une animation créée par Amelia Bellamy-Royds qui montre la différence entre les trois valeurs <code>calcMode</code> mentionnées jusqu’ici.</li>
</ul><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" /><a href="http://codepen.io/AmeliaBR/pen/EzAju/">SVG/SMIL calcMode comparison</a>de Amelia Bellamy-Royds dans<a href="https://codepen.io">CodePen</a></div><ul><li>La quatrième valeur acceptée par <code>calcMode</code> est <code>spline</code>. Elle interpole d’une valeur à l’autre de la liste des <code>values</code> selon une fonction temporelle définie par une courbe de bézier cubique. Les points sur la spline sont définis dans l’attribut <code>keyTimes</code> et les points de contrôle pour chaque intervalle sont définis dans l’attribut <code>keySplines</code>.</li>
</ul><p> <em>NdT : pour mieux comprendre les keysplines, vous pouvez consulter cette page sur l’<a href="http://books.google.fr/books?id=7MtkGjIgOxkC&amp;pg=PA323&amp;lpg=PA323&amp;dq=keysplines+courbes+de+b%C3%A9zier&amp;source=bl&amp;ots=TAmY4E6dq9&amp;sig=KSp_p_fQa2SxglCFOfSZPfie0Fk&amp;hl=fr&amp;sa=X&amp;ei=oKdeVOKdGMPaaIjUgFA&amp;ved=0CCsQ6AEwAg#v=onepage&amp;q=keysplines%20courbes%20de%20b%C3%A9zier&amp;f=false">interpolation spline</a>, ou celle-ci sur <a href="http://pilatinfo.org/learnsvg/html/chapitre09/page09-1.htm">keySplines</a>.</em></p><p>Vous avez remarqué un nouvel attribut dans la dernière phrase : <code>keySplines</code>. À quoi sert-il ?</p><p>Là encore, reprenons les équivalences CSS.</p><p>En CSS, vous pouvez spécifier le rythme de l’animation <em>à l’intérieur</em> de chaque keyframe, au lieu de le spécifier pour toute l’animation. Cela vous donne un meilleur contrôle de chaque keyframe. Un bon exemple de cette fonctionnalité est l’effet de la balle qui rebondit. Les keyframes ressembleraient à ceci :</p><pre>//CSS
@keyframes bounce {
  0% {
      top: 0;
      animation-timing-function: ease-in;
  }
  15% {
      top: 200px;
      animation-timing-function: ease-out;
  }
  30% {
      top: 70px;
      animation-timing-function: ease-in;
  }
  45% {
      top: 200px;
      animation-timing-function: ease-out;
  }
  60% {
      top: 120px;
      animation-timing-function: ease-in;
  }
  75% {
      top: 200px;
      animation-timing-function: ease-out;
  }
  90% {
      top: 170px;
      animation-timing-function: ease-in;
  }
  100% {
      top: 200px;
      animation-timing-function: ease-out;
  }</pre><p>}</p><p>À la place des mots-clés définissant les fonctions d’easing, nous aurions pu utiliser les courbes de bézier correspondantes :</p><ul><li><code>ease-in</code> = <code>cubic-bezier(0.47, 0, 0.745, 0.715)</code></li>
<li><code>ease-out</code> = <code>cubic-bezier(0.39, 0.575, 0.565, 1)</code></li>
</ul><p>Commençons en spécifiant les keyTimes et la liste de <code>values</code> pour donner à notre cercle orange le même effet rebondissant.</p><pre>//SVG
&lt;animate
  xlink:href="#orange-circle"
  attributeName="cy"
  from="50"
  to="250"
  dur="3s"
  begin="click"
  values="50; 250; 120;250; 170; 250; 210; 250"
  keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1"
  fill="freeze"
  id="circ-anim" /&gt;</pre><p>L’animation commencera au clic et s’arrêtera une fois atteinte la valeur finale. Ensuite, pour spécifier le rythme de chaque keyframe, nous allons ajouter l’attribut <code>keySplines</code>.</p><p>L’attribut <code>keySplines</code> accepte un ensemble de points de contrôle de Bézier associés avec la liste <code>keyTimes</code>, qui définissent une fonction cubique de Bézier contrôlant l’allure de chaque intervalle. La valeur de l’attribut est une liste de points de contrôles séparés par un point-virgule. Chaque point de contrôle est décrit par un ensemble de quatre valeurs : x1 y1 x2 y2, représentant les points de contrôle Bézier pour un segment temporel. Les valeurs doivent être comprises entre 0 et 1 et l’attribut est ignoré si le <code>calcMode</code> n’est pas réglé sur <code>spline</code>.</p><p>Plutôt que de prendre des fonctions de Bézier comme valeurs, les <code>keySplines</code> prennent les coordonnées des deux points de contrôle utilisés pour dessiner la courbe. Les points de contrôle peuvent être vus sur ces captures d’écran prises sur le site de Lea Verou. On peut voir les coordonnées de chaque point, coloriées de la même façon que le point lui-même. Ce sont ces valeurs que nous allons utiliser avec l’attribut <code>keySplines</code> pour définir l’allure des animations keyframe.</p><p>Dans SMIL ces valeurs peuvent être séparées par des virgules ou par un espace. Les valeurs <code>keyTimes</code> qui définissent le segment associé sont les “points d’ancrage” Bézier, et les valeurs <code>keySplines</code> sont les points de contrôle. Par conséquent, il doit y avoir un ensemble de points de contrôle <em>en moins</em> par rapport au nombre de <code>keyTimes</code>.</p><figure><img src="https://la-cascade.io/images/control-points-compressor.png" alt="" /></figure><p>Si nous revenons à notre example de ballon qui rebondit, les coordonnées des points de contrôle pour les fonctions d’<code>ease-in</code> et <code>ease-out</code> apparaissent dans les images suivantes :</p><figure><img src="https://la-cascade.io/images/ease-in-compressor.png" alt="" /></figure><figure><img itemprop="url" src="https://la-cascade.io/images/ease-out-compressor.png" alt="" /></figure><p>Pour traduire cela en élément d’animation SVG, nous utilisons le code suivant :</p><pre>//SVG
&lt;animate
  xlink:href="#orange-circle"
  attributeName="cy"
  from="50"
  to="250"
  dur="3s"
  begin="click"
  values="50; 250; 120; 250; 170; 250; 210; 250"
  keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1"
  keySplines=".42 0 1 1;
              0 0 .59 1;
              .42 0 1 1;
              0 0 .59 1;
              .42 0 1 1;
              0 0 .59 1;
              .42 0 1 1;"
  fill="freeze"
  id="circ-anim"/&gt;</pre><p>Voici la démo :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/ecd0f3197b5fc0d7950ed94cc8afb97f/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Si vous ne voulez spécifier qu’une fonction d’easing pour l’animation entière, sans valeurs intermédiaires, il vous faut quand même spécifier les keyframes en utilisant l’attribut <code>keyTimes</code>, mais vous n’indiquez que les keyframes de début et de fin, c’est à dire <code>0; 1</code> et aucune <code>values</code> intermédiaire.</p><h3>Ajouter et accumuler des animations</h3><p>Parfois il peut être utile de définir qu’une animation commence là où la précédente s’est achevée. Ou bien de définir qu’une animation utilise les valeurs accumulées des animations précédentes comme valeur à partir de laquelle poursuivre. Pour cela, SVG a deux attributs bien nommés : <code>additive</code> et <code>accumulate</code>.</p><p>Supposons que nous ayons un élément que nous voulons élargir, ou une ligne que nous souhaitons allonger, ou un élément que nous voulons faire évoluer pas à pas d’une position à une autre. Cette fonctionnalité est particulièrement utile pour les animations répétées.</p><p>Comme pour toute autre animation, nous allons spécifier les valeurs <code>from</code> et <code>to</code>. Cependant, lorsque nous réglons la valeur d’<code>additive</code> sur <code>sum</code>, les valeurs de <code>from</code> et <code>to</code> seront relatives à la valeur originale de l’attribut animé. Si nous revenons à notre cercle, la position initiale de <code>cx</code> est 50. Lorsque nous fixons <code>from="0"</code> <code>to="100"</code>, le point de départ est donc 50 et le point d’arrivée est 100+50, c’est donc en pratique comme nous écrivions "<code>from="50" to="150"</code>".</p><p>Nous obtenons le résultat suivant :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/77b1afdefe05eff8f1d538e0f3f8727e/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>C’est tout ce que fait l’attribut <code>additive</code>. Il indique simplement si les valeurs <code>from</code> et <code>to</code> doivent être relatives à la valeur courante (ici, de <code>cx</code>) ou non. L’attribut prend l’une des deux valeurs suivantes : <code>sum</code> ou <code>replace</code>. Cette dernière est la valeur par défaut et elle signifie que les valeurs de <code>from</code> et <code>to</code> remplaceront les valeurs courantes ou originales — ce qui peut causer un saut bizarre juste avant le début de l’animation (faites l’expérience en remplaçant <code>sum</code> par <code>replace</code> dans l’exemple précédent).</p><p>Mais comment faire si nous voulons que les valeurs soient additionnées de manière telle que la seconde animation débute au point d’arrivée de la première ? C’est ici qu’intervient l’attribut <code>accumulate</code>.</p><p>L’attribut <code>accumulative</code> contrôle si l’animation est, ou non, cumulative. La valeur par défaut est <code>none</code>, ce qui signifie que par exemple lorsque l’animation est répétée elle recommence depuis le début. Vous pouvez la régler sur <code>sum</code>, qui spécifie que chaque répétition repart de la dernière valeur.</p><p>Si nous reprenons notre animation, <code>accumulate="sum"</code> donnera le résultat suivant :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/e21b7dd0af3d0a6db2828362bee24d48/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>L’attribut <code>accumulate</code> est ignoré si la valeur d'attribut cible n’est pas additionnable ou si l’élément d’animation ne se répète pas. Il sera également ignoré si la fonction d’animation est définie uniquement avec l’attribut <code>to</code>.</p><h3>Spécifier la fin de l’animation avec <code>end</code></h3><p>En plus de définir le début d’une animation, on peut définir sa fin, avec l’attribut <code>end</code>. Par exemple, nous pouvons déterminer qu’une animation se répètera indéfiniment, puis la faire cesser lorsqu’un autre élément débute son animation. L’attribut <code>end</code> accepte des valeurs similaires à celles de <code>begin</code>. On peut spécifier des valeurs absolues ou relatives pour le temps, les répétitions, les événements, etc.</p><p>Par exemple, dans la démo qui suit, le cercle orange se déplace lentement sur une période de 30 secondes. Le cercle vert s’animera quand on clique dessus, et l’animation du cercle orange cessera au moment où débutera celle du cercle vert. Cliquez sur le cercle vert pour voir le cercle orange s’arrêter :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/1a67cdf89a865d044e2993a81a4f26be/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>On peut évidemment réaliser le même genre de synchronisation d’animations lorsqu’il s’agit de deux animations appliquées au même élément. Par exemple, supposons que nous réglions la couleur du cercle de façon à ce qu’elle s'anime indéfiniment en passant d’une valeur à une autre. Puis, lorsqu’on clique sur l’élément il se déplace vers l’autre côté. Nous voulons que l’animation couleur s’arrête dès qu’on clique sur l’élément et que l’animation de déplacement est lancée.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/71fa25f8bd43d55ca04fa2259cb7d5f5/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><h3>Définir des intervalles d’animation avec plusieurs <code>begin</code> et <code>end</code></h3><p>En fait, les attributs <code>begin</code> et <code>end</code> acceptent tous les deux une liste de valeurs séparées par un point-virgule. Chaque valeur dans l’attribut <code>begin</code> correspondra à une valeur dans l’attribut <code>end</code>, formant ainsi des intervalles d’animation actifs et inactifs.</p><p>On peut le voir comme une voiture qui se déplace, avec les roues de la voiture qui seraient actives et inactives pendant certaines périodes de temps, selon que la voiture bouge ou pas. Vous pouvez même créer l’effet de la voiture animée en appliquant deux animations à la voiture : l’une qui déplace la voiture le long d’un chemin qui est aussi une animation additive et accumulative, et l’autre animation qui fait tourner les roues de la voiture dans des intervalles synchronisés avec le déplacement.</p><p>La démo suivante est un exemple de débuts et fins multiples (c’est à dire d’intervalles multiples), avec un rectangle qui tourne sur lui-même à intervalles déterminés, passant d'un état actif à inactif (faites rerun si l’animation s’est terminée).</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/cb46822d292b7a542eba729c897ed046/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Remarquez que dans cet exemple j’ai utilisé l’élément <code>&lt;animateTransform&gt;</code> pour faire tourner le rectangle sur son centre. Nous allons revenir sur cet élément plus en détail tout à l’heure.</p><p>Remarquez également que même si vous réglez <code>repeatCount</code> sur <code>indefinite</code> les valeurs <code>end</code> l’emporteront et l’animation ne se répètera pas indéfiniment.</p><h3>Restreindre la durée d’activité d’un élément avec <code>min</code> et <code>max</code></h3><p>De même qu’on peut restreindre le nombre de répétitions d’une animation, on peut restreindre la <strong>durée active</strong> d’une animation. Les attributs <code>min</code> et <code>max</code> spécifient la valeur minimum et maximum de la durée active. On a ainsi un moyen de contrôler les limites inférieures et supérieures de la durée active de l’élément. Chacun de ces attributs prend une valeur de type valeur d’horloge.</p><p>Pour <code>min</code>, cela spécifie la longueur de la valeur minimum de la durée active. La valeur doit être supérieure ou égale à zéro, qui est la valeur par défaut et ne contraint pas la durée active.</p><p>Pour <code>max</code>, la valeur d’horloge spécifie la longueur de la valeur maximum de la durée active. Elle doit également être supérieure à zéro. La valeur par défaut de <code>max</code> est <code>indefinite</code>, elle ne contraint pas la durée active.</p><p>Si les attributs <code>min</code> et <code>max</code> sont tous les deux spécifiés, la valeur de <code>max</code> doit être supérieure ou égale à la valeur de <code>min</code>, faute de quoi les deux attributs sont ignorés.</p><p>Mais qu’est-ce qui définit la durée active d’un élément ? Nous avons déjà mentionné la durée de répétition, en plus de la “simple durée” qui est la durée de l’animation sans répétition (spécifiée avec <code>dur</code>), alors comment toutes ces durées fonctionnent-elles ensemble ? Laquelle prend le dessus ? Et où intervient l’attribut <code>end</code> qui prendrait le pas sur tous les autres pour mettre fin à l’animation ?</p><p>Les choses se passent de la manière suivante : le navigateur va <em>d’abord</em> calculer la durée active en fonction des valeurs <code>dur</code>, <code>repeatCount</code>, <code>repeatDur</code> et <code>end</code>. <em>Puis</em>, il compare cette durée calculée avec les valeurs <code>min</code> et <code>max</code>. Si le résultat est à l’intérieur des limites, cette première durée calculée est correcte et ne sera pas modifiée. Sinon, deux situations sont possibles :</p><ul><li>Si la première durée calculée est supérieure à la valeur <code>max</code>, la durée active de l’élément est définie comme égale à <code>max</code>.</li>
<li>Si la première durée calculée est inférieure à la valeur <code>min</code>, la durée active de l’élément est définie comme égale à <code>min</code> et l’élément se comporte comme suit :
<ul><li>Si la durée de répétitions (ou la durée simple, si l’élément ne se répète pas) de l’élément est supérieure à <code>min</code>, alors l’élément est animé normalement pendant la durée active (avec la contrainte <code>min</code>).
<ul><li>Sinon, l’élément est animé normalement pour sa durée de répétition (ou sa durée simple s’il ne se répète pas) et il est arrêté (gelé) ou il n’est pas montré selon la valeur de l’attribut <code>fill</code>.</li>
</ul></li>
</ul></li>
</ul><p>Il nous reste maintenant à voir comment le navigateur calcule la durée active. Pour faire bref, je n’entrerai pas dans les détails ici. Mais vous pouvez trouver dans <a href="http://www.w3.org/TR/2001/REC-smil-animation-20010904/#ComputingActiveDur">la spécification</a> un tableau complet détaillant les combinaisons de <code>dur</code>, <code>repeatCount</code>, <code>repeatDur</code> et <code>end</code> et ce que deviendra la durée active en fonction de la combinaison de ces attributs.</p><p>Enfin, si on définit qu’un élément doit commencer avant son parent (par exemple avec une valeur de décalage négative), la durée minimum est mesurée à partir du temps calculé de départ, et non à partir du temps observé. Cela signifie que la valeur <code>min</code> peut n’avoir aucun effet observé.</p><h3>Un exemple d'animate : morphing des chemins</h3><p>Un des attributs qu’on peut animer en SMIL (mais pas en CSS) est l’attribut <code>d</code> (raccourci pour <em>data</em>) d’un <code>&lt;path&gt;</code> SVG. L’attribut <code>d</code> contient les données définissant le contour de la forme que nous dessinons. Elles sont constituées par un ensemble de commandes et de coordonnées qui indiquent au navigateur où et comment dessiner des points, des arcs, des lignes qui forment le chemin final.</p><p>L’animation de cet attribut nous permet de <em>morpher</em> les chemins SVG et de créer des effets d’interpolation de formes. Mais pour pouvoir réaliser ce morphing, les chemins de début, de fin et tous les chemins intermédiaires doivent avoir le même nombre de sommets et de points, qui doivent apparaître dans le même ordre. Si le nombre de sommets ne correspond pas, l’animation ne marchera pas. La raison est que les modifications de la forme sont produites par le déplacement des sommets et l’<a href="http://fr.wikipedia.org/wiki/Tweening">interpolation</a> de leur positions.</p><p>Pour animer un chemin SVG, on spécifie que l’<code>attributeName</code> doit être <code>d</code>, et on fixe les valeurs de <code>from</code> et <code>to</code> qui indiquent les formes de début et de fin, et on peut utiliser l'attribut <code>values</code> pour indiquer toute valeur intermédiaire.</p><p>Là non plus je n’entrerai pas dans les détails. Vous pouvez lire <a href="https://codepen.io/noahblon/post/an-intro-to-svg-animation-with-smil">cet excellent article de Noah Blon</a> dans lequel il explique comment il a créé une animation utilisant l’interpolation de formes avec <code>&lt;animate&gt;</code>. La démo live de l’article de <a href="https://la-cascade.io/auteurs/noah-blon">Noah</a> ressemble à ceci :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/noahblon/pen/IhLFK/">cette démo</a>de Noah Blon dans<a href="https://codepen.io">CodePen</a></div><p>Et voici un autre exemple de morphing par Felix Hornoiu :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/felixhornoiu/pen/dovub/">cette démo</a>de Felix Hornoiu dans<a href="https://codepen.io">CodePen</a></div><p>Vous pouvez même morpher les valeurs d’un chemin utilisé comme masque de détourage ! En voici un exemple par Heather Buchel :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/hbuchel/pen/qLxAB/">cette démo</a>de Heather Buchel dans<a href="https://codepen.io">CodePen</a></div><h2>Animer le long de chemins arbitraires avec animateMotion</h2><p>L’élément <code>&lt;animateMotion&gt;</code> est mon élément SMIL préféré. Vous pouvez l’utiliser pour déplacer un élément le long d’un chemin. On peut spécifier le chemin de déplacement de deux façons possibles, que nous allons voir tout à l’heure.</p><p>L’élément <code>&lt;animateMotion&gt;</code> accepte les mêmes attributs que mentionnés précédemment, plus trois autres : <code>keyPoints</code>, <code>rotate</code> et <code>path</code>. Par ailleurs, concernant l’attribut <code>calcMode</code>, la valeur par défaut est <code>paced</code> et non <code>linear</code>.</p><h3>Spécifier le chemin avec l’attribut path</h3><p>L’attribut <code>path</code> est utilisé pour spécifier le chemin de déplacement. Il est exprimé dans le même format et interprété de la même façon que l’attribut <code>d</code> sur l’élément <code>path</code>.</p><p>Nous allons animer notre cercle le long d’un chemin qui ressemble à ceci :</p><figure><img src="https://la-cascade.io/images/path-compressor.png" alt="ligne courbe descendante puis remontante" /></figure><p>Voici le code nécessaire pour déplacer le cercle le long de ce chemin :</p><pre>//SVG
&lt;animateMotion
  xlink:href="#circle"
  dur="1s"
  begin="click"
  fill="freeze"
  path="M0,0c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3                           c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4
        c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
        c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4
    c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
        c1.9-2.1,3.7-5.5,6.5-6.5" /&gt;</pre><p>Je voudrais attirer votre attention sur un point : les coordonnées à l’intérieur de path. Le chemin commence en se mouvant(<strong>M</strong>) vers le point de coordonnées (0,0), avant de commencer à dessiner une courbe (<strong>c</strong>) vers un autre point. Il est important de noter que le point (0,0) est en fait la position du cercle, où qu’il se trouve, et non l’angle supérieur gauche du système de coordonnées. Les coordonnées à l’intérieur de l’attribut <code>path</code> sont relatives à la position <em>actuelle</em> de l’élément !</p><p>Le résultat est le suivant :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/184082960ac3cc65d00b22f2551a330a/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Si vous spécifiiez le chemin en partant d’un point autre que (0,0), le cercle sauterait brusquement de sa position actuelle à la position spécifiée. Imaginez que vous dessiniez un chemin dans Illustrator puis que vous exportiez ces données de chemin pour les utiliser comme chemin de déplacement (c’est ce que j’ai fait la première fois...) le chemin exporté pourrait ressembler à ceci :</p><pre>//SVG
&lt;path fill="none" stroke="#000000" stroke-miterlimit="10" d="M100.4,102.2c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3
c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
c1.9-2.1,3.7-5.5,6.5-6.5"/&gt;</pre><p>Dans ce cas, le point de départ est (100.4, 102.2) et si nous utilisions ces données dans le chemin, notre cercle sauterait de 100 unités vers la droite et de 102 unités vers le bas, <em>puis</em> commencerait à se mouvoir le long du chemin relatif à sa nouvelle position. Donc gardez bien ceci à l’esprit lorsque vous préparerez le chemin de déplacement de vos animations.</p><p>Si on les utilise, les attributs <code>from</code>, <code>by</code>, <code>to</code> et <code>values</code> spécifient une forme sur le canevas en cours qui représente le chemin de déplacement.</p><h3>Spécifier le chemin avec l’élément mpath</h3><p>Il existe une autre façon de spécifier un chemin de déplacement. Au lieu d’utiliser l’attribut relatif <code>path</code>, on peut référencer un chemin externe grâce à l’élément <code>&lt;mpath&gt;</code>. Le <code>&lt;mpath&gt;</code>, qui est un enfant de l’élément <code>&lt;animateMotion&gt;</code> référence alors le chemin externe avec l’attribut <code>xlink:href</code>.</p><pre>//SVG
&lt;animateMotion xlink:href="#circle" dur="1s" begin="click" fill="freeze"&gt;
&lt;mpath xlink:href="#motionPath" /&gt;
&lt;/animateMotion&gt;</pre><p>Le chemin de déplacement <code>&lt;path&gt;</code> peut être défini n’importe où dans le document. Il peut même littéralement être défini dans un élément <code>&lt;defs&gt;</code> et ne pas être rendu sur le canevas. Dans l’exemple suivant, le chemin est rendu parce que la plupart du temps vous voudrez montrer le chemin que suit l’élément.</p><p>Notez que la position du cercle est “multipliée” ou “transformée” par les coordonnées dans les données du chemin.</p><p>Dans l’exemple suivant, nous avons un chemin situé au milieu du canevas. Le cercle est positionné au début du chemin. Cependant, lorsque le chemin de déplacement est appliqué, le cercle ne commence pas à se mouvoir depuis sa position courante. Regardez la démo pour une meilleure explication.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/0642931398bf1cf3ed1ff9b3e6b52398/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Vous avez remarqué la façon dont le cercle suit la même forme que le chemin mais à partir d’une position différente ? Ceci est dû au fait que la position du cercle est transformée par les valeurs des données du chemin.</p><p>Pour éviter cela, on peut commencer avec un cercle positionné à (0,0).</p><p>Une autre façon de faire est d’appliquer <a href="http://sarasoueidan.com/blog/svg-transformations/">une transformation</a> qui “remet à zéro” les coordonnées du cercle.</p><p>L’exemple qui suit est une version modifiée de la démo précédente, utilisant un chemin fermé et répétant l’animation de manière indéfinie.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/ef9f0e1242263cf23067b09be894cfa9/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><h3>Prévalence de règles pour animateMotion</h3><p>Puisqu’il existe plus d’une façon de faire la même chose avec <code>animateMotion</code>, il est logique d’avoir une prévalence de certaines règles sur d’autres :</p><ul><li>Concernant la définition du chemin de déplacement, l’élément <code>mpath</code> prévaut sur l’attribut <code>path</code>, qui lui même prévaut sur <code>values</code>, qui prévaut sur <code>from</code>, <code>by</code> et <code>to</code>.</li>
<li>Concernant la détermination des points correspondant aux attributs <code>keyTimes</code>, l’attribut <code>keyPoints</code> prévaut sur <code>path</code> qui lui même prévaut sur <code>values</code>, qui prévaut sur <code>from</code>, <code>by</code> et <code>to</code>.</li>
</ul><h3>Fixer l’orientation d’un élément le long d’un chemin avec rotate</h3><p>Dans l’exemple précédent, l’élément que nous animions le long du chemin était un cercle. Mais que se passe-t-il si nous animons un élément qui a une certaine orientation, par exemple l’icône d’une voiture ? Nous nous servirons de l’icône <a href="http://www.freepik.com/free-vector/transport-icons-collection_753635.htm">conçue par Freepik</a>.</p><p>Dans cet exemple, j’ai remplacé le cercle par un groupe ayant un ID de “car”, qui contient l’élément constituant le groupe. Puis, afin d’éviter le problème de saut brusque rencontré précédemment, j’ai appliqué une transformation à la voiture qui la translate de façon telle qu’elle se retrouve en position initiale à (0,0). Les valeurs de la transformation correspondent aux coordonnées du point où le premier chemin de la voiture commence à être dessiné (juste après la commande move <strong>M</strong>).</p><p>La voiture se déplace le long du chemain mais... voici à quoi ça ressemble :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/3a300b8c4c0f9db4ff345f5d44992b74/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>L'orientation de la voiture est fixe, elle ne change pas pour s’adapter au chemin de déplacement. Pour modifier cela, nous allons utiliser l’attribut <code>rotate</code>.</p><p>L’attribut <code>rotate</code> peut prendre l’une de ces trois valeurs :</p><ul><li><code>auto</code> : indique que l’objet pivote dans le temps en fonction de l’angle de la direction (c’est à dire le vecteur directionnel tangent) du chemin de déplacement.</li>
<li><code>auto-reverse</code> : indique que l’objet pivote selon l’angle de direction + 180 degrés.</li>
<li>un nombre : indique que l’élément se voit appliquer une transformation constante, où l’angle de rotation est le nombre de degrés spécifié.</li>
</ul><p>Pour corriger l’orientation de la voiture, nous allons régler la valeur de rotation sur <code>auto</code>. Nous obtenons le résultat suivant :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/74af0bd0bbc7ca46d4d568ca0d473b40/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Si vous préférez que la voiture se retrouve en dehors du chemin plutôt qu’à l’intérieur, <code>auto-reverse</code> vous permet de le faire :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/1027d099f0e9cca94f8f8865d169c49f/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>C’est mieux, mais nous avons encore un petit problème : la voiture a l’air de rouler en marche arrière le long du chemin ! Pour corriger cela, nous devons faire pivoter la voiture sur son axe des y. On y parvient avec scale. Donc si nous appliquons la transformation au groupe <code>g</code> ayant l’ID de <code>car</code>, la voiture avancera comme prévu. La transformation <code>scale</code> est enchaînée avec les autres translations :</p><pre>//SVG
&lt;g id="car" transform="scale (-1, 1) translate(-234.4, -182.8)"&gt;</pre><p>Et voici la démo finale :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/48caf2f5fa42a8c154fcb5dec0dbe4d5/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><h3>Contrôler la distance d’animation le long du chemin</h3><p>L’attribut <code>keyPoints</code> nous offre la possibilité de spécifier la progression le long du chemin de déplacement pour chacune des valeurs de <code>keyTimes</code>. Si on utilise des <code>keyPoints</code>, <code>keyTimes</code> prendra les valeurs de <code>keyPoints</code> au lieu de celles spécifiées dans une liste de <code>values</code>.</p><p><code>keyPoints</code> accepte une liste de valeurs décimales entre 0 et 1, séparées par des points-virgules, et il indique à quel endroit l’objet doit se déplacer à un moment donné, spécifié par les valeurs <code>keyTimes</code> correspondantes. Les calculs de distances sont déterminés par les algorithmes du navigateur. Chaque valeur de progression dans la liste correspond à une valeur dans la liste de l’attribut <code>keyTimes</code>. Si une liste de <code>keyPoints</code> est spécifiée, il doit y avoir exactement autant de valeurs dans la liste <code>keyPoints</code> que dans la liste <code>keyTimes</code>.</p><p>Une chose importante à noter ici est qu’il faut régler la valeur de <code>calcMode</code> sur <code>linear</code> pour que <code>keyPoints</code> fonctionne.</p><p>L’exemple qui suit est d’Amelia Bellamy-Royds (dont vous devriez absolument visiter le <a href="http://codepen.io/AmeliaBR/">profil CodePen</a>) il utilise <code>keyPoints</code> pour faire comme si on commençait un mouvement depuis un point en retrait, car nous n’avons pas cette possibilité par défaut actuellement dans SMIL.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/AmeliaBR/pen/ewvrC/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><h2>Déplacer un texte le long d’un chemin arbitraire</h2><p>Le déplacement d’un texte le long d’un chemin est différent du déplacement des autres éléments SVG le long d’un chemin. Pour animer du texte, vous devrez utiliser l’élément <code>&lt;animate&gt;</code> et non pas l’élément <code>&lt;animateMotion&gt;</code>.</p><p>Tout d’abord, positionnons le texte le long d’un chemin. On peut le faire en emboîtant un élément <code>&lt;textPath&gt;</code> à l’intérieur de l’élément <code>&lt;text&gt;</code>. Le texte qui sera positionné le long d’un chemin sera défini à l’intérieur de l’élément <code>&lt;textPath&gt;</code> et non comme un enfant de l’élément <code>&lt;text&gt;</code>.</p><p>Le <code>textPath</code> va référencer le chemin que nous voulons utiliser, comme nous l’avons fait dans les exemples précédents. Le chemin référencé peut soit être rendu sur le canvas, soit défini à l’intérieur de <code>&lt;defs&gt;</code>. Regardez le code de la démo suivante en cliquant sur html :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/ebfc92e45e24b29c266f50e6f617cdf5/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Pour animer le texte le long de ce chemin, nous allons utiliser l’élément <code>&lt;animate&gt;</code> pour animer l’attribut <code>startOffset</code>.</p><p>Le <code>startOffset</code> représente le décalage éventuel du texte sur le chemin. 0% représente le début du chemin, 100% la fin, donc si l’offset est réglé à 50% le texte commencera à mi-chemin .</p><p>En animant le <code>startOffset</code>, nous allons créer l’effet du texte qui se déplace sur le chemin. Regardez le code pour plus de détails.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/501308e154923359ed1cdbfa29eadcc0/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><h2>Animer les transformations</h2><p>L’élément <code>&lt;animateTransform&gt;</code> anime un attribut de transformation sur un élément cible, permettant par là-même aux animations de contrôler la translation, le redimensionnement, la rotation et la déformation. Il prend les mêmes attributs que ceux mentionnés pour l’élément <code>&lt;animate&gt;</code>, plus un : <code>type</code>.</p><p>L’attribut <code>type</code> est utilisé pour spécifier le type de transformation animé. Il prend l’une de ces cinq valeurs : <code>translate</code>, <code>scale</code>, <code>rotate</code>, <code>skewX</code> et <code>skewY</code>.</p><p>Les attributs <code>from</code>, <code>by</code> et <code>to</code> prennent une valeur exprimée avec la même syntaxe que celle qui est disponible pour le type de transformation concerné :</p><ul><li>Pour un <code>type="translate"</code> chaque valeur individuelle est exprimée comme <code>&lt;tx&gt; [,&lt;ty&gt;]</code>.</li>
<li>Pour un <code>type="scale"</code> chaque valeur individuelle est exprimée comme <code>&lt;sx&gt; [,&lt;sy&gt;]</code>.</li>
<li>Pour un <code>type="rotate"</code> chaque valeur individuelle est exprimée comme <code>&lt;rotate-angle&gt; [&lt;cx&gt; &lt;cy&gt;]</code>.</li>
<li>Pour un <code>type="skewX"</code> et <code>type="skewY"</code> chaque valeur individuelle est exprimée comme <code>&lt;skew-angle&gt;</code>.</li>
</ul><p>Si vous n’êtes pas habitué à la syntaxe des fonctions de l'attribut <code>transform</code> de SVG, je vous recommande de lire l’article que j’ai écrit à ce sujet : <a href="http://sarasoueidan.com/blog/svg-transformations/">Understanding SVG Coordinate Systems and Transformations (Part 2): The Transform Attribute</a>, avant de continuer avec ce guide.</p><p>Revenons à une démo précédente, celle où nous faisions tourner sur lui-même le rectangle rose en utilisant l’élément <code>&lt;animateTransform&gt;</code>. Le code de la rotation ressemble à ceci :</p><pre>//SVG
&lt;rect id="deepPink-rectangle" width="50" height="50" x="50" y="50" fill="deepPink" /&gt;
&lt;animateTransform
    xlink:href="#deepPink-rectangle"
    attributeName="transform"
    attributeType="XML"
    type="rotate"
    from="0 75 75"
    to="360 75 75"
    dur="2s"
    begin="0s"
    repeatCount="indefinite"
    fill="freeze"
    /&gt;</pre><p>Les attributs <code>from</code> et <code>to</code> spécifient l’angle de rotation (début et fin) et le centre de la rotation (75, 75). Dans les deux, le centre de la rotation reste inchangé bien sûr. Si l’on ne spécifie pas le centre, il sera par défaut le coin supérieur gauche du canevas SVG.</p><p>La démo live du code est la suivante :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/1bb859d4103d5e32b037f69e906319fb/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><p>Et voici un exemple amusant par Gabriel, avec un simple <code>animateTransform</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/guerreiro/pen/obhzc/">cette démo</a>de Gabriel Guerreiro dans<a href="https://codepen.io">CodePen</a></div><p>Animer une transformation unique est simple, toutefois les choses peuvent devenir compliquées lorsqu’on inclut des transformations multiples, en particulier du fait qu’une <code>animateTransform</code> peut en écraser une autre, ce qui fait qu’au lieu d’ajouter et d’enchaîner des effets, vous terminerez avec l’inverse. Ajoutez à cela la manière dont fonctionnent les systèmes de coordonnées SVG (cf. mon article cité plus haut). Pour transformer les SVG, je vous recommande d’utiliser les transformations CSS.</p><h2>L’élément set</h2><p>L’élément <code>&lt;set&gt;</code> offre une manière simple de régler la valeur d’un attribut pour une durée donnée. Il accepte tous les types d’attributs, dont ceux qui ne peuvent pas être raisonnablement interpolés, tels que les chaînes de caractères et les valeurs booléennes. L’élément <code>set</code> n’est pas additif. Les attributs additifs et accumulatifs ne sont pas permis et seront ignorés si on les utilise.</p><p>Puisque <code>&lt;set&gt;</code> est utilisé pour donner une valeur spécifique à un élément, pour une durée déterminée, il n’accepte pas tous les attributs mentionnés pour les éléments d'animation précédents. Par exemple, il n’a pas d’attribut <code>from</code> ou <code>by</code> car les valeurs ne changent pas progressivement sur la période de temps.</p><p>Pour <code>set</code>, vous pouvez spécifier l’élément que vous ciblez, le nom et le type d’attribut, la valeur <code>to</code>, et le timing d’animation peut être contrôlé via <code>begin</code>, <code>dur</code>, <code>end</code>, <code>min</code>, <code>max</code>, <code>restart</code>, <code>repeatCount</code>, <code>repeatDur</code> et <code>fill</code>.</p><p>Dans l’exemple qui suit, on fixe (<code>set</code>) la couleur du rectangle tournant au bleu lorsqu’on le clique. La couleur reste bleue pendant 3 secondes, puis revient à sa valeur d’origine. À chaque fois qu’on clique sur le rectangle, l’animation <code>set</code> est déclenchée et la couleur change pour 3 secondes.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />Voir<a href="http://codepen.io/SaraSoueidan/pen/af159baaf57bc38eb40288db722e1245/">cette démo</a>de Sara Soueidan dans<a href="https://codepen.io">CodePen</a></div><h3>Éléments, attributs et propriétés peuvent être animés</h3><p>Tous les attributs SVG ne peuvent pas être animés, et parmi ceux qui peuvent l’être, tous ne peuvent utiliser l’intégralité des éléments d’animation. Pour une liste complète des attributs animables, et un tableau montrant lesquels peuvent être animés par quels éléments, vous pouvez vous référer à <a href="http://www.w3.org/TR/SVG2/animate.html#AnimationAttributesAndProperties">cette section de la spécification SVG Animation</a>.</p><h3>Pour conclure</h3><p>SMIL a un potentiel énorme, je n’ai fait qu’effleurer la surface et je n’ai abordé que les bases les plus simples. De nombreux effets très impressionnants peuvent être réalisés, en particulier ceux qui impliquent le morphing et la transformation des formes. <em>The sky is the limit</em>. Soyez fous ! et n’oubliez pas de partager ce que vous créez avec la communauté ! Merci de votre lecture.</p></div>]]></description>
      <link>https://la-cascade.io/articles/guide-des-animations-svg</link>
      <guid>https://la-cascade.io/articles/guide-des-animations-svg</guid>
      <pubDate>Wed, 17 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS animation, une introduction]]></title>
      <description><![CDATA[<p><em>Une présentation claire et vivante des animations CSS par Rachel Cope, avec exemples de code et présentation live sur CodePen. Un bon article pour apprendre ou pour réviser ses classiques.</em></p><div class="articleContent"><p>Le cerveau humain est programmé pour être attentif au mouvement. L’ajout d’animations à votre site web ou à votre appli est une façon efficace d’attirer l’attention de vos utilisateurs vers vos produits ou vers une partie importante de votre interface.</p><p>Lorsqu’elles sont bien faites, les animations peuvent ajouter interaction et feedback, contribuer à l’émotion et au plaisir apportés par la navigation et ajouter de la personnalité à votre interface. En fait, animer signifie donner de la vie.</p><blockquote cite="https://abookapart.com/products/designing-for-emotion">
<p>Le premier objectif du design émotionnel est de faciliter la communication humaine. Si nous faisons bien notre boulot, l’ordinateur passe au second plan et c’est une véritable personnalité qui apparaît.</p>
<p><cite>Aaron Walter, Design Émotionnel</cite></p>
</blockquote><p>Dans cet article, nous allons passer en revue les bases de l’animation CSS. Vous pouvez retrouver tous les exemples qui suivent dans <a href="https://codepen.io/collection/nbEZgX/">cette page CodePen</a>.</p><h2>Les blocs constitutifs de l’animation.</h2><p>Les animations CSS sont constituées de deux blocs de base.</p><ol><li>Les keyframes, qui définissent les étapes et les styles d’animation.</li>
<li>Les propriétés d’animation, qui assignent les @keyframes à un élément CSS spécifique et définissent la façon dont il est animé.</li>
</ol><p>Donc une définition initiale, puis sa mise en oeuvre.</p><h3>Bloc #1: Keyframes</h3><p>Les keyframes constituent les fondations de l’animation. Elles définissent ce à quoi va ressembler l’animation à chaque étape de son évolution dans le temps. Chaque <code>@keyframe</code> est composée de :</p><ul><li><strong>Nom de l’animation</strong> : un nom que vous donnez à l’animation pour la décrire et servir de référence, par exemple <code>bounceIn</code> (rebond).</li>
<li><strong>Étapes de l’animation</strong> : chaque étape est représentée par un pourcentage. <code>0%</code> représente le début de l’animation et <code>100%</code> l’état final de l’animation. On peut ajouter autant d’étapes intermédiaires que l’on veut.</li>
<li><strong>Propriétés CSS</strong> : Les propriétés CSS définies à chaque étape.</li>
</ul><p>Prenons un exemple simple de <code>@keyframes</code> que j’ai appelé “bounceIn” (rebond). Ce <code>@keyframes</code> comprend trois étapes. À la première étape (0%) l’élément a une opacité égale à 0 et il est redimensionné à 10% de sa taille, au moyen de <code>CSS transform scale</code>. À la seconde étape (60%), l’élément commence à apparaître et il est redimensionné à 120% de sa taille normale. À l’étape finale (100%), il redescend à sa taille normale.</p><p>Les <code>@keyframes</code> sont ajoutés à votre feuille de style CSS :</p><pre class="language-css">@keyframes bounceIn {
  0% {
    transform: scale(0.1);
    opacity: 0;
  }
  60% {
    transform: scale(1.2);
    opacity: 1;
  }
  100% {
    transform: scale(1);
  }
}</pre><p>Si vous avez besoin d’une petite révision sur les propriétés Transform de CSS, vous pouvez consulter <a href="https://developer.mozilla.org/fr/docs/Web/CSS/transform">cette page de MDN</a> qui fait un point complet et synthétique.</p><h3>Bloc #2: Propriétés d’animation</h3><p>Une fois définies les <code>@keyframes</code>, les propriétés d’animation doivent être ajoutées pour pouvoir faire fonctionner votre animation. C'est l’étape de mise en oeuvre.</p><p>Les propriétés d’animation font deux choses :</p><ul><li>Elles assignent les <code>@keyframes</code> aux éléments que vous voulez animer</li>
<li>Elles définissent la façon dont ils sont animés.</li>
</ul><p>Les propriétés d’animation sont ajoutées aux sélecteurs CSS (ou aux éléments) que vous voulez animer. Vous devez impérativement ajouter les deux propriétés d’animation suivantes pour que votre animation puisse fonctionner :</p><ul><li><code>animation-name</code>: le nom de l’animation, tel que vous l’avez défini dans <code>@keyframes</code>.</li>
<li><code>animation-duration</code> : la durée de l’animation en secondes (p.ex. 5s) ou en millisecondes (p.ex. 200ms).</li>
</ul><p>Dans notre exemple de <code>bounceIn</code>, nous allons ajouter <code>animation-name</code> et <code>animation-duration</code> à la div que nous voulons animer.</p><pre class="language-css">div {
  animation-duration: 2s;
  animation-name: bounceIn;
}</pre><p>Il existe aussi une syntaxe raccourcie :</p><pre class="language-css">div {
  animation: bounceIn 2s;
}</pre><p>En ajoutant <code>keyframes</code> et les propriétés d'animation, nous avons une animation simple !</p><figure role="group"><img src="https://la-cascade.io/images/animation-bounceIn.gif" alt="Le texte 'bounce in' (rebond) s'avance vers le lecteur, puis recule, comme s'il rebondissait en-dessous du spectateur." /></figure><h2>Raccourcis des propriétés d’animation</h2><p>Chaque propriété d’<code>animation</code> peut être définie individuellement, mais pour la clarté et la concision du code il est recommandé d’utiliser les raccourcis. Toutes les propriétés peuvent être ajoutées en une seule ligne dans l’ordre suivant :</p><pre class="language-xml">animation: [animation-name] [animation-duration] [animation-timing-function]
[animation-delay] [animation-iteration-count] [animation-direction]
[animation-fill-mode] [animation-play-state];</pre><p>N’oubliez pas que les deux premières propriétés sont obligatoires.</p><h3>Un mot sur les préfixes</h3><p>À ce jour, de nombreux navigateurs Webkit utilisent encore la version préfixée -webkit des animations, keyframes et transitions. Jusqu’à ce qu’elles adoptent la version standard, il nous faudra donc inclure à la fois la version non préfixée et la version préfixée -webkit dans votre code (pour la bonne lisibilité du code, nous n’utilisons ici que la version non préfixée).</p><p>Voici à quoi ressemblent les keyframes et les animations avec leur préfixe -webkit :</p><pre class="language-css">div {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
  -webkit-animation-name: bounceIn;
  animation-name: bounceIn;
}</pre><pre class="language-css">@-webkit-keyframes bounceIn {
  /* styles */
}
@keyframes bounceIn {
  /* styles */
}</pre><p>Pour vous faciliter la vie, vous pouvez utiliser <a href="https://www.bourbon.io/">Bourbon</a>, une bibliothèque de mixins Sass qui contient une liste à jour des préfixes vendeurs pour tous les navigateurs modernes. Voici comment générer les animations et keyframes préfixées avec Bourbon :</p><pre class="language-css">div {
  @include animation(bounceIn 2s);
}</pre><pre class="language-css">@include keyframes(bouncein) {
  /* styles */
}</pre><h2>Les autres propriétés d’animation</h2><p>Outre les propriétés obligatoires <code>animation-name</code> et <code>animation-duration</code>, vous pouvez personnaliser et complexifier vos animations à l’aide des propriétés suivantes :</p><ul><li><code>animation-timing-function</code></li>
<li><code>animation-delay</code></li>
<li><code>animation-iteration-count</code></li>
<li><code>animation-direction</code></li>
<li><code>animation-fill-mode</code></li>
<li><code>animation-play-state</code></li>
</ul><p>Passons-les en revue.</p><h3>Animation-timing-function</h3><p><code>animation-timing-function</code> définit l’allure (au sens de vitesse) de votre animation. Vous pouvez spécifier son timing à l’aide des options prédéfinies : <code>ease</code>, <code>linear</code>, <code>ease-in</code>, <code>ease-out</code>, <code>ease-in-out</code>, <code>initial</code>, <code>inherit</code>, ou bien vous pouvez créer vos propres fonctions de timing à l’aide de <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function">courbes de Bézier</a>. Lea Verou a créé un outil en ligne très efficace pour cela.</p><figure><img src="https://la-cascade.io/images/animation-timing.gif" alt="Des balles de couleur qui tombent puis remontent pour disparaître (et l'animation se répète)" /></figure><p>La valeur par défaut est <code>ease</code>, qui démarre lentement, accélère, puis ralentit à l’arrivée. Vous pouvez lire une description de chaque fonction <a href="https://www.w3schools.com/cssref/css3_pr_animation-timing-function.php">ici</a>.</p><p>La syntaxe CSS :</p><pre class="language-css">animation-timing-function: ease-in-out;</pre><p>La syntaxe raccourcie (recommandée) :</p><pre class="language-css">animation: [animation-name] [animation-duration]
  [animation-timing-function];
animation: bounceIn 2s ease-in-out;</pre><h3>Animation-delay</h3><p><code>animation-delay</code> vous permet de spécifier à quel moment une animation (ou une partie d’animation) va commencer. Une valeur positive (p.ex. <code>2s</code>) fera débuter l’animation 2 secondes après qu’elle ait été déclenchée. L’élément demeurera inanimé jusque là. Une valeur négative (p.ex. <code>-2s</code>) fera débuter l’animation immédiatement, mais à 2 secondes de son développement (donc comme si elle avait déjà commencé il y a deux secondes). La valeur de retard (<code>delay</code>) est exprimée secondes ou en millisecondes.</p><figure><img src="https://la-cascade.io/images/animation-delay.gif" alt="Un soleil, puis un nuage qui le recouvre partiellement, puis la pluie qui tombre du nuage." /></figure><p>Syntaxe CSS :</p><pre class="language-css">animation-delay: 5s;</pre><p>La syntaxe raccourcie (recommandée) :</p><pre class="language-css">animation: [animation-name] [animation-duration]
  [animation-timing-function] [animation-delay];
animation: bounceIn 2s ease-in-out 3s;</pre><h3>Animation-iteration-count</h3><p><code>animation-iteration-count</code> spécifie le nombre de fois que l’animation doit être jouée. Les valeurs possibles sont :</p><ul><li><code>(un nombre)</code> - un nombre spécifique d’itérations (la valeur par défaut est <code>1</code>)</li>
<li><code>infinite</code> - l’animation se répète indéfiniment</li>
<li><code>initial</code> - fixe le décompte d’itération à sa valeur par défaut</li>
<li><code>inherit</code> - hérite de son parent</li>
</ul><figure><img src="https://la-cascade.io/images/animation-iteration.gif" alt="Un cœur qui bat" /></figure><p>Syntaxe CSS :</p><pre class="language-css">animation-iteration-count: 2;</pre><p>La syntaxe raccourcie (recommandée) :</p><pre class="language-css">animation: [animation-name] [animation-duration]
  [animation-timing-function] [animation-delay]
  [animation-iteration-count];
animation: bounceIn 2s ease-in-out 3s 2;</pre><h3>Animation-direction</h3><p>La propriété <code>animation-direction</code> spécifie si l’animation doit elle jouée à l’endroit, à l’envers ou dans les deux sens.</p><p>Les valeurs possibles sont :</p><ul><li><code>normal</code> (valeur par défaut) - L’animation est jouée à l’endroit. Chaque cycle part du point initial (0%) pour aller jusqu’au point final (100%).</li>
<li><code>reverse</code> - L’animation est jouée à l’envers. Chaque cycle part du point final (100%) pour aller jusqu’au point initial (0%).</li>
<li><code>alternate</code> - L’animation change de sens à chaque cycle, elle va de 0% à 100% puis repart de 100% pour aller à 0% etc.</li>
<li><code>alternate-reverse</code> - L’animation change de sens à chaque cycle, mais cette fois-ci elle va de 100% à 0% puis repart de 0% pour aller à 100% etc.</li>
</ul><figure><img src="https://la-cascade.io/images/animation-direction.gif" alt="Une montagne, des nuages qui passent dans un sens puis dans l'autre, le soleil qui se lève puis qui se couche et devient rouge au moment de disparaître." /></figure><p>Syntaxe CSS :</p><pre class="language-css">animation-direction: alternate;</pre><p>La syntaxe raccourcie (recommandée) :</p><pre class="language-xml">animation: [animation-name] [animation-duration] [animation-timing-function]
[animation-delay] [animation-iteration-count] [animation-direction];
animation:  bounceIn 2s ease-in-out 3s 3 alternate;</pre><h3>Animation-fill-mode</h3><p><code>animation-fill-mode</code> spécifie si les styles d’animation sont visibles avant ou après que l’animation ne soit jouée. Cette propriété n’est pas très claire de prime abord, mais une fois qu’on l’a comprise elle peut être très utile.</p><p>Par défaut, l’animation n’affectera pas les styles de l’élément avant qu’elle n’ait commencé (s’il y a un retard — <em>delay</em> — d’animation) ou après que l’animation soit terminée. La propriété <code>animation-fill-mode</code> peut prendre le pas sur ce comportement, avec les valeurs possibles suivantes :</p><ul><li><code>backwards</code> - Avant l’animation (pendant le retard), les styles du keyframe initial (0%) sont appliqués à l’élément.</li>
<li><code>forwards</code> - Après que l’animation se soit achevée, les styles définis dans le dernier keyframe (100%) sont conservés par l’élément.</li>
<li><code>both</code> - L’animation appliquera les règles de backwards et forwards qui étendent les propriétés avant et après l’animation.</li>
<li><code>normal</code> (valeur par défaut) - L’animation n’applique aucun style à l’élément avant ou après l’animation.</li>
</ul><p>Dans l’exemple suivant, on voit que le rectangle turquoise conserve ses dimensions finales car l’option forwards est activée, alors que le rectangle rouge revient à ses dimensions initiales dès la fin de l’animation (comportement par défaut).</p><figure><img src="https://la-cascade.io/images/animation-fill.gif" alt="Deux rectangles s'avancent en même temps, le turquoise s'agrandit puis reste aux dimensions finales, le rouge s'agrandit puis revient d'un coup à ses dimesions initiales." /></figure><p>Syntaxe CSS :</p><pre class="language-css">animation-fill-mode: forwards;</pre><p>La syntaxe raccourcie (recommandée) :</p><pre class="language-xml">animation: [animation-name] [animation-duration] [animation-timing-function]
[animation-delay] [animation-iteration-count] [animation-direction]
[animation-fill-mode];
animation:  bounceIn 2s ease-in-out 3s 3 forwards;</pre><h3>Animation-play-state</h3><p><code>animation-play-state</code> spécifie si l’animation est en train d’être jouée ou si elle est en mode pause. Reprendre une animation en mode pause la fait démarrer là où elle était arrêtée.</p><p>Les valeurs possibles sont :</p><ul><li><code>playing</code> - L’animation est en cours</li>
<li><code>paused</code> - L’animation est en mode pause.</li>
</ul><figure><img src="https://la-cascade.io/images/animation-play.gif" alt="Un chronomètre turquoise avec une aiguille qui tourne, et qui s'arrête au survol de la souris, puis reprend sa course quand la souris se retire." /></figure><p>Exemple :</p><pre class="language-css">.div:hover {
  animation-play-state: paused;
}</pre><h3>Animations multiples</h3><p>Pour ajouter des animations multiples à un sélecteur, il suffit de séparer les valeurs par une virgule. Voici un exemple :</p><pre class="language-css">.div {
  animation: slideIn 2s, rotate 1.75s;
}</pre><h2>En avant les animations !</h2><p>Et voilà ! Avec ces propriétés basiques, les animations potentielles sont infinies. La meilleure façon d’apprendre est de se lancer et de créer toutes les animations qui vous passent par la tête.</p><p>Voici quelques ressources pour vous y aider :</p><p><a href="https://thoughtbot.com/upcase/design">Upcase for designers</a> - Une communauté d'apprentissage en ligne proposant des cours sur les techniques de design et de développement front.</p><p><a href="https://codepen.io/">CodePen</a> - Un terrain de jeu CSS où vous pouvez éditer votre code et voir immédiatement le résultat. CodePen comprend déjà Autoprefixer, vous n’aurez donc pas à vous soucier des préfixes vendeurs. Il fonctionne également avec les langages préprocesseurs de votre choix (Sass, Less, ainsi que haml pour html).</p><p><a href="https://animate.style/">Animate.css</a> - Une bibliothèque d’animations avec laquelle jouer pour explorer les possibilités infinies d’animation.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-animation-une-introduction</link>
      <guid>https://la-cascade.io/articles/css-animation-une-introduction</guid>
      <pubDate>Tue, 16 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS, aider la veuve et l'orpheline]]></title>
      <description><![CDATA[<p><em>CSS nous permet de contrôler facilement la première ligne d'un texte, mais sa capacité à contrôler la dernière ligne reste limitée. Un rappel sur widows et orphans par Dudley Storey.</em></p><div class="articleContent"><p>Alors que CSS nous offre de nombreuses options pour <a href="http://demosthenes.info/blog/226/Classic-typography-effects-in-CSS-first-line-run-in">contrôler la :first-line</a> d'un texte, sa capacité à contrôler la dernière ligne reste limitée. Ce serait pourtant parfois bien utile.</p><h2>Vestiges &amp; Fragments</h2><p>“<a href="https://la-cascade.io/widows/">Widows</a>” et “<a href="https://la-cascade.io/orphans/">orphans</a>” (veuves et orphelines) désignent un mot ou une ligne de texte mis en page d’une façon qui dérange le flux de la lecture et l’aspect de la page. Le plus souvent, ce sont des mots qui se retrouvent à pendouiller à la fin d’un paragraphe. Dans les media paginés, ce sont souvent des mots de fin de paragraphe qui se retrouvent sur une nouvelle page :</p><figure role="group"><img src="https://la-cascade.io/images/demosthenes_info_-_CSS_last-line__Controlling_Widows___Orphans.jpeg" alt="" /><figcaption>Exemple de “veuve” dans un texte imprimé</figcaption></figure><p>Les navigateurs n’ont pas de concept de “page” pour l’écran, mais des veuves peuvent apparaître lorsque le texte est imprimé, et on peut le contrôler ainsi :</p><pre>p { widows: 3; }</pre><p>On peut traduire cette instruction par “si un paragraphe est coupé dans la mise en page, la partie du paragraphe qui apparaît dans la page suivante doit comporter au moins trois lignes”. Un navigateur compatible avec la propriété espacera les éléments de manière à ce que ce soit possible :</p><figure role="group"><img src="https://la-cascade.io/images/demosthenes_info_-_CSS_last-line__Controlling_Widows___Orphans-2.jpeg" alt="" /><figcaption>Une page imprimée avec le problème de veuves résolu</figcaption></figure><p>De l’autre côté, les “orphelines” apparaissent en tête de paragraphe. L’exemple le plus courant est celui d’un paragraphe qui commence en bas de page :</p><figure role="group"><img src="https://la-cascade.io/images/demosthenes_info_-_CSS_last-line__Controlling_Widows___Orphans-3-1.jpeg" alt="" /><figcaption>Un exemple de texte avec orpheline</figcaption></figure><p>Là encore, on peut contrôler la situation en donnant à la propriété <code>orphans</code> une valeur raisonnable :</p><pre>p { orphans: 3; }</pre><p>Ce qui signifie : un paragraphe doit commencer avec au moins trois lignes sur une page avant de pouvoir être coupé. Sinon, le paragraphe doit commencer sur la page suivante.</p><p>Le résultat :</p><figure role="group"><img src="https://la-cascade.io/images/demosthenes_info_-_CSS_last-line__Controlling_Widows___Orphans-4.jpeg" alt="" /><figcaption>Une page imprimée avec le problème d’orphelines résolu</figcaption></figure><h2>Suggestion d’utilisation</h2><p><code>widows</code> et <code>orphans</code> devraient tous deux avoir des valeurs raisonnables par défaut dans vos feuilles de style :</p><pre>p { widows: 3; orphans: 3: }</pre><p>Des éléments comme les titres peuvent aussi connaître ce genre de problème, mais il est plus courant de traiter le problème avec un <code>page-break</code>.</p><h2>Qui est qui ?</h2><p>Une manière commode (même si un peu <em>Dickensienne</em>) de mémoriser ces termes est de se dire :</p><ul><li>Les orphelines “se retrouvent seules au commencement”</li>
<li>Les veuves “se retrouvent seules à la fin”.</li>
</ul><h2>Veuves &amp; orphelines à l’écran</h2><p>Par sa nature même, le design responsif crée d’innombrables fragments de texte veuf. Certains peuvent être traités par une utilisation intelligente de <a href="http://demosthenes.info/blog/429/Class-Typography-Effects-Hyphenation">hyphens</a> et de la justification, mais les autres ne peuvent être évités.</p><p>On vous dira souvent que les propriétés <code>widows</code> et <code>orphans</code> ne peuvent être utilisées que pour l’imprimé, ce n’est pas vrai : dans les navigateurs compatibles, ces propriétés peuvent également être appliquées aux <a href="http://demosthenes.info/blog/79/CSS-Layouts-Newspaper-Style-Columnar-Text">mises en page de type journal</a>, qui se heurtent souvent au même problème :</p><figure role="group"><img src="https://la-cascade.io/images/demosthenes_info_-_CSS_last-line__Controlling_Widows___Orphans-5.jpeg" alt="" /><figcaption>Texte orphelin dans une colonne</figcaption></figure><p>Le CSS (sans préfixes) et une solution pour le texte orphelin :</p><pre>div { column-count: 2; column-gap: 2rem; }
p { line-height: 1.6; font-size: 1rem; orphans: 2; }</pre><p>Le résultat :</p><figure role="group"><img src="https://la-cascade.io/images/demosthenes_info_-_CSS_last-line__Controlling_Widows___Orphans-6.jpeg" alt="" /><figcaption>Texte orphelin dans une colonne</figcaption></figure><h2>Tout faire tenir sur une ligne</h2><p>Les cas les plus extrêmes de textes veufs se produisent dans les titres, où un mot final se retrouve tout seul sur une nouvelle ligne. Il existe des solutions pour cela : <a href="http://fittextjs.com/">FitText</a> est un plugin jQuery qui redimensionne le texte dynamiquement en fonction de la taille de la fenêtre navigateur. Il existe aussi des solutions SVG. Ma préférence personnelle va à l’utilisation d’<a href="http://demosthenes.info/blog/660/Using-vw-and-vh-Measurements-In-Modern-Site-Design">unités <code>vw</code></a> pour faire tenir un titre sur une ligne unique, bien que cela exige souvent un peu de calcul et d’expérimentation.</p><h3>Compatibilité navigateurs</h3><p>La compatibilité est <em>décente</em> : Chrome et IE ont une très bonne compatibilité, mais Firefox et Safari les ignorent totalement. Il faut donc les considérer comme des éléments d’<a href="http://s-jdm.developpez.com/tutoriels/web/traductions/comprendre-amelioration-progressive/">amélioration progressive</a> : des touches finales appréciables mais non vitales pour le contenu de votre page.</p></div>]]></description>
      <link>https://la-cascade.io/articles/css-aider-la-veuve-et-lorphelin</link>
      <guid>https://la-cascade.io/articles/css-aider-la-veuve-et-lorphelin</guid>
      <pubDate>Sun, 14 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Créer un background vidéo fullscreen avec HTML5]]></title>
      <description><![CDATA[<p><em>Il n'est pas possible d'intégrer une vidéo avec les propriétés CSS background ou background-image, mais Dudley Storey nous montre comment forcer l'apparition d'une vidéo responsive fullscreen derrière les éléments HTML.</em></p><div class="articleContent"><p>Les propriétés CSS <code>background</code> et <code>background-image</code> n’acceptent que des images <a href="http://thenewcode.com/64/Bitmap-Images-for-the-Web-Formats-and-Optimisation-Options">bitmap</a> ou <a href="https://la-cascade.io/tags/svg">SVG</a> et des valeurs de <a href="https://la-cascade.io/tags/couleur/">couleurs</a> ou de <a href="https://la-cascade.io/articles/les-degrades-css/">dégradés</a>, il n’est donc pas possible d’y intégrer une vidéo. Cependant, nous pouvons reproduire l’apparence d’une vidéo d'arrière-plan plein écran en forçant son apparition derrière d’autres éléments HTML. Le défi est d’avoir une vidéo plein écran et aussi responsive que nos images de background.</p><p> <em>Note : pour illustrer cet article, nous utiliserons une vidéo d'Alexandre Wagner</em>.</p><figure role="group"><img src="https://la-cascade.io/images/polina-1.jpeg" alt="" /><figcaption>Nous utiliserons une vidéo d’<a href="http://www.alexanderwagnerphoto.com/">Alexander Wagner</a></figcaption></figure><h2>Quelques considérations préliminaires</h2><p>Avant de nous lancer dans la réalisation, voici quelques facteurs qu’il convient de garder à l’esprit :</p><ul><li>N’utilisez pas cette technique simplement parce que <em>vous le pouvez</em> : <strong>le contenu vidéo doit amplifier le message du site</strong>, évitez les effets cosmétiques vides de sens.</li>
<li>La vidéo sera sans doute réglée par défaut sur <code>autoplay</code>, mais il est préférable de la régler sur mute, et même, idéalement, il vaudrait mieux qu’elle ne comporte <strong>pas de son</strong> du tout. Vous pouvez créer un bouton pour remettre le son avec JavaScript.</li>
<li>La vidéo devrait afficher une image de rechange pour les navigateurs incompatibles avec HTML5. L’image sera utilisée également comme arrière-plan pour les mobiles : la plupart des smartphones et tablettes ne supportent pas <code>autoplay</code>, pour des raisons évidentes.</li>
<li>La durée est importante : Une vidéo <strong>trop courte</strong> semble répétitive (si elle est diffusée en boucle), et si elle est <strong>trop longue</strong> elle devient une histoire en elle-même, un contenu qui mérite d’être traité comme un élément séparé. Je suggèrerais une durée de 12 à 30 secondes.</li>
<li><strong>L’accessibilité</strong> est importante : tout texte placé sur la vidéo devrait offrir un contraste permettant sa lecture. Les utilisateurs doivent accéder facilement à une interface de contrôle pour mettre la vidéo en pause. Idéalement, la vidéo ne devrait passer qu’une seule fois.</li>
<li><strong>La bande passante</strong> : la vidéo doit être courte et compressée aussi efficacement que possible. En même temps, elle doit pouvoir se redimensionner sur tous les terminaux. Dans les cas les plus complexes, vous pourriez envisager d'utiliser des <a href="http://thenewcode.com/820/Make-HTML5-Video-Adaptive-With-Inline-Media-Queries">media queries en ligne</a>, ou <a href="http://thenewcode.com/702/matchMedia-Media-Queries-For-JavaScript">matchmedia</a> de JavaScript pour proposer des qualités différentes de la vidéo en fonction de l'écran. Essayez de ne pas dépasser 5Mb, idéalement restez en-dessous des 500K.</li>
</ul><p>En gardant tous ces facteurs à l'esprit, passons maintenant aux techniques nous permettant de réaliser notre objectif. Nous utiliserons pour cela une courte vidéo d’<a href="http://www.alexanderwagnerphoto.com/">Alexander Wagner</a>, vous pouvez voir le résultat (et le code) sur ce CodePen :</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/dudleystorey/pen/knqyK/">Fullscreen HTML5 Page Background Video</a>de Dudley Storey dans<a href="https://codepen.io">CodePen</a></div><p>Pour voir la vidéo en plein écran, regardez <a href="http://thenewcode.com/samples/polina.html">cette démo</a>.</p><h2>Une approche purement CSS</h2><p>On construit la vidéo HTML5 comme habituellement :</p><pre>&lt;video autoplay loop poster="polina.jpg" id="bgvid"&gt;
  &lt;source src="polina.webm" type="video/webm"&gt;
  &lt;source src="polina.mp4" type="video/mp4"&gt;
&lt;/video&gt;</pre><p>Attention : l’ordre des fichiers vidéo est vital, Chrome a un bug actuellement qui fait qu’il ne jouera pas une vidéo .webm si le fichier n’est pas le premier dans la liste.</p><p>L’image de fallback sera remplacée par la première image de la vidéo une fois celle-ci chargée, donc ce serait une bonne idée de prendre cette première image comme image de fallback.</p><p>Pour afficher la vidéo plein écran :</p><pre>video#bgvid {
  position: fixed; right: 0; bottom: 0;
  min-width: 100%; min-height: 100%;
  width: auto; height: auto; z-index: -100;
  background: url(polina.jpg) no-repeat;
  background-size: cover;
}</pre><p>Les navigateurs anciens ne reconnaîtront pas les formats vidéo, mais ils devraient malgré tout reconnaître la balise <code>&lt;video&gt;</code> (à l'exception d'IE8, voir ci-dessous). Pour ces navigateurs, nous créons une <code>background-image</code> pour l’élément, en utilisant la même image de remplissage.</p><h3>Note sur IE8</h3><p>Non seulement IE8 ne reconnaît pas la balise <code>&lt;video&gt;</code> mais il ne reconnaît aucun nouvel élément de HTML5. C’est un problème puisque nous voulons pouvoir, <em>a minima</em>, appliquer un style à l’élément et placer une image de background à l’intérieur. Pour y parvenir, il nous faut deux choses : tout d’abord une ligne de JavaScript, dans une boucle conditionnelle :</p><pre>&lt;!--[if lt IE 9]&gt;
&lt;script&gt;
document.createElement('video');
&lt;/script&gt;
&lt;![endif]--&gt;</pre><p>Ensuite, dans notre CSS, une déclaration qui permette à IE de comprendre qu’il s’agit d’un élément de niveau bloc :</p><pre>video { display: block; }</pre><p>Avec cela, IE8 peut au moins appliquer un style à l’élément <code>&lt;video&gt;</code> en y insérant une image de d’arrière-plan.</p><h2>Quid des mobiles ?</h2><p>L’affichage plein écran d’une vidéo de background sur les terminaux mobiles pose plusieurs défis :</p><ol><li>La plupart des plateformes mobiles (en particulier iOS) refusent l’autoplay des vidéos HTML5 pour éviter des chargements de données potentiellement ruineux.</li>
<li>Dans ce cas, la vidéo sera affichée avec un bouton play embarqué, ce qui à son tour...</li>
<li>...peut empiéter sur le fonctionnement de touches du terminal, et rendre impossible le bon fonctionnement de liens présents dans le contenu figurant au-dessus de la vidéo.</li>
</ol><p>Même s’il est possible d’utiliser une détection de vidéo autoplay avec JavaScript, la solution la plus simple est d’utiliser une media query qui substitue complètement la vidéo par l’image de fallback pour les petits écrans. On ajoute à notre CSS précédent :</p><pre>@media screen and (max-device-width: 800px) {
html { background: url(polina.jpg) #000 no-repeat center center fixed; }
#bgvid { display: none; }
}</pre><p>Le plus important ici c'est la media query elle-même, elle devra être modifiée en fonction des attentes du site et de l’espace disponible. Actuellement, elle détecte si l’affichage écran est inférieur à 800px de large, auquel cas elle remplace la vidéo par une image statique d’arrière-plan. Remarquez qu’on ne tient pas compte de Rétina : un iPad3 sera toujours considéré comme ayant 768px alors que sa résolution est bien plus élevée.</p><h2>Intégrer l'accessibilité</h2><p>Les utilisateurs souffrant de <a href="http://fr.wikipedia.org/wiki/Syst%C3%A8me_vestibulaire">troubles vestibulaires</a> peuvent être désorientés par le mouvement, en particulier lorsqu’ils essaient de lire un texte situé sur une image mouvante. Les utilisateurs souffrant d’autisme (pas nécessairement aigu) peuvent être dérangés par un changement rapide. Pour ces utilisateurs — et pour tous les autres — un bouton pause devrait être clairement visible. Idéalement, la vidéo devrait également s’arrêter et disparaître lorsqu’elle a été jouée entièrement. Pour cela, ajoutons un élément <code>&lt;button&gt;</code> à notre page :</p><pre>&lt;button id="vidpause"&gt;Pause&lt;/button&gt;</pre><p>Puis ce JavaScript en bas de notre page :</p><pre>var vid = document.getElementById("bgvid");
var pauseButton = document.getElementById("vidpause");
function vidFade() {
  vid.classList.add("stopfade");
}
vid.addEventListener('ended', function() {
  // only functional if "loop" is removed
  vid.pause();
  // to capture IE10
  vidFade();
});
pauseButton.addEventListener("click", function() {
  vid.classList.toggle("stopfade");
  if (vid.paused) {
    vid.play();
    pauseButton.innerHTML = "Pause";
  } else {
    vid.pause();
    pauseButton.innerHTML = "Paused";
  }
})</pre><p>Le JavaScript fait appel à du CSS ajouté à votre feuille de styles (les préfixes constructeurs sont omis pour la clarté, et NDT: vous pouvez les omettre dans votre code en utilisant Autoprefixer :</p><pre>video#bgvid { transition: 1s opacity; }
.stopfade { opacity: .5; }</pre><p>Bien sûr, il convient également d’ajouter du CSS pour faire disparaître votre élément bouton des terminaux mobiles, selon la solution proposée plus haut, sinon votre utilisateur ne comprendra pas pourquoi il y a un bouton sur une image.</p><h2>Alternatives purement JavaScript</h2><p>Même si à mon avis une solution HTML/CSS est plus intéressante qu’un <a href="http://thenewcode.com/195/Frameworks">framework</a>, sachez qu’il existe au moins <a href="http://syddev.com/jquery.videoBG/">un plugin jQuery</a> et quelques codes JavaScript solides pour parvenir au même résultat.</p><h3>Conclusion</h3><p>Une vidéo en arrière-plan peut avoir un fort impact sur votre site, mais rappelez-vous toujours qu’un grand pouvoir vous donne de grandes responsabilités : utilisez ces fonctionnalités judicieusement.</p><p><a href="http://thenewcode.com/samples/polina.html">Regardez la démo plein écran</a>.</p><p> Un autre article intéressant sur le sujet :</p><p><a href="http://www.alsacreations.com/tuto/lire/1620-une-video-arriere-plan-sur-toute-la-page.html">Une vidéo d’arrière-plan sur toute la page en HTML et CSS</a>, la traduction (légèrement adaptée) de l’article de Florent Verschelde par Victor Brito sur Alsacréations.</p></div>]]></description>
      <link>https://la-cascade.io/articles/video-en-background</link>
      <guid>https://la-cascade.io/articles/video-en-background</guid>
      <pubDate>Wed, 10 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Rendre un SVG responsif]]></title>
      <description><![CDATA[<p><em>Infiniment redimensionnable, le format SVG n'en est pas moins étonnamment difficile à rendre responsif. Dudley Storey montre comment y parvenir.</em></p><div class="articleContent"><p>Pour un format d’image infiniment redimensionnable, SVG peut être étonnament difficile à rendre responsif : les images vectorielles ne s’ajustent pas par défaut à la taille du viewport.</p><h2>Une image SVG responsive</h2><p><strong>En tant qu’image</strong>, votre SVG peut se redimensionner avec le contenu de la page, comme tous les autres :</p><pre>&lt;img src="monkey.svg" alt="Monkey face" style="width: 100%; height: auto;"&gt;</pre><p>Ça fonctionne dans la plupart des cas, mais parfois ce n’est pas suffisant, surtout si vous embarquez votre SVG via une balise <code>&lt;object&gt;</code> ou en insérant le code directement dans la page. Dans ce cas, la simple modification de <code>width</code> et <code>height</code> ne suffit pas.</p><h2>Un SVG en ligne responsif</h2><p>Le code SVG embarqué, une fois collé dans le <code>&lt;body&gt;</code> d’un document HTML, ressemblera à ceci :</p><pre>&lt;body&gt;
&lt;svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve"&gt;
&lt;circle fill="#F7941E" stroke="#231F20" stroke-width="10" cx="250" cy="250" r="200" opacity="0.6" /&gt;
&lt;/svg&gt;
&lt;/body&gt;</pre><p>Une fois l’élément racine <code>&lt;svg&gt;</code> nettoyé, le code est beaucoup plus présentable :</p><pre>&lt;svg version="1.1" viewBox="0 0 500 500"&gt;
&lt;circle fill="#F7941E" stroke="#231F20" stroke-width="10" cx="250" cy="250" r="200" opacity="0.6" /&gt;
&lt;/svg&gt;</pre><p>La suppression des attributs redondants de l’élément <code>&lt;svg&gt;</code> rend l’illustration responsive, mais il y a un coût : cela ajoute un espace au-dessus et en-dessous de l’image vectorielle. On pourrait supposer que le coupable est l’attribut <code>viewport</code>, qui est toujours présent, mais ce n’est pas le cas, laissons-le tranquille. Il nous reste trois étapes pour intégrer l’élément SVG responsif dans notre page :</p><p>Tout d’abord, entourons le code SVG avec une <code>&lt;div&gt;</code> et ajoutons un attribut <code>preserveAspectRatio</code>, ainsi qu’une classe à l’élément racine <code>svg</code> :</p><pre>&lt;div class="svg-container"&gt;
&lt;svg version="1.1" viewBox="0 0 500 500" preserveAspectRatio="xMinYMin meet" class="svg-content"&gt;
&lt;circle fill="#F7941E" stroke="#231F20" stroke-width="10" stroke-miterlimit="10" cx="250" cy="250" r="200" opacity="0.6" /&gt;
&lt;/svg&gt;
&lt;/div&gt;</pre><p>Cela déplace l’illustration SVG en haut de son conteneur. Pour terminer la présentation, nous utilisons une variante de la vieille astuce de l’élément-<a href="https://la-cascade.io/articles/le-positionnement-css/">absolument-positionné</a>-dans-un-conteneur-relatif avec un padding décalé :</p><pre>.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%;
vertical-align: middle;
overflow: hidden;
}</pre><figure class="svg-container" role="group"><figcaption>Illustration SVG responsive d’une calligraphie japonaise Shodô, à l’intérieur d'un conteneur</figcaption></figure><p>Remarquez que la <code>width</code> utilisée dans le CSS suppose que vous voulez que votre image couvre toute la largeur de la page (ou tout au moins de son conteneur parent). Le <code>padding-bottom</code> a pour valeur le ratio entre la hauteur et la largeur de l’illustration SVG. En divisant la hauteur du <code>viewbox</code> de l’élément par sa largeur, on obtient ici un ratio de 1:1 (voir plus haut : <code>viewBox="0 0 500 500"</code>), et par conséquent le padding-bottom doit être fixé à 100%. Si l’image SVG était plus large que haute, par exemple dans un ratio 1:2, le <code>padding-bottom</code> serait fixé à 50%.</p><p>Enfin, on positionne le SVG à l’intérieur du conteneur avec un petit CSS :</p><pre>.svg-content {
display: inline-block;
position: absolute;
top: 0;
left: 0;
}</pre><p>Avec cette solution, notre illustration SVG peut se redimensionner gracieusement sur la page sans déranger les autres contenus. Le même code fonctionne sur une balise <code>&lt;object&gt;</code> utilisée pour embarquer le dessin vectoriel :</p><pre>&lt;div class="svg-container"&gt;
&lt;object type="image/svg+xml" data="samurai.svg" width="100%" height="100%" class="svg-content"&gt;
&lt;/object&gt;
&lt;/div&gt;</pre><p>Attention : <em>tout</em> le contenu situé à l’intérieur de sera redimensionné, y compris le texte.</p></div>]]></description>
      <link>https://la-cascade.io/articles/rendre-svg-responsif</link>
      <guid>https://la-cascade.io/articles/rendre-svg-responsif</guid>
      <pubDate>Tue, 09 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Toi seul : utiliser only-child de CSS]]></title>
      <description><![CDATA[<p><em>Les cas d'utilisation de only-child sont nombreux. Comme souvent avec les pseudo-classes, il nous permet d'écrire un code concis et adapté au contenu généré dynamiquement.</em></p><div class="articleContent"><p>Une étape avant d’arriver au sélecteur <a href="https://la-cascade.io/articles/empty-une-pseudo-classe-pas-si-vide/">:empty</a>, <code>:only-child</code> sélectionne les éléments qui sont entièrement seuls à l’intérieur de leur conteneur. On pourrait se demander comment diable utiliser ce sélecteur, mais les cas d’utilisation sont étonnamment nombreux.</p><figure role="group"><img src="https://la-cascade.io/images/demosthenes_info_-_Only_You__Using_only-child_in_CSS.jpeg" alt="Un tableau dans lequel les distances entre une ville et elle-même sont vides" /><figcaption>Photographie CC <a href="https://500px.com/photo/79871265/untitled-by-nesim-kurnaz">Nesim Kurnaz</a></figcaption></figure><h2>Only-child pour les images “héros”</h2><p>Sur mon blog (<a href="http://thenewcode.com">the new code</a>) on trouve une bonne utilisation d’<code>:only-child</code> où la plupart des articles ont une illustration dans le <code>&lt;header&gt;</code>. La plupart de ces images sont entières, de bord à bord, mais <em>seulement</em> si elles sont le seul occupant du <code>&lt;header&gt;</code>. Habituellement, on utilise une classe ou même on utilise un style en ligne :</p><pre>&lt;article&gt;
  &lt;header&gt;
  &lt;img src="sad-kid.jpg" alt style="width: 100%; height: auto"&gt;
  &lt;/header&gt;
  …
&lt;/article&gt;</pre><p>Mais si on réfléchit à la logique de cette mise en page, on se rend compte qu’on pourrait faire beaucoup plus simple (et éviter le style en ligne) en utilisant <code>:only-child</code> :</p><pre>header img:only-child { width: 100%; height: auto; }</pre><p>Ce qu’on pourrait traduire par “si une image est le seul élément à l’intérieur d'un header, lui donner la pleine largeur de son élément parent”.</p><p>Remarquez que ça fonctionne même si l’image est enveloppée dans un élément <code>&lt;figure&gt;</code> à l’intérieur du <code>&lt;header&gt;</code>. Avec ce sélecteur, l’élément <code>&lt;figure&gt;</code> n'est pas compté dans les autres enfants car il n’a aucune spécificité, l’image est donc toujours considérée comme le “seul enfant”. Par contre, si on ajoute une <code>&lt;figcaption&gt;</code> qui serait donc un “frère” de l’image (immédiatement au-dessus ou au-dessous), le sélecteur ne s’applique plus. Pour obtenir le même résultat, nous pourrions alors utiliser le sélecteur <code>:only-of-type</code>.</p><h2>Vérifier si un élément a un frère</h2><p>CSS n’a pas vraiment la capacité de dire combien d’éléments se trouvent sur une page (c’est JavaScript qui sait faire ça), mais on peut quand même s’assurer qu’un style est appliqué à un élément à la condition qu’il ne soit pas le seul élément à l’intérieur de son parent.</p><p>Par exemple, supposons que nous voulions appliquer un style au dernier paragraphe d’une <code>&lt;div&gt;</code>, mais uniquement s’il n'est pas le seul élément de cette <code>&lt;div&gt;</code>. Notre contenu est généré dynamiquement, il n’y a donc pas moyen de savoir combien on aura de paragraphes dans notre <code>&lt;div&gt;</code>.</p><p>Mais si nous utilisons le sélecteur <code>:only-child</code> combiné avec le <a href="https://la-cascade.io/articles/la-pseudo-classe-de-negation/">sélecteur de négation</a> <code>:not</code>, nous pouvons déterminer si le paragraphe n’est pas seul avant de lui appliquer un style :</p><pre>div p:last-child:not(:only-child) { font-weight: bolder; }</pre><p>Grâce à cette sélection, le dernier paragraphe sera en gras, mais seulement s’il n’est pas le seul élément dans la <code>&lt;div&gt;</code>. Pour être encore plus précis, on pourrait utiliser <code>:last-of-type</code> et <code>:only-of-type</code> dans le même assemblage de sélecteurs.</p><h3>Compatibilité</h3><p><a href="https://caniuse.com/?search=only-child">La compatibilité</a> d’<code>:only-child</code> est excellente, tous les navigateurs modernes la supportent.</p><h3>Alternatives</h3><p>D’autres sélecteurs accomplissent la même chose : <code>:first-child:last-child</code> (qui signifie “le premier enfant de l’élément est aussi son dernier enfant”) et <code>:nth-child(1):nth-last-child(1)</code> (même signification), bien qu’avec une plus forte spécificité.</p><p><a href="https://developer.mozilla.org/fr/docs/Web/CSS/:only-child">Voir la page MDN de :only-child</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/toi-seul-utiliser-only-child-de-css</link>
      <guid>https://la-cascade.io/articles/toi-seul-utiliser-only-child-de-css</guid>
      <pubDate>Mon, 08 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[La première variable CSS : currentColor]]></title>
      <description><![CDATA[<p><em>En attendant l'arrivée des variables CSS, Dudley Storey nous rappelle l'existence de currentColor et nous en montre quelques applications</em></p><div class="articleContent"><p>Les variables CSS se fraient lentement leur chemin vers une mise en oeuvre prochaine dans les navigateurs. Une variable existe pourtant depuis des années : <code>currentColor</code> ! Cette fonctionnalité CSS a une bonne compatibilité navigateurs et quelques applications pratiques intéressantes. Voyons comment nous pouvons l’utiliser.</p><h2>Une règle héritée</h2><p>Une des caractéristiques les moins connues de CSS est que si vous réglez votre <code>color</code> dans une déclaration qui comporte également une <code>border</code> et que vous omettez de spécifier la couleur de cette dernière, la bordure héritera par défaut de la couleur du texte :</p><pre>h1 { color: hsl(0,0%,44%); padding: 1rem; border-bottom: 4px solid; }</pre><p>Le résultat :</p><figure><img src="https://la-cascade.io/images/CSS-currentColor.jpeg" alt="" /></figure><p>C’est une astuce sympa : si vous changez la couleur de votre titre, celle du soulignement sera automatiquement modifiée. La même chose s’applique à <code>outline</code> et <code>box-shadow</code>.</p><p>En utilisant currentColor, nous pouvons étendre cette fonctionnalité aux éléments enfants.</p><h2>Un exemple pratique de currentColor</h2><p>Nous avons dépassé depuis longtemps l’époque des liens bleus sur les pages web. Depuis une dizaine d’années, la pratique courante est de donner aux liens la même couleur que le texte dans lequel ils se trouvent. Bien sûr, il nous faut mettre en évidence le fait qu’il s’agit d'un lien. Une de mes techniques préférées est celle-ci :</p><pre>p { color: #333; }
p a {
  text-decoration: none; color: #333;
  font-weight: bolder;
  display: inline-block;
  padding-bottom: .5rem;
  border-bottom: 1px dashed #333;
}</pre><p>Certes, ça marche, mais je pense que vous avez vu le problème : nous indiquons que les liens doivent avoir la même couleur que le reste du texte, et nous utilisons encore une fois cette couleur pour la bordure inférieure. <strong>Nous répétons trois fois la même valeur de couleur</strong>. Si un jour nous décidions de changer notre design, il nous faudrait laborieusement passer en revue notre feuille de styles et appliquer les modifications une à une ( <em>NdT : sauf si vous utilisiez Sass bien sûr, puisque vous auriez déjà utilisé des variables</em>).</p><p>Procédons plutôt de la sorte : nous allons définir la couleur du texte et laisser les autres propriétés à l’intérieur du lien hériter de la couleur via <code>currentColor</code> ( <em>NdT : CSS n'est pas sensible à l'utilisation de majuscules, on peut écrire</em> <code>currentcolor</code> <em>comme ci-dessous</em>).</p><pre>p { color: #333; }
p a {
  text-decoration: none;
  color: currentcolor;
  font-weight: bolder;
  display: inline-block;
  padding-bottom: .5rem;
  border-bottom: 1px dashed currentcolor;
}</pre><p>Il y a certes d’autres façons de parvenir au même résultat, en particulier en utilisant <code>inherit</code>, mais un exemple comme celui-ci par contre est impossible sans <code>currentColor</code> :</p><pre>body { color: #f0f; }
hr { height: 10px; background: currentcolor; }</pre><p>On peut utiliser <code>currentColor</code> de tas de façons inattendues, par exemple avec <a href="https://la-cascade.io/articles/les-degrades-css/">les dégradés</a> et les SVG. Ainsi, pour avoir des sprites SVG en ligne qui s’affichent plutôt comme des icônes fontes, on pourrait utiliser :</p><pre>svg { fill: currentcolor; }</pre><p>De cette manière, chaque icône SVG prendra la <code>color</code> de son élément parent.</p><p>Ce qui serait <em>vraiment</em> génial ce serait de pouvoir faire quelque chose comme <code>color: (currentColor) 10% lighter</code> mais ce genre de manipulation n'est pas possible dans le standard CSS, elles relèvent encore du domaine des préprocesseur, en tout cas jusqu'à présent.</p><h3>Compatibilité</h3><p>La compatibilité est excellente. Tous les navigateurs modernes et leurs équivalents mobiles, y compris IE9+, supportent le mot-clé.</p><h3>Conclusion</h3><p>L'utilisation de <code>currentColor</code> dans vos feuilles de styles est une bonne façon de renforcer les <a href="http://fr.wikipedia.org/wiki/Ne_vous_r%C3%A9p%C3%A9tez_pas">bonnes pratiques DRY</a>, la cohérence de votre design, et éventuellement de vous préparer à migrer vers les préprocesseurs. Dans le web à venir, les variables joueront un plus grand rôle dans le développement et le design front-end.</p><p> _NdT : Une autre utilisation possible de currentColor, que je viens de découvrir grâce à la <a href="http://css-tricks.com/lodge/">série de vidéos de Chris Coyier sur SVG</a>, concerne la résolution de certains problèmes spécifiques d'application de style CSS sur les SVG.</p></div>]]></description>
      <link>https://la-cascade.io/articles/la-premiere-variable-css-currentcolor</link>
      <guid>https://la-cascade.io/articles/la-premiere-variable-css-currentcolor</guid>
      <pubDate>Tue, 02 Dec 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[:empty, une pseudo-classe pas si vide]]></title>
      <description><![CDATA[<p><em>Dudley Storey montre ici comment utiliser la pseudo-classe :empty, depuis l'application d'un style CSS aux tableaux et aux navigations dynamiques, jusqu'au nettoyage de votre balisage HTML.</em></p><div class="articleContent"><p>Lorsque nous écrivons notre CSS, nous sommes des <a href="http://fr.wikipedia.org/wiki/Zatoichi">Zatoïchi</a> du développement web. Nous écrivons de belles déclarations et nous les envoyons vers des documents HTML dans l’espoir qu’ils se rencontrent, mais nous connaissons rarement le <em>contenu spécifique</em> d’un élément sélectionné : la question de savoir combien de mots figurent dans un paragraphe, ou si le paragraphe est vide, relève traditionnellement de la responsabilité de JavaScript ou PHP ou d’autres langages.</p><p>Souvent on emploie des langages côté-serveur pour créer du contenu dynamique à l’intérieur d'un conteneur HTML. Lorsque l’opération échoue, c’est aux développeurs front-end qu’il revient de traiter le problème. Plutôt que d’ajouter du code avec JavaScript ou PHP, nous pouvons utiliser CSS pour nos conteneurs vides.</p><h2>Le mystère de la cellule vide résolu</h2><p>Les tableaux sont souvent remplis avec des données dynamiques, mais certaines cellules peuvent ne pas contenir d’information. Habituellement, on laisse ces cellules telles quelles, mais on pourrait tout aussi bien mettre en valeur le fait qu’elles ne contiennent rien.</p><p>Voici un bon exemple d’un tel cas, un tableau montrant les distances entre villes. Il n’y a évidemment pas de distance entre une ville et elle-même, ce qui produit un certain nombre de cellules vides.</p><figure role="group"><img src="https://la-cascade.io/images/The_CSS__empty_Selector.jpeg" alt="Un tableau dans lequel les distances entre une ville et elle-même sont vides" /><figcaption>Tableau de distances entre villes.</figcaption></figure><p>Le balisage de la table serait à peu près celui-ci (j’utilise des raccourcis HTML pour aller plus vite) :</p><pre>&lt;table&gt;
&lt;caption&gt;Distances Between Cities On The Pacific Rim (miles)&lt;/caption&gt;
&lt;col&gt;&lt;col&gt;&lt;col&gt;&lt;col&gt;
&lt;tr&gt;&lt;th&gt;&lt;th scope=col&gt;Auckland&lt;th scope=col&gt;Papeete&lt;th scope=col&gt;Los Angeles
&lt;tr&gt;&lt;th scope=row&gt;Auckland&lt;td&gt;&lt;td&gt;2542&lt;td&gt;6518
&lt;tr&gt;&lt;th scope=row&gt;Papeete&lt;td&gt;2542&lt;td&gt;&lt;td&gt;4114
&lt;tr&gt;&lt;th scope=row&gt;Los Angeles&lt;td&gt;6518&lt;td&gt;4114&lt;td&gt;&lt;/table&gt;</pre><p>C’est un excellent cas d’utilisation de <code>:empty</code> puisque les cellules vides <em>doivent être</em> incluses dans le tableau si l’on veut conserver son sens. Avec <code>:empty</code> il est très facile de cibler les cellules qui n’ont pas de contenu :</p><pre>td:empty { background: #777; }</pre><p>Vous avez remarqué la structure du code à la toute fin du tableau, avec la balise fermante <code>&lt;/table&gt;</code> juste après le dernier élément <code>&lt;td&gt;</code> vide. Si ce n’était <em>pas</em> le cas, la balise <code>&lt;td&gt;</code> isolée serait considérée comme étant “ouverte” et non pas vide. Une approche alternative serait d’utiliser <code>&lt;td&gt;&lt;/td&gt;</code> sans espace entre les deux.</p><p>Même si c’est un peu étrange, on peut combiner les sélecteurs :empty et <code>:not()</code> pour donner un style aux cellules non-vides.</p><pre>td:not(:empty) { /* styles pour les cellules non vides */ }</pre><p>Ce serait une approche inhabituelle, puisque notre présupposé est que la majorité des cellules ont du contenu et peuvent être ciblées à l’aide d’un simple sélecteur <code>&lt;td&gt;</code>, mais c’est une approche valide en CSS.</p><h2>Réhabiliter le lien manquant</h2><p>Sur un site, la navigation est souvent générée de façon dynamique, mais parfois incomplète. Il est possible qu’un espace soit réservé pour un lien qui n’apparaît jamais, ou seulement de manière sporadique. Même si cela implique généralement un travail supplémentaire côté serveur, dans l’intervalle il y a une solution CSS simple pour éviter que votre navigation ne ressemble à un sourire aux dents écartées :</p><pre>nav[role="navigation"] a:empty { display: none; pointer-events: none; }</pre><p>Un lien comportant un attribut <code>href</code> mais sans contenu ne sera pas rendu par le navigateur. Donc si nous prenons ce HTML :</p><pre>&lt;nav role="navigation"&gt;
    &lt;a href="index.html"&gt;Home&lt;/a&gt;
    &lt;a href="contact.html"&gt;Contact&lt;/a&gt;
    &lt;a href="tools.html"&gt;Tools&lt;/a&gt;
    &lt;a href="classes.html"&gt;&lt;/a&gt;
&lt;/nav&gt;</pre><p>...et que nous ajoutons le CSS qui précède, le résultat sera que le dernier lien, qui est vide, n’apparaîtra pas (dans ce cas d'ailleurs, le <code>pointer-events</code> est redondant puisque le lien n'apparaîtra pas, et ne peut donc pas être cliqué).</p><h2>Exceptions</h2><p>Attention : l’espace entre les balises ouvrante et fermante est considéré comme une information, de même que des balises (même sans contenu) à l’intérieur de l’élément ciblé, par conséquent les deux éléments suivants ne sont pas considérés comme vides :</p><pre>&lt;a href="classes.html"&gt;  &lt;/a&gt;
&lt;a href="classes.html"&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;</pre><p>Comme déjà évoqué, les balises qui ne sont pas refermées (même si leur fermeture est optionnelle en HTML) ne sont pas considérées comme vides, même si elles n’ont pas de contenu. Une balise paragraphe isolée est “ouverte” et donc n’est pas vide :</p><pre>&lt;p&gt;</pre><p>alors même qu’on aurait certainement (s’il n’y a pas de retour à la ligne) :</p><pre>&lt;p&gt;&lt;p&gt;</pre><p>Dans ce dernier cas, le premier paragraphe est vide, mais le second (en supposant que rien ne s’ajoute immédiatement après) ne l’est pas.</p><p>Les éléments “auto-fermants” sont considérés comme vides : <code>&lt;br&gt;</code>, <code>&lt;hr&gt;</code>, <code>&lt;img&gt;</code>, etc. répondent à <code>:empty</code>.</p><p>Les éléments sont considérés comme vides si leur seul contenu est un commentaire :</p><pre>&lt;p&gt;&lt;!-- ce paragraphe est vide --&gt;&lt;/p&gt;</pre><h2>Utiliser :empty comme testeur de qualité du code</h2><p>Inévitablement, les développeurs se laissent aller à la paresse. “Hé, j’ai besoin d’un peu d’espace en-dessous de cet élément. OK, je sais, je vais ajouter un paragraphe vide”.</p><pre>&lt;p&gt;un contenu réel…&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;</pre><p>Ou pire encore, une balise <code>&lt;br&gt;</code>. Ce balisage vide, de remplissage, va à l’encontre des bonnes règles d’écriture de CSS et il est difficile à retrouver. Nous pouvons utiliser <code>:empty</code> pour obtenir une visualisation rapide du balisage faible :</p><pre>*:empty, br { border: 2px solid red; }</pre><h3>Compatibilité navigateurs et conclusion</h3><p>La compatibilité de <code>:empty</code> est excellente, tous les navigateurs modernes, IE9+ y compris, le reconnaissent.</p><p><a href="https://developer.mozilla.org/fr/docs/Web/CSS/:empty">Voir la page MDN de :empty</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/empty-une-pseudo-classe-pas-si-vide</link>
      <guid>https://la-cascade.io/articles/empty-une-pseudo-classe-pas-si-vide</guid>
      <pubDate>Sat, 29 Nov 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[La pseudo-classe de négation]]></title>
      <description><![CDATA[<p><em>Parmi les pseudo-classes, il en est une qu'on oublie souvent, c'est :not(). La pseudo-classe de négation peut pourtant s'avérer très utile dans bien des situations, comme l'explique ici Shay Howe.</em></p><div class="articleContent"><p>Il y a quelques semaines, j'ai <a href="https://twitter.com/shayhowe/status/502525269992046594">tweeté</a> un petit bout de CSS que j’utilise fréquemment et j’ai été surpris du retour qu’il a eu — ce qui m’a donné envie de le partager ici aussi. Quel était ce CSS ? Le sélecteur suivant, tout simple :</p><pre>li:not(:last-child)</pre><p>Souvent, lorsqu’on travaille sur des listes on souhaite appliquer un style spécifique à tous les éléments <code>li</code> de la liste sauf un, en général le premier ou le dernier. Autrefois j’utilisais le CSS suivant :</p><pre>li {
  border-bottom: 1px solid #ccc;
}
li:last-child {
  border: none;
}</pre><p>Le problème avec cette méthode c’est que nous définissons des styles pour finalement les écraser avec un sélecteur de spécificité supérieure — dans notre cas en ajoutant la pseudo–classe <code>:last-child</code>. Ce faisant, nous donnons du travail supplémentaire à notre navigateur et nous ralentissons le rendu de ces styles.</p><p>Plutôt que de se donner du travail inutile et d’écraser nos styles, nous pouvons utiliser la <a href="https://developer.mozilla.org/fr/docs/Web/CSS/:not">pseudo–classe de négation</a> <code>:not()</code> en association avec une autre pseudo-classe structurelle ou basée sur la position, le plus fréquemment ce sera <code>:first-child</code> ou <code>:last-child</code> pour cibler plus précisément l’application de nos styles. Notre CSS plus performant ressemblerait à ceci :</p><pre>li:not(:last-child) {
  border-bottom: 1px solid #ccc;
}</pre><p>Voici le code en action sur CodePen :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/shayhowe/pen/gKGsn/">La pseudo-classe de négation</a>par Shay Howe<a href="https://codepen.io">CodePen</a></div><p>Ici, nous n’écrasons pas de styles précédents puisque nous n’appliquons de styles qu’aux éléments voulus. De plus, la compatibilité navigateurs est la même puisque <code>:not()</code>, <code>:first-child</code> et <code>:last-child</code> ont la même compatibilité.</p><p>Si vous utilisez une classe <code>.dernier</code> ou des pseudo–classes structurelles ou de position, je vous recommande de passer à la pseudo–classe de négation <code>:not()</code>. Je l’utilise depuis un certain temps maintenant et je me rends compte qu’elle m’a servi dans des situations compliquées et m’a aidé à écrire un CSS plus performant.</p><p>Si vous avez des commentaires ou des questions, n’hésitez pas à me contacter par <a href="https://twitter.com/intent/tweet?text=The%20Negation%20Pseudo-class%20%E2%80%93%20http%3A%2F%2Fbit.ly%2F1x6SGFj%20%E2%80%93%20by%20%40shayhowe%20of%20%40bellycardtech&amp;source=webclient">Twitter</a>, je serais ravi de connaître votre façon d’utiliser la pseudo–classe de négation.</p></div>]]></description>
      <link>https://la-cascade.io/articles/la-pseudo-classe-de-negation</link>
      <guid>https://la-cascade.io/articles/la-pseudo-classe-de-negation</guid>
      <pubDate>Fri, 07 Nov 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Portal CSS]]></title>
      <description><![CDATA[<p><em>Ce projet de Donovan Hutchinson est une excellente introduction aux transformations et animations CSS, ludique et claire.</em></p><div class="articleContent"><p>Vous n'avez pas nécessairement besoin de JavaScript pour créer des projets 3D impressionnants dans le navigateur web. Dans cet article, je vais vous montrer comment créer et animer une scène inspirée de <a href="http://fr.wikipedia.org/wiki/Portal_(jeu_vid%C3%A9o)">Portal</a>, uniquement à l'aide de CSS.</p><p>Vous pouvez regarder la <a href="http://hop.ie/portal/">démo Portal CSS</a> en ligne et télécharger le <a href="https://github.com/donovanh/portal">projet sur Github</a>.</p><h2>Vidéo d'explication Portal</h2><p>Pour vous montrer les étapes de création, stylisation et animation d'une scène 3D, j'ai choisi de recréer une scène de la vidéo d'entraînement de Portal. En particulier, le look stylisé, façon bande dessinée, de la première partie de la vidéo dans laquelle une silhouette passe à travers un portail et réapparaît de l'autre côté. Voici la vidéo originale :</p><iframe width="560" height="315" src="https://www.youtube.com/embed/V5paXrfkYmI?rel=0" frameborder="0" allowfullscreen="allowfullscreen">[embedded content]</iframe><p>Cette vidéo m'a époustouflé lorsqu'elle est sortie. <a href="http://en.wikipedia.org/wiki/Portal_(video_game)">Portal</a> (développé à partir de <a href="http://fr.wikipedia.org/wiki/Narbacular_Drop">Narbacular Drop</a>) a introduit un peu de <em>fun</em> dans les plateformes 3D.</p><p>Les graphiques isométriques de la vidéo d'introduction sont très différents du jeu, mais ils arrivent à reproduire son style. Dans cet article, je vais essayer de reproduire ce style bande dessinée en utilisant seulement HTML et CSS.</p><p>Voici en particulier le décor que nous allons créer :</p><figure><img src="https://la-cascade.io/images/portal1.jpeg" alt="" /></figure><h3>Un mot rapide sur les préfixes</h3><p>J'ai supprimé toutes les versions préfixées des règles CSS dans le code qui suit. Je vous recommande d'utiliser quelque chose comme <a href="http://leaverou.github.io/prefixfree/">prefix free</a> ou <a href="http://sass-lang.com/">Sass</a> pour les gérer à votre place. Vous pourrez trouver les versions préfixées de CSS et Sass sur <a href="https://github.com/donovanh/portal">Github</a>.</p><p>Le projet qui suit a été développé et testé sur Chrome. Il utilise un CSS qui ne fonctionnera pas comme il faut avec Internet Explorer. Il couvre quelques techniques intéressantes de CSS 3D qui, même si elles ne sont pas toujours d'usage courant peuvent s'avérer intéressantes dans certains projets front-end.</p><h2>On commence</h2><p>Nous allons d'abord planter le décor dans lequel construire notre création 3D. Pour cela, nous avons besoin d'un élément HTML auquel nous allons donner des propriétés indiquant au navigateur qu'il doit s'attendre à trouver du contenu 3D. Commençons avec un HTML simple :</p><pre>//HTML
&lt;article class="container"&gt;...&lt;/article&gt;</pre><p>Notre conteneur est une balise <code>&lt;article&gt;</code>. En HTML5,&gt; <em>article</em> représente un contenu autonome qui pourrait être reproduit ailleurs tout en gardant du sens.</p><p>La première propriété à appliquer est <a href="https://docs.webplatform.org/wiki/css/properties/perspective">perspective</a>. Cette propriété prend une valeur en pixels et représente la profondeur de la scène 3D. Plus la valeur est petite, moins l'effet est dramatique, et il est habituel de la fixer quelque part entre 800 et 1.200px.</p><figure><p><img src="https://la-cascade.io/images/portal2.gif" alt="image" /></p>
</figure><p>Pour donner l'impression que ce décor est une grande pièce, nous allons donner une valeur élevée à cette perspective, à 2.600px. Comme déjà indiqué, nous ne tenons pas compte des préfixes vendeurs et nous écrivons simplement :</p><pre>//CSS
article.container {
    perspective: 2600px;
}</pre><h3>Point de fuite</h3><p>Le conteneur a une profondeur, l'étape suivante consiste à déterminer un angle de vue. En ajustant la propriété <a href="https://docs.webplatform.org/wiki/css/properties/perspective-origin">perspective-origin</a>, nous pouvons établir <a href="http://fr.wikipedia.org/wiki/Point_de_fuite">le point de fuite</a> et déterminer si nous regardons du dessus ou de côté.</p><pre>//CSS
.container {
  perspective-origin: 50% -1400px;
}</pre><p>La propriété <code>perspective-origin</code> prend deux valeurs, correspondant au décalage horizontal et vertical. Dans notre cas, nous le plaçons à mi-chemin en travers du décor et 1.400px au-dessus. Il en résultera un point de vue placé au-dessus de l'objet, regardant vers le bas.</p><p>J'ai déterminé ces valeurs en les ajustant manuellement dans le panneau Chrome web inspector et en jugeant à l'oeil. Lorsque vous créerez votre scène, vos valeurs seront peut-être plus ou moins élevées, cela dépendra de l'effet que vous voulez faire passer. N'oubliez pas que ces valeurs peuvent être animées et on peut créer des effets intéressants de déplacement de perspective.</p><h3>Pas de vecteurs, Victor</h3><p>Les objets que nous positionnons en HTML sont des éléments HTML normaux. Ils ont une largeur, une hauteur, et ils sont rectangulaires. Lorsque vous construisez un objet en 3D, vous mettez chaque rectangle en place. D'autres méthodes, différentes, décrivent des points et des lignes pour créer des formes, mais ce n'est pas le cas ici. Cela signifie aussi qu'il n'y a pas beaucoup de formes simples à partir desquelles dessiner.</p><p>Les éléments HTML sont placés dans le décor 3D grâce à la propriété <code>transform</code>.</p><h3>Transformer</h3><p>La propriété <code>transform</code> consiste en une série d'ajustements de l'élément HTML. Ces ajustements peuvent prendre la forme de <code>translate</code> pour déplacer l'élément, <code>rotate</code> pour ajuster son angle, <code>skew</code> et même <code>scale</code>. On peut accumuler ces ajustements pour créer des transformations complexes, par exemple :</p><pre>//CSS
.example {
    transform: rotateY(45deg) translateZ(-100px);
}</pre><p>Cette règle fait tourner un élément de 45 degrés sur l'axe des Y, puis le déplace en arrière (en profondeur) de 100px sur l'axe des Z. L'effet donnerait ceci :</p><figure><p><img src="https://la-cascade.io/images/portal3.png" alt="image" /></p>
</figure><h3>La propriété transform-origin</h3><p>Lorsqu'on fait tourner les éléments, il faut garder à l'esprit que les transformations ont une origine que nous pouvons fixer. <a href="https://docs.webplatform.org/wiki/css/properties/transform-origin">Transform-origin</a> est un point auquel se réfèrent les valeurs X, Y et Z. Voici sa valeur par défaut :</p><pre>//CSS
.default-origin {
    transform-origin: 50% 50% 0;
}</pre><p>En réalisant cet exemple, j'ai conservé les valeurs par défaut, mais il est intéressant de savoir qu'elles sont là et qu'on peut les modifier.</p><h2>Construisons</h2><p>Notre décor est planté, nous pouvons maintenant assembler notre chef-d'oeuvre en 3D. Quand on commence à construire des objets en 3D à l'aide de HTML et CSS, il est utile de prendre un petit moment pour bien comprendre comment cette approche diffère de celle des logiciels de 3D.</p><pre>//HTML
&lt;section class="stage"&gt;
    &lt;div class="shadow"&gt;&lt;/div&gt;
    &lt;div class="back-left"&gt;&lt;/div&gt;
    &lt;div class="back-right"&gt;&lt;/div&gt;
    &lt;div class="platform-left"&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
    &lt;div class="platform-right"&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
    &lt;div class="pit-left"&gt;&lt;/div&gt;
    &lt;div class="pit-right"&gt;&lt;/div&gt;
    &lt;div class="pit-back"&gt;&lt;/div&gt;
&lt;/section&gt;</pre><p>C-dessus, nous avons une section <em>stage</em>, qui contiendra tous nos éléments. Un ensemble de div forme la partie principale de la structure. Ce sont les deux plateformes, un puits, des murs, et une ombre.</p><p>Lorsque j'ai commencé à construire ce décor, j'ai essayé de placer les murs directement sur la scène, en la tournant et en ajustant sa position. Cependant, comme le décor est vu depuis un angle isométrique, une approche plus simple était de placer les parties du décor puis de faire tourner le tout de 45 degrés en une seule fois.</p><p>Gardons ceci à l'esprit et plaçons nos éléments HTML à partir du schéma suivant :</p><figure><p><img src="https://la-cascade.io/images/portal4.png" alt="image" /></p>
</figure><p>Comme on peut le voir, le fond gauche est aligné sur la gauche, mais le fond droit fait face à l'observateur. Pour ajuster ceci, nous ferons tourner le tout de 45 degrés tout à l'heure.</p><p>Avant d'appliquer les transformations, nous devons donner à nos div quelques propriétés partagées :</p><pre>//CSS
.stage div {
    position: absolute;
    transform-style: preserve-3d;
}</pre><p>Chaque div sera positionnée absolument et la propriété <code>transform-style</code> indique au navigateur que des transformations 3D doivent être appliquées en fonction de la perspective que nous avons fixée plus tôt.</p><p>Nous pouvons maintenant commencer à positionner les div :</p><pre>//CSS
.stage .back-left {
    width: 500px;
    height: 120px;
    background-color: #6b522b;
    transform: rotateY(90deg) translateX(-256px);
    border-top: 6px solid #8a683d;
    border-left: 6px solid #574625;
}</pre><p>Les règles ci-dessus donnent une largeur de 500px, qui est la longueur du côté gauche de notre décor 3D, une hauteur de 120px et une couleur de background marron clair. La div est ensuite pivotée de 90 degrés et repoussée le long de l'axe des X. La div a une bordure de 6 px pour donner l'illusion de la profondeur.</p><p>Une transformation similaire est appliquée au fond droit :</p><pre>//CSS
.stage .back-right {
    width: 446px;
    height: 120px;
    background-color: #9c7442;
    transform: translateX(253px) translateZ(3px);
    border-top: 6px solid #b5854a;
    border-right: 6px solid #78552c;
}</pre><p>La div est un peu plus petite, car la pièce originale dans la vidéo de Portal n'est pas tout à fait carrée.</p><p>Ensuite, ajoutons les plateformes et les côtés du puits :</p><pre>//CSS
.stage .platform-left {
    width: 446px;
    height: 220px;
    background-color: #bcb3a8;
    transform: rotateX(90deg) translateY(396px) translateX(253px) translateZ(-13px);
    border-bottom: 6px solid #857964;
}
.stage .platform-right {
    width: 446px;
    height: 164px;
    background-color: #bcb3a8;
    transform: rotateX(90deg) translateY(88px) translateX(253px) translateZ(-41px);
    border-right: 6px solid #554c3d;
    border-bottom: 6px solid #847660;
}
.stage .pit-left {
    width: 447px;
    height: 800px;
    background-color: #4d4233;
    transform: translate3D(254px, 125px, 285px);
}
.stage .pit-right {
    width: 451px;
    height: 800px;
    top: -1400px;
    background-color: #847660;
    transform: translate3D(254px, 125px, 173px);
}
.stage .pit-back {
    width: 170px;
    height: 220px;
    background-color: #6b522b;
    transform: rotateY(90deg) translate3D(-200px, 87px, 168px);
}</pre><p>Le résultat final est un décor qui devrait ressembler à ceci :</p><figure><p><img src="https://la-cascade.io/images/portal5.png" alt="image" /></p>
</figure><p>Ce n'est pas encore ça. Nous devons faire pivoter tout ce décor pour le voir comme il faut. Ajoutons un <code>transform</code> à la section :</p><pre>//CSS
.stage {
    width: 460px;
    margin: 0 auto;
    transform-style: preserve-3d;
    transform: rotateY(-45deg);
}</pre><p>Le résultat devrait maintenant être celui-ci :</p><figure><p><img src="https://la-cascade.io/images/portal6.png" alt="image" /></p>
</figure><p>Vos pouvez remarquer que les bordures créent un joli effet de profondeur, en particulier sur les coins, là où les différentes bordures colorées se rencontrent en formant un angle de 45 degrés. Comme ce décor doit être vu à 45 degrés, cet effet marche très bien dans la plupart des cas. Certains coins ne sont pas aussi réussis, mais si l'on considère la simplicité du procédé et l'absence d'images, je trouve que c'est un compromis acceptable.</p><h3>Dans l'ombre</h3><p>Dans la vidéo, il y a une belle ombre sous les plateformes. Nous pouvons reproduire cet effet avec la propriété CSS <code>box-shadow</code>.</p><pre>//CSS
.stage .shadow {
    width: 550px;
    height: 550px;
    background-color: transparent;
    transform: rotateX(90deg) translateZ(-166px) translateX(550px);
    box-shadow: -600px 0 50px #afa79f;
}</pre><p>Les règles ci-dessus ajoutent une <code>box-shadow</code> à la div <em>shadow</em>, qui est elle-même transparente. La <code>box-shadow</code> est décalée de 600px de façon à ce que la div shadow n'empiète pas sur l'ombre. Le tout est pivoté et positionné en dehors du décor, afin que seule une partie de l'ombre soit visible. Le résultat devrait ressembler à ceci :</p><figure><p><img src="https://la-cascade.io/images/portal7-1.png" alt="image" /></p>
</figure><h2>Rouge et Bleu</h2><p>Ensuite, il nous faut ajouter un peu de décoration et les portails étincelants.</p><figure><p><img src="https://la-cascade.io/images/portal8.png" alt="image" /></p>
</figure><p>Le HTML dont nous avons besoin est assez simple :</p><pre>//HTML
&lt;div class="portal red"&gt;&lt;/div&gt;
&lt;div class="portal blue"&gt;&lt;/div&gt;</pre><p>Il y a une div pour chaque portail, une rouge et une bleue. Elles ont toutes les deux un style similaire, avec des dégradés utilisés pour donner l'effet brillant. Comme il s'agit d'un élément HTML simple, le CSS comprend un pseudo-élément auquel nous pouvons appliquer un style pour obtenir l'effet désiré.</p><p>La première étape est de donner sa forme générale au portail :</p><pre>//CSS
.stage .portal {
    width: 48px;
    height: 72px;
    background-color: black;
    border-radius: 44px/62px;
    box-shadow: 0 0 15px 4px white;
}</pre><p>On crée ainsi le portail, en utilisant la propriété <code>border-radius</code> pour obtenir une forme ovale, et une <code>box-shadow</code> blanche pour la brillance. Un pseudo-élément est ensuite ajouté, avec les mêmes dimensions, et la bordure blanche :</p><pre>//CSS
.stage .portal:before {
    content: "";
    display: block;
    width: 48px;
    height: 72px;
    border: 4px solid white;
    border-radius: 44px/62px;
    margin-top: -4px;
    margin-left: -4px
}</pre><p>Jusqu'à présent les mêmes styles s'appliquent aux deux portails. Mais puisque l'un est rouge et l'autre bleu, nous allons utiliser des ensembles de règles CSS séparés pour décrire les caractéristiques propres à chacun. D'abord le portail rouge, puis le bleu :</p><pre>//CSS
.stage .portal.red {
    background: radial-gradient(#000000, #000000 50%, #ff4640 70%);
    border: 7px solid #ff4640;
    transform: translate3D(223px, 25px, 385px) rotateY(90deg) skewX(5deg);
}
.stage .portal.blue {
  background: radial-gradient(#000000, #000000 50%, #258aff 70%);
  border: 7px solid #258aff;
  transform: translate3D(586px, 25px, 4px) skewX(-5deg);   }</pre><p>On donne au portail rouge un background <a href="https://la-cascade.io/les-degrades-css/#radial">dégradé radial</a> et une bordure rouge. Dans ce cas, le <code>transform</code> le fait pivoter et le place sur le mur gauche. Même chose pour le portail bleu, mais avec un dégradé bleu et un positionnement sur le mur de droite. Dans mon test, ils étaient tous les deux un peu de travers, alors j'ai ajouté un effet de déformation (<em>skew</em>) qui leur donne meilleure allure.</p><h3>Un portail étincelant</h3><p>Le HTML que nous avons créé initialement comprenait une balise <code>span</code> sur chaque plateforme. Ces spans ont été ajoutés de façon à être stylisés avec un dégradé radial pour donner un effet de luminosité éclatante sous chacun des portails.</p><pre>//CSS
.stage .platform-left span {
    display: block;
    position: absolute;
    width: 120px;
    height: 200px;
    left: 0;
    background: radial-gradient(left, #f3cac8, #c8b8ad 70px, #bcb3a8 90px);
}
.stage .platform-right span {
    display: block;
    position: absolute;
    width: 150px;
    height: 60px;
    left: 280px;
    background: radial-gradient(top, #cdebe8, #c2cbc1 40px, #bcb3a8 60px);
}</pre><p>Les deux spans sont positionnés absolument et on leur donne un dégradé rouge et bleu, positionné sous chacun des portails. On aurait pu utiliser un pseudo-élément pour obtenir cet effet, mais comme l'animation des pseudo-élements n'est pas très bien supportée (même dans des versions de Webkit), un span séparé les remplace.</p><h3>La porte</h3><p>Un succès inattendu a été l'utilisation des bordures pour créer ce qui ressemble à une ouverture dans le mur de droite, représentant la sortie. Pour créer cette porte, j'ai utilisé une simple div et quelques bordures colorées qui donnent l'illusion de la profondeur.</p><figure><p><img src="https://la-cascade.io/images/portal9.png" alt="image" /></p>
</figure><p>Le HTML de la porte est très simple. Ajoutez le code suivant à l'intérieur de la section <em>stage</em>.</p><pre>//HTML
&lt;div class="door"&gt;&lt;/div&gt;</pre><p>Pour donner un style à la porte, il nous faut quelques bordures et un <code>transform</code> qui la positionne dans le mur de droite :</p><pre>//CSS
.stage .door {
    width: 65px;
    height: 85px;
    background: #efe8dd;
    border-bottom: 6px solid #bcb3a8;
    border-left: 7px solid #78552e;
    transform: translate3D(450px, 34px, 4px);
}</pre><p>Deux bordures sont utilisées pour créer cet effet. Les bordures <em>bottom</em> et <em>left</em> correspondent à la plateforme et à un côté du mur. Comme il n'y a pas de bordure spécifiée pour le haut de la porte, la bordure de gauche est coupée par le haut de la div, ce qui fonctionne bien.</p><h2>Les personnages</h2><p>Les portails et la porte sont en place, il nous faut maintenant un personnage pour sauter dans l'un et réapparaître par l'autre. La première étape consiste à créer la persone.</p><p>Dans mes premiers tests, j'ai essayé d'utiliser un personnage et d'arrêter l'animation au premier portail puis de continuer immédiatement de l'autre côté. Mais quand j'animais un seul personnage, il y avait un scintillement pendant son transfert de l'autre côté. Pour éviter ce problème, j'utilise deux personnages et je les anime séparément.</p><h3>Construire le personnage</h3><figure><p><img src="https://la-cascade.io/images/portal10.png" alt="image" /></p>
</figure><p>La forme du premier personnage est constituée de deux parties principales, la tête et le corps. Les jambes sont ajoutées en utilisant des pseudo éléments sur le corps. Une structure similaire est aussi intégrée pour créer l'ombre :</p><pre>//HTML
&lt;div class="dude one"&gt;
  &lt;figure class="head"&gt;&lt;/figure&gt;
  &lt;figure class="body"&gt;&lt;/figure&gt;
  &lt;div class="dude-shadow one"&gt;
    &lt;figure class="head"&gt;&lt;/figure&gt;
    &lt;figure class="body"&gt;&lt;/figure&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre><p>Comme l'ombre (<em>dude-shadow</em>) est incluse dans la div contenant le personnage, elle peut être animée simultanément. Voici le CSS :</p><pre>//CSS
.dude, .dude-shadow {
    width: 30px;
    height: 100px;
}
.dude figure, .dude-shadow figure {
  display: block;
  background-color: black;
  position: absolute;
}
.dude figure.head, .dude-shadow figure.head {
    top: 0;
    left: 3px;
    width: 20px;
    height: 20px;
    border-radius: 22px;
}
.dude figure.body, .dude-shadow figure.body {
    top: 21px;
    width: 26px;
    height: 30px;
    border-radius: 30px 30px 0 0;
}
.dude figure.body:before, .dude figure.body:after, .dude-shadow figure.body:before, .dude-shadow figure.body:after {
  content: "";
  position: absolute;
  width: 9px;
  height: 15px;
  background-color: black;
  top: 30px;
}
.dude figure.body:before, .dude-shadow figure.body:before {
  left: 3px;
}
.dude figure.body:after, .dude-shadow figure.body:after {
  left: 14px;
}</pre><p>Ces règles sont dédoublées dans chaque cas, pour décrire à la fois le personnage et son ombre. Chaque partie est positionnée absolument et on utilise <code>border-radius</code> pour créer des formes arrondies. Les pseudo-éléments représentant les jambes sont décrits puis positionnés dans des règles séparées.</p><h3>le personnage 1</h3><p>Une fois la forme du personnage réalisée, positionnons celui-ci sur son point de départ :</p><pre>//CSS
.stage .dude.one {
    transform: translate3D(514px, 50px, 375px) rotateY(78deg);
}
.stage .dude-shadow.one {
    transform: translateX(-12px) rotateX(90deg) translateY(8px);
    opacity: 0.1;
}</pre><p>Les <code>transform</code> CSS positionnent à la fois le personnage et son ombre. Plutôt que de donner une couleur grise à l'ombre, on utilise la propriété opacité, réglée à 0.1, ce qui permet à des détails de background d'être vus en-dessous de l'ombre.</p><p>Le premier personnage est maintenant sur son point de départ et pivoté selon un angle similaire à celui de la vidéo. Nous allons ajouter l'animation plus tard, pour le faire sauter à travers le portail.</p><h3>Des bras</h3><figure><p><img src="https://la-cascade.io/images/portal11.png" alt="image" /></p>
</figure><p>Le deuxième personnage a quelques détails supplémentaires, des bras, l'idée étant que lorsque le personnage passe à travers le portail, il lève les bras en signe de victoire. Voici le HTML :</p><pre>//HTML
&lt;div class="dude two"&gt;
    &lt;figure class="head"&gt;&lt;/figure&gt;
    &lt;figure class="body"&gt;&lt;/figure&gt;
    &lt;figure class="arm left"&gt;&lt;/figure&gt;
    &lt;figure class="arm right"&gt;&lt;/figure&gt;
    &lt;div class="dude-shadow two"&gt;
        &lt;figure class="head"&gt;&lt;/figure&gt;
        &lt;figure class="body"&gt;&lt;/figure&gt;
        &lt;figure class="arm left"&gt;&lt;/figure&gt;
        &lt;figure class="arm right"&gt;&lt;/figure&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><p>Le second personnage sera invisible au début de l'animation, puis il saute à travers le portail à mi-chemin de l'animation (après que le premier personnage ait sauté). Pour mettre ceci en place, le deuxième personnage est positionné sur le portail.</p><pre>//CSS
.stage .dude.two {
    transform: translate3D(610px, 40px, 10px) rotateY(15deg);
}
.stage .dude.two figure.arm {
    position: absolute;
    width: 20px;
    height: 8px;
    background: black;
    top: 20px;
}
.stage .dude.two figure.arm.left {
    left: -13px;
    transform: rotateZ(40deg);
}
.stage .dude.two figure.arm.right {
    right: -10px;
    transform: rotateZ(-40deg);
}
.stage .dude-shadow.two {
    transform: translateY(12px) translateX(-16px) translateZ(-6px) rotateZ(-90deg) rotateY(90deg) rotateZ(50deg) skewX(30deg) scaleX(0.8);
    opacity: 0.1;
}</pre><p>Une deuxième animation sera appliquée aux bras, dans laquelle ceux-ci seront d'abord invisibles pour apparaître ensuite.</p><h2>Le décor est planté</h2><p>Les personnages sont là dans leur décor, nous sommes prêts pour l'animation.</p><figure><p><img src="https://la-cascade.io/images/portal12.png" alt="image" /></p>
</figure><p>Voyons comment nous pouvons donner l'illusion que le personnage saute dans le premier portail et réapparaît dans le second.</p><h2>Animation</h2><p>Si vous regardez <a href="http://hop.ie/portal/">la démo</a>, vous verrez plusieurs animations. Plutôt que de passer en revue toutes les animations, je vais me concentrer sur l'animation du personnage passant d'un portail à l'autre.</p><h3>Keyframe animation</h3><p>L'animation des éléments HTML dans le temps est réalisée en utilisant des <a href="https://docs.webplatform.org/wiki/css/atrules/@keyframeshttps://docs.webplatform.org/wiki/css/atrules/@keyframes">keyframes</a>, et en attachant un ensemble de keyframes à un élément au moyen d'une propriété <a href="https://docs.webplatform.org/wiki/css/properties/animation">animation</a>. Nous allons commencer en animant le premier personnage, qui s'approchera du portail de gauche et sautera au travers. Voici un ensemble de keyframes qui permettent de réaliser cette animation :</p><pre>//CSS
@keyframes move-dude-one {
    /* Le personnage entre en scène */
    0% {
        transform: translate3D(514px, -10px, 375px) rotateY(78deg) scaleY(2);
    }
    /* Il attend un moment */
    1%, 18% {
        transform: translate3D(514px, 50px, 375px) rotateY(78deg) scaleY(1);
        opacity: 1;
    }
    /* Il se dirige vers le portail */
    34%, 39% {
        transform: translate3D(284px, 40px, 375px) rotateY(78deg);
        opacity: 1;
    }
    /* Il fait une pause, puis saute */
    41%, 42% {
        transform: translate3D(234px, 40px, 375px) rotateY(78deg);
        opacity: 1;
    }
    /* Il disparaît */
    43%, 100% {
        transform: translate3D(234px, 40px, 375px) rotateY(78deg);
        opacity: 0;
    }
}</pre><p>Les keyframes sont une série d'étapes, décrites à l'aide de pourcentages. Les pourcentages sont relatifs au timing de l'animation, c'est à dire que si l'animation dure 10 secondes, 10% représenteraient une étape d'une durée de 1 seconde.</p><p>Afin de voir nos personnages sauter à travers les portails dans une belle continuité, nous allons créer deux animations de 10 secondes chacune qui fonctionneront de manière simultanée. J'ai mis quelques commentaires dans le code pour décrire chaque étape de l'animation. La propriété <code>transform</code> est utilisée à chaque étape pour régler la position et l'angle des personnages.</p><p>À 43% de l'animation, l'<code>opacity</code> du personnage est fixée à 0. C'est le moment où le personnage disparaît dans le portail. Le second personnage devrait donc apparaître vers 43% grâce à son animation.</p><p>Avant cela, appliquons cette première animation au premier personnage :</p><pre>//CSS
.dude.one {
    animation: move-dude-one 10s linear infinite;
    opacity: 0;
}</pre><p>La propriété <code>animation</code> ci-dessus applique l'animation à l'élément <em>dude one</em>. Il l'attache au moyen du nom de l'animation (<em>move-dude-one</em>), lui assigne une durée de 10 secondes et une répétition à l'infini.</p><p>Une opacité de 0 permet de garantir que le personnage est invisible avant le début de l'animation.</p><p>Passons maintenant à l'animation du second personnage.</p><pre>//CSS
@keyframes move-dude-two {
    /* Le personnage est d'abord invisible */
    0%, 42% {
        transform: translate3D(610px, 40px, 10px) rotateY(15deg);
        opacity: 0;
    }
    /* Il apparaît */
    42.5% {
        transform: translate3D(610px, 40px, 10px) rotateY(15deg);
        display: block;
        opacity: 1;
    }
    /* Il s'avance sur la plateforme */
    46%, 75% {
        transform: translate3D(610px, 40px, 120px) rotateY(15deg);
        opacity: 1;
    }
    /* Il reste là un moment */
    76%, 97% {
        transform: translate3D(610px, -10px, 120px) rotateY(15deg) scaleY(2);
        opacity: 0;
    }
    /* Il s'envole dans les airs ! */
    98%, 100% {
        transform: translate3D(610px, -10px, 120px) rotateY(15deg) scaleY(2);
        opacity: 0;
    }
}
@keyframes arms {
    /* Pas de bras */
    0%, 53% {
        opacity: 0;
    }
    /* Il a des bras ! */
    54%, 100% {
        opacity: 1;
    }
}</pre><p>Comme prévu, cette animation commence autour de 42%. Le personnage saute par le portail, il reste immobile quelques instants, puis il s'envole dans les airs. Un deuxième ensemble de keyframes décrit l'animation des bras. Ils sont invisibles au départ, puis apparaissent à mi-chemin de l'animation.</p><p>Nous pouvons appliquer ces keyframes au deuxième personnage de la façon suivante :</p><pre>//CSS
.dude.two {
    animation: move-dude-two 10s linear infinite;
    opacity: 0;
}
.dude.two figure.arm {
    animation: arms 10s linear infinite;
    opacity: 0;
}</pre><p>De cette manière, les deux animations sont appliquées. Comme elles ont toutes les deux une durée identique de 10 secondes, et qu'elles se reproduisent à l'infini, elles sont parfaitement coordonnées.</p><p>Si ce n'est déjà fait, vous pouvez vérifier <a href="http://hop.ie/portal/">le résultat final</a> dans un navigateur moderne, de préférence pas Internet Explorer.</p><h2>Précautions</h2><p>Puisque nous parlons des navigateurs, je dois dire que tout ceci ne fonctionnera pas dans IE... Firefox est un peu bof, mais pas mal. Safari y est presque et Chrome est bon à 100%. Mais on va y arriver. ( <em>NdT : l'article date de juin 2013, on y est</em>).</p><p>Ça marche bien aussi sur la plupart des terminaux (toute question de navigateur mise à part), un test sur iPhone montre une performance meilleure encore que sur un laptop avec Chrome, parce que les règles CSS utilisées (transformations 3D) utilisent la carte graphique.</p><h3>Demo et contact</h3><p>Regardez <a href="http://hop.ie/portal/">la démo</a> ou téléchargez le code sur <a href="https://github.com/donovanh/portal">Github</a>.</p><p>Je serais ravi de connaître votre avis, vous pouvez me joindre sur <a href="https://twitter.com/donovanh">Twitter</a>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/portal-css</link>
      <guid>https://la-cascade.io/articles/portal-css</guid>
      <pubDate>Sat, 01 Nov 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Centrer en CSS, un guide complet]]></title>
      <description><![CDATA[<p><em>Le centrage en CSS est souvent un véritable casse-tête, car il existe plusieurs techniques différentes selon les cas d'utilisation. Chris Coyier les a listées et nous donne toutes les solutions.</em></p><div class="articleContent"><p>Le centrage en CSS est souvent un casse-tête. <em>Pourquoi faut-il que ce soit si difficile ?</em> En fait, la difficulté ne vient pas du centrage lui-même mais de la multiplicité des techniques disponibles pour centrer en CSS et qui dépendent chacune de la situation. La vraie difficulté est donc de savoir quelle technique utiliser dans une situation donnée.</p><p>Nous allons lister toutes ces situations et en principe vous serez équipé pour la route.</p><p><em>NdT : Chris Coyier s'intéresse ici au <strong>centrage en général</strong>, pour une introduction complète au <strong>centrage d'une div</strong>, consultez l'article</em> <a href="https://la-cascade.io/articles/centrer-une-div-guide-complet">Centrer un bloc Div, guide complet</a>, <em>de Steve Pear</em>.</p><p>Si je veux centrer...</p><h2>Centrer horizontalement</h2><h3>Éléments inline ou inline-* (p.ex. texte ou lien)?</h3><p>Vous pouvez centrer horizontalement des <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline/">éléments inline</a> à l'intérieur d'un élément parent de niveau bloc avec cette ligne simple :</p><pre>//CSS
.center-children {
  text-align: center;
}</pre><p>Voici ce que ça donne sur Code Pen (<em>comme toujours, vous pouvez cliquer sur HTML et CSS pour voir le code, sur Result pour voir le résultat, et sur Edit si vous voulez voir l'original sur Code Pen et jouer avec</em>) :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/HulzB/">Centering Inline Elements</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Ça fonctionnera très bien avec inline, inline-block, inline-table, inline-flex, etc.</p><h3>Éléments block ?</h3><p>Vous pouvez centrer un élément <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline/">de niveau bloc</a> en lui donnant une marge gauche et droite automatique, ce qui se traduit par :</p><pre>//CSS
.center-me {
  margin: 0 auto;
}</pre><p>NB : Il va de soi que l'élément en question a une largeur déterminée, sinon il prendrait toute la largeur de l'élément parent et n'aurait pas besoin d'être centré.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/eszon/">Centering Single Block Level Element</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Ça marchera quelle que soit la largeur de l'élement bloc que vous voulez centrer ou celle de son élément parent.</p><h3>Y a-t-il plus d'un élément block ?</h3><p>Si vous avez deux éléments blocs, ou plus, à centrer dans une rangée, une bonne solution consistera souvent à changer le type de <code>display</code>. Voici deux exemples, le premier utilise <code>display: inline-block</code>, le second utilise <a href="https://la-cascade.io/articles/flexbox-guide-complet/">Flexbox</a> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/ebing/">Centering Row of Blocks</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Voilà pour les rangées. Et si vous avez plusieurs éléments blocks empilés les uns sur les autres, la technique de marge automatique fonctionne parfaitement :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/haCGt/">Centering Blocks on Top of Each Other</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h2>Centrer verticalement</h2><p>Le centrage vertical est un peu plus délicat en CSS.</p><h3>Éléments inline ou inline-* (p.ex. texte ou lien)?</h3><h4>Est-ce une ligne unique ?</h4><p>Des éléments inline ou texte peuvent apparaître centrés verticalement parfois simplement parce qu'il y a un padding top et bottom égal :</p><pre>//CSS
.link {
  padding-top: 30px;
  padding-bottom: 30px;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/ldcwq/">Centering text (kinda) with Padding</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Si vous ne pouvez pas utiliser le padding et que vous cherchez à centrer un texte qui doit rester sur une ligne unique, le truc est de donner à la propriété <code>line-height</code> la même valeur qu'à <code>height</code>.</p><pre>//CSS
.center-text-trick {
  height: 100px;
  line-height: 100px;
  white-space: nowrap;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/LxHmK/">Centering a line with line-height</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h4>Ou des lignes multiples ?</h4><p>Là aussi on peut obtenir le centrage avec des padding top et bottom égaux.</p><p>Si pour une raison quelconque vous ne pouvez pas utiliser cette technique, peut-être l'élément dans lequel est situé le texte est-il une cellule de tableau, ou bien on peut forcer cet élément à se comporter comme s'il était une cellule. La propriété <code>vertical-align</code> gère cette situation, puisqu'elle sert habituellement à aligner des contenus situés sur une rangée.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/ekoFx/">Centering text (kinda) with Padding</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>Une autre solution consiste à <a href="https://la-cascade.io/articles/flexbox-guide-complet/">utiliser flexbox</a>. Centrer un flex-child dans un flex-parent est assez facile :</p><pre>//CSS
.flex-center-vertically {
  display: flex;
  justify-content: center;
  flex-direction: column;
  height: 400px;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/uHygv/">Vertical Center Multi Lines of Text with Flexbox</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><p>N'oubliez pas que cela fonctionne uniquement si le container parent a une hauteur fixe (en px, en % ou ce que vous voulez), c'est pourquoi le container ici a une hauteur.</p><p>Si vous ne pouvez utiliser aucune de ces techniques, il vous reste encore celle du “ghost-element”, l'élément fantôme, dans lequel un pseudo-élément prenant toute la hauteur est placé à l'intérieur du container et le texte est aligné verticalement sur lui :</p><pre>//CSS
.ghost-center {
  position: relative;
}
.ghost-center::before {
  content: " ";
  display: inline-block;
  height: 100%;
  width: 1%;
  vertical-align: middle;
}
.ghost-center p {
  display: inline-block;
  vertical-align: middle;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/ofwgD/">Ghost Centering Multi Line Text</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h3>Élements block</h3><h4>Connaissez-vous la hauteur de l'élément ?</h4><p>Il est assez courant de ne pas connaître la hauteur d'un élément, pour des tas de raisons : Si la largeur change, la réorganisation du texte peut changer la hauteur, une modification du style du texte peut également changer la hauteur, de même qu'un ajout de texte... Idem si le ratio d'aspect de votre image est fixe, tout redimensionnement entraînera une modification de sa hauteur.</p><p>Mais si vous connaissez sa hauteur, vous pouvez le centrer avec :</p><pre>//CSS
.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  height: 100px;
  margin-top: -50px; /* account for padding and border if not using box-sizing: border-box; */
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/HiydJ/">Center Block with Fixed Height</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h4>La hauteur de l'élément est-elle inconnue ?</h4><p>Si vous ne connaissez pas la hauteur de l'élément, vous pouvez le centrer en le remontant de la moitié de sa hauteur après l'avoir fait descendre de la moitié de la hauteur du contenant :</p><pre>//CSS
.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/lpema/">Center Block with Unknown Height</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h4>Pouvez-vous utiliser Flexbox ?</h4><p>Sans surprise, c'est bien plus facile avec <a href="http://css-tricks.com/snippets/css/a-guide-to-flexbox/">flexbox</a>.</p><pre>//CSS
.parent {
  display: flex;
  flex-direction: column;
  justify-content: center;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/FqDyi/">Center Block with Unknown Height with Flexbox</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h2>Horizontalement et verticalement</h2><p>Vous pouvez combiner les techniques qui précèdent pour obtenir des éléments parfaitement centrés. Mais il me semble qu'elles peuvent se regrouper en trois catégories :</p><h3>Éléments de hauteur et largeur fixes</h3><p>Vous pouvez utiliser des marges négatives égales à la moitié de cette hauteur et de cette largeur, un positionnement absolu à 50%/50% centrera l'élément :</p><pre>//CSS
.parent {
  position: relative;
}
.child {
  width: 300px;
  height: 100px;
  padding: 20px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -70px 0 0 -170px;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/JGofm/">Center Block with Fixed Height and Width</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h3>Éléments de hauteur et largeur inconnues</h3><p>Si vous ne connaissez pas la largeur ou la hauteur, vous pouvez utiliser la propriété <code>transform</code> et une translation négative de 50% dans les deux directions (elle sera basée sur les largeur et hauteur actuelles de l'élément) :</p><pre>//CSS
.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/lgFiq/">Center Block with Unknown Height and Width</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h3>Pouvez-vous utiliser Flexbox ?</h3><p>Pour centrer dans les deux directions avec flexbox, vous devez utiliser deux propriétés de centrage :</p><pre>//CSS
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/msItD/">Center Block with Unknown Height and Width with Flexbox</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h2>Conclusion</h2><p>Centrer horizontalement, centrer verticalement, vous pouvez tout centrer sans problème en CSS !</p></div>]]></description>
      <link>https://la-cascade.io/articles/centrer-en-css-un-guide-complet</link>
      <guid>https://la-cascade.io/articles/centrer-en-css-un-guide-complet</guid>
      <pubDate>Sat, 06 Sep 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Raccourcis et astuces Emmet]]></title>
      <description><![CDATA[<p><em>Emmet est un plugin pour éditeurs de textes qui vous aide à créer HTML et CSS à la vitesse de l'éclair. Rappel des raccourcis principaux et quelques fonctionnalités moins connues.</em></p><div class="articleContent"><p><em>NdT : Deux articles de la Cascade ont déjà présenté <a href="http://emmet.io/">Emmet</a>, l'un de manière globale (<a href="https://la-cascade.io/articles/goodbye-zen-coding-hello-emmet/">Goodbye Zen Coding, Hello Emmet !</a>), l'autre plus spécifiquement pour CSS (<a href="https://la-cascade.io/articles/emmet-un-turbo-dans-votre-css/">Emmet, un turbo dans votre CSS</a>). Inutile de vanter à nouveau les mérites d'Emmet pour vous faciliter le travail. Cet article recense les <strong>raccourcis d'Emmet</strong> et rafraîchira notre mémoire !</em></p><p><em>Pour compléter cet article de Matt McFadyen, vous trouverez un article de Jordan Moore (Astuces Emmet) à la suite, à propos de quelques fonctionnalités d'Emmet moins connues</em>.</p><h2>Raccourcis Emmet</h2><p>(par <small>Matt McFadyen</small>)</p><p>Emmet est un plugin pour éditeurs de texte, utile pour accroître votre productivité grâce à de nombreux raccourcis vous épargnant la saisie de code répétitif et ennuyeux. J'utilise Emmet pour automatiser la création de listes, pour la numérotation incrémentée de classes, pour CSS etc. Voici quelques-uns des raccourcis les plus utiles, au cas où vous les auriez oubliés.</p><p>Dans les exemples qui suivent, la syntaxe en blanc correspond à Emmet, en tapant la touche tabulation on obtient la syntaxe colorée HTML.</p><h2>HTML</h2><h3>Utiliser &gt; pour ajouter un élément enfant (child)</h3><pre>//CSS
  li&gt;p
  &lt;li&gt;
    &lt;p&gt;/p&gt;
  &lt;/li&gt;
  ul&gt;li&gt;p
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;</pre><h3>Utiliser + pour ajouter un élément frère (sibling)</h3><pre>//CSS
  ul&gt;li&gt;p+a
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
      &lt;a href=""&gt;&lt;/a&gt;
    &lt;/li&gt;
  &lt;/ul&gt;</pre><h3>Utiliser * pour multiplier les éléments</h3><pre>//CSS
  ul&gt;li*3&gt;p+img
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
      &lt;img src="" alt=""&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
      &lt;img src="" alt=""&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
      &lt;img src="" alt=""&gt;
    &lt;/li&gt;
  &lt;/ul&gt;</pre><h3>Utiliser . pour ajouter un nom de classe</h3><pre>//CSS
  ul.wrapper
  &lt;ul class="wrapper"&gt;&lt;/ul&gt;
  .container
  &lt;div class="container"&gt;&lt;/div&gt;</pre><h3>Utiliser () pour grouper des éléments multiples</h3><pre>//CSS
  ul&gt;(header&gt;ul&gt;li*2&gt;a)+footer&gt;p
  &lt;ul&gt;
    &lt;header&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;a href=""&gt;&lt;/a&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;a href=""&gt;&lt;/a&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/header&gt;
    &lt;footer&gt;
      &lt;p&gt;&lt;/p&gt;
    &lt;/footer&gt;
  &lt;/ul&gt;</pre><p>ou encore :</p><pre>//CSS
  ul&gt;(li&gt;p+img+a)+li*2&gt;p+img
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
      &lt;img src="" alt=""&gt;
      &lt;a href=""&gt;&lt;/a&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
      &lt;img src="" alt=""&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;/p&gt;
      &lt;img src="" alt=""&gt;
    &lt;/li&gt;
  &lt;/ul&gt;</pre><h3>Utiliser {} pour insérer du texte dans un élément</h3><pre>  a{clique moi}
    &lt;a href=""&gt;clique moi&lt;/a&gt;
  p&gt;{Clique }+a{ici}+{ pour continuer}
    &lt;p&gt;Clique &lt;a href=""&gt;ici&lt;/a&gt; pour continuer&lt;/p&gt;</pre><h3>Ajouter une numérotation avec $</h3><pre>  ul&gt;li.item$*5
  &lt;ul&gt;
    &lt;li class="item1"&gt;&lt;/li&gt;
    &lt;li class="item2"&gt;&lt;/li&gt;
    &lt;li class="item3"&gt;&lt;/li&gt;
    &lt;li class="item4"&gt;&lt;/li&gt;
    &lt;li class="item5"&gt;&lt;/li&gt;
  &lt;/ul&gt;</pre><h3>Commencer la numérotation à X avec $@X</h3><pre>  ul&gt;li.item$@3*5
  &lt;ul&gt;
    &lt;li class="item3"&gt;&lt;/li&gt;
    &lt;li class="item4"&gt;&lt;/li&gt;
    &lt;li class="item5"&gt;&lt;/li&gt;
    &lt;li class="item6"&gt;&lt;/li&gt;
    &lt;li class="item7"&gt;&lt;/li&gt;
  &lt;/ul&gt;</pre><h3>Ordre décroissant avec $@-</h3><pre>  ul&gt;li.item$@-{pizza $@-}*5
  &lt;ul&gt;
    &lt;li class="item5"&gt;pizza 5&lt;/li&gt;
    &lt;li class="item4"&gt;pizza 4&lt;/li&gt;
    &lt;li class="item3"&gt;pizza 3&lt;/li&gt;
    &lt;li class="item2"&gt;pizza 2&lt;/li&gt;
    &lt;li class="item1"&gt;pizza 1&lt;/li&gt;
  &lt;/ul&gt;</pre><h3>Remonter d'un élément enfant avec ^</h3><pre>  div&gt;p&gt;em{hello}^a
  &lt;div&gt;
    &lt;p&gt;&lt;em&gt;hello&lt;/em&gt;&lt;/p&gt;
    &lt;a href=""&gt;&lt;/a&gt;
  &lt;/div&gt;</pre><h4>Ajouter un attribut avec [attr_name="valeur"]</h4><pre>  img[src="http://placage.com/300/300" alt="nicCage"]
  &lt;img src="http://placage.com/300/300" alt="nicCage"&gt;</pre><h4>En résumé</h4><pre>  div.list&gt;ul&gt;(li.item$&gt;p{paragraph $}
  +img[src="http://placage.com/300/300"])
  +li.item$@2*4&gt;p{paragraph $@2}
  +img[src="http://placage.com/$@1$$/$@5$$"]+a
  ^^^footer&gt;p{Place cage vrs placesheen}
  &lt;div class="list"&gt;
    &lt;ul&gt;
      &lt;li class="item1"&gt;
        &lt;p&gt;paragraph 1&lt;/p&gt;
        &lt;img src="http://placecage.com/300/300" alt=""&gt;
      &lt;/li&gt;
      &lt;li class="item2"&gt;
        &lt;p&gt;paragraph 2&lt;/p&gt;
        &lt;img src="http://placecage.com/105/505" alt=""&gt;
        &lt;a href=""&gt;&lt;/a&gt;
      &lt;/li&gt;
      &lt;li class="item3"&gt;
        &lt;p&gt;paragraph 3&lt;/p&gt;
        &lt;img src="http://placecage.com/202/606" alt=""&gt;
        &lt;a href=""&gt;&lt;/a&gt;
      &lt;/li&gt;
      &lt;li class="item4"&gt;
        &lt;p&gt;paragraph 4&lt;/p&gt;
        &lt;img src="http://placecage.com/303/707" alt=""&gt;
        &lt;a href=""&gt;&lt;/a&gt;
      &lt;/li&gt;
      &lt;li class="item5"&gt;
        &lt;p&gt;paragraph 5&lt;/p&gt;
        &lt;img src="http://placecage.com/404/808" alt=""&gt;
        &lt;a href=""&gt;&lt;/a&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
  &lt;footer&gt;
    &lt;p&gt;Place cage vrs placesheen&lt;/p&gt;
  &lt;/footer&gt;</pre><p>Le premier regroupement contient une <code>&lt;li&gt;</code> qui a deux éléments enfants : <code>&lt;p&gt;</code> qui contient du texte et <code>&lt;img&gt;</code> qui contient un attribut <code>src</code>.</p><p>Le regroupement suivant contient les <code>&lt;li&gt;</code> 2 à 5, en multipliant des listes dont les noms de classe, le contenu de paragraphe, les valeurs d'attributs <code>src</code> s'incrémentent selon diverses syntaxes. Chaque <code>&lt;li&gt;</code> contient également une ancre, invariable.</p><p>Enfin, nous utilisons 3 fois ^ de façon à sortir de <code>&lt;li&gt;</code>, puis de <code>&lt;ul&gt;</code>, puis de <code>&lt;div&gt;</code>, afin d'ajouter notre footer final.</p><h2>CSS</h2><p>Voici une liste de raccourcis courants :</p><figure><img src="https://la-cascade.io/images/em13-compressor.png" alt="" /></figure><p>N'oubliez pas que CodePen est compatible avec Emmet !</p><h2>Astuces Emmet</h2><p>(par <small>Jordan Moore</small>)<br /><em>NdT : Pour compléter ce petit rappel, voici un autre article, de</em> <strong>Jordan Moore</strong>, <em>sur quelques fonctionnalités mal connues d'Emmet, qui montrent sa puissance incroyable</em>.</p><h3>Calcul en ligne</h3><p>Emmet contient un calculateur intégré qui vous permet de résoudre des équations directement à l'intérieur de votre code. Je l'utilise quotidiennement pour convertir des valeurs <em>px</em> en <em>em</em>, en particulier pour les valeurs <em>em</em> imbriquées, simplement en tapant <code>Cmd</code> <code>Shift</code> <code>Y</code> sur une équation comme 24/16 (valeur souhaitée en pixels / valeur de base en pixels).</p><p>Vous pouvez enchaîner le calcul et les abréviations, par exemple en tapant <code>mb24/16</code> et en faisant <code>Cmd</code> <code>Shift</code> <code>Y</code>, puis tabulation, vous obtenez :</p><pre>margin-bottom: 1.5em;</pre><h3>Retrouver une balise</h3><p>Quelquefois lorsque j'écris mon HTML je cherche une balise fermante que je n'arrive pas à retrouver rapidement. En faisant <code>Ctrl</code> <code>Shift</code> <code>T</code> avec le curseur sur la balise ouvrante (ou fermante), je saute directement à la balise fermante (ou ouvrante) correspondante.</p><h3>Commentaires</h3><p>Pour éviter de me retrouver dans la situation précédente, je recommande d'insérer un commentaire sous vos balises fermantes. Mais écrire le nom de la classe d'un élément encore une fois, et l'intégrer dans les commentaires, est une perte de temps et d'énergie qui n'a de sens que si vous devez revoir votre code - c'est pourquoi on l'oublie souvent.</p><p>Emmet rend toutefois cette tâche extrêmement simple, en ajoutant juste un petit snippet à la fin d'une abréviation. Si vous tapez : <code>.container&gt;ul&gt;li*5&gt;a|c</code>, vous obtiendrez :</p><pre>&lt;div class="container"&gt;
    &lt;ul&gt;
        &lt;li&gt;&lt;a href=""&gt;&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=""&gt;&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=""&gt;&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=""&gt;&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=""&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;
&lt;!-- /.container --&gt;</pre><p>Bref, pour obtenir le commentaire (et tout le bénéfice qui vient avec), il vous a suffi d'écrire <code>|c</code>.</p><h3>Convertir une image en Data URI</h3><p>Une des fonctionnalités les moins utilisées d'Emmet est sa capacité à convertir les images en Data URI. L'utilisation de Data URI en lieu et place d'une image externe vous permet d'économiser une requête HTTP, ce qui améliore la performance de votre site en réduisant le temps de latence.</p><p>Pour convertir une image en Data URI, placez le curseur à l'intérieur de la balise image et faites <code>Ctrl</code> <code>Shift</code> <code>D</code>.</p><hr /><h3>Liens complémentaires</h3><p><a href="http://docs.emmet.io/css-abbreviations/">Documentation Emmet</a><br /><a href="http://docs.emmet.io/cheat-sheet/">Anti-sèche Emmet (syntaxe, HTML, CSS)</a><br /><a href="http://webdesign.tutsplus.com/tutorials/applications/build-bootstrap-in-minutes-using-emmet/">Bootstrap en quelques minutes avec Emmet</a> (en anglais)<br /><a href="http://www.grafikart.fr/tutoriels/sublime-text-2/emmet-376">tutoriel vidéo sur Emmet</a>, par Grafikart</p><p>Note sur les <strong>Raccourcis Emmet</strong> :<br />La première partie de cette traduction, l'article de Matt McFadyen, n'est plus disponible en ligne. Il a été traduit avec l'aimable autorisation de l'auteur.<br />Copyright Matt McFadyen © 2014.</p></div>]]></description>
      <link>https://la-cascade.io/articles/une-liste-de-raccourcis-emmet</link>
      <guid>https://la-cascade.io/articles/une-liste-de-raccourcis-emmet</guid>
      <pubDate>Mon, 28 Jul 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Créer des sphères en CSS]]></title>
      <description><![CDATA[<p><em>Nous aussi nous pouvons faire des bulles, grâce à Donovan Hutchinson, maître des sphères.</em></p><div class="articleContent"><p>J'ai parlé récemment de la création de triangles CSS qui utilisent les <code>border-radius</code> pour les angles. Essayons maintenant les sphères.</p><h2>Flat design</h2><p>Nous pouvons utiliser deux approches pour réaliser des sphères en CSS.</p><p>L'une d'elles consiste à créer une sphère en 3D, en utilisant de nombreux éléments. Il en existe de nombreux <a href="http://www.cssplay.co.uk/menu/cssplay-3D-sphere.html">exemples</a> <a href="http://codepen.io/peterwestendorp/pen/wGECk">remarquables</a>. L'inconvénient est qu'elles requièrent du navigateur l'affichage de nombreux éléments, ce qui peut avoir un impact sur la performance. Par ailleurs, elles ont souvent un aspect un peu brut, du fait que l'affichage d'une sphère lisse et parfaite ferait appel à encore plus d'éléments.</p><p>Je vais donc tenter une autre approche, en utilisant les dégradés CSS pour créer un effet 3D sur un élément simple.</p><h2>Démo et code source</h2><p>Tous les exemples qui suivent sont accessibles via <a href="http://codepen.io/donovanh/">mon compte CodePen</a>, ou en sélectionnant les liens “Edit on Codepen” de chaque exemple.</p><p>Dans les exemples de code, j'ai omis les préfixes constructeurs, mais je recommande l'utilisation d'un outil comme <a href="https://github.com/postcss/autoprefixer">Autoprefixer</a>, ou l'ajout manuel des préfixes.</p><h2>Forme de base</h2><p>Avant d'entrer dans les détails, nous allons créer un cercle, en commençant par le balisage HTML :</p><pre>&lt;figure class="circle"&gt;&lt;/figure&gt;</pre><p>Nous faisons appel à l'élément <code>figure</code> ici, mais on pourrait utiliser n'importe quel élément. <code>figure</code> est un élément utilisé en HTML pour représenter une image ou un diagramme faisant partie d'un contenu, mais dont la suppression n'aurait pas d'incidence sur la signification du contenu.</p><p>Pour créer un cercle à partir de cet élément, je vais lui donner une largeur et une hauteur, et un <code>border-radius</code> de 50%. Toute valeur supérieure à 50% aura pour résultat un coin parfaitement arrondi.</p><pre>//CSS
.circle {
 display: block;
 background: black;
 border-radius: 50%;
 height: 300px;
 width: 300px;
 margin: 0;
}</pre><p>Et voilà, un superbe disque :</p><p>Maintenant que nous avons notre cercle de base, nous pouvons commencer à lui ajouter quelques styles pour lui donner une allure sphérique.</p><h2>Ombrages, notions de base</h2><p>La première chose que les tutoriels de sphères en 3D vous montrent c'est l'ajout d'un dégradé radial simple, légèrement décalé vers le haut à gauche.</p><p>Nous pouvons le faire avec ce CSS :</p><pre>.circle {
 display: block;
 background: black;
 border-radius: 50%;
 height: 300px;
 width: 300px;
 margin: 0;
 background: radial-gradient(circle at 100px 100px, #5cabff, #000);
}</pre><p>Vous devriez obtenir ceci :</p><h3>Dégradés radiaux</h3><p>La propriété <a href="https://la-cascade.io/articles/les-degrades-css/#radial">dégradé radial</a> prend quelques arguments. Le premier est la position du point d'où partira le dégradé. La syntaxe est “<em>forme</em> at <em>position</em>”, soit dans notre exemple <code>circle at 100px 100px</code>, un cercle dont le point central est situé à 100px à partir de la gauche et 100px à partir du haut.</p><p>Ensuite, on spécifie une série de couleurs. Vous pouvez en spécifier plus de deux, mais dans ce cas il est nécessaire de préciser la position de chacune, afin que le dégradé sache où les couleurs se mélangent.</p><p>Dans notre exemple, nous n'utilisons que deux couleurs. Le navigateur supposera donc que la première est à 0% et la deuxième à 100%, et il réalisera un dégradé entre ces deux couleurs. Si nous voulions d'autres étapes dans le dégradé, nous pourrions spécifier les distances en pixels ou en pourcentages, comme nous le verrons tout à l'heure.</p><p>Bon, nous avons déjà quelque chose qui à une allure de 3D, ce n'est pas si mal mais essayons de faire mieux.</p><h2>Ombres &amp; 3D</h2><p>Selon les ombres que vous appliquez à votre surface, vous pouvez donner un aspect différent à vos sphères. Mais pour commencer, plantons un décor pour installer la nôtre.</p><p>Le HTML s'enrichit un peu :</p><pre>//HTML
&lt;section class=”stage”&gt;
 &lt;figure class=”ball”&gt;&lt;span class=”shadow”&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/section&gt;</pre><p>L'élément “ball” contient un <code>span</code> que nous allons utiliser pour créer une ombre, et il est enveloppé dans une <code>div</code> “stage”. Celle-ci nous servira a créer la perspective et à positionner l'ombre, pour obtenir un effet 3D.</p><p>Appliquons maintenant quelques styles à <em>stage</em> et positionnons notre ombre :</p><pre>//CSS
.stage {
 width: 300px;
 height: 300px;
 perspective: 1200px;
 perspective-origin: 50% 50%;
}
.ball .shadow {
 position: absolute;
 width: 100%;
 height: 100%;
 background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0) 50%);
 transform: rotateX(90deg) translateZ(-150px);
 z-index: -1;
}</pre><p>Je n'ai pas intégré les préfixes dans cet exemple, mais ceux de CodePen sont entièrement préfixés. Je donne à la div <em>stage</em> une perspective de 1200px. La propriété <code>perspective</code> est similaire au point de fuite en 3D.</p><p>L'ombre est ensuite placée sous la balle, on lui donne un dégradé puis on la positionne en utilisant <code>transform</code>. Les transformations CSS nous permettent de faire tourner des objets, de les agrandir, de les déplacer ou de les étirer dans un espace en 3D. Nous faisons tourner l'ombre de 90° sur l'axe des x, puis nous la déplaçons de 150px vers le bas pour la mettre sous la balle. Comme nous avons établi une perspective, nous la regardons légèrement de haut en bas et nous voyons une forme ovale étirée.</p><p>C'est un peu mieux maintenant. Ajoutons encore quelques ombres à la balle elle-même.</p><h2>Ombrages multiples</h2><p>Dans le monde réel, il est rare qu'un objet soit illuminé d'un seul côté. Les surfaces renvoient la lumière vers d'autres surfaces et l'objet est éclairé de plusieurs côtés à la fois. Pour donner plus de réalisme à notre balle, nous allons faire comme s'il y avait deux sources de lumière, en utilisant <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css/#pseudo-elements">un pseudo-élément</a> pour ajouter deux dégradés.</p><pre>.ball {
 display: inline-block;
 width: 100%;
 height: 100%;
 margin: 0;
 border-radius: 50%;
 position: relative;
 background: radial-gradient(circle at 50% 120%, #81e8f6, #76deef 10%, #055194 80%, #062745 100%);
}
.ball:before {
 content: “”;
 position: absolute;
 top: 1%;
 left: 5%;
 width: 90%;
 height: 90%;
 border-radius: 50%;
 background: radial-gradient(circle at 50% 0px, #ffffff, rgba(255, 255, 255, 0) 58%);
 filter: blur(5px);
 z-index: 2;
}</pre><p>Ici nous avons deux dégradés un peu plus complexes.</p><p>Le premier est un effet subtil de réflexion de lumière par le bas, et nous l'appliquons à l'élément <code>ball</code>. Le centre du dégradé est positionné à mi-chemin de la largeur de la balle, et à 120% de sa hauteur. Le centre est donc situé hors de la surface de la balle. Cela évite que la couleur finale, qui est nette, ne soit visible et cela nous donne un dégradé plus doux.</p><p>Le second dégradé est le reflet d'un éclairage placé sur le dessus. Il est réglé à 90% de la largeur de la balle et à 90% de sa hauteur. Il est centré au sommet et se dégrade jusqu'à disparaître à peu près à mi-hauteur de la balle.</p><p>J'ai utilisé <a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after/">le pseudo-élément <code>:before</code></a> plutôt que de créer un nouvel élément pour contenir l'ombrage.</p><p>Comme ce dégradé est assez cru, j'ai utilisé le filtres CSS <code>blur</code> pour adoucir la lumière. Actuellement <a href="https://la-cascade.io/articles/les-filtres-css/">cet effet</a> est disponible uniquement pour Chrome et Safari (webkit) mais il sera sans doute compatible avec d'autres navigateurs bientôt.</p><p>L'association de nos deux dégradés produit un effet bien plus intéressant :</p><h2>Plus brillant</h2><p>Notre effet est encore assez doux, nous allons lui ajouter un peu de brillant en créant quelque chose comme une boule de billard.</p><p>Pour réaliser cet effet, nous allons utiliser comme précédemment un reflet léger par en-dessous, mais nous allons ajuster la lumière du dessus, qui sera plus petite et plus précise. Nous allons devoir utiliser deux pseudo-éléments pour contenir la couleur de la boule, la lumière venue du dessous et le reflet.</p><pre>.ball {
 display: inline-block;
 width: 100%;
 height: 100%;
 margin: 0;
 border-radius: 50%;
 position: relative;
 background: radial-gradient(circle at 50% 120%, #323232, #0a0a0a 80%, #000000 100%);
}
.ball:before {
 content: “”;
 position: absolute;
 background: radial-gradient(circle at 50% 120%, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 70%);
 border-radius: 50%;
 bottom: 2.5%;
 left: 5%;
 opacity: 0.6;
 height: 100%;
 width: 90%;
 filter: blur(5px);
 z-index: 2;
}
.ball:after {
 content: “”;
 width: 100%;
 height: 100%;
 position: absolute;
 top: 5%;
 left: 10%;
 border-radius: 50%;
 background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8) 14%, rgba(255, 255, 255, 0) 24%);
 transform: translateX(-80px) translateY(-90px) skewX(-20deg);
 filter: blur(10px);
}</pre><p>Ici, nous avons appliqué la couleur initiale en subtil dégradé sur la boule elle-même (<code>.ball</code>).</p><p>Le pseudo-élément <code>:before</code> contient une lumière un peu plus claire, qui commence à la base de la boule et crée un effet de reflet venu de la surface sur laquelle elle repose.</p><p>La nouveauté ici est l'ajout du pseudo-élément <code>:after</code>. Il contient un dégradé radial qui part d'un blanc quasi opaque au centre et devient transparent à environ 24%. Cela crée un effet blanc brillant auquel, pour lui donner plus de réalisme, nous appliquons une transformation CSS.</p><p>La transformation consiste à déplacer le reflet vers la gauche de 80px et vers le haut de 90px et à étirer la forme. L'effet <code>skew</code> étire le cercle selon l'axe des x, pour qu'il ressemble à l'éclat qu'on verrait sur une boule.</p><h2>Boule n°8</h2><p>Et pendant que nous y sommes, ajoutons-lui le numéro 8.</p><p>Nous avons besoin d'un élément supplémentaire pour contenir le 8, et de quelques styles pour le placer sur la boule.</p><pre>//HTML
&lt;section class=”stage”&gt;
 &lt;figure class=”ball”&gt;
 &lt;span class=”shadow”&gt;&lt;/span&gt;
 &lt;span class=”eight”&gt;&lt;/span&gt;
 &lt;/figure&gt;
&lt;/section&gt;
//CSS
.ball .eight {
 width: 110px;
 height: 110px;
 margin: 30%;
 background: white;
 border-radius: 50%;
 transform: translateX(68px) translateY(-60px) skewX(15deg) skewY(2deg);
 position: absolute;
}
.ball .eight:before {
 content: “8";
 display: block;
 position: absolute;
 text-align: center;
 height: 80px;
 width: 100px;
 left: 50px;
 margin-left: -40px;
 top: 44px;
 margin-top: -40px;
 color: black;
 font-family: Arial;
 font-size: 90px;
 line-height: 104px;
}</pre><p>Nous utilisons à nouveau le <code>border-radius</code> de 50% pour créer un cercle, et ce cercle est ensuite positionné en haut à droite en utilisant la propriété <code>transform</code>. Plutôt que de mettre le chiffre 8 en contenu, j'utilise le pseudo-sélecteur pour ajouter le contenu via CSS, puis pour étirer le chiffre de la même manière que le cercle qui le contient.</p><p>Et voilà une boule n°8 éclatante.</p><h2>Je t'ai à l'oeil</h2><p>Un truc sympa avec les transformations CSS, c'est qu'on peut les animer. Grâce aux <code>keyframes</code> CSS, vous pouvez décrire une série de transformations formant une animation, et les appliquer à un élément. Pour le démontrer, je vais créer et animer un oeil.</p><p>Première étape, nous allons modifier les couleurs utilisées dans notre exemple précédent. Quelques petits ajustements et nous aurons notre oeil. Tout d'abord le HTML :</p><pre>&lt;section class=”stage”&gt;
 &lt;figure class=”ball”&gt;
 &lt;span class=”shadow”&gt;&lt;/span&gt;
 &lt;span class=”iris”&gt;&lt;/span&gt;
 &lt;/figure&gt;
&lt;/section&gt;</pre><p>Le CSS est similaire, pour l'essentiel, à notre boule de billard, à l'exception de l'iris et de la pupille.</p><pre>.iris {
 width: 40%;
 height: 40%;
 margin: 30%;
 border-radius: 50%;
 background: radial-gradient(circle at 50% 50%, #208ab4 0%, #6fbfff 30%, #4381b2 100%);
 transform: translateX(68px) translateY(-60px) skewX(15deg) skewY(2deg);
 position: absolute;
 animation: move-eye-skew 5s ease-out infinite;
}
.iris:before {
 content: “”;
 display: block;
 position: absolute;
 width: 37.5%;
 height: 37.5%;
 border-radius: 50%;
 top: 31.25%;
 left: 31.25%;
 background: black;
}
.iris:after {
 content: “”;
 display: block;
 position: absolute;
 width: 31.25%;
 height: 31.25%;
 border-radius: 50%;
 top: 18.75%;
 left: 18.75%;
 background: rgba(255, 255, 255, 0.2);
}</pre><p>Un dégradé bleu forme la partie colorée de l'iris, puis on crée la pupille et un reflet avec des pseudo-éléments. J'ai également ajouté la propriété <code>animation</code> à l'élément <code>.iris</code>. Pour attacher une animation à un élément, on utilise la syntaxe suivante :</p><pre>animation: animation-name 5s ease-out infinite;</pre><p>Dans cet exemple, on appliquerait une animation intitulée “animation-name”, qui aurait une durée de 5 secondes, tournerait en boucle indéfiniment, et aurait une valeur d'introduction/sortie (<em>easing</em>) de <code>ease-out</code>. <em>Ease-out</em> est le fait pour l'animation de ralentir lorsqu'elle arrive à la fin, ce qui crée un effet plus naturel. <em>NdT : Pour plus d'infos sur les animations et sur l'utilisation du timing, vous pouvez consulter <a href="http://www.alsacreations.com/tuto/lire/1299-timing-des-animations-et-des-transitions-en-css3.html">cet article</a> d'alsacréations ou <a href="http://letrainde13h37.fr/17/transitions-et-animations-css/">celui-ci</a> de Vincent de Oliveira</em>.</p><p>Tant que nous n'avons pas créé notre animation, notre oeil est bien statique.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/donovanh/pen/nwsqa/">Spheres tutorial: 5 Eyeball</a>de Donovan hutchinson dans<a href="https://codepen.io">CodePen</a></div><p>Créons quelques <code>keyframes</code> pour décrire la façon dont notre globe oculaire devrait se mouvoir.</p><pre>//CSS
@keyframes move-eye-skew {
 0% {
 transform: none;
 }
 20% {
 transform: translateX(-68px) translateY(30px) skewX(15deg) skewY(-10deg) scale(0.95);
 }
 25%, 44% {
 transform: none;
 }
 50%, 60% {
 transform: translateX(68px) translateY(-40px) skewX(5deg) skewY(2deg) scaleX(0.95);
 }
 66%, 100% {
 transform: none;
 }
}</pre><p>Les keyframes peuvent paraître un peu compliquées au début. Elles consistent à décrire l'état d'un élément au cours d'une série d'étapes. Chaque étape est exprimée par un pourcentage. Dans notre exemple, l'iris commencera sans aucune transformation appliquée. On est à 0%. Puis, à 20% de la durée de l'animation (la nôtre fait 5 secondes, donc la première étape se situe à 1 seconde), une transformation est appliquée : l'objet est déplacé et étiré vers la gauche. Comme il s'agit d'une animation, et non d'une suite d'états fixes, le navigateur calcule ce qui se passe entre ces deux points (0% et 20%) et crée une transition en douceur.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/donovanh/pen/iBolr/">Spheres tutorial: 5b Eyeball (animated)</a>de Donovan hutchinson dans<a href="https://codepen.io">CodePen</a></div><p>Il en va de même avec chaque <code>keyframes</code>, et l'animation tout entière dure 5 secondes.</p><h2>Bulles</h2><p>L'association des ombrages et des animations peut produire des effets intéressants. C'est l'été, on fait des bulles?</p><p>Pour fabriquer des bulles, on fait comme précédemment mais avec plus de transparence pour la couleur principale et deux pseudo-éléments pour ajouter la brillance.</p><p>J'ai créé un CodePen pour que vous voyiez le CSS :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/donovanh/pen/pvrzK/">Spheres tutorial: 6 Bubble (animated)</a>de Donovan hutchinson dans<a href="https://codepen.io">CodePen</a></div><p>L'animation utilise la valeur <code>scale</code> de <code>transform</code> pour faire se dandiner notre petite bulle.</p><pre>@keyframes bubble-anim {
 0% {
 transform: scale(1);
 }
 20% {
 transform: scaleY(0.95) scaleX(1.05);
 }
 48% {
 transform: scaleY(1.1) scaleX(0.9);
 }
 68% {
 transform: scaleY(0.98) scaleX(1.02);
 }
 80% {
 transform: scaleY(1.02) scaleX(0.98);
 }
 97%, 100% {
 transform: scale(1);
 }
}</pre><p>L'animation s'applique à la bulle tout entière et à ses pseudo-éléments.</p><h2>Utiliser des images</h2><p>Jusqu'à présent, nos sphères ont été créées sans recourir à des images. L'utilisation d'une image de background peut ajouter des détails, tout en permettant l'application des effets que nous avons vus grâce aux pseudo-éléments. Par exemple, nous pouvons prendre une balle de tennis <em>flat</em> et créer une illusion de profondeur avec des dégradés.</p><p>La texture <em>flat</em> :</p><figure role="group"><img src="https://la-cascade.io/images/flat2.png" width="300" height="300" alt="" /></figure><p>La sphère après ombrages :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/donovanh/pen/vsEIK/">Spheres tutorial: 7 Tennis ball</a>de Donovan hutchinson dans<a href="https://codepen.io">CodePen</a></div><br /><h2>Le tour du monde</h2><p>On peut aussi appliquer une animation à la position des images de background. Nous pouvons ainsi créer une mappemonde.</p><figure role="group"><img src="https://la-cascade.io/images/mappemonde.png" alt="image plate du monde" /></figure><p>Cette image plate a été légèrement étirée en haut et en bas pour être utilisée comme image de background.</p><p>Avec un peu d'ombrages et d'animations, nous pouvons créer un globe qui a des allures de 3D.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/donovanh/pen/GBIiv/">Globe</a>de Donovan hutchinson dans<a href="https://codepen.io">CodePen</a></div><p><em>NdT : Du même auteur, vous pouvez consulter</em> <a href="https://la-cascade.io/articles/portal-css/">Portal CSS</a> <em>sur La Cascade, une intro ludique aux transformations 3D et aux animations CSS</em>.</p></div>]]></description>
      <link>https://la-cascade.io/articles/creer-des-spheres-en-css</link>
      <guid>https://la-cascade.io/articles/creer-des-spheres-en-css</guid>
      <pubDate>Sun, 27 Jul 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Les filtres CSS]]></title>
      <description><![CDATA[<p><em>En été, il n'y a pas que les filtres solaires, c'est aussi le moment idéal pour se pencher sur une propriété qui peut être utile... par Paula Borowska.</em></p><div class="articleContent"><h2>Qu'est-ce que les filtres CSS ?</h2><p>Honnêtement, il y a des propriétés CSS stupéfiantes, et CSS filters en fait partie. Les filtres ont une capacité étonnante de transformer des images et des pages web tout entières. C'est incroyablement fort quand on y pense, alors même que certains navigateurs ne peuvent toujours pas traiter les <code>border-radius</code> ou les <code>@font-face</code> correctement.</p><h2>Comment utiliser les filtres CSS ?</h2><p>L'utilisation des filtres CSS est extrêmement simple, toutefois il faut noter que la syntaxe n'est pas tout à fait habituelle. De nombreuses valeurs prennent des paramètres, et pour de bonnes raisons. Prenons l'exemple d'une échelle de gris (grayscale) et de sa syntaxe.</p><pre>img {
        -webkit-filter: grayscale(50%);
}</pre><p>Tout d'abord, il y a un préfixe webkit. Puis la valeur est définie avec des parenthèses et un paramètre. À peu près tous les filtres CSS ont des paramètres, qui définissent la quantité de changement à appliquer. Dans l'exemple qui précède, l'image sera seulement transformée pour 50% en noir et blanc. Si l'on avait 100%, la transformation serait totale (voir l'exemple <code>grayscale</code> plus bas). Une bonne façon de comprendre la logique est de se dire “quel niveau de gris est-ce que je veux atteindre” ? En gros, quelle intensité du filtre est-ce que je veux appliquer.</p><h2>Les différents types de filtres</h2><p>Il existe de nombreux filtres, certains plus habituels que d'autres, certains plus utiles que d'autres aussi. Mais dans cet article, nous allons essayer d'en passer en revue le plus possible, pour vous donner une bonne idée des possibilités des filtres CSS. Notre image de démo aujourd'hui est cette magnifique photo de voiture que j'ai prise il y a peu...</p><figure><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Grayscale</h3><p>Je viens de mentionner grayscale. Il transforme une image en noir et blanc, selon un pourcentage qui va de 0% à 100% où 0% correspond à aucun filtre et 100% à un filtre total - il ne reste plus que du noir, du gris et du blanc.</p><pre>img { -webkit-filter: grayscale(100%); }
img { -webkit-filter: grayscale(50%); }</pre><figure class="c1"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c2"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Sepia</h3><p>Je ne sais pas si on applique encore beaucoup ce type d'effet, mais si vous le voulez, il est là. Son utilisation est identique à celle de grayscale.</p><pre>img { -webkit-filter: sepia(100%); }
img { -webkit-filter: sepia(50%); }</pre><figure class="c3"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c4"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Blur</h3><p>Le filtre <code>blur</code> (floutage) fonctionne d'une manière assez similaire au filtre Gaussien de Photoshop. Le nombre de pixels définit l'intensité du floutage, plus le nombre de pixels est grand, plus l'image sera floue.</p><pre>img { -webkit-filter: blur(5px); }
img { -webkit-filter: blur(50px); }</pre><figure class="c5"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c6"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Saturation</h3><p>Si vous connaissez <a href="https://99designs.fr/blog/conseils-design/la-theorie-des-couleurs/">la théorie des couleurs</a>, vous savez que la saturation définit l'intensité de la couleur. Contrairement aux filtres précédents, celui-ci n'a pas de limite, vous pouvez spécifier ce que vous voulez, par exemple 200% ou 2000%, plus le pourcentage sera élevé, plus la couleur sera vive. Entre 0% et 100%, la couleur devient plus terne, et à 100% l'image est inchangée.</p><pre>img { -webkit-filter: saturate(20%); }
img { -webkit-filter: saturate(200%); }
img { -webkit-filter: saturate(2000%); }</pre><figure class="c7"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c8"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c9"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Contrast</h3><p>Ce filtre fonctionne un peu comme la saturation, il n'y a pas de limite au pourcentage appliqué. Entre 0% et 100% vous choisissez un contraste faible, vous donne l'image inchangée et au-delà vous passez à un contraste fort.</p><pre>img { -webkit-filter: contrast(50%); }
img { -webkit-filter: contrast(500%); }</pre><figure class="c10"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c11"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Brightness</h3><p>Ce filtre est le dernier de cette série de trois. Il fonctionne comme <code>saturation</code> et <code>contrast</code>, entre 0% et 100% l'image est moins lumineuse, au-delà elle l'est plus, et la valeur par défaut est 100%.</p><pre>img { -webkit-filter: brightness(50%); }
img { -webkit-filter: brightness(500%); }</pre><figure class="c12"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c13"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Hue-rotation</h3><p>Celui-ci est intéressant, il prend la roue des couleurs (voir l'article <a href="https://la-cascade.io/articles/utiliser-hsl-pour-vos-couleurs">utiliser HSL</a>) et la fait tourner du nombre de degrés que vous indiquez, en modifiant chacune des couleurs en fonction. Les valeurs vont de 0° à 360°.</p><pre>img { -webkit-filter: hue-rotate(45deg); }
img { -webkit-filter: hue-rotate(120deg); }
img { -webkit-filter: hue-rotate(240deg); }</pre><figure class="c14"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c15"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><figure class="c16"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h3>Invert</h3><p>Comme son nom le suggère, ce filtre inverse les couleurs de l'image. Il fonctionne comme grayscale avec des valeurs comprises entre 0% et 100%. Il faut donc juste indiquer le niveau de l'effet que vous souhaitez appliquer à votre image.</p><pre>img { -webkit-filter: -webkit-filter: invert(100%); }</pre><figure class="c17"><img src="https://la-cascade.io/images/filter1-compressor.jpeg" alt="" /></figure><h2>Les limites des filtres CSS</h2><p> <em>NdT : Pour vérifier la compatibilité, il suffit comme toujours de consulter <a href="http://caniuse.com/css-filters">Can I Use</a>. À la date de traduction, IE est totalement incompatible, Firefox est partiellement compatible, mais la compatibilité de Chrome, Safari et Opera, y compris pour les versions mobiles, est excellente. Aujourd'hui elle est excellente chez tous</em>.</p><h3>Vitesse de chargement</h3><p>Deuxième point auquel il faut être attentif, le temps de chargement de votre page peut être affecté. Les filtres CSS peuvent être appliqués à de nombreux éléments, pas seulement aux images. Plus vous en ajoutez, plus votre site risque d'être ralenti - c'est compréhensible dans la mesure où la manipulation des éléments est plus complexe que les opérations habituelles de CSS.</p><h3>Utilité</h3><p>Dernier point, et au vu de ce qui précède, on peut se poser la question de savoir s'il ne vaut pas mieux ouvrir Photoshop et faire le travail en amont. Cela dit, la possibilité d'éditer les images dans le navigateur est géniale alors pourquoi pas ?</p><p> <em>NdT : Oui les filtres sont utiles : ils s'appliquent à toutes sortes d'images, y compris celles produites en CSS, où Photoshop ne vous sera d'aucun secours. Voyez l'article de Donovan Hutchinson sur la <a href="https://la-cascade.io/creer-des-spheres-en-css/">création de sphères en CSS</a> pour une utilisation (simple) du filtre CSS <code>blur</code>.</em></p><h3>Plus vous en savez</h3><p>Maintenant que vous savez de quoi il s'agit, j'espère que vous appréciez leurs capacités étonnantes. C'est un grand progrès en termes de ce que HTML, CSS et nos navigateurs peuvent faire pour nous.</p></div>]]></description>
      <link>https://la-cascade.io/articles/les-filtres-css</link>
      <guid>https://la-cascade.io/articles/les-filtres-css</guid>
      <pubDate>Sat, 26 Jul 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Les dégradés SVG]]></title>
      <description><![CDATA[<p><em>Les dégradés SVG permettent de remplir quasiment sans effort une forme complexe, et par rapport aux dégradés CSS ils présentent l'avantage d'être présents dans le DOM</em></p><div class="articleContent"><p>Pourquoi utiliser les dégradés SVG plutôt que les dégradés CSS, c'est une longue discussion, mais dans cet article nous nous allons simplement nous concentrer sur l'utilisation pratique des dégradés SVG, si vous choisissez cette solution. ( <em>NdT : si vous voulez plus d'information sur les dégradés CSS, vous pouvez consulter <a href="https://la-cascade.io/articles/les-degrades-css/">cet article</a>.)</em>.</p><p>Les dégradés <a href="https://la-cascade.io/tags/svg/">SVG</a> permettent de remplir quasiment sans effort une forme complexe, et par rapport aux dégradés CSS ils présentent l'avantage d'être présents dans le DOM. Cette approche est pratique en particulier quand un dégradé est une partie permanente de votre design. Nos styles CSS peuvent évoluer au fil du temps, mais le coeur de notre création artistique restera souvent inchangé, et du coup il est préférable que cette création réside dans le SVG lui-même, dans le DOM.</p><p>De plus, si vous décidez plus tard d'animer votre dégradé, vous pouvez ajouter cette animation directement dans l'élément SVG.</p><h2>Les bases</h2><p>SVG propose deux types de dégradés, linéaire et radial. Les détails <a href="https://developer.mozilla.org/fr/docs/Web/SVG/Element/defs">sont définis</a> à l'intérieur d'un élément <code>&lt;defs&gt;</code>. L'élément <code>&lt;defs&gt;</code> contient des instructions qui peuvent être réutilisées tout au long du document, mais qui ne donneront pas lieu à affichage tant qu'il n'est pas appelé. Le fait de définir les éléments du dégradé à l'intérieur d'un élément <code>&lt;defs&gt;</code> nous permet de mieux comprendre le contenu du SVG et offre une meilleure accessibilité.</p><p>SVG utilise la notion générale de <em>paint server</em> (“serveur de peinture”) qui est une méthode permettant au remplissage (<em>fill</em>) et au traçé (<em>stroke</em>) d'un objet d'être défini par une ressource disponible ailleurs. Les dégradés sont une des nombreuses options <em>paint</em> que l'on peut appeler pour remplir le background et les bordures de formes et de textes.</p><p>Pour illustrer cette notion, voici à quoi ressemblera la structure d'un dégradé linéaire simple :</p><pre>&lt;svg&gt;
    &lt;defs&gt;
        &lt;linearGradient id="gradientName"&gt;
            &lt;stop offset="&lt;%&gt;" stop-color="&lt;color&gt;" /&gt;
            &lt;stop offset="&lt;%&gt;" stop-color="&lt;color&gt;" /&gt;
        &lt;/linearGradient&gt;
    &lt;/defs&gt;
&lt;/svg&gt;</pre><p>Une fois que vous avez donné un ID à votre dégradé (dans notre exemple : <code>gradientName</code> ), il peut être appelé à travers les attributs <em>fill</em> et/ou <em>stroke</em> dans le SVG qui l'utilisera, par exemple en écrivant <code>fill= "url(#gradientName)"</code>.</p><h2>Les Dégradés linéaires</h2><p>Les dégradés linéaires passent d'une couleur à une autre de façon régulière le long d'une ligne. Le dégradé est défini par un axe et éventuellement par un angle.</p><p>Chaque <em>stop</em> défini sur cette ligne représentera la couleur à l'intérieur de l'élément <code>&lt;linearGradient&gt;</code>. À chaque <em>stop</em> la couleur est à 100% de saturation et l'espace entre deux stops est le lieu où s'effectue la transition d'une couleur à la suivante. Il est possible d'utiliser des couleurs supplémentaires, comme nous le verrons tout à l'heure.</p><p>Regardons à quoi ressemble le code SVG pour un dégradé linéaire simple, comportant deux stops couleur, puis nous passerons en revue les options d'attributs disponibles.</p><figure><img itemprop="image" src="https://la-cascade.io/images/simplegradient.webp" alt="un dégradé simple, de bleu à rouge" /></figure><pre>&lt;svg&gt;
    &lt;defs&gt;
        &lt;linearGradient id="Gradient-1"
             x1="0" y1="0" x2="100%" y2="0"&gt;
            &lt;stop offset="0%" stop-color="lightblue" /&gt;
            &lt;stop offset="100%" stop-color="#ef5b2b" /&gt;
        &lt;/linearGradient&gt;
    &lt;/defs&gt;
    &lt;rect x="450" y="10" width="200" height="100" fill= "url(#Gradient-1)" stroke="#333333" stroke-width="4px" /&gt;
&lt;/svg&gt;</pre><h3>Attributs des dégradés linéaires</h3><p>Comme nous l'avons vu, les détails du dégradé sont définis à l'intérieur d'un élément <code>&lt;linearGradient&gt;</code>. À l'intérieur de celui-ci, nous pouvons utiliser tout un tas d'attributs pour le personnaliser.</p><h4>ID</h4><p>Les dégradés doivent avoir un ID unique de façon à pouvoir être appliqués à nos formes ou textes SVG.</p><h4>x1, y1, x2, y2</h4><p>Les valeurs d'attributs x1, y1, x2 et y2 représentent les points de départ et d'arrivée qui définissent les stops (les changements de couleurs). Ces pourcentages s'appliquent sur l'axe choisi. S'ils ne sont pas spécifiés, toutes les valeurs seront égales à 0 par défaut, sauf x2 qui prendra la valeur 100% par défaut.</p><p>Ce sont aussi ces valeurs qui définiront si notre axe est horizontal ou vertical, ou quelque part entre les deux. Par exemple une valeur y de 100% et une valeur x de 0 produiront un axe horizontal, et l'inverse donnera un axe vertical. Si les deux ont une valeur de 100% (ou n'importe quelle valeur différente de 0), l'axe sera oblique.</p><h4>gradientUnits</h4><p>L'attribut gradientUnits définit le système de coordonnées pour les valeurs x1, x2, y1 et y2. Les deux options possibles sont "userSpaceOnUse" ou "objectBoundingBox". <code>userSpaceOnUse</code> définit le système de coordonnées en unités absolues, alors que <code>objectBoundingBox</code> établit ce système à l'intérieur des limites de la forme SVG elle-même. Par défaut, la valeur de l'attribut est <code>objectBoundingBox</code>.</p><h4>spreadMethod</h4><p>La valeur de l'attribut <code>spreadMethod</code> spécifie la façon dont le dégradé va se répandre à travers la forme, s'il commence ou se termine à l'intérieur des limites du SVG. En gros, si le dégradé est défini d'une façon telle qu'il ne remplit pas toute la forme, qu'advient-il de l'espace vide ? Il y a trois options ici : <code>pad</code>, <code>repeat</code> ou <code>reflect</code>.</p><p>Une valeur de <code>pad</code> indique que la première et la dernière couleur du dégradé doivent couvrir le reste de la forme (voir l'exemple ci-dessous). Une valeur <code>repeat</code> indique que le dégradé doit répéter le motif depuis le début jusqu'à couvrir toute la surface. L'utilisation de <code>reflect</code> aura pour résultat de faire se refléter de manière continue le motif de dégradé, du début à la fin et de la fin au début, jusqu'à couvrir toute la forme (voir l'exemple ci-dessous).</p><p>Sans autre indication, la valeur par défaut est <code>pad</code>.</p><figure><img src="https://la-cascade.io/images/svggradient2-compressor.png" alt="les trois effets spreadmethod" /></figure><p>L'image ci-dessus montre comment les différentes valeurs de <code>spreadMethod</code> impactent visuellement <em>le même dégradé</em>. Il est important de se rappeler que ces valeurs d'attribut n'auraient aucun effet sur un dégradé remplissant déjà l'intégralité de la forme.</p><p>Les points de départ et d'arrivée du dégradé ci-dessus sont (voir le code complet plus bas) :</p><pre>x1="20%" y1="30%" x2="40%" y2="80%"</pre><h4>gradientTransform</h4><p>L'attribut <code>gradientTransform</code> est optionnel, il nous permet de transformer plus encore le dégradé avant de l'appliquer, comme avec CSS Transforms.</p><h4>xlink:href</h4><p>Avec cet attribut, vous pouvez appeler l'ID d'un autre dégradé, duquel le dégradé en cours devrait "hériter". Dans les images ci-dessus, il y a trois rectangles. Ces rectangles appellent tous les mêmes stops couleurs mais ils appellent également des valeurs <code>spreadMethod</code> qui résident dans un ID spécial à l'intérieur d'élément <code>&lt;linearGradient&gt;</code> additionnels.</p><p>Voici le code pour ces éléments :</p><pre>&lt;defs&gt;
    &lt;linearGradient id="Gradient-1"
    x1="20%" y1="30%" x2="40%" y2="80%"&gt;
        &lt;stop offset="0%" stop-color= "#1cb98f" /&gt;
        &lt;stop offset="50%" stop-color= "#f99450" /&gt;
        &lt;stop offset="100%" stop-color= "#876fc3" /&gt;
    &lt;/linearGradient&gt;
    &lt;linearGradient id="pad"
                    xlink:href="#Gradient-1"
                    spreadMethod="pad" /&gt;
    &lt;linearGradient id="repeat"
                    xlink:href="#Gradient-1"
                    spreadMethod="repeat" /&gt;
    &lt;linearGradient id="reflect"
                    xlink:href="#Gradient-1"
                    spreadMethod="reflect" /&gt;
&lt;/defs&gt;</pre><p>Chaque rectangle appelle un ID spécifique décrivant une <code>spreadMethod</code> différente à chaque fois, mais ils héritent tous des stops couleur définis dans "#Gradient-1".</p><p>Voici comment ces dégradés sont appelés à l'intérieur de trois rectangles :</p><pre>&lt;rect x="10" y="10"
      width="200" height="100"
      fill= "url(#pad)"
      stroke="#333333"
      stroke-width="4px" /&gt;
&lt;rect x="230" y="10"
      width="200" height="100"
      fill= "url(#repeat)"
      stroke="#333333"
      stroke-width="4px" /&gt;
&lt;rect x="450" y="10"
      width="200" height="100"
      fill= "url(#reflect)"
      stroke="#333333"
      stroke-width="4px" /&gt;</pre><p> NdT : <a href="https://www.w3.org/TR/SVG2/">SVG 2</a> a supprimé le besoin de l'espace de nom <code>xlink</code>, donc au lieu de xlink:href vous devriez utiliser <code>href</code>. Si vous devez prendre en charge des versions antérieures du navigateur, l'attribut xlink:href déprécié peut être utilisé comme solution de repli en plus de l'attribut href, e.g. .</p><h3>Les stops</h3><p>Maintenant que nous comprenons les bases des attributs de <code>&lt;linearGradient&gt;</code>, nous pouvons passer aux attributs de <code>&lt;stop&gt;</code> que nous avons aperçus dans l'exemple de code précédent.</p><p>Comme on l'a vu, les stops couleur sont définis à l'intérieur de l'élément <code>&lt;linearGradient&gt;</code>. Quelle couleur voulons-nous voir à un certain endroit ? Nous disposons de trois attributs ici : <em>offset</em>, <em>stop-color</em> et <em>stop-opacity</em>. L'<em>offset</em> indique à quel endroit fixer le stop couleur. Le <em>stop-color</em> définit la couleur. Vous pouvez également inclure une valeur <em>stop-opacity</em> qui appliquerait une opacité sur la couleur située au point stop.</p><pre>&lt;defs&gt;
    &lt;linearGradient id="Gradient-2"&gt;
        &lt;stop offset="0%"
              stop-color="purple"
              stop-opacity=".3" /&gt;
        &lt;stop offset="100%"
              stop-color="blue"
              stop-opacity=".5" /&gt;
    &lt;/linearGradient&gt;
&lt;/defs&gt;</pre><p>Le dégradé est maintenant complété et peut être appelé sur les attributs <em>fill</em> ou <em>stroke</em> dans l'élément SVG, à partir de son ID, par exemple en faisant <code>fill= "url(#Gradient-2)"</code>.</p><h3>Autres exemples de dégradés linéaires</h3><p>Voici quelques démos qui mettent en action toutes ces notions.</p><p>Pour la démo sur le texte “Apple” il y a un élément <code>&lt;text&gt;</code> à l'intérieur de notre élément <code>&lt;svg&gt;</code>. Les définitions de dégradés sont situées dans un élément <code>&lt;defs&gt;</code> qui se trouve aussi à l'intérieur de <code>&lt;svg&gt;</code> (cliquez sur HTML, CSS et Result pour voir les détails).</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/SitePoint/pen/nCeiJ/">SVG Linear Gradient Example</a>by SitePoint<a href="https://codepen.io">CodePen</a></div><p>Pour avoir une autre perspective, regardons ces quelques icônes dans la démo qui suit. Chaque fruit SVG a sa propre définition de <code>&lt;linearGradient&gt;</code>. Les remplissages et les traits peuvent être constitués des mêmes dégradés ou de dégradés différents, ou peuvent être une couleur solide...</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/SitePoint/pen/Kmhpd/">SVG Linear Gradient Icons</a>by SitePoint<a href="https://codepen.io">CodePen</a></div><h2>Les dégradés radiaux</h2><p>Les dégradés radiaux sont à la fois très similaires et très différents des dégradés linéaires. Le dégradé, au lieu de se propager sur une ligne suit une expansion concentrique. Les stops commencent au centre du cercle et suivent le mouvement d'expansion.</p><h3>Attributs des dégradés radiaux</h3><p>La plupart des attributs sont les mêmes que ceux que nous avons vus, sauf le système de coordonnées qui est différent.</p><h4>cx, cy, r</h4><p>Les attributs cx, cy, r définissent le plus grand cercle (c'est à dire le plus externe) pour le dégradé radial. Le dégradé sera dessiné de telle façon que la limite de dégradé de 100% corresponde au périmètre de ce plus grand cercle. Si non spécifiées, les valeurs sont par défaut 50%. cx et cy sont les coordonnées du centre, r représente le rayon, en d'autres termes la longueur du dégradé. Une valeur r égale à 0 donnera une couleur unique jusqu'au dernier stop couleur.</p><h4>fx, fy</h4><p>Ces attributs représentent les coordonnées du foyer du dégradé, le cercle situé le plus à l'intérieur. Le dégradé sera dessiné de telle manière que la limite de dégradé de 0% corresponde au point (fx,fy). Si l'attribut fx n'est pas spécifié, la valeur de fx coïncidera avec celle de cx.</p><p>La démo ci-dessous montre un dégradé radial à l'intérieur d'un texte SVG. Ce premier exemple a un foyer de <code>fx= "45%" fy= "45%"</code>.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/SitePoint/pen/ECbAa/">SVG Radial Gradient example</a>de SitePoint dans<a href="https://codepen.io">CodePen</a></div><p>L'exemple suivant a un foyer de <code>fx="90%" fy="70%"</code> :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/SitePoint/pen/yeLnJ/">SVG Radial Gradient with different focal point</a>de SitePoint dans<a href="https://codepen.io">CodePen</a></div><p>Le foyer (un bleu-vert) s'est déplacé vers la droite. Pour rééquilibrer la répartition des stops, nous pourrions changer les valeurs de cx et cy.</p><h3>Exemple de dégradé radial</h3><p>Voici à nouveau les icônes repésentant des fruits, cette fois-ci avec des dégradés radiaux.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/SitePoint/pen/KDdlo/">Icons with Various SVG Radial Gradients</a>de SitePoint dans<a href="https://codepen.io">CodePen</a></div><h2>Compatibilité navigateurs</h2><p>La compatibilité navigateurs de SVG est excellente, aussi bien pour les ordinateurs de bureau que pour les appareils mobiles.</p><p>Toutefois, Firefox et Safari semblent avoir des problèmes avec <code>spreadMethod</code> qui n'est pas réglée par défaut sur la valeur <code>pad</code>. Pour éviter cela, il suffit de faire en sorte que votre dégradé remplisse entièrement la forme, sauf évidemment si votre intention est d'avoir un remplissage partiel.</p><hr /><h3>Ressources complémentaires en anglais</h3><ul><li><a href="http://www.w3.org/TR/SVG/pservers.html">Gradients and patterns SVG 1.1</a>, 2e édition de la spécification.</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient">linearGradient</a>, par Mozilla</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient">radialGradient</a>, par Mozilla</li>
</ul><h3>Ressources complémentaires en français</h3><ul><li><a href="http://www.yoyodesign.org/doc/w3c/svg1/pservers.html">Les dégradés et les motifs SVG 1.0</a>, par yoyodesign, la spécification complète (et assez claire et concise pour une fois)</li>
<li><a href="http://svground.fr/degrades.php">Les dégradés de couleur</a>, par SVGround, la bible du SVG</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/les-degrades-svg</link>
      <guid>https://la-cascade.io/articles/les-degrades-svg</guid>
      <pubDate>Fri, 06 Jun 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Subtilités de CSS3 Transitions]]></title>
      <description><![CDATA[<p><em>Louis Lazaris montre quelques utilisations inattendues des transitions CSS3 et un piège à éviter. Animez vos pages en pur CSS.</em></p><div class="articleContent"><p><em>Cet article est la réunion de deux articles de Louis Lazaris sur les transitions CSS3</em>.</p><p>La façon la plus courante d'utiliser les transitions CSS3 est en association avec la pseudo-classe <code>:hover</code>.</p><p>Voici une transition typique, en pur CSS, qui modifie la couleur d'un lien lorsqu'on passe la souris :</p><pre>a, a:link, a:visited {
    color: lightblue;
    transition: color .4s linear;
}
a:hover {
    color: white;
}</pre><p>On anime la propriété <code>color</code> quand on passe la souris sur un lien, c'est très simple et vous l'avez sans doute déjà vu ou utilisé. Mais l'utilisation des transitions n'est pas limitée à <code>:hover</code>.</p><p>Vous pouvez animer les propriétés CSS grâce à des transitions qui utilisent d'autres techniques CSS, dont voici quelques-unes.</p><h2>Transition avec :active</h2><p>La pseudo-classe <code>:active</code> cible <a href="http://reference.sitepoint.com/css/pseudoclass-active">tout élément qui est en cours d'activation</a>. La façon la plus simple d'activer un élément est de cliquer dessus, c'est le <em>mouse down</em>.</p><p>Le CSS qui suit et la démo qui l'accompagne montrent l'utilisation de <code>:active</code> avec une transition CSS3 qui imitent un événement <code>mousedown</code> :</p><pre>.box {
    width: 300px;
    height: 300px;
    background: #222;
    transition: width 2s ease, height 2s ease;
}
.box:active {
    width: 500px;
    height: 500px;
}</pre><p>Avec ce code, la largeur et la hauteur de la boîte sont animées lorsque vous maintenez le bouton de votre souris enfoncé. Lorsque vous relâchez le bouton, la boîte s'anime pour revenir à ses dimensions d'origine. Voici <a href="http://www.impressivewebs.com/demo-files/transition-active/">la démo</a>.</p><h2>Transition avec :focus</h2><p>Vous pouvez utiliser la pseudo-classe <code>:focus</code> pour réaliser une animation similaire. Cette fois-ci, nous allons utiliser un formulaire dans lequel nous animerons la largeur de tout élément qui reçoit le focus :</p><pre>input, textarea {
    width: 280px;
    transition: width 1s ease;
}
input:focus, textarea:focus {
    width: 340px;
}</pre><p>Et voici <a href="http://www.impressivewebs.com/demo-files/transition-focus/">la démo</a>.</p><h2>Transition avec :checked</h2><p>Vous pouvez animer des checkboxes et des boutons radio lorsqu'ils sont “checkés” - même si l'impossibilité de changer réellement leur style impose des limitations.</p><p>Nous changerons simplement la largeur, comme si nous appliquions une indentation à la checkbox sélectionnée :</p><pre>input[type="checkbox"]:checked {
    height: 20px;
    transition: width 1s ease;
}
input[type="checkbox"]:checked {
    width: 30px;
}</pre><p>Et voici <a href="http://www.impressivewebs.com/demo-files/transition-checked/">la démo</a>.</p><h2>Transition avec :disabled</h2><p>Continuons avec nos formulaires, cette fois nous allons mélanger des transitions CSS3 et un peu de jQuery pour animer la couleur de background d'éléments du formulaire à chaque fois qu'ils sont désactivés via l'attribut <code>disabled</code> :</p><pre>input[type="text"], textarea {
    background: #e2e2e2;
    transition: background 1s ease;
}
input:disabled, textarea:disabled {
    background: #666666;
}</pre><p>Et le jQuery, vite fait, qui ajoute/supprime l'attribut <code>disabled</code> :</p><pre>$(function() {
    $('input[type="radio"]').click(function() {
        if ($(':checked').val() === "other") {
            $('input[type="text"]').removeAttr("disabled");
        } else {
            $('input[type="text"]').attr("disabled", "disabled");
        }
    });
});</pre><p>Lorsque le dernier bouton radio est sélectionné (celui qui a une valeur de <code>other</code>), l'attribut de la boîte de texte est supprimé (<code>removeAttr</code>). Si une autre option est sélectionnée, l'attribut <code>disabled</code> est ajouté à nouveau au dernier bouton.</p><p>La pseudo-classe <code>:disabled</code> dépend de l'existence de cet attribut, donc l'animation ne se produira que lorsque l'attribut est ajouté ou supprimé. Voici <a href="http://www.impressivewebs.com/demo-files/transition-disabled/">la démo</a>.</p><h2>Transitions avec les media queries</h2><p>Cette dernière animation est sans doute la moins susceptible d'être utilisée en pratique, parce que les seuls à modifier la taille de la fenêtre pour voir ce qui se passe sont les développeurs web.</p><p>Cela dit, c'est une autre façon d'utiliser les animations CSS3. La page d'accueil de <a href="http://modernizr.com">Modernizr</a> s'en sert.</p><p>Voici le code :</p><pre>.box {
    width: 440px;
    height: 440px;
    background: #222;
    margin: 0 auto;
    transition: width 2s ease, height 2s ease;
}
@media only screen and (max-width : 960px) {
    .box {
        width: 300px;
        height: 300px;
    }
}</pre><p>Dans cet exemple nous animons deux propriétés différentes simultanément, en séparant les deux par une virgule. Le media query diminue la taille de la boîte lorsque la largeur de l'écran est inférieure à 961px. Vous pouvez modifier la largeur de votre écran pour voir <a href="http://www.impressivewebs.com/demo-files/transition-media-queries/">la démo en action</a>.</p><h2>Un piège à éviter</h2><p>Comme on vient de le voir, les transitions peuvent être déclenchées de multiples façons, et même via JavaScript. La transition en elle-même ne dépend d'aucun événement. Bien que ce soit l'événement qui déclenche la transition, elle en est totalement indépendante (comme il se doit dans une bonne séparation présentation / comportement).</p><p>C'est pourquoi vous remarquerez un comportement inattendu si vous placez la transition dans la partie de votre CSS qui déclenche l'événement.</p><p>En voici une illustration avec cette transition simple qui utilise la pseudo-classe <code>:hover</code> :</p><pre>a:link, a:visited {
    font-size: 40px;
    transition: font-size 1s ease;
}
a:hover {
    font-size: 100px;
}</pre><p>Vous pouvez voir l'effet dans <a href="http://jsbin.com/aweruj/334/edit">cette démo</a>. Très simple, non ? Vous passez le curseur sur le lien, et la <code>font-size</code> s'anime (transitionne) de 40px à 100px. Vous sortez du lien, et elle transitionne de 100px à 40px.</p><p>Essayons maintenant ceci :</p><pre>a:link, a:visited {
    font-size: 40px;
}
a:hover {
    font-size: 100px;
    transition: font-size 1s ease;
}</pre><p>Qu'y a-t-il de différent ? Eh bien au lieu de mettre la propriété transition sur l'état naturel du lien, je l'ai mise sur son état hover. Et le résultat ? Vous l'avez sans doute deviné, mais voici <a href="http://jsbin.com/umaliy/46/edit">la démo</a>. La transition étant maintenant sur l'état hover, elle ne se produit que sur cet état, c'est à dire lorsque hover se produit. Quand vous sortez du lien (c'est à dire quand vous revenez à l'état naturel du lien), la propriété change instantanément de 100px à 40px, comme s'il n'y avait pas de transition, ce qui est le cas.</p><p>Ce n'est pas grand chose, mais il faut le garder à l'esprit si vous placez vos transitions sur l'état de l'événement plutôt que sur l'état naturel de l'élément. Dans certains cas, ça peut être l'effet souhaité, comme nous allons le voir maintenant.</p><h2>Un cas d'utilisation</h2><p>On pourrait imaginer que la transition sur hover soit beaucoup plus longue que la transition sur la sortie du hover, voici ce que ça pourrait donner :</p><pre>a:link, a:visited {
    font-size: 40px;
    transition: font-size 1s ease;
}
a:hover {
    font-size: 100px;
    transition: font-size 3s ease;
}</pre><p>Et <a href="http://jsbin.com/itihoc/70/edit">la démo</a>. Dans cet exemple, la transition sur hover dure trois secondes alors que la sortie ne dure qu'une seconde (changement de la partie transition-duration de la notation raccourcie). Ça peut être pratique dans les situations où vous souhaitez que la partie déclenchée par l'utilisateur se déroule d'une certaine façon alors que le “retour à la normale” peut se faire rapidement.</p></div>]]></description>
      <link>https://la-cascade.io/articles/subtilites-de-css3-transitions</link>
      <guid>https://la-cascade.io/articles/subtilites-de-css3-transitions</guid>
      <pubDate>Fri, 30 May 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Shapes, une introduction]]></title>
      <description><![CDATA[<p><em>L'article de Sara Soueidan paru dans A List Apart a fait le buzz dernièrement. Sara présente ici très clairement ce qui sera l'avenir des formes et du design dans CSS.</em></p><div class="articleContent"><p>Des rectangles dans des rectangles, telle est depuis toujours la structure de nos pages web. Depuis longtemps, nous tentons de nous libérer de leurs limitations en utilisant CSS pour <a href="https://la-cascade.io/articles/creer-des-formes-en-css">créer des formes géométriques</a>, mais ces formes n'ont jamais affecté le contenu situé à l'intérieur des éléments, ni la façon dont ces éléments affectent les autres éléments de la page.</p><p>La nouvelle spécification CSS Shapes change tout cela. Proposée par <a href="https://blog.adobe.com/webplatform/category/features/css-shapes/">Adobe</a> à la mi-2012, elle vise à fournir aux designers web une nouvelle façon de modifier le flux du contenu, à l'intérieur et autour de formes arbitrairement complexes - ce que nous n'avons jamais pu réaliser auparavant, pas même avec Javascript.</p><p>Dans l'image qui suit par exemple, remarquez comment le texte entoure les images circulaires. Sans Shapes, le texte serait rectangulaire, détruisant la touche sophistiquée qui élève son design à un niveau supérieur.</p><p>Notez comment le texte suit la forme du bol dans cet exemple. Avec CSS Shapes, nous pouvons créer le même genre d'effets pour le web.</p><figure role="group"><img src="https://la-cascade.io/images/shape-outside-example.webp" alt="Image d'une mise en page de magazine avec du texte qui s'enroule autour d'images circulaires." /></figure><p>Regardons maintenant la façon dont fonctionne Shapes, et comment vous pourrez l'utiliser.</p><h2>Compatibilité navigateurs</h2><p>Pour l'instant, CSS Shapes est supporté par Webkit Nightly et par Chrome Canary, mais le module niveau 1 en est au statut de Recommandation, donc les propriétés et la syntaxe définies dans les spécifications sont stables et devraient être mises en oeuvre d'ici peu par les autres navigateurs. (NdT: <em><a href="https://caniuse.com/css-shapes">La compatibilité est excellente</a> depuis longtemps</em>) Ce niveau se concentre sur les propriétés qui modifient le flux du contenu autour d'une forme, et plus précisément sur la propriété shape-outside et celles qui lui sont associées.</p><p>Combinées avec d'autres fonctions de pointe telles que les masques (<a href="https://www.w3.org/TR/css-masking/">Clipping et Masking</a>), les <a href="https://www.w3.org/TR/filter-effects-1/">filtres CSS</a>, et la composition d'images (<a href="https://drafts.fxtf.org/compositing-1/">Compositing et Blending</a>), CSS Shapes va nous permettre de créer des design plus soignés et sophistiqués sans avoir à passer par des éditeurs graphiques comme Photoshop ou InDesign.</p><p>Les prochains niveaux de CSS Shapes concerneront l'insertion d'un contenu à l'intérieur d'une forme. Par exemple, aujourd'hui il est facile de créer un losange en CSS : il suffit d'appliquer à notre élément une rotation de 45° puis une rotation inverse au contenu situé à l'intérieur, de façon à ce qu'il retrouve son alignement horizontal sur la page. Cependant, le contenu ne sera pas affecté par la forme de son contenant et il restera rectangulaire. Lorsque la propriété <code>shape-inside</code> de CSS Shapes sera mise en oeuvre, le contenu pourra épouser la forme de son contenant, et nous aurons des design qui ressembleront à celui-ci.</p><figure role="group"><img src="https://la-cascade.io/images/rhombic.webp" alt="" /><figcaption>Bientôt, CSS Shapes permettra au texte situé à l'intérieur de formes telles que ces losanges, de s'ajuster aux limites de son contenant, au lieu de déborder ou d'être tronqué.</figcaption></figure><p>Pour utiliser CSS Shapes dans Chrome Canary, il vous faudra activer le flag "fonctions expérimentales". Si vous n'êtes pas sûr de la marche à suivre, vous pouvez consulter cet article sur le blog d'Adobe.</p><h2>Créer une forme avec CSS Shapes</h2><p>Pour appliquer une forme à un élément, on utilise une des propriétés de Shapes et on lui passe une valeur qui est une fonction. C'est dans cette fonction que vous passerez les arguments définissant la forme que vous voulez donner à votre élément.</p><p>Successivement : la propriété, la valeur (qui est une fonction), les paramètres de la fonction</p><figure role="group"><img src="https://la-cascade.io/images/shape-rule.webp" alt="" /></figure><p>Les formes seront créées en utilisant l'une des fonctions suivantes :</p><ul><li><code>circle()</code></li>
<li><code>ellipse()</code></li>
<li><code>inset()</code></li>
<li><code>polygon()</code></li>
</ul><p>Chaque forme est définie par un ensemble de points. Certaines fonctions utilisent les points comme paramètres, d'autres utilisent des paramètres relatifs, mais toutes finissent par dessiner une forme comme un ensemble de points. Nous entrerons dans le détail des paramètres de chaque fonction dans les exemples qui suivent.</p><p>Une forme peut également être définie en l'extrayant d'une image, par un canal alpha. Lorsqu'on passe une image comme valeur d'une propriété Shapes, le navigateur extrait la forme de l'image à partir de shape-image-threshold (seuil), comme nous le verrons tout à l'heure. La forme est définie par les pixels dont la valeur est supérieure au seuil. L'image doit être <a href="https://caniuse.com/cors">compatible CORS</a> (Cross-Origin Resource Sharing). Si l'image ne peut pas être affichée (par exemple si elle n'existe pas), aucune forme ne sera appliquée.</p><p>Les propriétés Shapes qui acceptent pour valeur ces fonctions sont :</p><ul><li><code>shape-outside</code>: Le contenu extérieur s'adapte à la forme</li>
<li><code>shape-inside</code> : Le contenu intérieur s'adapte à la forme</li>
</ul><p>Vous pouvez utiliser la propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/shape-outside"><code>shape-outside</code></a> avec la propriété <code>shape-margin</code> pour ajouter une marge autour de la forme afin de créer plus d'espace entre elle et le contenu. De la même façon, <code>shape-inside</code> fonctionne avec une propriété complémentaire <code>shape-padding</code> qui ajoute un padding à l'intérieur.</p><p>Déclarer une forme sur un élément peut se faire en une seule ligne de CSS :</p><pre class="language-css">.element {
  shape-outside: circle(
  ); /* le contenu s'enroulera autour du cercle défini sur l'élément */
}</pre><p>ou bien :</p><pre class="language-css">.element {
  shape-outside: url(chemin/vers/image-avec-forme.png);
}</pre><p>mais...</p><p>Pour que la forme soit appliquée à votre élément, il faut remplir deux conditions :</p><ol><li>L'élément doit être flotté. Il en sera peut-être différemment à l'avenir, mais pour l'instant, hors <code>float</code> point de salut.</li>
<li><strong>L'élément doit avoir des dimensions définies</strong>. Les hauteur et largeur de l'élément seront en effet utilisées pour établir un système de coordonnées.</li>
</ol><p>Comme nous l'avons vu, les formes sont définies par un ensemble de points. Ces points ayant des coordonnées, le navigateur a besoin d'un système de coordonnées pour positionner chaque point sur l'élément. L'exemple qui précède fonctionnera donc si nous incluons quelque chose comme :</p><pre class="language-css">.element {
  float: left;
  height: 10em;
  width: 15em;
  shape-outside: circle();
}</pre><p>Le fait de donner à un élément des dimensions spécifiques n'affecte pas son caractère responsif (nous y reviendrons).</p><p>Chaque forme étant définie par un ensemble de points positionnés en utilisant une paire de coordonnées, toute modification des coordonnées d'un point aura un effet sur la forme créée. Par exemple, l'image suivante montre une forme hexagonale créée à l'aide de la fonction polygon() . La forme consiste en six points. Modifier la coordonnée horizontale du point orange résultera en une forme différente, et affectera le flux de contenu à l'intérieur et/ou à l'extérieur de l'élément.</p><figure role="group"><img src="https://la-cascade.io/images/shape-points.webp" alt="" /><figcaption>Si l'élément est flotté à droite et que cette forme lui est appliquée, le flux du contenu situé sur sa gauche sera modifié si les coordonnées du point orange sont changées dans la fonction polygon().</figcaption></figure><p>Si l'élément est flotté à droite et que cette forme lui est appliquée, le flux du contenu situé sur sa gauche sera modifié si les coordonnées du point orange sont changées dans la fonction polygon().</p><h2>La boîte de référence</h2><p>Les formes CSS sont définies et créées à l'intérieur d'une boîte de référence, qui est la boîte utilisée pour dessiner la forme. En plus des hauteur et largeur de l'élément, les boîtes (nommées d'après le <a href="https://la-cascade.io/articles/box-sizing-pour-les-nuls">modèle de la boîte</a>) - <em>margin box</em>, <em>content box</em>, <em>padding box</em>, et <em>border box</em> - sont utilisées pour spécifier l'étendue de la forme sur l'élément.</p><p>Par défaut, la référence est margin box, donc si l'élément auquel vous appliquez une forme a une marge en bas, la forme que vous définissez ne se limitera pas aux dimensions de l'élément lui-même, elle s'étendra jusqu'à la marge en question. Si vous voulez utiliser une des autres valeurs de boîtes, vous pouvez l'indiquer en même temps que la fonction passée dans les propriétés :</p><pre class="language-css">shape-outside: circle(250px at 50% 50%) padding-box;</pre><p>Le mot-clé <code>padding-box</code> dans la règle ci-dessus indique que la forme sera appliquée et restreinte à la padding box de l'élément. La fonction <code>circle()</code> définit une forme circulaire, sa taille et sa position sur l'élément.</p><h2>Définir des formes avec les fonctions</h2><p>Commençons avec un avatar circulaire entouré de texte, les profils d'utilisateurs ou les témoignages de consommateurs sont souvent présentés ainsi.</p><figure role="group"><img src="https://la-cascade.io/images/demo-user-profile-screenshot.webp" alt="" /><figcaption>Avec CSS Shapes, le texte s'enroule autour de la forme au lieu de rester rectangulaire.</figcaption></figure><p>Nous allons utiliser la fonction <code>circle()</code> pour appliquer une forme circulaire à l'image de profil en utilisant le balisage suivant :</p><pre class="language-html">&lt;img
  src="http://api.randomuser.me/0.3.2/portraits/men/7.jpg"
  alt="profile image"
/&gt;
&lt;p&gt;
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum
  itaque nam blanditiis eveniet enim eligendi quae adipisci?
&lt;/p&gt;
&lt;p&gt;
  Assumenda blanditiis voluptas tempore porro quibusdam beatae
  deleniti quod asperiores sapiente dolorem error! Quo nam quasi
  soluta reprehenderit laudantium optio ipsam ducimus consequatur enim
  fuga quibusdam mollitia nesciunt modi.
&lt;/p&gt;
Peut-être vous demandez-vous pourquoi nous n'utilisons pas
border-radius pour arrondir l'image ? La réponse est que la propriété
border-radius n'a aucun effet sur le flux ou la superficie du contenu
interne ou externe, il n'agit que sur la bordure d'un élément et sur
le background. Ce dernier s'adapte en fonction des modifications de
bordure, et c'est tout. Le contenu interne demeure rectangulaire et le
texte à l'extérieur voit et traite l'élément comme s'il était
rectangulaire - parce qu'en fait il l'est toujours.</pre><p>Pourquoi ne pas utiliser la propriété <code>border-radius</code> pour rendre l'image circulaire - comme on le fait habituellement pour arrondir une image ou un élément :</p><pre class="language-css">img {
  float: left;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  margin-right: 15px;
}</pre><figure role="group"><img src="https://la-cascade.io/images/demo-user-profile-screenshot-incomplete.webp" alt="" /><figcaption>Sans CSS Shapes, le texte voit l'image comme un rectangle, il entoure une forme rectangulaire et non circulaire.</figcaption></figure><p>Dans un navigateur non compatible avec CSS Shapes, le contenu extérieur se positionnera autour de l'image comme si elle n'était pas circulaire. Avec les navigateurs anciens, ce sera donc la solution de remplacement (fallback).</p><p>Pour adapter le flux de contenu à une certaine forme, vous pouvez utiliser les propriétés Shapes :</p><pre class="language-css">img {
  float: left;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  margin-right: 15px;
  shape-outside: circle();
  shape-margin: 15px;
}</pre><p>De cette façon, le texte "verra" la forme circulaire appliquée à l'image et se lovera autour d'elle, comme dans la première illustration. En cas d'incompatibilité navigateur, c'est la deuxième illustration qui s'affichera.</p><p>On peut utiliser la fonction <code>circle()</code> telle quelle, ou lui passer des paramètres. La syntaxe officielle est :</p><pre class="language-xml">circle() = circle([&lt;shape-radius]? [at &lt;position&gt;]?)</pre><p>Le point d'interrogation indique que ces paramètres sont optionnels et peuvent être omis. En cas d'omission d'un paramètre, celui-ci prend une valeur par défaut. Lorsque vous utilisez <code>circle()</code> tel quel, sans définir explicitement sa position, il positionnera par défaut le cercle au centre de l'élément.</p><p>On peut spécifier le rayon du cercle avec n'importe quelle unité de longueur (<code>px</code>, <code>em</code>, <code>pt</code>, ...). On peut également spécifier le rayon en utilisant <code>closest-side</code> (côté le plus proche) ou <code>furthest-sid</code>e<code>(côté le plus éloigné), mais</code>closest-side` est la valeur par défaut, ce qui signifie que le navigateur définira le rayon comme étant la longueur entre le centre de l'élément et son côté le plus proche.</p><pre class="language-css">shape-outside: circle(
  farthest-side at 25% 25%
); /* définit un cercle dont le rayon est égal à la moitié du côté le plus long, et qui est positionné aux points de coordonnées 25% 25% dans le système de coordonnées de l'élément */
shape-inside: circle(
  250px at 500px 300px
); /* définit un cercle dont le centre est positionné à 500px horizontalement et 300px verticalement, avec un rayon de 250px */</pre><figure role="group"><img src="https://la-cascade.io/images/closest-side-farthest-side.webp" alt="" /></figure><p>La fonction <code>ellipse()</code> est similaire à la fonction <code>circle()</code> , elle utilise les mêmes listes de valeurs, mais au lieu d'avoir un seul paramètre de rayon, elle en a deux : un pour la longueur du rayon sur l'axe des x, l'autre pour l'axe des y.</p><pre class="language-xml">ellipse() = ellipse([&lt;shape-radius&gt;{2}]? [at &lt;position&gt;]?)</pre><p>La fonction <code>inset()</code> est utilisée pour créer des formes rectangulaires. Dans la mesure où les éléments sont déjà rectangulaires, nous pouvons l'utiliser d'une manière plus fine, par exemple en créant des rectangles à bords arrondis, avec un flux de contenu qui s'adapte.</p><figure role="group"><img src="https://la-cascade.io/images/inset-example.webp" alt="" /></figure><p>La fonction <code>inset()</code> prend de 1 à 4 valeurs offset qui définissent les retraits (offset) depuis les bords des boîtes de référence vers l'intérieur. Ils spécifient l'endroit où le rectangle sera inséré à l'intérieur de l'élément. Les coins arrondis sont définis exactement de la même façon que les <code>border-radius</code> en utilisant de 1 à 4 valeurs, en conjonction avec le mot-clé <code>round</code> .</p><pre class="language-xml">inset() = inset(offset{1,4} [round &lt;border-radius&gt;]?)</pre><p>Voici comment on créera un rectangle arrondi sur un élément flotté :</p><pre class="language-css">.element {
  float: left;
  width: 250px;
  height: 150px;
  shape-outside: inset(0px round 100px) border-box;
}</pre><p>La dernière fonction Shapes est le <code>polygon()</code> , qui permet de définir des formes arbitraires plus complexes en utilisant une quantité de points. La fonction prend un ensemble de paires de coordonnées, chaque paire spécifiant la position d'un point, et l'ensemble des points définissant la forme.</p><p>Dans l'exemple qui suit, une image flottée à droite prend toute la hauteur de l'écran en utilisant les unités viewport. Nous voulons que le texte de gauche suive les contours du sablier situé à l'intérieur de l'image, et nous utilisons la fonction <code>polygon()</code> pour définir une forme irrégulière.</p><figure role="group"><img src="https://la-cascade.io/images/polygon-example-incomplete.webp" alt="" /></figure><p>Pour l'image ci-dessus, notre CSS sera :</p><pre class="language-css">img.right {
  float: right;
  height: 100vh;
  width: calc(100vh + 100vh / 4);
  shape-outside: polygon(
    40% 0,
    100% 0,
    100% 100%,
    40% 100%,
    45% 60%,
    45% 40%
  );
}</pre><p>Pour les coordonnées des points définissant l'image, vous pouvez utiliser des unités de longueur ou des pourcentages, comme je l'ai fait ici.</p><p>Ces quelques lignes suffisent à produire l'image ci-dessus, cependant vous avez pu constater que la fonction n'a pas eu d'effet sur le reste de l'image à l'extérieur de la forme définie. En fait, appliquer une fonction Shapes à un élément - que ce soit une image, un container, ou quelque chose entre les deux - n'affectera rien d'autre que l'aire du flux de contenu. Les backgrounds, les bordures et tout le reste demeurent inchangés.</p><p>Si nous voulons visualiser la forme du polygone que nous avons créé, nous devons découper les parties de l'image qui se trouvent à l'extérieur de la forme. Pour cela, nous pouvons utiliser la propriété clip-path du module CSS Masking.</p><p>La propriété clip-path prend les mêmes fonctions et valeurs que la propriété Shapes. Si nous passons la définition du polygone utilisée dans la propriété shape-outside à la propriété clip-path , nous découpons la partie de l'image correspondante.</p><p>img.right { float: right; height: 100vh; width: calc(100vh + 100vh/4); shape-outside: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%); /_ clip the image to the defined shape _/ clip-path: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%); } Le résultat est le suivant :</p><figure role="group"><img src="https://la-cascade.io/images/polygon-example-finished.webp" alt="" /></figure><p>La propriété clip-path nécessite encore d'utiliser des préfixes, elle marchera dans Chrome avec le préfixe -webkit- . Vous pouvez voir <a href="https://codepen.io/SaraSoueidan/pen/rNVrbr/04a4c8380e4aa5a8e6a2b0014b2db198">une démo live ici</a>. (NdT: <em>la <a href="https://caniuse.com/?search=clip-path">compatibilité de clip-path</a> est excellente aujourd'hui</em>).</p><p>La propriété <a href="https://la-cascade.io/articles/comprendre-clip-path">clip-path</a> accompagne à merveille les propriétés Shapes, car elle permet de visualiser les formes en découpant toute partie de l'élément qui se trouve en dehors de la forme définie. Vous l'utiliserez sans doute souvent avec les propriétés Shapes.</p><p>La propriété <code>polygon()</code> prend par ailleurs un mot-clé optionnel, qui peut être soit nonzero soit evenodd . Ce mot indique la façon de traiter les surfaces à l'intérieur de la forme polygonale qui pourraient être en intersection. Pour les détails, vous pouvez consulter la propriété SVG fill-rule.</p><h2>Définir une forme en utilisant une image</h2><p>Pour définir une forme en utilisant une image, cette dernière doit avoir un canal alpha à partir duquel le navigateur peut extraire la forme.</p><p>Une forme est définie par les pixels dont la valeur alpha est supérieure à un certain seuil. Celui-ci est par défaut égal à <code>0.0</code> (entièrement transparent), mais vous pouvez le définir explicitement en utilisant la propriété <code>shape-image-threshold</code> . Dans ce cas, tout pixel qui n'est pas transparent sera utilisé comme partie de la forme définie à partir de l'image.</p><p>Dans un niveau futur de CSS Shapes, il est possible que l'on utilise la luminance d'une image plutôt que les données alpha, auquel cas <code>shape-image-threshold</code> sera étendu pour appliquer un seuil alpha ou luminance.</p><p>Nous allons utiliser l'image suivante pour définir une forme sur un élément et envelopper celui-ci de texte.</p><figure role="group"><img src="https://la-cascade.io/images/leaf.webp" alt="image d'une feuille noire sur fond blanc" /></figure><p>Avec <code>shape-outside</code> et <code>url()</code> pointant vers notre image, nous pouvons définir le flux du contenu autour de notre élément en forme de feuille.</p><pre class="language-css">.leaf-shaped-element {
  float: left;
  width: 400px;
  height: 400px;
  shape-outside: url(leaf.png);
  shape-margin: 15px;
  shape-image-threshold: 0.5;
  background: #009966 url(path/to/background-image.jpg);
  mask-image: url(leaf.png);
}</pre><p>Bien sûr, si vous deviez appliquer un background à l'élément, ce background devrait être découpé en dehors de la forme définie, ce que nous permet la propriété mask-image (accompagnée des préfixes appropriés) du Module Masking, puisque la propriété clip-path ne prend pas d'image alpha comme valeur. Voici le résultat :</p><figure role="group"><img src="https://la-cascade.io/images/shape-image-example.webp" alt="" /></figure><p>Si vous créez des formes complexes, il pourra être préférable de définir une forme en utilisant une image (par exemple en utilisant le canal alpha d'une image sur Photoshop) plutôt que de définir des points.</p><p>Il est également préférable d'utiliser une image plutôt qu'une fonction lorsque vous avez plusieurs float ou plusieurs surfaces réservées à l'intérieur d'un élément - parce qu'on ne peut pas, pour l'instant du moins, déclarer plusieurs formes sur un élément. Par contre, si votre image est constituée de plusieurs zones, le navigateur pourra les extraire et les utiliser.</p><h2>CSS Shapes et design responsif</h2><p>CSS Shapes est-il compatible avec mon workflow responsif ? La spécification en cours (<code>shape-outside</code>) a déjà réglé la question, elle vous permet de spécifier les dimensions de l'élément soit en pourcentages, soit en unités de longueur, et les points composant la forme (paramètres de la fonction forme) peuvent également être définis en pourcentages.</p><p><code>shape-inside</code> n'est pas aussi avancé, mais c'est parce qu'il a été repoussé au Module Niveau 2. Ses limitations actuelles seront résolues au prochain niveau.</p><h2>Les outils pour Shape</h2><p>La création de formes complexes à travers les fonctions Shapes peut faire peur, en particulier s'agissant de polygon() . Heureusement, l'équipe d'Adobe a créé des outils interactifs qui nous facilitent la vie. Bear Travis a créé une collection d'outils Shapes qui nous permettent de créer des formes polygonales de manière visuelle. L'outil génère ensuite la fonction pour nous. C'est très utile avec une limite : vous ne pourrez pas insérer une image pour créer votre forme. Un outil plus avancé et plus interactif a été développé par Adobe. Il a été publié récemment en tant qu'extension de l'éditeur de texte d'Adobe, Brackets. Il vous permet de visualiser et éditer des formes directement dans votre navigateur, et il comporte une fonction live preview qui met à jour la page lorsque vous modifiez les valeurs Shapes de votre CSS. Vous pouvez ainsi voir instantanément la façon dont vos formes interagissent avec les autres éléments de la page.</p><figure role="group"><img src="https://la-cascade.io/images/shapes-polygon.webp" alt="" /><figcaption>Création et modification d'une forme polygonale avec le mode live preview de Bracket. Capture d'écran par Razvan Caliman.</figcaption></figure><p>Razvan Caliman a écrit un <a href="http://blog.brackets.io/2014/04/17/css-shapes-editor/">article</a> sur le blog de Bracket qui explique comment vous pouvez intégrer l'éditeur Shapes dans Bracket et l'utiliser dès aujourd'hui. (NdT: <em>Il semble que le lien ne fonctionne plus</em>)</p><h2>L'avenir : Exclusions CSS</h2><p>La spécification CSS Shapes couvrait autrefois Shapes et Exclusions, mais les deux ont été séparées. Shapes définit les propriétés shape-inside et shape-outside , Exclusion de son côté définira les propriétés nous permettant d'entourer de contenu les éléments non flottés, tels que les éléments positionnés absolument. On pourra de la sorte entourer de contenu la forme tout entière, de tous côtés, comme on le voit dans l'image qui suit.</p><figure role="group"><img src="https://la-cascade.io/images/exclusion-example.webp" alt="" /><figcaption>À l'avenir, CSS Exclusions nous permettra d'envelopper de texte une forme, telle que cette citation au milieu. Si la forme était circulaire, le texte en suivrait le contour. Image par <a href="http://cargocollective.com/justinthomaskay">Justin Thomas Kay</a>.</figcaption></figure><p>Des mises en page similaires, avec des éléments positionnés absolument au centre d'un article et un flux de contenu environnant, seront possibles.</p><h2>CSS Shapes, un peu plus loin</h2><p>La spécification en cours est un premier pas. Bientôt, de nouvelles options nous donneront plus de contrôle sur la création de formes et le flux de contenu, et la création de designs sera une question de quelques lignes de code. Pour l'instant, les éditeurs du spec sont concentrés sur la publication de shape-outside , et il est vraisemblable que CSS Shapes sera utilisable avec les meilleurs navigateurs avant la fin de cette année.</p><p>Vous pouvez d'ores et déjà utiliser CSS Shapes dans le cadre d'un workflow conçu en amélioration progressive, puisque les fallbacks sont faciles à mettre en oeuvre. Je les utilise depuis peu dans mon propre site web, et le fallback est très "normal". Pour des designs plus complexes, vous pouvez utiliser un script pour vérifier la compatibilité navigateur et fournir une solution de rechange si la réponse est négative. Vous pouvez étendre les tests de Modernizr avec ce script pour tester la compatibilité avec <code>shape-outside</code>.</p><p>CSS Shapes construit un nouveau pont entre les design web et imprimé. Les exemples fournis dans cet article sont simples, mais devraient vous donner une bonne base pour créer des designs aussi complexes que ceux d'un magazine ou d'un poster, sans avoir à vous soucier de savoir si votre maquette pourra être recréée à l'écran. Quel que soit votre domaine d'exploration, depuis les <a href="https://www.sarasoueidan.com/blog/css-shapes/">mises en pages non rectangulaires</a> jusqu'à l'<a href="https://www.sarasoueidan.com/blog/animating-css-shapes/">animation de formes</a>, le moment est venu d'expérimenter !</p><p>NdT: Voir aussi le formidable article de Sara Soueidan <a href="https://www.sarasoueidan.com/blog/animating-css-shapes/">Animating CSS Shapes with CSS Animations and Transitions</a> pour l'animation des CSS Shapes (en anglais).</p><div class="caniuse"><h2>Compatibilité à ce jour</h2><p class="ciu_embed" data-feature="css-shapes" data-periods="future_1,current,past_1,past_2" data-accessible-colours="false"><picture><source type="image/webp" srcset="https://caniuse.bitsofco.de/image/css-shapes.webp" /><source type="image/png" srcset="https://caniuse.bitsofco.de/image/css-shapes.png" /><img src="https://caniuse.bitsofco.de/image/css-shapes.jpg" alt="Data on support for the css-shapes feature across the major browsers from caniuse.com" /></picture></p><p><em><small>(Un grand merci à <a href="https://la-cascade.io/auteurs/ire-aderinokun">Ire Aderinokun</a> !)</small></em></p></div></div>]]></description>
      <link>https://la-cascade.io/articles/css-shapes-une-introduction</link>
      <guid>https://la-cascade.io/articles/css-shapes-une-introduction</guid>
      <pubDate>Fri, 09 May 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Animer un SVG avec CSS]]></title>
      <description><![CDATA[<p><em>Chris Coyier s'est amusé à créer une petite animation SVG en CSS, sans passer par des bibliothèques compliquées. C'est fait maison, simple, efficace et clair comme toujours avec Chris.</em></p><div class="articleContent"><p>Il existe plusieurs façons d'animer une image svg, depuis la balise <code>animate</code> jusqu'aux bibliothèques comme <a href="http://snapsvg.io">Snap.svg</a> ou <a href="http://www.svgjs.com">SVG.js</a>. Nous allons essayer autre chose ici, en utilisant SVG à l'intérieur de notre HTML et en animant les parties de l'image avec CSS.</p><p>Je me suis amusé avec ça dernièrement, <a href="http://www.wufoo.com/landing/1/?utm_source=csstricks&amp;utm_medium=ppc&amp;cmpid=brand&amp;utm_network=d">Wufoo</a> souhaitant rafraîchir le graphisme de ses pubs sur <a href="http://css-tricks.com">CSS-Tricks</a>. Voici une idée de ce que nous allons réaliser :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/chriscoyier/pen/dvjhn/">Wufoo SVG Ad</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h2>1. Concevoir la pub</h2><p>Ça va ressembler à une <a href="http://cdn.css-tricks.com/wp-content/uploads/2014/04/How_to_Draw_Owl.jpg">leçon de dessin sommaire</a>, mais notre objectif étant l'animation, nous allons passer sur le reste vite fait. Je souhaitais une pub super simple à partir de leur logo classique, de leurs couleurs etc., auquels j'ajouterais une touche personnelle.</p><ol><li>Faire sauter les lettres dans la page. Wufoo est un mot marrant, les lettres peuvent s'amuser un peu.</li>
<li>Dans le bon vieux temps, on faisait des T-Shirts avec un dinosaure devant, et derrière il y avait "Fast. Smart. Formidable", des caractéristiques que Wufoo partage avec les dinosaures, sans parler du jeu de mots sur FORMidable… (NdT: Wufoo est un outil permettant d'élaborer des formulaires, <em>form</em> en anglais). Faisons apparaître et disparaître ce slogan.</li>
<li>Pour aller au bout de notre idée, faisons apparaître la tête d'un dinosaure qui surgit, intrigué, des profondeurs, et disparaît à la vitesse de l'éclair, laissant le mot "fast" s'afficher.</li>
</ol><p>J'ai mis tout ça sur Illustrator :</p><figure role="group"><img src="https://la-cascade.io/images/ansvg1-compressor.jpeg" alt="des images conçues sur illustrator" /></figure><p>Remarquez que le logo et le texte du slogan sont des formes vectorielles, leur rendu en <code>&lt;path&gt;</code> (chemins) SVG sera très simple.</p><p>Le texte "Fast." est laissé en tant que texte dans Illustrator. Quand je le sauvegarderai, il sera conservé sous la forme d'élément <code>&lt;text&gt;</code>.</p><h2>2. Sauvegarder en format SVG</h2><p>Illustrator peut le sauvegarder directement en format SVG :</p><figure role="group"><img src="https://la-cascade.io/images/ansvg2-compressor.png" alt="comment sauvegarder sur illustrator" /></figure><p>Vous pouvez ouvrir ce fichier SVG dans votre éditeur de texte et voir le code SVG :</p><figure role="group"><img src="https://la-cascade.io/images/ansvg3-compressor.png" alt="le contenu complexe du fichier svg" /></figure><h2>3. Nettoyer le SVG, lui ajouter des classes</h2><p>Pour le nettoyage, vous pouvez utiliser <a href="https://github.com/svg/svgo">SVGO</a> qui optimisera le fichier, retirera le DOCTYPE et toutes les choses inutiles. Mais ce qui est plus important ici, c'est de donner des classes aux différentes formes, afin que nous puissions les sélectionner dans notre CSS.</p><pre>//CSS
&lt;svg version="1.1" id="wufoo-ad" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve"&gt;
  &lt;!-- background --&gt;
  &lt;rect class="wufoo-background" fill="#D03E27" width="400" height="400" /&gt;
  &lt;!-- logo letters --&gt;
  &lt;path class="wufoo-letter" fill="#F4F4F4" d="M60.858,129...." /&gt;
  &lt;path class="wufoo-letter" fill="#F4F4F4" d="..." /&gt;
     &lt;!-- etc --&gt;
  &lt;!-- dinosaur --&gt;
  &lt;g class="trex"&gt;
     &lt;path ... /&gt;
     &lt;path ... /&gt;
  &lt;/g&gt;
&lt;/svg&gt;</pre><h2>4. Insérer le SVG</h2><p>Vous pouvez copier-coller ce SVG dans votre HTML, à l'endroit où vous voulez que la pub apparaisse. Si vous ne voulez pas que ça embrouille votre template, vous pouvez aussi faire quelque chose comme :</p><pre>//HTML
&lt;aside class="sidebar"&gt;
   &lt;div class="module module-ad"&gt;
       &lt;?php include("ads/wufoo.svg"); ?&gt;
   &lt;/div&gt;
   ...</pre><h2>5. Animer !</h2><p>Nos formes sont maintenant dans le <a href="https://la-cascade.io/articles/le-dom-cest-quoi-exactement">DOM</a>, nous pouvons les cibler et leur appliquer un style comme à n'importe quel autre élément HTML. Allons-y.</p><p>Pour commencer, disons que cette animation doit avoir une durée totale de 10 secondes.</p><h4>Fade in/out des mots</h4><p>Le premier événement est l'apparition des mots Fast. Smart. Formidable. Chaque mot sera affiché pendant une seconde. Nous allons donc réaliser une animation dans laquelle chaque mot apparaît pour une durée égale à 10% du temps total :</p><pre>//CSS
@keyframes hideshow {
  0% { opacity: 1; }
  10% { opacity: 1; }
  15% { opacity: 0; }
  100% { opacity: 0; }
}</pre><p>Puis ciblons le premier mot et fixons la durée de l'animation à 10 secondes (10% de cette durée = 1 seconde) :</p><pre>//CSS
.text-1 {
  animation: hideshow 10s ease infinite;
}</pre><p>Les deux mots suivants seront d'abord cachés (<code>opacity: 0;</code>) puis utiliseront exactement la même animation mais avec un délai, pour les faire partir successivement :</p><pre>//CSS
.text-2 {
  opacity: 0;
  animation: hideshow 10s 1.5s ease infinite;
}
.text-3 {
  opacity: 0;
  animation: hideshow 10s 3s ease infinite;
}</pre><p>La demie seconde supplémentaire entre chaque mot permet un fade out en douceur avant l'apparition du mot suivant.</p><h4>Lettres bondissantes</h4><p>Passons maintenant aux lettres de WUFOO et à leur petite danse :</p><figure role="group"><img src="https://la-cascade.io/images/ansvg4-compressor.gif" alt="les lettres de wufoo s'animent" /></figure><p>L'astuce ici est de donner une durée de 5 secondes à notre animation, mais de la faire fonctionner dans un sens puis dans l'autre. De cette façon, elle correspond bien à notre durée totale de 10 secondes, elle se produit au milieu comme nous le souhaitons, et nous n'avons besoin de paramétrer qu'un seul sens.</p><p>Chaque lettre a un petit délai, décalé par rapport aux autres :</p><pre>//SCSS
.wufoo-letter {
  animation: kaboom 5s ease alternate infinite;
  &amp;:nth-child(2) {
    animation-delay: 0.1s;
  }
  &amp;:nth-child(3) {
    animation-delay: 0.2s;
  }
  &amp;:nth-child(4) {
    animation-delay: 0.3s;
  }
  &amp;:nth-child(5) {
    animation-delay: 0.4s;
  }
}
@keyframes kaboom {
  90% {
    transform: scale(1.0);
  }
  100% {
    transform: scale(1.1);
  }
}</pre><p>Pour abréger, j'ai écrit ce code en SCSS et sans y mettre les préfixes constructeurs.</p><p>Je trouve que la propriété <code>animation-delay</code> devrait pouvoir supporter de façon native une valeur aléatoire, ce serait sympa de voir un délai différent à chaque apparition.</p><h4>Le dinosaure, enfin</h4><p>Dès que les mots ont disparu, le dinosaure lève la tête. L'animal est construit avec de nombreux <code>path</code>, mais nous pouvons le cibler globalement grâce à l'attribut groupe <code>&lt;g&gt;</code> qui enveloppe tous ces chemins.</p><p>Pour animer une position, <a href="http://css-tricks.com/tale-of-animation-performance/">il est préférable d'utiliser translate</a> et c'est ce que nous allons faire :</p><pre>//CSS
@keyframes popup {
  0% {
    transform: translateY(150px);
  }
  34% {
    transform: translateY(20px);
  }
  37% {
    transform: translateY(150px);
  }
  100% {
    transform: translateY(150px);
  }
}</pre><p>Nous voulons que cette animation "dure" 3 secondes, en fait elle dure 10 secondes mais vous n'en verrez que 3 secondes, car lorsque <code>translateY(150px)</code> se déclenche, le dinosaure est enfoui si profond que vous ne voyez rien. Aux alentours de 37% de cette animation (vers 3 secondes) vous le verrez apparaître lentement puis disparaître rapidement vers le bas.</p><p>Pour appliquer cette animation, nous devons nous assurer que :</p><ul><li>
<p>Le dinosaure est invisible au départ.</p>
</li>
<li>
<p>L'animation comporte un délai, de façon à ce que la danse des lettres soit achevée.</p>
<pre>  //CSS
  .trex {
    transform: translateY(150px);
    animation: popup 10s 6.5s ease infinite;
  }</pre></li>
</ul><p>Le dinosaure se cache à la dernière seconde lorsque le mot "Fast." revient à l'écran (parce que toutes les animations sont définies comme <code>infinite</code> ce qui les relance dès qu'elles sont terminées).</p><h2>6. Une pub responsive et cliquable</h2><p>Un avantage considérable de SVG est que la qualité de l'image est toujours impeccable quelle que soit la taille. Pour obtenir une image flexible qui conserve son ratio (même équilibre global des proportions), nous pouvons utiliser la bonne vieille technique de la boîte avec padding.</p><pre>//HTML
&lt;div class="wufoo-ad-wrap"&gt;
  &lt;svg class="wufoo-ad"&gt;
     ...
  &lt;/svg&gt;
&lt;/div&gt;
//CSS
.wufoo-ad-wrap {
  height: 0;
  padding-top: 100%;
  position: relative;
}
.wufoo-ad {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}</pre><p>L'idée ici est que le "wrap" sera toujours un carré parfait, aux dimensions calculées à partir de sa largeur. Nous positionnons ensuite le SVG de façon absolue à l'intérieur de ce carré parfait, qui se redimensionnera avec bonheur.</p><p>Puisqu'il s'agit d'une pub, qui doit évidemment être cliquable, on pourrait utiliser <code>&lt;a href=""&gt;</code> à la place de <code>&lt;div&gt;</code> pour le contenant wrap, dans ce cas n'oubliez pas d'ajouter <code>display: block</code>.</p><p>La <a href="http://codepen.io/chriscoyier/pen/dvjhn/">démo finale</a> est ici.</p></div>]]></description>
      <link>https://la-cascade.io/articles/animer-un-svg-avec-css</link>
      <guid>https://la-cascade.io/articles/animer-un-svg-avec-css</guid>
      <pubDate>Wed, 23 Apr 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Combinateurs et pseudo-classes CSS]]></title>
      <description><![CDATA[<p><em>Nous poursuivons notre introduction aux basiques de CSS avec un article de Steven Bradley sur les combinateurs et les pseudo-classes. La maîtrise de cette syntaxe vous aidera à mieux coder.</em></p><div class="articleContent"><h2>Les combinateurs</h2><p>Comme leur nom le suggère, les combinateurs aident à combiner différents sélecteurs pour former de nouveaux sélecteurs, plus spécifiques.</p><p>Il existe quatre types de combinateurs ciblant les relations parent/enfants et frères existant entre les éléments.</p><h3>Combinateur descendant E F</h3><p>Ce premier combinateur est représenté par un <em>espace</em> entre deux éléments, par exemple ul / espace / li :</p><pre>ul li</pre><p>Ce combinateur cible un élément F qui est un descendant de l'élément E. Les combinateurs de descendants ne se limitent pas aux enfants, ils ciblent tous les descendants.</p><pre>//HTML
&lt;ul&gt;
  &lt;li&gt;List Item 1&lt;/li&gt;
  &lt;li&gt;List Item 2
    &lt;ol&gt;
      &lt;li&gt;List Item 2-1&lt;/li&gt;
      &lt;li&gt;List Item 2-2&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;List Item 3&lt;/li&gt;
&lt;/ul&gt;
//CSS
ul li {background: red;}</pre><p>Toutes les listes auront un background rouge, car chacune est un descendant (enfant ou petit-enfant) de la liste non-ordonnée.</p><figure role="group"><img src="https://la-cascade.io/images/combination-lock-3.jpeg" alt="Un cadenas à code" /></figure><h3>Combinateur enfant E &gt; F</h3><p>Cible un élément F qui est l'enfant d'un élément E. À la différence du combinateur précédent, F doit être un enfant direct de E.</p><p>Avec le même HTML que ci-dessus et le CSS :</p><pre>ul&gt;li {background: red;}</pre><p>seuls les List Item 1, 2 et 3 auront un background rouge, car ils sont les enfants de ul, alors que les items 2-1 et 2-2 sont ses petits-enfants.</p><h3>Combinateur adjacent E + F</h3><p>Cible un élément F immédiatement précédé par un élément E. Le mot adjacent est important : seul le <strong>premier</strong> élément après E sera ciblé.</p><pre>//HTML
&lt;h1&gt;Heading&lt;/h1&gt;
&lt;p&gt;Paragraph 1&lt;/p&gt;
&lt;p&gt;Paragraph 2&lt;/p&gt;
&lt;p&gt;Paragraph 3&lt;/p&gt;
//CSS
h1+p {font-size: 1.5em;}</pre><p>Seul le paragraphe 1 aura le style spécifié.</p><h3>Combinateur général siblings E ~ F</h3><p>Cible un élément F précédé par un élément E. À la différence du combinateur adjacent qui cible uniquement le premier frère, celui-ci cible tous les frères (siblings).</p><p>Avec le même HTML que ci-dessus et le CSS :</p><pre>h1~p {font-size: 1.5em;}</pre><p>tous les paragraphes auront le même style défini ci-dessus.</p><h3>Au-delà des sélecteurs simples</h3><p>Remarquez bien que vous n'êtes pas limités aux sélecteurs simples. Tous les sélecteurs, y compris les sélecteurs d'attributs, peuvent être employés d'un côté ou de l'autre du combinateur :</p><pre>ul a[title]
li#first&gt;a[rel="external"]
h1+p.intro
h2.myclass~p[class="intro"]</pre><h2>Les pseudo-classes</h2><p>Il existe beaucoup de pseudo-classes, le W3C les a regroupées ainsi :</p><ul><li>pseudo-classes dynamiques</li>
<li>pseudo-classes cibles</li>
<li>pseudo-classes de langage</li>
<li>pseudo-classes d'éléments UI (interface utilisateur)</li>
<li>pseudo-classes de négation</li>
<li>pseudo-classes structurelles</li>
</ul><p>Vous en connaissez (et utilisez) certaines.</p><figure role="group"><img src="https://la-cascade.io/images/css-selectors.jpeg" alt="des cartes éparpillées sur une table, avec des noms de pseudo-classes écrits." /></figure><h3>Pseudo-classes dynamiques</h3><p>Ce groupe-ci, je suis certain que vous le connaissez déjà. Il s'agit des pseudo-classes relatives aux liens et aux actions utilisateurs.</p><h4>Pseudo-classes de liens</h4><p><strong>E:link</strong> cible un élément E qui est la source d'un lien non encore visité.<br /><strong>E:visited&gt;</strong> cible un élément E qui est la source d'un lien ayant été visité.</p><h4>Pseudo-classes d'action utilisateur</h4><p>Ciblent un élément E lors de certaines actions utilisateurs.</p><p><strong>E:active</strong> lorsque le lien est actif (c.à.d lorsqu'on a cliqué dessus)<br /><strong>E:hover</strong> lorsque le visiteur passe la souris sur le lien<br /><strong>E:focus</strong> lorsque le lien a un focus actif</p><p>Je suppose que vous les connaissez suffisamment pour que je n'aie pas besoin d'approfondir. Une chose à garder en mémoire toutefois : lorsque vous utilisez :link, :visited, :hover et :active sur un même élément, rappelez-vous qu'ils doivent être listés dans cet ordre, et pour cela rappelez-vous LoVeHAte !</p><h4>Pseudo-classe de cible</h4><p>Si vous avez déjà créé une ancre en ajoutant un # à une url, alors vous avez déjà créé une pseudo-classe de cible dans votre html.</p><p><strong>E:target</strong> cible un élément E qui est la cible (appelée ancre) de l'url à laquelle on se réfère.</p><pre>//HTML
&lt;a href="domaine.com/cette-page.html#un-endroit-dans-la-page"&gt;...&lt;/a&gt;
&lt;!-- et plus loin dans la page : --&gt;
&lt;span id="un-endroit-dans-la-page"&gt;&lt;/span&gt;
//CSS
span:target {background: yellow;}</pre><p>Le code ci-dessus place un background jaune derrière le span.</p><p>Un cas d'usage intéressant est lorsqu'on veut aider notre lecteur qui a cliqué sur un lien à trouver tout de suite le contenu (le mot, le paragraphe…) correspondant à ce lien.</p><h4>Pseudo-classes de langage</h4><p><strong>E:lang(fr)</strong> cible un élément E dans le langage spécifié (ici "fr" = français)</p><p>//HTML</p><pre>&lt;body lang=fr&gt;
  &lt;p&gt;Je suis français.&lt;/p&gt;
&lt;/body&gt;
//CSS
p:lang(fr) {color: red;}</pre><p>Si vous utilisez des langues multiples dans une page, vous avez la possibilité de cibler spécifiquement un texte dans telle ou telle langue.</p><h4>Pseudo-classes d'UI</h4><p>Pour améliorer l'usabilité des formulaires, on ajoute souvent des contraintes comme permettre ou interdire l'affichage de certains champs en fonction de ce que le visiteur a déjà rempli. Par défaut, les éléments html ne sont ni activés (enabled) ni désactivés (disabled). JavaScript sert typiquement à cela, mais on peut aussi le faire manuellement (quitte à les modifier dynamiquement ensuite).</p><p><strong>E:enabled</strong> cible un élément d'interface utilisateur E qui est activé.</p><p><strong>E:disabled</strong> cible un élément d'interface utilisateur E qui est désactivé.</p><p><strong>E:checked</strong> cible un élément d'interface utilisateur E qui est "checké", comme un bouton-radio ou une checkbox.</p><p>//HTML</p><pre>&lt;form&gt;
  Preferred Contact:
    &lt;input type="radio" id="prefer" value="email" checked="checked" /&gt; Email
    &lt;input type="radio" id="prefer" value="phone" /&gt; Phone
  Email: &lt;input type="text" id="email" enabled="enabled" /&gt;
  Phone: &lt;input type="text" id="phone" disabled="disabled" /&gt;
&lt;/form&gt;
//CSS
:enabled {color: green;}
:disabled {color: red;}
:checked {background: yellow;}</pre><p>Ici, le rouge et le vert sont utilisés pour signaler aux visiteurs les éléments du formulaire disponibles. Les items checkés ont un background jaune, pour rendre plus visible leur statut de "déjà fait".</p><p>Il est probable que nous utiliserions Javascript pour changer les attributs enabled et disabled, selon la méthode choisie par l'utilisateur.</p><h4>Pseudo-classe de négation</h4><p>La <a href="https://la-cascade.io/articles/la-pseudo-classe-de-negation/">pseudo-classe de négation</a> fait exactement ce à quoi on peut s'attendre. Avec elle, on cible tout ce qui n'est pas le sélecteur nié.</p><p><strong><a href="https://la-cascade.io/not/">E:not(S)</a></strong> cible un élément E qui n'est pas égal au sélecteur S spécifié entre parenthèses.</p><pre>//HTML
&lt;div class="one"&gt;&lt;/div&gt;
&lt;div class="two"&gt;&lt;/div&gt;
&lt;div class="three"&gt;&lt;/div&gt;
//CSS
div:not(.two) {color: orange;}</pre><p>Le CSS appliquera une couleur orange au texte des première et troisième div, qui n'ont pas la classe "two". C'est simple, mais ça peut devenir rapidement complexe, attention.</p><p>Vous trouverez certainement d'autres façons de cibler les éléments que vous voulez sans utiliser le sélection de négation, mais une négation peut remplacer beaucoup de sélecteurs à elle toute seule, elle peut donc être appropriée dans certains cas.</p><h2>Les pseudo-classes structurelles</h2><p>Les pseudo-classes structurelles ont été introduites afin de pouvoir cibler des éléments html à partir d'informations tirées du <a href="https://la-cascade.io/articles/le-dom-cest-quoi-exactement/">DOM</a> qui ne peuvent être facilement représentées par de simples sélecteurs ou combinateurs.</p><p>Vous en utilisez peut-être déjà certaines. Elles vous éviteront souvent d'ajouter des id ou classes inutiles.</p><p><strong>E:root</strong> cible un élément E qui est la racine du document. En html il s'agit toujours de l'élément html.</p><pre>:root {background: blue;}
html {background: blue;}</pre><p>Ces lignes de CSS sont fonctionnellement équivalentes. Ok, ce n'est peut-être pas la plus utile des pseudo-classes structurelles, en tout cas c'est la plus simple à expliquer !</p><p><strong>E:nth-child(n)</strong> cible un élément E qui est le n-ième enfant de son parent.</p><p>Supposons que nous ayons une table comportant de nombreuses lignes.</p><pre>tr:nth-child(4) {background: #ccc;}</pre><p>Le CSS ci-dessus indique qu'il faut trouver la quatrième ligne et lui donner un background gris clair.</p><p>On utilise souvent la pseudo-classe nth-child pour colorer alternativement les lignes d'une table.</p><pre>tr:nth-child(2n+1) {background: #ccc;}
tr:nth-child(2n) {background: #eee;}</pre><p>2n+1 représente les lignes impaires et 2n les lignes paires. On peut aussi utiliser les valeurs impaire (odd) et paire (even).</p><pre>tr:nth-child(odd) {background: #ccc;}
tr:nth-child(even) {background: #eee;}</pre><p>Bien entendu vous n'est pas limité à 2 :</p><pre>tr:nth-child(10n+1) {background: #ccc;}</pre><p>Ici, les 11e, 21e, 31e, etc lignes auront un background gris clair.</p><p><strong>E:nth-last-child(n)</strong> cible un élément E qui est le n-ième enfant de son parent, en comptant à partir du dernier enfant.</p><p>nth-last-child fonctionne comme nth-child, mais en commençant par le dernier élément de la liste. Reprenons notre exemple de table :</p><pre>tr:nth-last-child(1) {background: #ccc;}</pre><p>Ici, c'est la dernière ligne qui aura un background gris clair,</p><pre>tr:nth-last-child(4) {background: #ccc;}</pre><p>et ici c'est la 4ème ligne en partant du bas qui aura ce background.</p><p>On peut utiliser les même valeurs :</p><pre>tr:nth-last-child(2n+1) {background: #ccc;}
tr:nth-last-child(2n) {background: #eee;}
tr:nth-last-child(odd) {background: #ccc;}
tr:nth-last-child(even) {background: #eee;}</pre><p>Ces deux façons d'écrire ont le même résultat, des lignes paires et impaires avec un background différent. Il n'est pas sûr que nth-last-child soit la meilleure pseudo-classe pour cet effet, mais vous pouvez l'utiliser.</p><p>Une utilisation plus spécifique à nth-last-child est de cibler un ou plusieurs éléments à la fin d'une liste.</p><figure role="group"><img src="https://la-cascade.io/images/ps3numbers-4.jpeg" alt="quelques chiffres dans des nuages" /></figure><p><strong>:nth-of-type et :nth-last-of-type</strong><br />Les autres pseudo-classes structurelles sont des variations de ce qui précède, donc nous allons simplement voir leurs applications spécifiques.</p><p><strong>E:nth-of-type(n)</strong> cible un élément E qui est le n-ième frère du même type.</p><p><strong>E:nth-last-of-type(n)</strong> cible un élément E qui est le n-ième frère du même type, en partant du dernier.</p><p>nth-of-type et nth-last-of-type fonctionnent de la même façon que nth-child et nth-last-child, la différence étant qui nous ciblons un type d'élément spécifique et non pas n'importe quel enfant.</p><p>On utilise les pseudo-classes "of-type" lorsque le parent de l'élément qu'on cible a plusieurs types d'éléments enfants :</p><pre>&lt;div&gt;
 &lt;p&gt;&lt;/p&gt;
&lt; img src="" alt="" / &gt;
 &lt;p&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;/li&gt;
    &lt;li&gt;&lt;/li&gt;
  &lt;/ul&gt;
 &lt;p&gt;&lt;/p&gt;
&lt;/div&gt;
//CSS
p:nth-of-type(2) {font-size: 1.2em;}
p:nth-last-of-type(1) {font-size: 1.2em;}</pre><p>Je suis sûr que vous voyez quels paragraphes sont ciblés par le CSS ci-dessus. Et la raison pour laquelle on utilise ici les "of-type" est que les éléments situés dans la div sont de types différents.</p><p><strong>:first-child et :last-child</strong><br />Ce sont en fait des raccourcis pour nth-child(1) et nth-last-child(1), et comme ces deux pseudo-classes, ils sous-entendent que les enfants sont de même type.</p><p><strong>E:first-child</strong> cible un élément E qui est le premier enfant de son parent.</p><p><strong>E:last-child</strong> cible un élément E qui est le dernier enfant de son parent.</p><p>On utilise souvent ces pseudo-classes dans les barres de navigation lorsqu'on veut donner un style au premier ou au dernier élément du menu pour les différencier des autres. Ou bien, il arrive fréquemment qu'on ajoute une bordure gauche ou droite aux éléments du menu pour les séparer, mais il faut du coup en ajouter (ou retirer) une d'un côté ou de l'autre. li:last-child ou li:first-child sont pratiques pour y arriver.</p><p><strong>:first-of-type et :last-of-type</strong><br />Ce sont les équivalents fonctionnels de nth-of-type(1) et nth-last-of-type(1). Ils fonctionnent de la même façon que first-child et last-child, sauf qu'ils ciblent des éléments d'un type particulier.</p><p><strong>E:first-of-type</strong> cible un élément E qui est le premier frère de son type.</p><p><strong>E:last-of-type</strong> cible un élément E qui est le dernier frère de son type.</p><p>Utilisation typique pour ces pseudo-classes : appliquer un style au premier paragraphe à l'intérieur d'une div, d'un article ou d'une section.</p><p><strong>:only-child et :only-of-type</strong><br />Ciblent des éléments qui n'ont qu'un enfant.</p><p><strong>E:only-child</strong> cible un élément E qui est le seul enfant de son parent.</p><p><strong>E:only-of-type</strong> cible un élément E qui est le seul de son type dans sa fratrie.</p><p><strong>:empty</strong></p><p><strong>E:empty</strong> cible un élément E qui n'a pas d'enfants, ni de texte. C'est une façon de cibler les attributs vides. Par exemple, il ne ciblerait pas :</p><pre>&lt;p&gt;Voici un texte&lt;/p&gt;</pre><p>mais il ciblerait :</p><pre>&lt;p&gt;&lt;/p&gt;</pre><p>Pour finir, si l'anglais n'est pas un problème voici <a href="https://www.youtube.com/watch?v=Konn2NMmSXw">une formidable vidéo de Chris Coyier</a> présentant les pseudo-classes et pseudo-éléments.</p><h2>Les pseudo-éléments</h2><p>Parfois nous aimerions appliquer un style à des <strong>éléments</strong> mais nous ne pouvons le faire à partir d'informations tirée du <a href="https://la-cascade.io/articles/le-dom-cest-quoi-exactement">DOM</a>. Nous résolvons le problème en ajoutant un élément (un span par exemple) auquel nous donnons une classe. Dans certains cas, le recours aux <strong>pseudo-éléments</strong> s'avère plus simple.</p><p>Nous en avons quatre :</p><ul><li><strong>:first-line</strong></li>
<li><strong>:first-letter</strong></li>
<li><strong>:before</strong></li>
<li><strong>:after</strong></li>
</ul><p><strong>E:first-line</strong> cible la première ligne formatée d'un élément E.</p><pre>p:first-line {text-transform: uppercase;}</pre><p>Le CSS ci-dessus change la première ligne de tous les paragraphes, et bien sûr la <em>première ligne de texte</em> est dynamique si votre mise en page est flexible.</p><p><strong>E:first-letter</strong> cible la première lettre d'un élément E.</p><p>Une utilisation évidente serait la création de <a href="http://fr.wikipedia.org/wiki/Lettrine">lettrines</a> :</p><pre>&lt;p class="intro"&gt;This is the first paragraph&lt;/p&gt;
//CSS
p.intro:first-letter {
    font-size:4em;
    font-weight:bold;
    color: #f00;
    float:left;
}</pre><p><strong>E:before et E:after</strong> ciblent un contenu généré avant ou après un élément E.</p><p>Une utilisation courante est l'ajout de guillemets stylisés avant et après une citation :</p><pre>&lt;blockquote&gt;&lt;/blockquote&gt;
//CSS
blockquote::before {content: "\2018";}
blockquote::after {content: "\2019;;";}</pre><p>Pour une approche détaillée de <strong>:before</strong> et <strong>:after</strong>, vous pouvez lire <a href="https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after/">l'article de Louis Lazaris</a> ici-même.</p></div>]]></description>
      <link>https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css</link>
      <guid>https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css</guid>
      <pubDate>Sun, 13 Apr 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Pseudo-éléments :before & :after]]></title>
      <description><![CDATA[<p><em>Cet article de Louis Lazaris s'adresse à ceux qui ont découvert avec émerveillement les trucs sympas qu'on peut faire avec les pseudo-éléments et veulent mieux connaître cette technique très utilisée. On commence par :before et :after.</em></p><div class="articleContent"><p>Cet article s'adresse à ceux qui ont découvert les trucs cools qu'on peut faire avec les pseudo-éléments et veulent mieux connaître cette technique. La spécification CSS contient <a href="http://reference.sitepoint.com/css/pseudoelements">d'autres pseudo-éléments</a>, mais je me concentrerai ici sur <code>:before</code> et <code>:after</code> et pour la simplicité je parlerai de "pseudo-éléments" en me référant spécifiquement à ces deux-là. ( <em>NdT : pour plus d'infos sur les pseudo-éléments et pseudo-classes, vous pouvez consulter <a href="https://la-cascade.io/articles/combinateurs-et-pseudo-classes-css/">cet article</a> et pour une plongée en profondeur sur :before et :after <a href="https://la-cascade.io/articles/plongee-en-profondeur-dans-les-pseudo-elements-before-et-after">cet autre article</a> ici-même</em>).</p><h2>Que fait un pseudo-élément ?</h2><p>Il fait exactement ce que son nom implique : il crée un élément factice et l'insère avant ou après le contenu de l'élément que vous avez ciblé.</p><p>Un pseudo-élément ne change rien dans le document lui-même, en fait il insère des éléments "fantômes" qui sont visibles par l'utilisateur et auxquels on peut appliquer un style CSS.</p><h2>Syntaxe basique</h2><p>Les pseudo-éléments <code>:before</code> et <code>:after</code> sont très simples à coder, en voici un exemple :</p><pre>#exemple:before {
   content: "#";
}
#exemple:after {
   content: ".";
}</pre><p>Il y a deux choses à noter à propos de cet exemple. D'abord, nous ciblons ici le même élément en utilisant <code>#exemple:before</code> et <code>#exemple:after</code>. À proprement parler, ce sont les pseudo-éléments dans ce code.</p><p>Ensuite, sans la propriété <code>content</code> , les pseudo-éléments ne servent à rien. Si le sélecteur pseudo-élément est nécessaire pour cibler l'élément, il n'est pas pour autant suffisant, vous n'insérerez rien tant que vous n'aurez pas ajouté la propriété <code>content</code>.</p><p>Dans l'exemple que nous venons de voir, on insère un symbole # avant le contenu de l'élément ayant l'id <code>exemple</code> et un point après.</p><h2>À propos de la syntaxe</h2><p>Vous pourriez tout aussi bien laisser la propriété <code>content</code> vide et traiter le pseudo-élément comme une boîte vide :</p><pre>#example:before {
   content: "";
   display: block;
   width: 100px;
   height: 100px;
}</pre><p>Toutefois, vous ne pouvez pas supprimer la propriété <code>content</code>, le pseudo-élément ne fonctionnerait pas. A minima, la propriété <code>content</code> doit contenir des "" vides.</p><p>Vous avez peut-être remarqué qu'on peut aussi utiliser la syntaxe <code>::before</code> et <code>::after</code>. Pour faire bref, il n'y a pas de différence entre les deux syntaxes, c'est juste une façon de différencier les pseudo-éléments et les pseudo-classes en CSS3 mais vous pouvez oublier cette syntaxe.</p><h2>Caractéristiques du contenu inséré</h2><p>Comme déjà mentionné, le contenu inséré n'est pas visible dans les sources de la page (si vous cherchez sur DevTools), il n'est visible que dans le CSS.</p><p>De plus, l'élément inséré est par défaut <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline/">un élément inline</a>. Pour lui donner une hauteur, un padding, des marges, etc, vous devrez le définir explicitement comme un élément block.</p><p>Cela nous amène à une brève description de la façon d'appliquer un style à nos pseudo-éléments. Regardons ce graphique tiré de mon éditeur de texte :</p><figure><img src="https://la-cascade.io/images/styles-pseudo-elements-compressor.jpeg" alt="display, width, height sont les styles qui affectent le pseudo élément" /></figure><p>Dans cet exemple, j'ai surligné les styles qui seront appliqués aux éléments insérés avant et après le contenu de l'élément cible. Les pseudo-éléments ont ceci d'unique qu'on insère le contenu <em>et</em> le style dans le même bloc de déclaration.</p><p>Notez également que les règles d'héritage CSS s'appliquent aux éléments insérés. Si par exemple vous avez défini une police de caractères <code>Helvetica, Arial, sans-serif</code> pour l'élément <code>body</code> de votre document, le pseudo-élément héritera de cette police comme n'importe quel autre élément.</p><p>De la même façon, les pseudo-éléments n'héritent pas de styles qui ne sont pas naturellement hérités de leurs parents, tels que les paddings et les marges.</p><h2>Avant ou après quoi ?</h2><p>Notre intuition nous dit que le contenu sera inséré avant et après l'élément cible. Mais comme je l'ai déjà suggéré, ce n'est pas le cas.</p><p>Le contenu injecté sera un enfant de l'élément cible, mais il sera placé "avant" ou "après" tout autre contenu dans cet élément.</p><p>Pour mieux comprendre, prenons un exemple. Tout d'abord le HTML :</p><pre>&lt;p class="box"&gt;Other content.&lt;/p&gt;</pre><p>Et maintenant le CSS qui insère le pseudo-élément :</p><pre>p.box {
   width: 300px;
   border: solid 1px white;
   padding: 20px;
}
p.box:before {
   content: "#";
   border: solid 1px white;
   padding: 2px;
   margin: 0 10px 0 0;
}</pre><p>Dans le HTML, tout ce qu'on voit est un paragraphe avec une classe <code>box</code>, et les mots "Other content" à l'intérieur (c'est ce que vous verriez si vous inspectiez la source). Dans le CSS, le paragraphe a une largeur, un padding et une bordure visible.</p><p>Puis nous avons le pseudo-élément. Il insère un symbole # "avant" le contenu du paragraphe. Le CSS qui suit lui donne une bordure, un padding, des marges.</p><p>Et voici le résultat dans notre navigateur :</p><figure><img src="https://la-cascade.io/images/autre-contenu-compressor.jpeg" alt="symbole inséré avant le paragraphe, le symbole comporte une bordure, un padding et des marges" /></figure><p>La boîte extérieure est notre paragraphe. La bordure qui entoure le symbole # représente les limites de notre pseudo-élément. Autrement dit, celui-ci n'est pas inséré "avant" le paragraphe, il est placé avant "Other content" à l'intérieur du paragraphe.</p><h2>Insérer du contenu non-textuel</h2><p>Nous avons vu que nous pouvions donner à la propriété <code>content</code> une valeur textuelle - y compris éventuellement une chaîne de caractères vide (""). Mais nous avons encore deux options possibles.</p><p>Tout d'abord, nous pouvons inclure une URL qui pointe vers une image, exactement comme nous le ferions pour inclure une image de background dans le CSS :</p><pre>p:before {
   content: url(image.jpg);
}</pre><p>Remarquez qu'il n'y a pas de guillemets. Si c'était le cas, cela deviendrait une chaîne de caractères et on insèrerait le texte "url(image.jpg)" comme contenu au lieu d'insérer l'image elle-même.</p><p>Bien entendu, nous pouvons inclure une <a href="https://www.alsacreations.com/article/lire/1439-data-uri-schema.html">Data URI</a> à la place de la référence de l'image, tout comme pour un background CSS.</p><p>Nous avons également la possibilité d'inclure une fonction sous la forme <code>attr(X)</code>. Selon <a href="http://www.w3.org/TR/CSS2/generate.html#propdef-content">les termes de la spécification</a>, "cette fonction retourne sous forme de chaîne de caractères la valeur de l'attribut X pour le sujet du sélecteur".</p><p>Par exemple :</p><pre>a:after {
   content: attr(href);
}</pre><p>Que fait cette fonction <code>attr()</code> ? Elle prend la valeur de l'attribut spécifié (href) et la retourne sous forme de texte, qui sera inséré par le pseudo-élément.</p><p>Le code ci-dessus aura pour effet d'afficher sur la page la valeur de <code>href</code> de chaque élément <code>&lt;a&gt;</code> et de le placer immédiatement après chaque élément <code>&lt;a&gt;</code>. Un cas d'usage classique concerne la feuille de style "impression", puisque cela permet d'inscrire en clair l'URL après chaque lien sur les documents imprimés.</p><p>Nous pourrions aussi utiliser cette fonction pour aller chercher la valeur de l'attribut <code>title</code> d'un élément, ou même les valeurs des <a href="http://fr.wikipedia.org/wiki/Microdonn%C3%A9e">microdonnées</a>. Toutefois, s'il serait pratique d'aller chercher le <code>title</code> ou le texte <code>alt</code> d'une image pour l'afficher sur la page avec un pseudo-élément, ce n'est pas possible. Rappelez-vous que le pseudo-élément doit être un enfant de l'élément auquel il est appliqué. Les images, qui sont des <a href="http://www.w3.org/TR/html-markup/syntax.html#syntax-elements">éléments vides</a> (void elements), n'ont pas l'éléments enfants, par conséquent cela ne marche pas. Même chose pour tous les éléments vides, tels que <code>&lt;input&gt;</code> (NdT : à part ces deux là, les autres ne sont pas très intéressants).</p><h2>Accessibilité</h2><p>Les pseudo-éléments, on l'a vu, n'apparaissent pas dans le DOM, ils ne sont pas réels. De ce fait, les appareils ou logiciels d'assistance pour les personnes ayant des déficiences ne peuvent pas y accéder. Veillez à ne pas utiliser de pseudo-éléments pour générer un contenu indispensable à l'usabilité ou à l'accessibilité de vos pages.</p><p><strong>Ressources intéressantes sur :before et :after</strong></p><p><a href="http://a.singlediv.com/">A Single Div</a>, des exemples d'illustrations réalisées à partir d'une simple div et de CSS utilisant <code>:before</code> et <code>:after</code>, très impressionnant !</p></div>]]></description>
      <link>https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after</link>
      <guid>https://la-cascade.io/articles/les-pseudo-elements-css-before-et-after</guid>
      <pubDate>Sat, 05 Apr 2014 08:00:00 +0200</pubDate>
    </item>
    <item>
      <title><![CDATA[Centrer un bloc div, guide complet]]></title>
      <description><![CDATA[<p><em>Comment centrer une div ? Steve Pear fait le tour de la question du centrage de div en CSS et propose des solutions pour tous les cas de figure.</em></p><div class="articleContent"><p>Tout développeur a eu un jour des problèmes pour centrer un bloc div… Centrer le <em>contenu d'une div</em> est simple, mais centrer <em>la div elle-même</em> est plus délicat, et quand il s'agit de centrer une div verticalement vous entrez dans un monde de douleur.</p><figure role="group"><img src="https://la-cascade.io/images/Big_Lewbowski_World_Of_Pain_New_Brown_Shirt-compressor.jpeg" alt="citation du film The Big Lebowski, you are entering a world of pain" /></figure><p>L'objectif de cet article est de montrer comment centrer n'importe quelle div, horizontalement, verticalement ou les deux à la fois, à l'intérieur d'une page ou d'une div.</p><p><em>NdT : Steve Pear s'intéresse ici spécifiquement au <strong>centrage d'une div</strong> : pour une introduction complète au <strong>centrage du contenu</strong> d'une div, consultez l'article</em> <a href="https://la-cascade.io/articles/centrer-en-css-un-guide-complet">Centrer en CSS, un guide complet</a>, <em>de Chris Coyier : le centrage du contenu d'une div n'est pas aussi simple que le dit Steve Pear !</em></p><h2>Centrer une div dans une page, les bases</h2><p>Cette méthode fonctionne avec n'importe quel navigateur.</p><pre>.center-div {
     margin: 0 auto;
     width: 100px;
}</pre><p>Le résultat dans CodePen (vous pouvez cliquer sur HTML et CSS pour en voir le contenu ou sur <em>edit on CodePen</em> pour le modifier) :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/Tipue/pen/voseD/">Centering a div in a page, basic</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La valeur <code>auto</code> de la propriété <code>margin</code> donne aux marges gauche et droite l'espace restant disponible dans la page. Il faut bien se rappeler de donner une propriété <code>width</code> à votre div.</p><h2>Centrer une div dans une div, à l'ancienne</h2><p>Cela fonctionne avec à peu près tous les navigateurs.</p><pre>.outer-div {
     padding: 30px;
}
.inner-div {
     margin: 0 auto;
     width: 100px;
}
//HTML
&lt;div class="outer-div"&gt;
        &lt;div class="inner-div"&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><p>Le résultat dans CodePen :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/Tipue/pen/apDLG/">Centering a div within a div, old-school</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La marge <code>auto</code> frappe encore, et la div intérieure doit avoir une propriété <code>width</code>.</p><figure role="group"><img src="https://la-cascade.io/images/world-of-pain-1.jpeg" alt="image tirée du film The Big Lebowski, avec les protagonistes au bowling" /><figcaption>“On vous l'avait bien dit les gars...”</figcaption></figure><h2>Centrer une div dans une div avec inline-block</h2><p>Avec la méthode <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline/">inline-block</a>, la div intérieure n'a pas besoin de propriété <code>width</code>. Fonctionne avec tous les navigateurs raisonnablement modernes.</p><pre>.outer-div {
     padding: 30px;
     text-align: center;
}
.inner-div {
     display: inline-block;
     padding: 50px;
}
//HTML
&lt;div class="outer-div"&gt;
        &lt;div class="inner-div"&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/Tipue/pen/Ednlt/">Centering a div within a div with inline-block</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La propriété <code>text-align</code> ne fonctionne qu'avec les éléments inline. La valeur <code>inline-block</code> affiche la div intérieure comme un élément inline <em>et</em> block, ce qui permet à la propriété <code>text-align</code> de la div extérieure de centrer la div intérieure.</p><h2>Centrer une div dans une div, horizontalement et verticalement</h2><p>On utilise l'astuce <code>margin auto</code> pour centrer une div dans le sens horizontal et vertical, et cela fonctionne avec tous les navigateurs modernes.</p><pre>.outer-div {
     padding: 30px;
}
.inner-div {
     margin: auto;
     width: 100px;
     height: 100px;
}
//HTML
&lt;div class="outer-div"&gt;
        &lt;div class="inner-div"&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><p>Le résultat dans CodePen :</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/Tipue/pen/vsKif/">Centering a div within a div, horizontally and vertically</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La div intérieure doit avoir des propriétés <code>width</code> et <code>height</code>. Cette méthode ne fonctionne pas si la div extérieure a une hauteur fixe.</p><h2>Centrer verticalement une div avec transform</h2><p>Cette méthode utilise <code>transform</code> pour centrer verticalement tout contenu à l'intérieur d'une div. On fait appel à un élément HTML vide qui sert de conteneur, ici j'ai choisi <code>&lt;p&gt;</code>.</p><pre>.center-div p
{
     position: relative;
     top: 50%;
     transform: perspective(1px) translateY(-50%);
}
// HTML
    &lt;div class="center-div"&gt;
        &lt;p&gt;Esse augue dolor&lt;/p&gt;
    &lt;/div&gt;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/Tipue/pen/NXwGqB">Vertical center in a div with transform</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La valeur <code>perspective</code> réduit le flou (<em>blurring</em>) sur un affichage haute-définition. Pour une meilleure compatibilité avec les navigateurs anciens, vous pouvez utiliser les préfixes constructeurs comme <code>-webkit-transform</code> et <code>-ms-transform</code>. Ce dernier remonte jusqu'à IE9.</p><h2>Centrer une div en bas de page</h2><p>Ici, on utilise <code>margin auto</code> et une div externe <a href="https://la-cascade.io/articles/le-positionnement-css">positionnée absolument</a>. Fonctionne avec tous les navigateurs modernes.</p><pre>.outer-div {
     position: absolute;
     bottom: 30px;
     width: 100%;
}
.inner-div {
     margin: 0 auto;
     width: 100px;
     height: 100px;
     background-color: #ccc;
}
//HTML
&lt;div class="outer-div"&gt;
        &lt;div class="inner-div"&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/Tipue/pen/bwLDh/">Centering a div at the bottom of a page</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La div intérieure doit avoir une propriété <code>width</code>. La distance la séparant du bas de page est définie grâce à la propriété <code>bottom</code> de la div extérieure.</p><p>Pour centrer une div en haut de page, remplacez la propriété <code>bottom</code> par <code>top</code>.</p><h2>Centrer une div dans une page, horizontalement et verticalement</h2><p>On utilise là encore <code>margin auto</code>, et une div extérieure positionnée absolument. Fonctionne avec tous les navigateurs modernes.</p><pre>.center-div {
     position: absolute;
     margin: auto;
     top: 0;
     right: 0;
     bottom: 0;
     left: 0;
     width: 100px;
     height: 100px;
     background-color: #ccc;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="http://codepen.io/Tipue/pen/CBbna/">Centering a div in a page, horizontally and vertically</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La div doit avoir les propriétés <code>width</code> et <code>height</code>.</p><h2>Centrer une div dans une page, responsive</h2><p>La largeur de la div est responsive, elle s'adapte à la largeur du viewport. Fonctionne sur tous les navigateurs.</p><pre>.center-div
{
     margin: 0 auto;
     max-width: 700px;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/Tipue/pen/sGHuI">Centering a div in a page, responsive</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La div centrée doit avoir une propriété <code>max-width</code>.</p><h2>Centrer une div dans une div responsive</h2><p>La div intérieure est responsive. Fonctionne avec tous les navigateurs.</p><pre>.outer-div
{
     padding: 30px;
}
.inner-div
{
     margin: 0 auto;
     max-width: 700px;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/Tipue/pen/yAbdC">Centering a div within a div, inner div responsive</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La div intérieure doit avoir une propriété <code>max-width</code>.</p><h2>Centrer deux divs responsives, côte à côte</h2><p>Deux divs côte à côte, toutes les deux sont responsives. Fonctionne avec tous les navigateurs.</p><pre>.container
{
     text-align: center;
}
.left-div
{
     display: inline-block;
     max-width: 300px;
     vertical-align: top;
}
.right-div
{
     display: inline-block;
     max-width: 150px;
}
@media screen and (max-width: 600px)
{
     .left-div, .right-div
     {
          max-width: 100%;
     }
}
//HTML
&lt;div class="container"&gt;
    &lt;div class="left-div"&gt;
    &lt;/div&gt;
    &lt;div class="right-div"&gt;
    &lt;/div&gt;
&lt;/div&gt;</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/Tipue/pen/pjdgad">Centering two responsive divs, side by side</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>Pour cela on utilise juste deux éléments <code>inline-block</code> dans un conteneur centré. Notez qu'on fait également appel à la media query de CSS. Lorsque la taille d'écran est inférieure à 600px, la propriété <code>max-width</code> de chacune des divs est fixée à 100%.</p><h2>Flexbox et le centrage de div</h2><figure role="group"><img src="https://la-cascade.io/images/dudeism-compressor.jpeg" alt="image tirée du film The Big Lebowski" /></figure><p>Le nouveau modèle de mise en page Flexbox simplifie le centrage. L'exemple ci-dessous centre une div horizontalement et verticalement.</p><pre>.container
{
     display: flex;
     align-items: center;
     justify-content: center;
     height: 100vh;
}
.item
{
     background-color: #f3f2ef;
     border-radius: 3px;
     width: 200px;
     height: 100px;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/Tipue/pen/QbrvYe">Flexbox, div centered</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>La propriété <code>height</code> du conteneur peut être ce qu'on veut, du moment qu'elle est plus large que la div centrée. Dans cet exemple, nous utilisons <code>vh</code>, qui est la hauteur de la fenêtre du navigateur, le viewport, plutôt que la hauteur de la page.</p><h2>Centrer une div dynamique, horizontalement et verticalement</h2><p>Cette méthode utilise la propriété <code>display</code> avec une valeur de <code>table</code>, ce qui lui donne le comportement d'un élément <code>table</code> et centre la div horizontalement et verticalement. La div centrée peut avoir un contenu dynamique, et donc une hauteur ou une largeur variable. Elle peut être responsive.</p><pre>.outer-div
{
     display: table;
     position: absolute;
     height: 100%;
     width: 100%;
}
.mid-div
{
     display: table-cell;
     vertical-align: middle;
}
.center-div
{
     margin: 0 auto;
     width: 300px;
     height: 100px;
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/Tipue/pen/PEEOYp">Centering a dynamic div, horizontally and vertically</a>de Steve Pear dans<a href="https://codepen.io">CodePen</a></div><p>Les propriétés <code>width</code> et <code>height</code> de la div centrée peuvent être ce que vous voulez.</p><hr /><h2 class="ressourcesComplementaires">Ressources complémentaires</h2><p>Consultez également dans La Cascade :</p><ul><li><a href="https://la-cascade.io/articles/alignement-en-css-guide-complet">Alignement en CSS, guide complet</a></li>
<li><a href="https://la-cascade.io/articles/centrer-en-css-un-guide-complet">Centrer en CSS, guide complet</a></li>
<li><a href="https://la-cascade.io/articles/css-flexbox-et-lalignement-guide-complet">CSS Flexbox et l'alignement, guide complet</a></li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/centrer-une-div-guide-complet</link>
      <guid>https://la-cascade.io/articles/centrer-une-div-guide-complet</guid>
      <pubDate>Fri, 28 Mar 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Les free fonts aujourd'hui]]></title>
      <description><![CDATA[<p><em>Jeremiah Shoaf, le créateur du site indispensable Typewolf, fait le point sur les polices gratuites et nous propose ses préférées. On peut trouver de vraies pépites aujourd'hui en open source !</em></p><div class="articleContent"><p>Autrefois considérées comme <em>amateurs</em> par les designers professionnels, les polices de caractères libres et open source connaissent depuis quelques années une véritable renaissance, avec une qualité qui s'est considérablement améliorée. Pour être honnêtes, les <strong>polices gratuites n'ont pas bonne réputation</strong> et elles sont souvent des contrefaçons de polices célèbres minutieusement ciselées. Est-il vraiment besoin de les reconsidérer ?</p><h2>D'abord, une histoire</h2><p>Quand j'ai commencé ma carrière de designer, vers 2003, j'ai voulu acheter la police DIN pour un projet. Mon directeur a immédiatement rejeté l'idée de payer pour une police et m'a tendu un CD contenant "5.000 polices gratuites" en me disant "ce CD contient toutes les polices dont un designer peut avoir besoin, pas besoin de dépenser bêtement de l'argent".</p><p>J'ai inséré le CD dans mon ordinateur et j'ai trouvé une collection des plus horribles polices qu'on puisse imaginer. Des modernes, des "rétro", des polices "Halloween" sinistres, des "technos", des polices sans crénage, avec des glyphes manquants, des polices disponibles avec une seule graisse et sans italiques.</p><p>Nulle part je n'ai trouvé DIN, ni d'ailleurs aucune police utilisable par un designer professionnel, et j'ai fini par utiliser Helvetica que nous avions achetée.</p><p>Retour rapide en 2014. Lorsque j'entends les mots "police gratuite", je ne peux pas m'empêcher de repenser à cet horrible CD. Mais les choses ont changé depuis, et il m'arrive fréquemment d'utiliser des polices libres pour mes projets.</p><h2>D'où viennent les Free Fonts ?</h2><p>Autrefois, les polices gratuites avaient deux provenances possibles : soit des designers amateurs qui créaient des polices pour s'amuser ou pour s'entraîner, soit des designers professionnels qui publiaient une variante libre d'une famille de polices comme un outil marketing, l'idée étant que les utilisateurs achèteraient la famille quand ils se rendraient compte de l'usage limité d'une police sans ses variantes de graisse et d'italiques.</p><h2>De l'importance de graisses et d'italiques multiples</h2><p>Pour un corps de texte correct, il vous faut avoir quatre variantes de police : <em>normal</em>, <em>italique</em>, <em>gras</em> et <em>italique gras</em>. Sans ces variantes de base, vous courez le risque de recourir aux <a href="https://alistapart.com/article/say-no-to-faux-bold/">terribles faux gras et fausses italiques</a> générés par les navigateurs, qui doivent être évités à tout prix — ce qui <a href="https://www.smashingmagazine.com/2013/02/setting-weights-and-styles-at-font-face-declaration/">peut se faire</a> facilement. D'autres graisses, comme <em>light</em> et <em>extra bold</em>, peuvent être utiles pour créer un contraste typographique entre les éléments.</p><h2>Les polices libres ont changé</h2><p>Récemment, de grandes compagnies comme Adobe et Google ont passé commande de polices qu'elles ont publiées gratuitement sur le web. Des designers professionnels se sont également impliqués dans l'open source en partageant des familles complètes de polices sur <a href="https://fonts.google.com/">Google Fonts</a>.</p><p>Grâce à la communauté open source, on trouve maintenant des polices gratuites que même les snobs de la typographie seraient heureux d'utiliser. Les polices qui suivent ont toutes des graisses multiples et des italiques correspondantes. Elles conviennent pour les titres et pour le corps de texte et leur rendu est excellent quelle que soit la taille de l'écran.</p><h3>ALEGREYA</h3><p><a href="https://fonts.google.com/specimen/Alegreya">Alegreya</a> est une police sérif élue par l'Association Typographique Internationale (ATypl) comme l'une des 53 "polices des dix dernières années" dans sa compétition Letter.2. Elle est disponible gratuitement sur Google Fonts, mais malheureusement la plupart des designers ne la connaissent pas. Je la vois rarement utilisée en ligne, ce qui est très dommage car c'est une formidable police. Alegreya a été conçue en pensant à l'impression, mais elle est excellente à l'écran.</p><p>Le designer, Juan Pablo del Peral, affirme qu'il a donné le même soin et la même attention aux détails pour les italiques et cela se voit - le style italique est particulièrement réussi. J'espère que des designers toujours plus nombreux l'utiliseront en 2014.</p><figure role="group"><img src="https://la-cascade.io/images/alegreya-font-sample.png" alt="" /><figcaption>Beef utilise Alegreya pour le corps de texte de son site, ce qui lui donne une allure majestueuse formant un beau contraste avec les titres en <a href="https://www.typewolf.com/avenir">Avenir</a>.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/alegreya-font-sample2.png" alt="" /><figcaption>Le beau style italique gras d'Alegreya est utilisé pour un titre de la section jobs de Beef.</figcaption></figure><p> <a href="https://www.typewolf.com/alegreya">Sites qui utilisent Alegreya</a></p><h3>SOURCE SANS PRO</h3><p>Publiée par Adobe en août 2012, Source Sans Pro est la première police open source d'Adobe. Son designer, Paul D. Hunt s'est inspiré de gothiques du début du 20e siècle, telles que Franklin Gothic et News Gothic. À mes yeux, Source Sans Pro est plus moderne, rappelant un peu FF Meta. Elle est faite pour les interfaces utilisateurs et rend très bien sur de petits écrans. La police est disponible dans 6 graisses différentes ce qui la rend très souple.</p><figure role="group"><img src="https://la-cascade.io/images/source-sans-pro-font-sample.png" alt="" /><figcaption><a href="https://www.cast83.com/">CAST83</a> utilise Source Sans Pro sur tout son site et montre la diversité de cette famille. De grands titres en light, le gras étant utilisé pour les capitales en taille plus réduite, ce qui crée un excellent contraste typographique.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/source-sans-pro-font-sample2.png" alt="" /><figcaption><a href="https://www.plentific.com/en-gb/">Plentific</a> utilise les poids extra-light et normal de Source Sans Pro pour créer un contraste entre différents niveaux de titres.</figcaption></figure><p> <a href="https://www.typewolf.com/source-sans-pro">Sites qui utilisent Source Sans Pro</a></p><h3>OPEN SANS</h3><p>Conçue par le célèbre designer Steve Matteson sur une commande de Google, <a href="https://fonts.google.com/specimen/Open+Sans">Open Sans</a> est l'une des polices open source les plus largement utilisées sur le web. C'est notamment la police par défaut du framework <a href="https://get.foundation/">Foundation 5</a> de Zurb et elle est utilisée sur de nombreuses pages du <a href="https://marketingplatform.google.com/about/analytics/">redesign Google</a>. J'ai même entendu qualifier Open Sans de police du "flat design". Les cinq graisses et leurs italiques correspondantes rendent cette sans-sérif humaniste utile dans de nombreuses situations.</p><figure role="group"><img src="https://la-cascade.io/images/open-sans-font-sample.png" alt="" /><figcaption><a href="https://vitorandrade.co/">Le site de Vitor Andrade</a> utilise Open Sans avec discrétion. Le design minimaliste, basé sur les fontes, est assez neutre, attirant l'attention sur l'excellent travail présenté sur le site.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/open-sans-font-sample2.png" alt="" /><figcaption>La version light d'Open Sans sert aux titres sur le site web The Industry.</figcaption></figure><p> <a href="https://www.typewolf.com/open-sans">Sites qui utilisent Open Sans</a></p><h3>ANONYMOUS PRO</h3><p><a href="https://fonts.google.com/specimen/Anonymous+Pro">Anonymous Pro</a> est une police monospace (police d'écriture à chasse fixe) que peu de designers connaissent, ce qui est surprenant quand on sait qu'elle a été conçue par <a href="https://www.marksimonson.com/">Mark Simonson</a>, le designer de Proxima Nova. Les polices monospace sont à la mode et Anonymous Pro est une excellente option.</p><p><a href="https://www.typewolf.com/inconsolata">Inconsolata</a>, disponible également sur Google Fonts, est plus utilisée, mais elle n'intègre pas les italiques contrairement à Anonymous Pro. En général, l'utilisation d'une police monospace en corps de texte n'est pas une bonne idée, mais dans le bon contexte elle peut donner à votre design une certaine fraîcheur.</p><figure role="group"><img src="https://la-cascade.io/images/anonymous-pro-font-sample.png" alt="" /><figcaption><a href="https://www.per1000.com/">Per Sandström</a> utilise Anonymous Pro en grand format dans son corps de texte sur un site où l'association avec <a href="https://www.typewolf.com/futura">Futura</a> pour les titres fonctionne étonnamment bien.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/anonymous-pro-font-sample2.png" alt="" /><figcaption>Les boutons utilisent la variante grasse d'Anonymous Pro sur <a href="https://www.per1000.com/">le site de Per</a>.</figcaption></figure><p> <a href="https://www.typewolf.com/anonymous-pro">Sites qui utilisent Anonymous Pro</a></p><h3>PLAYFAIR DISPLAY</h3><p><a href="https://fonts.google.com/specimen/Playfair+Display">Playfair Display</a> est une police sérif très contrastante conçue par Claus Eggers Sørensen. Elle rappelle <a href="https://www.typewolf.com/baskerville">Baskerville</a> et trouve son inspiration dans les fontes de la fin du 18e siècle. Bien que conçue à l'origine pour les titres, les 3 poids et leurs italiques lui permettent de convenir à de petites portions du corps de texte. Pour de plus longues portions, Playfair Display forme une belle association avec Georgia.</p><figure role="group"><img src="https://la-cascade.io/images/playfair-display-font-sample.png" alt="" /><figcaption>Playfair Display offre une belle variante italique qu'on peut voir sur le site de Boompa Records.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/playfair-display-font-sample2.png" alt="" /><figcaption>Playfair Display en gras pour les titres du site de Digital Abstracts.</figcaption></figure><p> <a href="https://www.typewolf.com/playfair-display">Sites qui utilisent Playfair Display</a></p><h3>ROBOTO</h3><p><a href="https://fonts.google.com/specimen/Roboto">Roboto</a> a été qualifiée de "<a href="https://typographica.org/on-typography/roboto-typeface-is-a-four-headed-frankenstein/">Frankenfont</a>" — une fusion d'Helvetica, DIN et Myriad. Je comprends la critique mais ça ne m'empêche pas d'aimer Roboto. Depuis cet article, <a href="https://www.androidpolice.com/2013/06/29/typeface-teardown-roboto-gets-a-facelift-in-android-4-3/">des améliorations ont été apportées à Roboto</a> et je trouve que cette police fonctionne bien sur toutes tailles et résolutions d'écrans, ce qui est son objectif.</p><p>Elle semble familière et pourtant plus on la regarde et plus on se rend compte qu'elle possède quelque chose d'unique. La famille Roboto intègre également <a href="https://fonts.google.com/specimen/Roboto+Slab">une jolie version slab</a> (égyptienne) et <a href="https://fonts.google.com/specimen/Roboto+Condensed">une version condensée</a>.</p><figure role="group"><img src="https://la-cascade.io/images/roboto-font-sample.png" alt="" /><figcaption>J'utilise Roboto sur mon site Type&amp;Grid et les polices ont un beau rendu sur les écrans à haute densité, même de petite taille.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/roboto-font-sample2.png" alt="" /><figcaption>La version light de Roboto sur le blog de Paone Creative.</figcaption></figure><p> <a href="https://www.typewolf.com/roboto">Sites qui utilisent Roboto</a></p><h3>LATO</h3><p>Lato signifie l'été en polonais, un nom qui va bien à cette police sans-sérif chaleureuse. Au départ, le designer Łukas Dziedzic a réalisé cette police pour un client mais lorsque celui-ci a changé d'avis, Łukas a décidé de publier sa police. Lato semble modeste et sans prétention lorsqu'on l'utilise dans le corps de texte mais la variante italique est très particulière et reconnaissable. Lato est utilisée par le dernier thème par défaut de Wordpress, Twenty Fourteen, et deviendra plus populaire de ce fait.</p><figure role="group"><img src="https://la-cascade.io/images/lato-font-sample.png" alt="" /><figcaption>Frank Chimero fait un bel usage de la version extra light dans son article "Ce que veulent les écrans", en capitales de grande taille, ce qui est nécessaire pour une graisse tellement délicate.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/lato-font-sample2.png" alt="" /><figcaption>Le site d'AIGA "100 ans de design" montre une version personnalisée "sans point sur les i" de Lato.</figcaption></figure><p> <a href="https://www.typewolf.com/lato">Sites qui utilisent Lato</a></p><h3>MERRIWEATHER</h3><p>Conçue par Eben Sorkin, <a href="https://fonts.google.com/specimen/Merriweather">Merriweather</a> est une police sérif créée pour la lecture à l'écran. Sa grande hauteur d'x et des sérifs costauds lui assurent une excellente lisibilité. Merriweather est encore en développement actif et s'améliore constamment. Il existe aussi <a href="https://fonts.google.com/specimen/Merriweather+Sans">une version sans-sérif</a> qui l'accompagne remarquablement.</p><figure role="group"><img src="https://la-cascade.io/images/merriweather-font-sample.png" alt="" /><figcaption>La version light de Merriweather donne au site de <a href="https://dicksonfong.com/">Dickson Fong</a> une allure élégante.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/merriweather-font-sample2.png" alt="" /><figcaption>Vtcreative fait ressortir le style light italique de Merriweather dans son footer.</figcaption></figure><p> <a href="https://www.typewolf.com/merriweather">Sites qui utilisent Merriweather</a></p><h3>KARLA</h3><p><a href="https://fonts.google.com/specimen/Karla">Karla</a> est une police grotesque sans-sérif conçue par Jonathan Pinhorn qui est pleine caractère et de bizarreries. Quelque chose en elle me rappelle la police à la mode <a href="https://www.typewolf.com/apercu">Aperçu</a>. L'espacement des caractères est peut-être un peu large pour le corps de texte et parfois le crénage peut sembler bancal, mais son originalité me fait oublier ces imperfections. C'est une police parfaite pour ajouter une touche de personnalité à votre design.</p><figure role="group"><img src="https://la-cascade.io/images/karla-font-sample.png" alt="" /><figcaption><a href="https://www.borschvodkaandtears.com/">Borsch, Vodka &amp; Tears</a> utilise Karla pour les quelques irruptions de corps de texte sur son site, et ça fonctionne.</figcaption></figure><figure role="group"><img src="https://la-cascade.io/images/karla-font-sample2.png" alt="" /><figcaption><a href="https://kalynnakano.com/">Kalyn Nakano</a> fait ressortir les variantes normal et gras de Karla sur son portfolio.</figcaption></figure><p> <a href="https://www.typewolf.com/karla">Sites qui utilisent Karla</a></p><h3>CLEAR SANS</h3><p><a href="https://github.com/intel/clear-sans">Clear Sans</a> est la contribution récente d'Intel à la communauté open source des polices de caractères. Priorité a été donnée à la lisibilité, par exemple le "i" majuscule a des empattements pour le distinguer du "l" minuscule. C'est donc un bon choix pour le design d'interface utilisateur où la clarté est essentielle. Clear Sans n'est pas disponible actuellement sur Google Fonts, donc il vous faudra l'héberger.</p><figure role="group"><img src="https://la-cascade.io/images/clear-sans-font-sample.png" alt="" /><figcaption>la délicate variante light de Clear Sans est utilisée pour le corps de texte sur le site de Clear Sans.</figcaption></figure><h3>FIRA SANS</h3><p>Conçue pour l'OS de Firefox, <a href="https://mozilla.design/firefox/">Fira Sans</a> a été récemment publiée en open source. Cette police a de nombreuses similarités avec FF Meta, ce qui n'est pas étonnant quand on sait qu'Erik Spiekermann est le créateur des deux. Il est rare de trouver une police de caractères gratuite créée par un designer aussi renommé. Fira Sans comprend une version monospace appelée Fira Mono.</p><figure role="group"><img src="https://la-cascade.io/images/fira-sans-screenshot.png" alt="" /></figure><h2>AUTRES POLICES INTÉRESSANTES</h2><ul><li><a href="https://fonts.google.com/specimen/Exo">Exo</a></li>
<li><a href="https://fonts.google.com/specimen/Signika">Signika</a></li>
<li><a href="https://fonts.google.com/specimen/Arimo">Arimo</a></li>
<li><a href="https://fonts.google.com/specimen/Raleway">Raleway</a></li>
<li><a href="https://fonts.google.com/specimen/Montserrat">Montserrat</a></li>
<li><a href="https://fonts.google.com/specimen/Domine">Domine</a></li>
<li><a href="https://fonts.google.com/specimen/Lora">Lora</a></li>
</ul><h2>N'UTILISEZ PAS LES POLICES GRATUITES POUR TOUT</h2><p>Aussi belles soient-elles, les designers ne devraient pas se contenter des seules polices gratuites, qui n'arriveront jamais au même niveau que les polices des meilleures fonderies. Budgétez des polices professionnelles chaque fois que vous le pouvez. Les fonderies ont besoin du soutien de la communauté des designers pour continuer à innover.</p><p>Ceci étant dit, si votre projet doit faire appel à des polices gratuites, pour des raisons budgétaires ou autres, dites-vous bien que le choix est toujours plus grand. Je tiens à jour <a href="https://www.typewolf.com/google-fonts">une liste de fontes open source</a> sur mon projet <a href="https://www.typewolf.com/">Typewolf</a>. Vous pouvez également me suivre sur <a href="https://twitter.com/typewolf">@typewolf</a>.</p><p>Créer une police demande beaucoup de temps, de patience et de travail, et les designers devraient être récompensés pour leur travail. Si vous décidez d'utilisez des polices gratuites, n'oubliez pas de leur renvoyer l'ascenseur en achetant d'autres fontes ou en faisant un don pour soutenir leurs efforts.<br />(NdT, pro domo : n'oubliez pas non plus que la création de musique demande du temps, de la patience et du travail, si vous voulez soutenir les artistes que vous aimez n'oubliez pas de payer pour leur travail).</p></div>]]></description>
      <link>https://la-cascade.io/articles/les-free-fonts-aujourdhui</link>
      <guid>https://la-cascade.io/articles/les-free-fonts-aujourdhui</guid>
      <pubDate>Sat, 15 Mar 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Les dégradés CSS]]></title>
      <description><![CDATA[<p><em>Surligner les rangées d'un tableau en CSS est très facile, mais les colonnes ? Les pseudo-éléments sont mis à contribution dans ce tutoriel court, facile et astucieux de l'indispensable Chris Coyier.</em></p><div class="articleContent"><p>En CSS, vous pouvez choisir de déclarer le background d'un élément comme une couleur solide, ou comme un dégradé. L'utilisation de dégradés CSS à la place d'images est préférable en termes de contrôle et de performance.</p><p>Qu'est-ce qu'un dégradé ? Typiquement, c'est le passage d'une couleur vers une autre, mais avec CSS vous pouvez contrôler exactement la façon dont ça se passe, depuis la direction jusqu'aux couleurs (aussi nombreuses que vous désirez) et jusqu'à l'endroit où vous voulez que ça se produise. Voyons ça en détail.</p><h2>Les dégradés comme background-image</h2><p>En CSS, la déclaration d'une couleur solide se fait en utilisant la propriété <code>background-color</code>, mais pour les dégradés on utilise <code>background-image</code>. C'est pratique, comme nous allons le voir tout à l'heure. Le raccourci <code>background</code> saura ce que vous voulez dire si vous déclarez l'un ou l'autre.</p><pre>//CSS
.gradient {
  /* pour une éventuelle solution de rechange */
background-color: red;
/* sera "au-dessus", si le navigateur est compatible */
background-image: linear-gradient(red, orange);
/* remet à zéro les autres propriétés, comme background-position, mais le navigateur ne sait pas ce que vous voulez */
background: red;
background: linear-gradient(red, orange);
}</pre><h2>Dégradés linéaires</h2><p>Le type de dégradés le plus courant et le plus utile est <code>linear-gradient()</code>. L'axe du dégradé peut être de gauche à droite, du haut vers le bas ou selon un angle que vous choisissez.</p><p>Si vous ne déclarez rien, la direction sera par défaut de haut en bas :</p><figure><img src="https://la-cascade.io/images/gradients1.png" alt="dégradé de haut en bas" /></figure><p>Les couleurs sont séparées par une virgule et peuvent être de tous les types que vous utilisez habituellement : hexadécimales, couleurs nommées, RGBA, HSLA, etc.</p><p>Pour rendre votre dégradé horizontal, vous devez passer un paramètre supplémentaire commençant par le mot "to" (vers) qui indique la direction :</p><pre>//CSS
.gradient {
  background-image:
    linear-gradient(
      to right,
      red, #f06d06
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients2.png" alt="dégradé de gauche à droite" /></figure><p>Cette syntaxe "to" fonctionne aussi pour les coins. Par exemple si vous voulez que l'axe du dégradé commence au coin inférieur gauche pour aller au coin supérieur droit, vous pouvez indiquer "to top right" :</p><pre>.gradient {
  background-image:
    linear-gradient(
      to top right,
      red, #f06d06
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients3.png" alt="dégradé du coin inférieur gauche au coin supérieur droit" /></figure><p>Si cette boîte était carrée, l'angle du dégradé serait de 45°, mais ce n'est pas le cas ici. Si vous voulez être sûr que l'angle soit de 45°, vous pouvez déclarer :</p><pre>//CSS
.gradient {
  background-image:
    linear-gradient(
      45deg,
      red, #f06d06
    );
}</pre><p>Vous n'êtes pas non plus limités à deux couleurs. En fait, vous pouvez intégrer autant de couleurs que vous le souhaitez, séparées par des virgules. En voici quatre :</p><pre>//CSS
.gradient {
  background-image:
    linear-gradient(
      to right,
      red,
      #f06d06,
      rgb(255, 255, 0),
      green
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients4.png" alt="dégradé avec stops multiples" /></figure><p>Vous pouvez également déclarer l'endroit où vous voulez qu'une couleur s'arrête. C'est ce qu'on appelle le color-stop. Si par exemple vous voulez que le jaune occupe l'essentiel de l'espace et le rouge une toute petite partie au début, vous pouvez déclarer un color-stop assez tôt :</p><pre>//CSS
.gradient {
  height: 100px;
  background-color: red;
  background-image:
    linear-gradient(
      to right,
      red,
      yellow 10%
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients5.png" alt="dégradé avec très peu de rouge et très peu de dégradé, tout se passe dans les 10% initiaux, le reste est du jaune pur" /></figure><p>Quand on parle de dégradés on pense à des couleurs qui se mélangent graduellement mais si vous utilisez deux color-stop identiques, vous passez instantanément d'une couleur à l'autre, ce qui peut être utile pour créer des backgrounds qui simulent des colonnes.</p><pre>//CSS
.columns-bg {
  background-image:
    linear-gradient(
      to right,
      #fffdc2,
      #fffdc2 15%,
      #d7f0a2 15%,
      #d7f0a2 85%,
      #fffdc2 85%
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients6.png" alt="3 colonnes" /></figure><p><strong>Compatibilité navigateurs / préfixes</strong><br />Jusqu'à présent, nous n'avons vu que la <strong>nouvelle syntaxe</strong>, mais les dégradés CSS existent depuis un bon bout de temps. La compatibilité navigateurs est bonne, là où ça devient complexe, c'est au niveau de la syntaxe et des préfixes. Il y a <strong>trois</strong> syntaxes différentes, qu'on peut voir ainsi :</p><ol><li><strong>Ancienne</strong> : la syntaxe originale, Webkit, avec des choses du genre <code>from()</code> et <code>color-stop()</code>.</li>
<li><strong>Intermédiaire</strong> : nouveautés du genre "left".</li>
<li><strong>Nouvelle</strong> : nouveau changement avec "to right".</li>
</ol><p>Et bien sûr les préfixes.</p><p>Essayons de mettre tout ça dans un tableau :</p><pre>CHROME                1-9: Ancienne, préfixée
                        10-25: Intermédiaire, préfixée
                        26: Nouvelle, non préfixée
SAFARI          3-: Incompatible
                        4-5.0: Ancienne, préfixée
                        5.1-6.0: Intermédiaire, préfixée
                        6.1: Nouvelle, non préfixée
FIREFOX         3.5-: Incompatible
                        3.6-15: Intermédiaire, préfixée
                        16: Nouvelle, non préfixée
OPERA           11.0-: Incompatible
                        11.1-11.5: Intermédiaire, préfixée, linéaire seulement
                        11.6-12: Intermédiaire, préfixée, radial ajouté
                        12.1: Intermédiaire, non préfixée
                        15: Nouvelle, non préfixée
IE                      8-: Incompatible
                        9: filtres seulement
                        10+: Nouvelle, non préfixée (+ Intermédiaire, préfixée)
ANDROID         2.0-: Incompatible
                        2.1-3.0: Intermédiaire, préfixée
                        4.0-4.3: Nouvelle, préfixée
                        4.4+: Nouvelle, non préfixée
iOS      3-:    Incompatible
                        3.2-4.3: Intermédiaire, préfixée
                        5.0-6.1: Nouvelle, préfixée
                        7.0: Nouvelle, non préfixée</pre><p>Il y a des tuilages, par exemple lorsqu'un navigateur supporte la nouvelle syntaxe, il supportera probablement les syntaxes anciennes, avec préfixe. Quoi qu'il en soit, la meilleure pratique reste : Si votre navigateur est compatible avec la nouvelle syntaxe, utilisez la.</p><p>Si vous vouliez avoir la compatibilité support la plus parfaite, un dégradé linéaire pourrait ressembler à ceci :</p><pre>//CSS
.gradient {
  /* Fallback (ou bien .jpg/.png) */
  background-color: red;
  /* SVG fallback pour IE 9 (avec data URI, ou avec filtre) */
  background-image: url(fallback-gradient.svg);
  /* Safari 4, Chrome 1-9, iOS 3.2-4.3, Android 2.1-3.0 */
  background-image:
    -webkit-gradient(linear, left top, right top, from(red), to(#f06d06));
  /* Safari 5.1, iOS 5.0-6.1, Chrome 10-25, Android 4.0-4.3 */
  background-image:
    -webkit-linear-gradient(left, red, #f06d06);
  /* Firefox 3.6 - 15 */
  background-image:
    -moz-linear-gradient(left, red, #f06d06);
  /* Opera 11.1 - 12 */
  background-image:
    -o-linear-gradient(left, red, #f06d06);
  /* Opera 15+, Chrome 25+, IE 10+, Firefox 16+, Safari 6.1+, iOS 7+, Android 4.4+ */
  background-image:
    linear-gradient(to right, red, #f06d06);
}</pre><p>Ça en fait du code ! Écrire tout ça à la main serait source d'erreurs et très ennuyeux. <a href="https://openclassrooms.com/fr/courses/6106181-simplifiez-vous-le-css-avec-sass/6612156-utilisez-autoprefixer-pour-creer-du-code-adapte-a-tous-les-navigateurs">Autoprefixer</a> s'en occupera très bien.</p><h2>Dégradés radiaux</h2><p>À la différence des dégradés linéaires qui vont d'un point à un autre sur une ligne, les dégradés radiaux irradient à partir d'un point. Ils sont souvent utilisés pour simuler une lumière.</p><p>Par défaut, la première couleur part du centre (center center) de l'élément et se dégrade progressivement vers les contours. Le dégradé est réparti de manière égale dans toutes les directions.</p><pre>//CSS
.gradient {
  background-image:
    radial-gradient(
      yellow,
      #f06d06
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients7.png" alt="irradiation depuis le centre, en forme d'ellipse" /></figure><p>Vous voyez comment ce dégradé prend par défaut une forme d'ellipse, du fait que l'élément contenant n'est pas un carré. Si nous voulons un cercle, nous pouvons le déclarer ainsi :</p><pre>//CSS
.gradient {
  background-image:
    radial-gradient(
      circle,
      yellow,
      #f06d06
    );
}</pre><p>Notez qu'avec cette déclaration le dégradé est circulaire et que le dégradé va par défaut jusqu'au côté le plus éloigné. Si nous voulons que le cercle soit entièrement compris dans notre élément, nous pourrions nous en assurer en spécifiant que le dégradé doit s'arrêter au côté le plus proche ("closest-side") :</p><pre>//CSS
.gradient {
  background-image:
    radial-gradient(
      circle closest-side,
      yellow,
      #f06d06
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients8-1.png" alt="irradiation circulaire depuis le centre, comprise intégralement dans les limites du plus petit côté" /></figure><p>Les valeurs possibles sont <code>closest-corner</code>(coin le plus proche), <code>closest-side</code> (côté le plus proche), <code>farthest-corner</code> (coin le plus éloigné) et <code>farthest-side</code> (côté le plus éloigné). En pratique, on peut se dire : "je veux que ce dégradé radial s'étende depuis le point central jusqu'à ...... , et qu'il se dégrade partout entre les deux, de la façon que j'indique".</p><p>Un dégradé radial ne part pas nécessairement du centre, vous pouvez spécifier un point de départ en utilisant "at ..." avec le premier paramètre :</p><pre>//CSS
.gradient {
  background-image:
    radial-gradient(
      circle at top right,
      yellow,
      #f06d06
    );
}</pre><p>Pour que ce soit plus évident, j'ai fait un carré et ajouté un color-stop :</p><figure><img src="https://la-cascade.io/images/gradients9.png" alt="irradiation depuis le coin supérieur droit" /></figure><p><strong>Compatibilité navigateurs</strong><br />C'est à peu près la même que pour les dégradés linéaires, à l'exception d'une très vieille version d'Opera. Mais tout comme pour les dégradés linéaires, la syntaxe a connu des changements. Là encore, il y a l'ancienne, l'intermédiaire et la nouvelle :</p><pre>//CSS
/* Exemple d'ancienne */
background-image:
  -webkit-gradient(radial, center center, 0, center center, 141, from(black), to(white), color-stop(25%, blue), color-stop(40%, green), color-stop(60%, red), color-stop(80%, purple));
/* Exemple d'intermédiaire */
background-image:
  -webkit-radial-gradient(45px 45px, farthest-corner, #F00 0%, #00F 100%) repeat scroll 0% 0% rgba(0, 0, 0, 0);
/* Exemple de nouvelle */
background-image:
  radial-gradient(circle farthest-side at right, #00F, #FFF);</pre><p>Les caractéristiques à retenir étant :</p><ul><li><strong>Ancienne</strong> : préfixée avec Webkit, comporte des choses comme <code>from()</code> et <code>color-stop()</code>.</li>
<li><strong>Intermédiaire</strong> : le premier paramètre était la localisation du centre. Attention, ça ne fonctionne plus du tout avec les navigateurs qui supportent la nouvelle syntaxe non préfixée, donc si utilisez cette syntaxe intermédiaire elle doit absolument être préfixée.</li>
<li><strong>Nouvelle</strong> : le premier paramètre peut être "verbeux", genre "circle closest-corner at top right".</li>
</ul><p>Là encore, je laisserais Autoprefixer s'en occuper. Vous écrivez avec la syntaxe nouvelle, il se charge des fallbacks. Les dégradés radiaux sont un peu plus compliqués que les linéaires, donc ma recommendation est de bien s'habituer à la nouvelle syntaxe et de n'utiliser qu'elle.</p><h2>Dégradés répétés</h2><p>Les "repeating gradients" sont <a href="http://caniuse.com/#feat=css-repeating-gradients">légèrement moins compatibles</a>. Ils existent en versions linéaires et radiales.</p><p>Avec les dégradés non-répétés, il existe <a href="https://la-cascade.io/les-motifs-css3/#colonnes">une astuce</a> pour créer un dégradé de manière à répéter un motif. Pour cela on crée un petit rectangle qu'on aligne avec d'autres petits rectangles en utilisant <code>background-size</code>.</p><p>Pas besoin de cette astuce avec les dégradés répétés. La taille du dégradé est déterminée par le color-stop final. Si c'est 20px, la taille du dégradé (qui se répètera ensuite) est un carré de 20px de côté.</p><pre>//CSS
.repeat {
  background-image:
    repeating-linear-gradient(
      45deg,
      yellow,
      yellow 10px,
      red 10px,
      red 20px /* determines size */
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients10.png" alt="motif répété diagonal, lignes jaunes et rouges" /></figure><p>Même chose avec les dégradés radiaux :</p><pre>//CSS
.repeat {
  background:
    repeating-radial-gradient(
      circle at 0 0,
      #eee,
      #ccc 50px
    );
}</pre><p>Résultat :</p><figure><img src="https://la-cascade.io/images/gradients11.png" alt="motif répété irradié depuis le coin supérieur gauche, répétition du même dégradé" /></figure><hr /><p><strong>Ressources complémentaires en anglais</strong></p><ul><li>Jouez avec ce que nous avons vu en utilisant <a href="http://css3please.com">CSS3, please!</a></li>
<li><a href="http://caniuse.com/#search=gradients">Can I Use</a> pour les dégradés</li>
<li>Les ressources de Mozilla sur les dégradés <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient">linéaires</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/repeating-linear-gradient">linéaires répétés</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/radial-gradient">radiaux</a> et <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/repeating-radial-gradient">radiaux répétés</a>.</li>
<li>Une <a href="http://lea.verou.me/css3patterns/">galerie de dégradés</a> (vous pouvez construire des motifs incroyables avec les dégradés).</li>
</ul><p><strong>Ressources complémentaires en français</strong></p><ul><li><a href="https://developer.mozilla.org/fr/docs/CSS/Utilisation_de_d%C3%A9grad%C3%A9s_CSS">Utilisation de dégradés CSS</a>, par Mozilla</li>
<li><a href="http://www.html5-css3.fr/css3/degrades-couleurs-css3-gradient">Les dégradés de couleur en CSS3 avec gradient</a>, par HTML5-CSS3.fr</li>
</ul><p><strong>Outils</strong></p><ul><li><a href="http://www.virtuosoft.eu/tools/css-gradient-generator/?t=radial&amp;s=farthest-corner&amp;r=on&amp;sh=ellipse&amp;h=left&amp;v=top&amp;sp=c5e3ef_0_%25__4badd2_50_%25__278fba_73.5_%25__8ed4f1_100_%25">CSS Gradient Generator</a> , comme son nom l’indique, un outil en ligne pour s’amuser avec les dégradés et comprendre comment ça marche.</li>
<li><a href="http://colinkeany.com/blend/">Blend</a>, un autre outil intuitif pour générer facilement des dégradés CSS</li>
</ul></div>]]></description>
      <link>https://la-cascade.io/articles/les-degrades-css</link>
      <guid>https://la-cascade.io/articles/les-degrades-css</guid>
      <pubDate>Sun, 09 Mar 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Flexbox, guide complet]]></title>
      <description><![CDATA[<p><em>Le module Flexbox Layout fournit une façon plus efficace de disposer, aligner et distribuer l'espace entre les éléments de votre page. 4 riches articles de Chris Coyier sont réunis ici.</em></p><div class="articleContent"><p><em>NdT : Ce tutoriel est la réunion de quatre articles de Chris Coyier formant une introduction à Flexbox. Vous pouvez ensuite consulter <a href="https://la-cascade.io/tags/flexbox/">tous les articles sur Flexbox traduits dans la Cascade</a> notamment les exemples concrets d'implémentation et les astuces techniques</em>.</p><p>Le module CSS3 <code>Flexbox Layout</code> fournit une façon efficace de disposer, aligner et distribuer l'espace entre les items d'un container, même lorsque leurs dimensions sont inconnues et/ou dynamiques - d'où le terme "flex".</p><p>L'idée principale est de donner à un élément contenant (container) la possibilité de changer les largeur et hauteur des éléments contenus (items), afin de remplir au mieux l'espace disponible, et de s'adapter à tous les terminaux et toutes les tailles d'écrans. Un container flexible permet aux items de s'étendre pour occuper la place disponible ou au contraire les réduit pour leur éviter de déborder.</p><p>Le plus important à retenir c'est qu'avec Flexbox la disposition n'est pas rigidement directionnelle, contrairement à ce que nous connaissons habituellement en CSS — où Block est basé sur un schéma vertical et Inline sur un schéma horizontal. Cela fonctionne bien pour les pages, mais ça manque de... flexibilité lorsqu'il s'agit d'applications complexes, en particulier lorsqu'il faut s'adapter aux changements d'orientation de device, redimensionner, étendre ou réduire l'espace, etc.</p><p><strong>Note importante</strong> : Flexbox est plutôt adapté aux composants d'une application, de petite échelle, alors que les grilles conviennent à des mises en page complexes et à grande échelle. <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet/">CSS Grid</a> et Flexbox ont des usages différents mais <a href="https://la-cascade.io/articles/grid-et-flexbox-le-duo-gagnant/">sont faits pour travailler ensemble</a> !</p><p>Nous allons commencer par décrire la mécanique, mais vous pouvez souhaiter regarder d'abord les <a href="#exemples">exemples d'usage de flexbox</a>.</p><h2>Les bases</h2><p>Flexbox est un module, pas une propriété, cela entraîne pas mal de conséquences, entre autres que Flexbox a des propriétés bien à lui. Certaines concernent le container (l'élément parent, qu'on appelle "flex container"), d'autres concernent le ou les enfants (les "flex items").</p><p>Alors que le positionnement CSS habituel est basé sur les directions de flux <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline/">block et inline</a>, le positionnement flex, lui, est basé sur les directions "flex-flow". L'illustration ci-dessous, tirée des spécifications, explique l'idée qui est à la base du positionnement flex :</p><figure><img src="https://la-cascade.io/images/flex01-1-compressor.png" alt="schéma du système de positionnement flexbox" /></figure><p>Les items seront disposés soit sur l'axe principal (<code>main axis</code>) depuis <code>main-start</code> ou <code>main-end</code>, ou sur l'axe perpendiculaire (<code>cross axis</code>) en partant de <code>cross-start</code> ou de <code>cross-end</code>. Le flex-flow suit donc l'axe principal ou l'axe perpendiculaire.</p><ul><li><strong>main axis</strong> - L'axe principal d'un container flex est l'axe primaire sur lequel les items sont disposés. Attention, il n'est pas forcément horizontal, tout dépendra de la propriété <code>justify-content</code> (voir ci-dessous).</li>
<li><strong>main-start | main-end</strong> - À l'intérieur du container, les items flex sont placés entre un point de départ (main-start) et un point d'arrivée (main-end).</li>
<li><strong>main size</strong> - La taille d'un item flex qui se trouve dans l'axe principal, qu'il s'agisse de la hauteur ou de la largeur, est la taille principale (main size). La propriété main size est soit "width", soit "height", selon l'orientation.</li>
<li><strong>cross axis</strong> - L'axe perpendiculaire à l'axe principal est appelé cross axis. Sa direction dépend de la direction de l'axe principal.</li>
<li><strong>cross-start | cross-end</strong> - Les lignes sont remplies avec les items et sont placées dans le container en partant du côté cross-start&lt; et en allant vers cross-end.</li>
<li><strong>cross-size</strong> - La largeur ou la hauteur d'un item, selon la dimension dans laquelle on se trouve (même principe que main size).</li>
</ul><figure role="group"><img src="https://la-cascade.io/images/flex01css_flexbox_axis4-1-compressor.jpeg" width="390" height="392" alt="autre version du schéma, main axis et cross axis" /></figure><p>Le schéma ci-dessus montre bien que l'axe principal peut être horizontal ou vertical. Dans le premier cas (éléments disposés horizontalement), on pourrait penser par exemple à des articles disposés en colonnes sur une page, ou à un groupe de photos (voir un <a href="#horiz">exemple</a> plus bas), ou encore à une barre de navigation horizontale. Dans le deuxième cas (éléments disposés verticalement), on peut imaginer une sidebar, des liens de navigation (voir un <a href="#nav">exemple</a> plus bas), etc.</p><h2>Propriétés</h2><p><strong>Commençons par les propriétés qui s'appliquent à l'élément parent, le container</strong>.</p><p>La première chose à faire est de définir un contexte général d'affichage. Le module flexbox fontionne à l'intérieur de ce contexte.</p><h3>display: flex|inline-flex;</h3><p>C'est ainsi qu'on définit un container flex, il est block par défaut ou inline selon la valeur donnée. Cela cée un contexte flex pour tous les descendants directs.</p><pre>display: flex | inline-flex;</pre><ul><li><code>flex</code> : Cette valeur génère un container flex, de niveau block, à l'intérieur de l'élément.</li>
<li><code>inline-flex</code> : Cette valeur génère un container flex, de niveau inline, à l'intérieur de l'élément.</li>
</ul><p>Notez que :</p><ul><li>les propriétés <code>columns-</code> du <a href="https://developer.mozilla.org/fr/docs/CSS/Colonnes_CSS3">module multi-colonnes</a> n'ont pas d'effet sur un container flex</li>
<li><code>float</code>, <code>clear</code> et <code>vertical-align</code> n'ont pas d'effet sur un item flex.</li>
</ul><p>Pour comprendre en se divertissant, le mieux est de jouer avec ces valeurs sur des outils en ligne tels que <a href="http://bennettfeely.com/flexplorer/">flexplorer</a> (voir liste en fin d'article).</p><h3>flex-direction</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/flex-direction">flex-direction</a> établit l'axe principal.</p><pre>flex-direction: row | row-reverse | column | column-reverse</pre><ul><li><code>row</code> (valeur par défaut): de gauche à droite si la lecture se fait dans ce sens, de droite à gauche dans le cas inverse <sup id="backto1"><a href="#1">(1)</a></sup>.</li>
<li><code>row-reverse</code> : inverse le sens</li>
<li><code>column</code> : comme <code>row</code> mais du haut vers le bas</li>
<li><code>column-reverse</code> : comme <code>row-reverse</code> mais du bas vers le haut</li>
</ul><h3>flex-wrap</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/flex-wrap">flex-wrap</a> définit si le container comprend une seule ligne ou plusieurs et la direction sur l'axe perpendiculaire (cross-axis), qui détermine la direction dans laquelle les nouvelles lignes seront empilées.</p><pre>flex-wrap: nowrap | wrap | wrap-reverse</pre><ul><li><code>nowrap</code> : (valeur par défaut) sur une seule ligne, de gauche à droite dans un système <code>ltr</code>, sinon l'inverse. La ligne peut déborder de son contenant.</li>
<li><code>wrap</code> : multiligne, de gauche à droite dans un système <code>ltr</code>, sinon l'inverse. Pas de débordement, on passe à la ligne.</li>
<li><code>wrap-reverse</code> : multiligne, de droite à gauche dans un système <code>ltr</code>, sinon l'inverse.</li>
</ul><h3>flex-flow</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/flex-flow">flex-flow</a> est un raccourci des propriétés "flex-direction" et "flex-wrap" qui ensemble définissent les axes "main" et "cross" du container flex. La valeur par défaut est <code>row nowrap</code>.</p><pre>flex-flow: &lt;‘flex-direction’&gt; || &lt;‘flex-wrap’&gt;</pre><h3>justify-content</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/justify-content">justify-content</a> définit l'alignement le long de l'axe principal. Elle permet de distribuer l'espace excédentaire lorsque tous les items flex sur une ligne sont inflexibles ou lorsqu'ils ont atteint leur taille maximale. Elle contrôle aussi l'alignement des items lorsqu'ils débordent.</p><pre>justify-content: flex-start | flex-end | center | space-between | space-around</pre><ul><li><code>flex-start</code> (par défaut) : les items sont regroupés en début de ligne</li>
<li><code>flex-end</code> : les items sont regroupés en fin de ligne</li>
<li><code>center</code> : les items sont centrés le long de la ligne</li>
<li><code>space-between</code> : les items sont répartis sur la ligne; le premier est collé du côté start, le dernier du côté end.</li>
<li><code>space-around</code> : les items sont répartis sur la ligne avec un espacement égal autour de chacun.</li>
</ul><figure><img src="https://la-cascade.io/images/flex02justify-compressor.png" alt="exemples de justify-content" /></figure><p><em>NdT : pour plus de détails sur space-between, vous pouvez lire l'article <a href="https://la-cascade.io/articles/guide-de-flexbox-space-between-loublie/">Guide de Flexbox : space-between, l'oublié</a> dans la Cascade</em>.</p><h3 id="align-items">align-items</h3><p>La propriété <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/align-items">align-items</a> définit la façon dont les items d'une ligne sont disposés le long de l'axe "cross". On peut le voir comme la version de <code>justify-content</code> pour "cross axis".</p><pre>align-items: flex-start | flex-end | center | baseline | stretch</pre><ul><li><code>flex-start</code> : l'item est placé au début de la ligne cross-start.</li>
<li><code>flex-end</code> : la marge "cross-end" de l'item est placée sur la ligne cross-end</li>
<li><code>center</code> : les items sont centrés sur l'axe cross</li>
<li><code>baseline</code> : les items sont alignés sur leur ligne de base</li>
<li><code>stretch</code> (par défaut) : les items sont étirés jusqu'à remplir le container (tout en respectant min-width/max-width)</li>
</ul><figure><img src="https://la-cascade.io/images/flex03align_items-compressor.png" alt="exemples d'align-items" /></figure><h3>align-content</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/align-content">align-content</a> aligne les lignes d'un container flex à l'intérieur de l'espace où il reste de l'espace sur l'axe cross, un peu comme <code>justify-content</code> aligne les items sur l'axe principal.</p><p>Note : cette propriété n'a pas d'effet quand la flexbox n'a qu'une seule ligne.</p><pre>align-content: flex-start | flex-end | center | space-between | space-around | stretch</pre><ul><li><code>flex-start</code> : lignes regroupées au début du container</li>
<li><code>flex-end</code> : lignes regroupées à la fin du container</li>
<li><code>center</code> : lignes regroupées au centre du container</li>
<li><code>space-between</code> : les lignes sont réparties, la première est collée du côté start, la dernière du côté end.</li>
<li><code>space-around</code> : les lignes sont réparties avec un espacement égal autour de chacune.</li>
<li><code>stretch</code> (par défaut) : les lignes s'étirent pour remplir tout l'espace.</li>
</ul><figure><img src="https://la-cascade.io/images/flex04align_content-compressor.png" alt="exemples de align-content" /></figure><p><strong>Passons maintenant aux propriétés qui s'appliquent aux éléments enfants, les items flex</strong>.</p><h3>order</h3><p>Par défaut, les items flex sont disposés par ordre d'arrivée. Cependant, la propriété <code>order</code> permet de contrôler l'ordre dans lequel ils apparaissent dans le container.</p><pre>order: &lt;nombre entier&gt;</pre><h3>flex-grow</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/flex-grow">flex-grow</a> définit la possibilité pour un item de grandir, si nécessaire. Elle accepte une valeur sans unité qui sert de proportion. Elle dicte l'espace que peut prendre l'item à l'intérieur de l'espace disponible dans le flex container.</p><p>Si tous les items ont <code>flex-grow</code> défini à 1, chaque enfant aura le même espace dans le container. Si vous donnez à l'un des enfants une valeur de 2, cet enfant prendra deux fois plus de place que les autres.</p><pre>flex-grow: &lt;nombre entier&gt; (par défaut = 0)</pre><p>Les chiffres négatifs ne sont pas valides.</p><h3>flex-shrink</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/flex-shrink">flex-shrink</a> définit la possibilité pour un item flex de rétrécir si nécessaire.</p><pre>flex-shrink: &lt;nombre entier&gt; (par défaut = 1)</pre><p>Les chiffres négatifs ne sont pas valides.</p><h3>flex-basis</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/flex-basis">flex-basis</a> définit la taille par défaut d'un élément avant que l'espace restant soit réparti.</p><pre>flex-basis: &lt;longueur&gt; | auto (par défaut = auto)</pre><p><em>NdT : pour plonger dans le menu détail de <code>flex-grow</code>, <code>flex-shrink</code>et <code>flex-basis</code>, vous pouvez consulter le passionnant article <a href="https://la-cascade.io/articles/css-flexbox-et-la-dimension-des-boites/">CSS Flexbox et la dimension des boîtes</a> dans La Cascade</em>.</p><h3>flex</h3><p>Cette propriété est le raccourci de <code>flex-grow</code> , <code>flex-shrink</code> et <code>flex-basis</code> . Les deuxième et troisième paramètres sont optionels. La valeur par défaut est <code>0 1 auto</code>.</p><pre>flex: none | [ &lt;'flex-grow'&gt; &lt;'flex-shrink'&gt;? || &lt;'flex-basis'&gt; ]</pre><h3>align-self</h3><p>La propriété <a href="https://developer.mozilla.org/fr/docs/Web/CSS/align-self">align-self</a> permet à des items flex de passer outre aux alignement par défaut ou à ceux spécifiés par <code>align-items</code>. Les valeurs sont les mêmes que pour ce dernier.</p><pre>align-self: auto | flex-start | flex-end | center | baseline | stretch</pre><h2>Exemples</h2><p>Commençons avec un exemple extrêmement simple, qui résout un problème que nous rencontrons tous les jours : <a href="https://la-cascade.io/articles/centrer-en-css-un-guide-complet/">le centrage parfait</a>. Rien de plus simple avec Flexbox.</p><pre>.parent {
  display: flex;
  height: 300px; /_ Ou ce que vous voulez _/
}
.child {
  width: 100px; /_ Ou ce que vous voulez _/
  height: 100px; /_ Ou ce que vous voulez _/
  margin: auto; /_ Magique ! _/
}</pre><p>Tout vient de ce qu'une marge réglée sur "auto" dans un container flex absorbe l'espace supplémentaire. Une marge verticale "auto" centrera l'item parfaitement sur les deux axes.</p><p>Utilisons maintenant quelques propriétés supplémentaires. Prenons une liste de 6 items, de dimension fixe, mais ils pourraient tout aussi bien être ajustables. Nous voulons qu'ils soient disposés de manière régulière sur l'axe horizontal, de façon à ce que lorsque nous modifions la taille de l'écran les items se répartissent sans avoir recours à des media queries.</p><pre>.flex-container {
  /_ On crée d'abord un contexte flex _/
  display: flex;
  /_ Puis on définit la direction du flux et le wrap
  _ Rappelez-vous que c'est la même chose que :
    _ flex-direction: row;
    _ flex-wrap: wrap;
  */
  flex-flow: row wrap;
  /_ Puis on définit la façon dont se répartit l'espace restant _/
  justify-content: space-around;
}</pre><p>Et voilà. Le reste n'est plus qu'une question de style. Ci-dessous un exemple de cette répartition. Le mieux est de le regarder sur <a href="https://codepen.io/HugoGiraudel/pen/LklCv">CodePen</a> et de faire varier la taille de l'écran pour voir ce qui se passe.</p><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/HugoGiraudel/pen/LklCv">Demo Flexbox 1</a>de<a href="https://la-cascade.io/auteurs/kitty-giraudel">Kitty Giraudel</a>dans<a href="https://codepen.io">CodePen</a></div><p>Essayons quelque chose d'autre. Admettons que nous ayons une barre de navigation alignée en haut à droite de notre page, mais nous souhaiterions qu'elle soit centrée pour les écrans de taille moyenne et sur une colonne pour des petits écrans. <a href="https://codepen.io/HugoGiraudel/pen/pkwqH">Facile</a> :</p><pre>/* Grand écran */
.navigation {
  display: flex;
  flex-flow: row wrap;
  /_ Aligne les items à end line sur main-axis _/
  justify-content: flex-end;
}
/* Écrans moyens */
@media all and (max-width: 800px) {
  .navigation {
    /_ on centre en répartissant l'espace entre les items _/
    justify-content: space-around;
  }
}
/* Petit écran */
@media all and (max-width: 500px) {
  .navigation {
    /_ On n'utilise plus row mais column _/
    flex-direction: column;
  }
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/HugoGiraudel/pen/pkwqH">Demo Flexbox 2</a>de Kitty Giraudel dans<a href="https://codepen.io">CodePen</a></div><p>Essayons encore mieux, en jouant avec la flexibilité des items flex ! Par exemple un <a href="https://codepen.io/HugoGiraudel/pen/qIAwr">layout mobile-first</a> sur 3 colonnes, avec un header et un footer pleine largeur. Le tout indépendamment de l'ordre des sources.</p><pre>.wrapper {
  display: flex;
  flex-flow: row wrap;
}
/* Tous les items sont à 100% width */
.header, .main, .nav, .aside, .footer {
  flex: 1 100%;
}
/* We rely on source order for mobile-first approach
- in this case:
- 1. header
- 2. nav
- 3. main
- 4. aside
- 5. footer
*/
/_ Écrans moyens _/
@media all and (min-width: 600px) {
  /_ Les 2 sidebars partagent une rangée _/
  .aside { flex: 1 auto; }
}
/* Grands écrans */
@media all and (min-width: 800px) {
  /_ on intervertit l'ordre de la 1ère sidebar et de main
  _ et on dit à l'élément de prendre 2 fois plus de place en largeur que les 2 sidebars
  */
  .main { flex: 2 0px; }
  .aside-1 { order: 1; }
  .main { order: 2; }
  .aside-2 { order: 3; }
  .footer { order: 4; }
}</pre><figure class="break-out">
</figure><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/HugoGiraudel/pen/qIAwr">Demo Flexbox 3</a>de Kitty Giraudel dans<a href="https://codepen.io">CodePen</a></div><p>Voyons maintenant la façon dont flexbox résout le problème suivant : comment faire pour qu'un nombre arbitraire de boîtes remplissent l'espace disponible dans la boîte parent et si nécessaire s'étendent au-delà (c'est à dire : ne s'écrasent pas pour tenir dans la boîte). Vous pouvez regarder <a href="http://css-tricks.com/video-screencasts/131-tinkering-flexbox/">cette vidéo</a> (en anglais) qui illustre ce que je veux dire par là.</p><p>Par "boîte", j'entends simplement un élément de niveau block. <code>div</code>, <code>section</code>, <code>article</code>, ce que vous voulez.</p><p>La hauteur par défaut d'une boîte est déterminée par son contenu. Les boîtes s'empilent les unes sur les autres. La hauteur de leur boîte parent pourrait également être déterminée par la somme de leurs hauteurs, mais il pourait en être autrement, par exemple si elle est définie explicitement ou si elle est soumise à quelque chose de variable, comme la taille de la fenêtre du navigateur. Si la boîte parent a une hauteur plus importante, il y aura simplement de l'espace vide en bas.</p><p>Pouvons-nous forcer les boîtes à se répartir l'espace disponible de façon égale ? Avec flexbox, oui.</p><figure role="group"><img src="https://la-cascade.io/images/flex05fill_height-compressor.svg" alt="à gauche il reste de l'espace, à droite les éléments occupent harmonieusement la page" /><figcaption>À gauche, par défaut. À droite, ce que nous voulons</figcaption></figure><p>Admettons que le HTML soit :</p><pre>&lt;section class="fill-height-or-more"&gt;
        &lt;div&gt;
                &lt;!-- stuff --&gt;
        &lt;/div&gt;
        &lt;div&gt;
                &lt;!-- stuff --&gt;
        &lt;/div&gt;
        &lt;div&gt;
                &lt;!-- stuff --&gt;
        &lt;/div&gt;
&lt;/section&gt;</pre><p>On démarre flexbox dans l'élément parent :</p><pre>// dans CSS
.fill-height-or-more {
  display: flex;
}</pre><p>et on empile les boîtes sur un axe vertical (<code>column</code>) plutôt qu'horizontal (<code>row</code>) qui est la valeur par défaut :</p><pre>.fill-height-or-more {
  display: flex;
  flex-direction: column;
}</pre><p>Avec cela, le rendu sera le même que si nous n'avions rien fait. Mais maintenant nous allons appliquer la propriété flex aux enfants, et ils vont remplir l'espace :</p><pre>.fill-height-or-more &gt; div {
  /_ ce sont les items flex _/
  flex: 1;
}</pre><p>Et c'est fait =)</p><p>Pour détailler : <code>flex: 1</code> est l'équivalent de <code>flex: 1 1 auto</code> , c'est le raccourci de trois propriétés différentes :</p><pre>flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;</pre><p>Ce qui est sympa avec flexbox c'est que tout ça marcherait avec n'importe quel nombre de boîte, ça pourrait être une boîte unique ou 100 boîtes. S'il reste de l'espace, il sera partagé, sinon, pas de problème.</p><p>Dans le monde d'avant flexbox, nous aurions sans doute essayé de savoir combien de boîtes il y avait, puis nous aurions fixé leur hauteur en pourcentage. Ça fonctionne pour remplir l'espace, mais s'il y avait trop de boîtes elles seraient écrasées. Voilà encore un truc sympa avec flexbox, il ne va pas écraser nos boîtes au point qu'elles n'affichent plus leur contenu :</p><figure role="group"><img src="https://la-cascade.io/images/flex06no_squish1-compressor.svg" alt="pourcentages: les items sont écrasés. flexbox, ils dépassent, on y accède en scrollant" /><figcaption>À gauche, utilisation de pourcentages. À droite, le comportement souhaité</figcaption></figure><p>Si nous voulons aller encore un peu plus loin, nous pouvons utiliser flexbox pour centrer le contenu à l'intérieur des boîtes. C'est là qu'on devient fou avec CSS. Le centrage vertical est difficile. Même avec flexbox ici, il va nous falloir transformer chacun de nos items en containers, puis utiliser un contenant interne qui devient l'item flex que nous centrons. Donc, oui, un élément de plus.</p><pre>// dans HTML
&lt;section class="fill-height-or-more"&gt;
        &lt;div&gt;
                &lt;div&gt;
                        &lt;!-- stuff --&gt;
                &lt;/div&gt;
        &lt;/div&gt;
    ...
// dans CSS
.fill-height-or-more &gt; div {
        /* un flex item... */
        flex: 1;
  /_ ...qui est aussi un flex container _/
  display: flex;
}</pre><p>Puis pour le centrer nous définissons la direction verticale à nouveau (<code>column</code>) et nous utilisons une autre propriété flexbox, <code>justify-content</code> :</p><pre>.fill-height-or-more &gt; div {
  flex: 1;
  display: flex
  justify-content: center;
  flex-direction: column;
}</pre><p>Voici ce que ça donne :</p><figure><img src="https://la-cascade.io/images/flex07vertically_centered-compressor.svg" alt="les items bien disposés" /></figure><p>D'un côté, c'est logique. Pour centrer quelque chose, il faut bien un élément dans lequel le centrer. D'un autre côté, avec une table et des cellules, on n'aurait pas eu besoin d'un élément supplémentaire... Bon enfin, voici la démo !</p><div class="pen"><img src="https://la-cascade.io/images/codepen.png" alt="" class="codepen-icon" />voir<a href="https://codepen.io/chriscoyier/pen/Jeryz">Demo Flexbox 3</a>de Chris Coyier dans<a href="https://codepen.io">CodePen</a></div><h3>Compatibilité navigateurs</h3><p>J'ai utilisé uniquement la dernière syntaxe ici. Les versions actuelles de Chrome, Opera sont compatibles. Les prochaines versions de Firefox et Android le seront aussi. Safari et iOS supportent la nouvelle syntaxe, avec des préfixes -webkit-. <a href="http://caniuse.com/flexbox">Can I Use</a> vous racontera toute l'histoire.</p><p>IE est bizarre. IE 10 est compatible avec l'ancienne version de flexbox, IE 11 avec la nouvelle. Pour cette démo pourtant il y a quelque chose qui ne fonctionne pas. La hauteur de <code>.fill-height-or-more</code> est bien rendue en utlisant <code>min-height</code>, mais les boîtes sont écrasées.</p><figure><img src="https://la-cascade.io/images/flex08ie11_bug-compressor.png" alt="problème avec IE 11" /></figure><p>Voici à quoi ressemble notre petit exemple lorsqu'on lui ajoute les préfixes constructeurs :</p><pre>.fill-height-or-more {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
  -moz-box-orient: vertical;
  -moz-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
}
.fill-height-or-more &gt; div {
  -webkit-box-flex: 1;
  -webkit-flex: 1;
  -moz-box-flex: 1;
  -ms-flex: 1;
  flex: 1;
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -moz-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
  -moz-box-orient: vertical;
  -moz-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
}</pre><p>Mon conseil : utilisez une syntaxe moderne, comme je l'ai fait précédemment, puis laissez <a href="https://la-cascade.io/autoprefixer-un-postprocesseur-pour-les-prefixes-vendeurs/">Autoprefixer</a> s'occuper du reste, il règlera non seulement le problème des préfixes constructeurs mais aussi celui de l'ancienne syntaxe.</p><h2>Flexbox ancien et nouveau</h2><p>Le flexbox que nous connaissons a subi de nombreux changements. Si vous cherchez flexbox dans Google, vous trouverez beaucoup d'informations dépassées. Si vous trouvez quelque chose comme <code>display: box;</code> ou une propriété <code>box-{*}</code> , c'est la vieille version de 2009. Si vous trouvez <code>display: flexbox;</code> ou la fonction <code>flex()</code> , c'est une phase bizarre de flexbox en 2011. Si vous voyez <code>display: flex</code> et <code>flex-{*}</code> , vous êtes sur la spécification actuelle.</p><hr /><p>Notes du Traducteur :</p><p>(1) Pour rappel, vous pouvez définir le sens de lecture dans CSS avec la propriété <code>direction</code> qui accepte les valeurs <code>ltr</code> - de gauche à droite (<em>left to right</em>) - et <code>rtl</code> - de droite à gauche   <a href="#backto1" class="c2">↩︎</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/flexbox-guide-complet</link>
      <guid>https://la-cascade.io/articles/flexbox-guide-complet</guid>
      <pubDate>Sat, 01 Feb 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[CSS Block, Inline et Inline-Block]]></title>
      <description><![CDATA[<p><em>Le premier d'une série de 3 articles de Louis Lazaris sur des notions de base de CSS. Nous commençons aujourd'hui avec les notions parfois confuses de Block, Inline et Inline-Block.</em></p><div class="articleContent"><p>Cet article est la traduction de deux articles de Louis Lazaris parus sur son blog <a href="https://www.impressivewebs.com">Impressive Webs</a>.</p><p>En CSS, les éléments peuvent être divisés en quelques catégories. Deux d'entre elles sont les éléments de niveau "block" et de niveau "inline". C'est un de ces domaines qui, lorsqu'on l'a bien compris, peut aider les débutants à passer au niveau supérieur.</p><h2>Éléments de niveau Block</h2><p>Un élément block a les caractéristiques suivantes, non limitatives :</p><ul><li>Si aucune largeur n'est définie, il prendra toute la largeur de son élément parent.</li>
<li>Il peut avoir des marges et des paddings.</li>
<li>Si aucune hauteur n'est définie, il prendra la hauteur de ses éléments enfants (en supposant qu'il n'y a pas de "float" ou de positionnement sur des éléments environnants).</li>
<li>Il ignore la propriété <code>vertical-align</code>.</li>
</ul><p>Il est donc inutile pour un élément block de définir une largeur ou de lui donner une <code>width: 100%</code> si vous voulez qu'il s'étende sur la largeur de son élément parent. Cela pourrait même avoir des effets indésirables.</p><p>Et comme l'indique le quatrième point de la liste ci-dessus, il n'est pas nécessaire non plus de "clearer" un élément block. S'il ne comprend aucun float, le clear sera automatique et il commencera à la "ligne" suivante dans l'affichage de la page.</p><p><strong>Exemples d'éléments block</strong> :</p><p><code>p</code>, <code>div</code>, <code>form</code>, <code>header</code>, <code>nav</code>, <code>ul</code>, <code>li</code>, et <code>h1</code>.</p><figure><img src="https://la-cascade.io/images/b_i1_block-compressor.jpeg" alt="Comportement des éléments block" /></figure><h2>Éléments de niveau Inline</h2><p>Un élément inline a les caractéristiques suivantes, non limitatives :</p><ul><li>Il s'inscrit dans le flux du texte</li>
<li>et donc ne 'saute' pas à la ligne comme le ferait un élément block</li>
<li>Il accepte la propriété <code>white-space</code>.</li>
<li>Il ignore les marges top et bottom mais applique les marges left et right, ainsi que tout padding.</li>
<li>Il ignore les propriétés <code>width</code> et <code>height</code>.</li>
<li>S'il est flotté à gauche ou à droite, il devient automatiquement un élément de niveau block, et prend toutes ses caractéristiques.</li>
<li>Il accepte la propriété <code>vertical-align</code>.</li>
</ul><p>Pour se faire une bonne idée de l'élément inline, on peut l'imaginer comme une <strong>boîte qui se comporte comme du texte</strong>. Un texte qui n'est pas interrompu par d'autres éléments s'écoule, lettre après lettre, et si vous ajoutez un élément inline dans le texte, il suivra le flux comme tout autre élément du texte.</p><p><strong>Exemples d'éléments inline</strong> :</p><p><code>a</code>, <code>span</code>, <code>b</code>, <code>em</code>, <code>i</code>, <code>cite</code>, <code>mark</code>, et <code>code</code>.</p><figure><img src="https://la-cascade.io/images/b_i2_inline-compressor.jpeg" alt="comportement d'un élément inline" /></figure><h2>Notes complémentaires</h2><p>Vous aurez remarqué que ces exemples d'éléments block et inline sont très révélateurs : les éléments block sont structurels alors que les éléments inline sont relatifs au texte. C'est une bonne façon de se rappeler qui est qui, même si au commencement cela peut vous paraître confus.</p><p>D'une manière générale, vous pouvez inclure n'importe quel élément block à l'intérieur d'un autre élément block. Vous pouvez également inclure n'importe quel élément inline dans un élément block et n'importe quel élément inline dans un autre élément inline. La seule chose qu'on ne puisse pas faire, c'est inclure un élément block à l'intérieur d'un élément inline, à une exception près : l'élément <code>a</code> peut envelopper n'importe quel type de contenu, block comme inline ou les deux.</p><p>Vous pouvez changer tout élément block en inline et vice-versa, en utilisant la propriété CSS display.</p><p>Dernière chose à noter, block et inline existent dans une perspective CSS, du point de vue de HTML5 les divers éléments ont été re-catégorisés pour être plus spécifiques.</p><h3>Astuce rapide: éléments remplacés</h3><p>Au tout début, j'ai dit que block et inline étaient simplement deux types de contenu. D'une manière générale, ce sont en effet les deux types principaux et il n'y a pas besoin de se soucier trop des autres.</p><p>Mais il y a ce qu'on appelle <a href="https://la-cascade.io/articles/quest-ce-quun-element-remplace/">les éléments remplacés</a>. Ce sont des éléments dont l'apparence et les dimensions de base sont définies par une ressource extérieure, par exemple des images, des plugins, des éléments d'un formulaire... Ils ne sont ni blocks, ni inline, on pourrait les considérer comme plus proches d'inline, mais avec une structure proche de block...</p><p>Quelques exemples d'éléments remplacés : <code>img</code>, <code>object</code>, <code>input</code>, <code>select</code>.</p><h2>Inline-Block</h2><p>Voici quelques définitions de la valeur <code>inline-block</code> pour la propriété <code>display</code>, relevées dans quelques sites de référence :</p><p>Pour <a href="http://reference.sitepoint.com/css/display">Sitepoint</a> : "Avec Inline-block, l'élément génère une boîte block qui est mise en forme comme s'il s'agissait d'une boîte inline".</p><p>Pour <a href="http://quirksmode.org/css/css2/display.html">QuirksMode</a> : "Un inline-block est placé inline (c'est à dire sur la même ligne que le contenu adjacent), mais il se comporte comme un block".</p><p>Pour <a href="http://robertnyman.com/2010/02/24/css-display-inline-block-why-it-rocks-and-why-it-sucks/">Robert Nyman</a> : "En gros, c'est une manière de mettre les éléments inline tout en préservant leurs capacités d'éléments block, tels que la possibilité de définir une largeur et une hauteur, des marges et paddings top et bottom, etc."</p><h3>Démonstration</h3><p>Voici une image d'<code>inline-block</code> à l'oeuvre, qui montre exactement comment il se comporte :</p><figure><img src="https://la-cascade.io/images/b_i3_inline_block_demo-compressor.jpeg" alt="démonstration d'inline-block, notamment de hauteur et padding" /></figure><h3>Comment l'utiliser ?</h3><p>Voici quelques cas où inline-block serait utile :</p><ul><li>Pour placer plusieurs éléments de type block sur la même ligne horizontale sans les flotter.</li>
<li>Pour permettre à un élément de type inline d'avoir une hauteur et une largeur tout en conservant sa nature inline.</li>
<li>Pour permettre à un élément inline d'avoir des marges ou des paddings.</li>
</ul><h3>Quelques notes complémentaires</h3><p>L'utilisation de <code>inline-block</code> ne va pas sans quelques petits inconvénients. Un élément inline-block est dépendant du <code>white-space</code> donc si vous affichez des listes en utilisant inline-block (dans une barre de navigation par exemple), les items de votre liste comporteront des espaces indésirés entre eux. Cela peut ne pas être gênant, auquel cas pas de problème. Sinon, pour retirer cet espace il vous faudra retirer de votre code HTML tout whitespace présent entre les éléments de la liste. Si votre code se présente ainsi :</p><pre>&lt;ul&gt;
        &lt;li&gt;Item One&lt;/li&gt;&lt;li&gt;Item Two&lt;/li&gt;&lt;li&gt;Item Three&lt;/li&gt;&lt;li&gt;Item Four&lt;/li&gt;&lt;li&gt;Item Five&lt;/li&gt;
&lt;/ul&gt;</pre><p>Ou pire :</p><pre>&lt;ul&gt;
        &lt;li&gt;Item One&lt;/li&gt;
    &lt;li&gt;Item Two&lt;/li&gt;
    &lt;li&gt;Item Three&lt;/li&gt;
    &lt;li&gt;Item Four&lt;/li&gt;
    &lt;li&gt;Item Five&lt;/li&gt;
&lt;/ul&gt;</pre><p>Ce problème peut évidemment être résolu en ajoutant <code>font-size: 0</code> à l'élément <code>&lt;ul&gt;</code> puis en augmentant la font-size des éléments de la liste. Mais ces solutions ne sont pas très "propres", je recommenderais donc dans ce cas d'utiliser une solution autre que <code>inline-block</code>.</p><p>Si vous déclarez plusieurs éléments utilisant <code>inline-block</code> et que ces éléments ont des hauteurs variables, vous devrez probablement ajouter quelque chose comme <code>vertical-align: top</code> pour garantir un alignement régulier. Voici <a href="http://www.brunildo.org/test/inline-block.html">une page intéressante</a> qui montre quelques problèmes et solutions relatifs à <code>inline-block</code>.</p><p>J'ai par ailleurs remarqué que le comportement d'<code>inline-block</code> n'était pas le même selon que l'élément était à l'intérieur d'un paragraphe ou pas.</p><h3>Compatibilité navigateurs</h3><p>Sans surprise, <code>inline-block</code> fonctionne de la même manière avec tous les navigateurs, sauf IE6 et IE7. Si vous devez absolument avoir une compatibilité avec IE7, il vous faudra définir la propriété <code>display</code> comme <code>inline</code>, puis utiliser la propriété <code>hasLayout</code> d'internet explorer.</p><hr /><h2 class="ressourcesComplementaires">Ressources complémentaires en français</h2><p><strong>Sur Block et Inline</strong> :</p><p><a href="http://www.ultra-fluide.com/ressources/xhtml/block-inline.xhtml">Block et Inline</a>, sur Ultra-Fluide.</p><p><strong>Sur Inline-Block</strong> :</p><p><a href="http://www.alsacreations.com/article/lire/1209-display-inline-block.html">Display inline-block</a>, sur Alsacréations.<br /><a href="http://jeremie.patonnier.net/post/2010/01/28/La-propri%C3%A9t%C3%A9-CSS-display-inline-block">La propriété CSS display: inline-block</a>, chez Jérémie.</p></div>]]></description>
      <link>https://la-cascade.io/articles/la-difference-entre-block-et-inline</link>
      <guid>https://la-cascade.io/articles/la-difference-entre-block-et-inline</guid>
      <pubDate>Sun, 19 Jan 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Le positionnement CSS]]></title>
      <description><![CDATA[<p><em>Le positionnement CSS permet de positionner des éléments de manière statique, relative, absolue ou fixe, les sortant ainsi du flux normal.</em></p><div class="articleContent"><p>Si vous avez commencé à vous attaquer à la mise en page CSS, vous utilisez probablement les <em>floats</em> comme moyen essentiel de mise en forme de vos pages. Peut-être avez-vous commencé à expérimenter quelques techniques du futur, avec l'espoir que les navigateurs seront bientôt compatibles.</p><p>Mais une technique de mise en page CSS qui est là pour durer est le positionnement CSS, c'est à dire l'utilisation de la propriété <code>position</code>. Dans cet article, je passerai en revue le positionnement CSS en détail et j'espère que vous en retirerez quelques options supplémentaires pour votre design.</p><h2>Positionnement statique</h2><p>Commençons par les élément HTML positionnés de façon statique :</p><pre>.exemple {
        position: static;
}</pre><p>Dans la plupart des cas, il est inutile de le mentionner, <code>static</code> étant la valeur par défaut de la propriété <code>position</code>. Cela signifie que si vous ne déclarez pas de valeur de position sur cet élément, il sera considéré comme “statique”. Que signifie cette valeur en termes de comportement de l'élément ?</p><p>Selon les <a href="http://dev.w3.org/csswg/css-position/">spécifications</a> de W3C, un élément positionné de manière statique est une “boîte normale”, positionnée dans ce qu'on appelle un flux normal. Cela signifie qu'un élément statique sera positionné en fonction de son rang par rapport aux autres éléments, dans un flux normal, le changement de son comportement dépendant de sa nature <a href="https://la-cascade.io/articles/la-difference-entre-block-et-inline">block ou inline</a>. D'autres facteurs peuvent aussi affecter la façon dont un élément statique se comporte mais en général ce comportement est aussi simple que possible.</p><h2>Positionnement relatif</h2><p>Une autre valeur possible de la propriété <code>position</code> :</p><pre>.exemple {
        position: relative;
}</pre><p>En quoi est-elle différente de la valeur <code>static</code> ? Un élément positionné de manière relative se comporte de la même façon qu'un élément statique, sauf qu'il est maintenant dépendant des valeurs de <em>quatre autres propriétés CSS</em>. Considérons l'exemple suivant :</p><pre>.box1 {
        width: 100px;
        height: 100px;
        background: blue;
}
.box2 {
        width: 100px;
        height: 100px;
        background: green;
        border: yellow solid;
        position: relative;
        top: 20px;
        left: 20px;
}
.box3 {
        width: 100px;
        height: 100px;
        background: red;
}
.box4 {
        width: 100px;
        height: 100px;
        background: pink;
}</pre><p>Nous supposons que ces quatre boîtes sont les seuls éléments de la page, comment vont-ils se comporter ? Eh bien, d'abord ils seront disposés sur la page dans l'ordre dans lequel ils apparaissent dans votre HTML, chaque boîte sur une nouvelle ligne. Mais la deuxième boîte (la verte avec une bordure jaune) sera décalée par rapport à sa place originale à cause des déclarations <code>top</code> et <code>left</code>.</p><p>La deuxième boîte est donc décalée de 20px à partir du haut et de 20px à partir de la gauche par rapport à sa position originale. Vous obtiendriez la même chose en ajoutant une <code>margin-top</code> et une <code>margin-left</code> de 20px - mais avec une différence significative : décaler la position à l'aide de <code>top</code>, <code>left</code>, <code>bottom</code> ou <code>right</code> n'affecte pas le flux des éléments qui l'entourent. Voici à quoi cela ressemble, et pour mieux comprendre vous pouvez jouer avec cette <a href="http://jsbin.com/idefal/1/edit">petite démo</a> :</p><figure><img src="https://la-cascade.io/images/position_relative-compressor.jpeg" alt="exemple de positionnement relatif: la deuxième boîte est décalée par rapport aux autres boîtes qui n'ont pas bougé" /></figure><p>Comme on le voit, un positionnement relatif peut entraîner un chevauchement. La place originale de l'élément est respectée, mais son décalage ne modifiera pas le positionnement des autres boîtes.</p><h2>Positionnement absolu</h2><p>La troisième valeur que vous pouvez utiliser pour la propriété <code>position</code> :</p><pre>.exemple {
        position: absolute;
}</pre><p>Un élément positionné absolument est complètement retiré du flux normal du document et, tout comme <code>position: relative</code> il est sujet aux décalages horizontaux et verticaux impliqués par l'utilisation de <code>top</code>, <code>left</code>, <code>bottom</code> et <code>right</code>.</p><p>La différence principale tient à son retrait du flux. Cela signifie que l'espace occupé à l'origine par cet élément ne sera plus respecté par les éléments qui l'entourent. Ceux-ci se comporteront comme s'il n'existait plus.</p><h3>Contextes de positionnement</h3><p>Lorsque vous décalez un élément positionné de manière relative, les décalages sont relatifs à la place originale de l'élément dans le flux normal. Avec un élément positionné de manière absolue, les décalages sont relatifs au viewport du navigateur ou, pour simplifier, à la fenêtre, ou au corps du document.</p><p>Mais le contexte de positionnement d'un élément positionné absolument peut être modifié en ajoutant <code>position: relative</code> à l'élément parent, ce qui crée un nouveau contexte de positionnement. Si cela vous paraît obscur, voici une <a href="http://jsbin.com/udopih/1/edit">démo</a>.</p><p>Et voici à quoi cela ressemble :</p><figure><img src="https://la-cascade.io/images/position_absolute-compressor.jpeg" alt="exemple de positionnement absolu: la deuxième boîte est réglée sur positionnement absolu et elle est décalée par rapport à son élément conteneur" /></figure><p>L'élément <code>body</code> a une bordure noire et l'élément <code>.container</code> une bordure orange. On voit que la boîte verte (positionnée en absolu) est décalée à l'intérieur du contexte de son élément parent <code>.container</code>, lui-même positionné de manière relative.</p><p>Remarquez bien ce qui se passe <a href="http://jsbin.com/otakoq/1/edit">si nous supprimons la déclaration</a> <code>position: relative</code> de l'élément “container” :</p><figure><img src="https://la-cascade.io/images/position_viewport-compressor.jpeg" alt="l'élément est maintenant positionné par rapport à la fenêtre et non plus par rapport à son élément parent" /></figure><p>Du fait de la suppression du contexte de positionnement explicite, la boîte verte est maintenant décalée <em>par rapport au viewport</em> (contexte de positionnement implicite) et, comme nous l'avons déjà dit, aucun des éléments environnants n'est affecté par le flux de la boîte verte soustraite au flux normal.</p><h2>Positionnement fixe</h2><p>Voici l'option de positionnement suivante :</p><pre>.exemple {
        position: fixed;
}</pre><p>Un élément en positionnement fixe appartient, selon les spécifications de W3C, à la catégorie des éléments en positionnement absolu. Leurs comportements sont en effet très similaires, avec toutefois deux différences essentielles : d'abord le contexte de positionnement est <em>toujours</em> le viewport, le contexte ne changera donc pas si l'on ajoute <code>position: relative</code> à l'élément parent. Ensuite, les éléments en position fixe ne bougent plus lorsque le document est scrollé. Regardez l'image ci-dessous, tirée du blog de Treehouse :</p><figure><img src="https://la-cascade.io/images/position_fixed-compressor.jpeg" alt="exemple de positionnement fixe" /></figure><p>Au sommet de la page, un message promotionnel est en position fixe, il reste là même quand vous faites défiler la page.</p><p>L'utilisation conjointe du positionnement fixe et de <a href="https://la-cascade.io/articles/comment-fonctionne-z-index">z-index</a> vous offre des possibilités de mise en page uniques.</p><h2>Nouvelles valeurs en CSS3</h2><p>Les quatre valeurs décrites ci-dessus sont celles que vous utiliserez le plus souvent avec la propriété <code>position</code>. Sachez cependant que le spec CSS3 comprend deux nouvelles valeurs : <code>position: center</code> et <code>position: page</code>.</p><p>Je n'entrerai pas dans les détails, car à ma connaissance ces valeurs ne sont actuellement compatibles avec aucun navigateur.</p><h2>Le présent et l'avenir du positionnement CSS</h2><p>Il y a des tonnes d'articles détaillés sur le positionnement, n'hésitez pas à vous y référer si vous voulez mieux comprendre toutes ces techniques.</p><p>Dans le futur, lorsque des techniques comme <a href="https://la-cascade.io/articles/flexbox-guide-complet">Flexbox</a>, <a href="https://la-cascade.io/articles/css-grid-layout-guide-complet">CSS Grid Layout</a> et d'autres nouveaux modules seront plus universellement compatibles, il est probable que vous aurez moins recours au positionnement CSS.</p></div>]]></description>
      <link>https://la-cascade.io/articles/le-positionnement-css</link>
      <guid>https://la-cascade.io/articles/le-positionnement-css</guid>
      <pubDate>Sat, 18 Jan 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Introduction à RDFa, 1ère partie]]></title>
      <description><![CDATA[<p><a href="https://en.wikipedia.org/wiki/RDFa">RDFa</a> connaît sa petite heure de gloire : Google utilise RDFa et les microformats pour indexer les sites web, et utilise les données analysées pour enrichir la présentation des résultats de recherche par des "rich snippets" (extraits enrichis). Yahoo! utilise RDFa depuis plus longtemps encore (<a href="#f1">1</a>). Avec ces deux moteurs de recherche géants sur la même trajectoire, un web nouveau est plus près que jamais.</p><p>Le web est conçu pour être consommé par des humains, et la plupart des informations riches et utiles que contiennent nos sites sont inaccessibles aux machines. Les humains peuvent s'adapter à toutes sortes de variations dans la mise en page, l'orthographe, les majuscules, les couleurs, la position du texte etc, et absorber la signification de la page dans toutes ses subtilités. Les machines, elles, ont besoin d'un peu d'aide.</p><p>Un nouveau web — un web sémantique — serait fait d'informations balisées d'une manière telle qu'un programme puisse facilement le comprendre. Avant de voir comment nous pourrions y parvenir, voyons ce que nous serions capables de faire avec lui.</p><h2>Recherche améliorée</h2><p>Ajouter à une page des données accessibles aux machines améliore notre capacité à trouver la bonne information. Imaginons un titre de journal annonçant "aujourd'hui le premier ministre s'est envolé pour l'Australie", en référence au premier ministre britannique, Gordon Brown. L'article ne nomme pas le premier ministre mais il est assez certain que cette information apparaîtra lorsque quelqu'un fera une recherche sur le nom de Gordon Brown.</p><p>Si cette information date de 1940 toutefois, nous ne voudrions pas qu'elle apparaisse dans une recherche sur Gordon Brown, par contre nous voudrions qu'elle apparaisse dans une recherche sur Winston Churchill.</p><p>Pour y parvenir, notre moteur de recherche doit associer un ensemble de données à un autre, il lui faut connaître les dates auxquelles les premiers ministres britanniques ont exercé leurs fonctions, puis les croiser avec la date de publication de l'article. Cela ne serait pas complètement impossible, mais quid si l'article en question est une fiction ou s'il concerne en réalité le premier ministre australien ? Les dates ne suffisent plus.</p><p>Les algorithmes d'indexation qui tentent de déduire un contexte à partir du texte s'amélioreront avec le temps, mais un balisage supplémentaire qui rend l'information non ambigüe ne peut qu'aider à la précision de la recherche.</p><h2>De meilleures interfaces utilisateurs</h2><p>Yahoo! et Google ont tous les deux commencé à utiliser RDFa pour améliorer l'expérience utilisateur en mettant en valeur la façon dont apparaissent les résultats de recherche. Voici l'approche de Google :</p><figure><img src="https://la-cascade.io/images/09-5-10-drooling-dog-snippet-metadata-circled.webp" alt="" /></figure><p>...et voici celle de Yahoo! :</p><figure><img src="https://la-cascade.io/images/rdfa_custom_examples.webp" alt="" /></figure><p>Il y a aussi un avantage commercial à avoir une meilleure "compréhension" des pages indexées : des publicités plus pertinentes, plus focalisées peuvent être placées à côté des résultats de recherche.</p><p>Maintenant que nous savons pourquoi nous pourrions avoir intérêt à insérer des donner plus accessibles aux machines, voyons comment nous pourrions y parvenir.</p><h2>Les métadonnées dans HTML</h2><p>Vous connaissez déjà les métadonnées basiques de HTML. Les plus utilisées sont les éléments meta et link , et vous savez peut-être que l'attribut <code>@rel</code> utilisé dans <code>link</code> peut aussi l'être dans <code>a</code> . (NB : j'utiliserai le terme "HTML" pour désigner "la famille de langages HTML", puisque ce que je décris s'applique de la même façon à HTML et XHTML).</p><p>Nous allons dans un premier temps nous pencher sur ces caractéristiques existantes, parce qu'elles nous fournissent le fondement conceptuel sur lequel RDFa a été bâti.</p><h2>L'utilisation de meta et link en HTML</h2><p>Les éléments <code>meta</code> et <code>link</code> sont situés dans la partie <code>&lt;head&gt;</code> d'un document HTML, ils permettent de fournir des informations relatives à ce document. Par exemple, je pourrais vouloir indiquer qu'il a été créé le 9 mai 2009, que j'en suis l'auteur et que je donne l'autorisation à tous d'utiliser cet article :</p><pre class="language-html">&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;RDFa: Tout le monde peut avoir une API&lt;/title&gt;
    &lt;meta name="author" content="Mark Birbeck" /&gt;
    &lt;meta name="created" content="2009-05-09" /&gt;
    &lt;link
      rel="license"
      href="http://creativecommons.org/licenses/by-sa/3.0/"
    /&gt;
  &lt;/head&gt;
&lt;/html&gt;</pre><p>Avec cet exemple, on voit comment HTML distingue clairement les métadonnées du document dans un espace distinct du texte principal. HTML utilise l'élément head pour les métadonnées et l'élément body pour le contenu de la page.</p><p>HTML nous permet aussi de rendre plus floues les frontières : nous pouvons placer l'attribut <code>@rel</code> dans un lien cliquable, tout en gardant la signification qu'il a dans <code>link</code>.</p><h3>Utilisation de @rel</h3><p>Imaginons que je veuille permettre aux visiteurs de mon site de voir ma license Creative Commons. En l'état actuel des choses, l'information dont je parle est cachée des lecteurs parce qu'elle est contenue dans le head. C'est facilement résolu en ajoutant une ancre dans le <code>body</code> :</p><pre class="language-html">&lt;a href="http://creativecommons.org/licenses/by-sa/3.0/"
  &gt;CC Attribution-ShareAlike&lt;/a
&gt;</pre><p>Voilà qui nous permet d'atteindre nos objectifs : d'abord, nous avons des métadonnées lisibles par les machines dans le <code>head</code> qui décrivent la relation entre le document et la licence :</p><pre class="language-html">&lt;link
  rel="license"
  href="http://creativecommons.org/licenses/by-sa/3.0/"
/&gt;</pre><p>...ensuite, nous avons un lien dans le <code>body</code> qui permet aux humains de cliquer et de lire la licence :</p><pre class="language-html">&lt;a href="http://creativecommons.org/licenses/by-sa/3.0/"
  &gt;CC Attribution-ShareAlike&lt;/a
&gt;</pre><p>Mais HTML nous permet également d'utiliser l'attribut <code>@rel</code> de <code>link</code> sur une ancre. En d'autres termes, il permet à des métadonnées qui devraient normalement figurer dans <code>head</code> d'apparaître dans le <code>body</code>.</p><p>Avec cette technique incroyablement puissante, nous pouvons exprimer à la fois les métadonnées pour les machines et le lien cliquable pour les humains, en une formule unique et pratique&amp;nbsp,:</p><pre class="language-html">&lt;a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"
  &gt;CC Attribution-ShareAlike&lt;/a
&gt;</pre><p>Cette méthode simple d'enrichissement du balisage inline n'est pas souvent utilisée dans les pages web, mais elle est au coeur de RDFa. Cela nous conduit au premier principe de RDFa :</p><h4>Règle n°1 :</h4><p>Les éléments <code>link</code> et <code>a</code> impliquent une relation entre le document courant et un autre document; l'attribut <code>@rel</code> nous permet de fournir une valeur qui décrira mieux cette relation.</p><p>Cependant, soyons clairs : l'utilisation de <code>@rel</code> avec <code>a</code> consiste à tirer parti d'une caractéristique déjà existante de HTML, sur laquelle RDFa ne fait qu'attirer l'attention.</p><h2>Appliquer des licences distinctes</h2><p>L'exemple précédent fournit une information à propos de la page web dans laquelle elle est incluse. Mais que se passe-t-il si la page contient plusieurs objets qui ont chacun une licence différente ? Les exemples de scénario abondent, tels que les pages de résultats de recherche de Flickr, Youtube ou SlideShare.</p><p>RDFa utilise l'idée simple qui sous-tend <code>@rel</code> — l'idée qu'il exprime la relation entre deux choses — en appliquant cet attribut à l'attribut <code>@src</code> de l'élément <code>img</code>.</p><p>Imaginons par exemple une page de résultats de recherche sur Flickr :</p><pre class="language-html">&lt;img src="http://la-cascade.ghost.io/image1.png" /&gt;
&lt;img src="http://la-cascade.ghost.io/image2.png" /&gt;</pre><p>Supposons que les deux pages ont une licence Creative Commons, la première image en Attribution-ShareAlike, la seconde en Attribution-Noncommercial-No Derivative works.</p><h3>Quelles balises utiliser ?</h3><p>Si vous avez deviné qu'il suffit de placer l'attribut <code>@rel</code> dans la balise img, bravo. Pour exprimer deux licences différentes, une pour chaque image, il suffit d'écrire :</p><pre class="language-html">&lt;img
  src="http://la-cascade.ghost.io/image1.png"
  rel="license"
  href="http://creativecommons.org/licenses/by-sa/3.0/"
/&gt;
&lt;img
  src="http://la-cascade.ghost.io/image2.png"
  rel="license"
  href="http://creativecommons.org/licenses/by-nc-nd/3.0/"
/&gt;</pre><p>Ici, vous voyez le principe de base en action — construire à partir des métadonnées déjà fournies par HTML. Partir de la structure de description inhérente au concept HTML permet de mieux s'orienter lorsqu'on utilise RDFa.</p><h4>Règle n°2 :</h4><p>Les attributs <code>@rel</code> et <code>@href</code> ne sont plus confinés aux éléments <code>a</code> et <code>link</code>, ils peuvent aussi être utilisés avec <code>img</code> pour indiquer une relation entre une image et autre chose.</p><h3>Ajouter des propriétés à body</h3><p>Dans notre illustration HTML, nous avons vu que nous pouvons aussi ajouter des propriétés textuelles au sujet du document :</p><pre class="language-html">&lt;meta name="author" content="Mark Birbeck" /&gt;
&lt;meta name="created" content="2009-05-01" /&gt;</pre><p>Cela nous dit qui a créé le document, et quand, mais on ne peut l'utiliser que dans la partie <code>head</code> du document. RDFa reprend cette technique et l'améliore en rendant son utilisation possible dans <code>body</code>. <code>@content</code> n'est plus confiné à la balise <code>meta</code>, il peut apparaître dans n'importe quel élément.</p><h4>Règle n°3 :</h4><p>Dans le HTML habituel, les propriétés sont fixées dans la partie head du document en utilisant @contentavec meta. Dans les documents HTML comportant RDFa, @content peut être utilisé pour fixer les propriétés de n'importe quel élément.</p><p>Il y a un petit changement par rapport à la façon dont <code>@content</code> est utilisé dans <code>head</code>, car comme l'attribut @name est déjà présent dans HTML, cela pourrait créer une certaine confusion. RDFa fournit un autre attribut appelé <code>@property</code> pour remplir ce rôle.</p><h4>Règle n°4 :</h4><p>Bien qu'HTML utilise la propriété <code>@name</code> pour fixer le nom d'une propriété dans <code>meta</code>, il ne peut pas être utilisé dans d'autres éléments, RDFa fournit à la place un nouvel attribut appelé <code>@property</code>.</p><p>Supposons que la date de publication de notre document et le nom de son auteur figurent dans la partie head de notre document et que ces mêmes informations figurent sous une forme lisible dans le corps du document :</p><pre class="language-html">&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;RDFa: Tout le monde peut avoir une API&lt;/title&gt;
    &lt;meta name="author" content="Mark Birbeck" /&gt;
    &lt;meta name="created" content="2009-05-09" /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;RDFa: Tout le monde peut avoir une API&lt;/h1&gt;
    Author: &lt;em&gt;Mark Birbeck&lt;/em&gt; Created: &lt;em&gt;May 9th, 2009&lt;/em&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p>Avec RDFa, nous pouvons fondre ces deux ensembles d'informations, les métadonnées, lisibles par les machines, étant localisées au même endroit que le texte lisible par les humains :</p><pre class="language-html">&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;RDFa: Tout le monde peut avoir une API&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;RDFa: Now everyone can have an API&lt;/h1&gt;
    Author:
    &lt;em property="author" content="Mark Birbeck"&gt;Mark Birbeck&lt;/em&gt;
    Published:
    &lt;em property="created" content="2009-05-14"&gt;May 14th, 2009&lt;/em&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p>Nous allons voir dans un instant comment nous pouvons améliorer encore cet exemple. Pour l'instant, il nous suffit de constater que la localisation de ces métadonnées dans le <code>body</code> ou dans le <code>head</code> est équivalente.</p><h2>Utiliser des vocabulaires</h2><p>Nous devons faire un petit détour ici. Nous pouvons nous permettre d'utiliser <code>@name="author"</code> dans le <code>head</code> car même si la propriété "author" (auteur) n'est définie dans aucune spécification, on a fini par l'intégrer. Mais RDFa permet — et requiert — une plus grande précision. Quand nous utilisons un terme comme "author" ou "created", nous devons indiquer d'où ce terme provient. Sinon, il n'y a pas moyen de savoir si vous donnez à "author" le même sens que quelqu'un d'autre.</p><p>Cela peut paraître inutile. Après tout, comment pourrait-il y avoir confusion sur un terme aussi simple ? Mais imaginons que le terme soit "country" sur un site de vacance, est-ce que ce terme désigne le pays ou bien la campagne ? (<a href="#f2">2</a>) Beaucoup de mots prêtent à confusion et si vous y ajoutez un contexte multilingue vous verrez que si nous voulons avancer avec nos métadonnées nous devons être précis. Cela impose d'indiquer la provenance des termes que nous utilisons.</p><p>En RDFa, on indique que l'on se réfère à un vocabulaire, dont on spécifie l'adresse ainsi :</p><pre class="language-xml">xmlns:dc="http://purl.org/dc/terms/"</pre><p>Si vous avez des notions d'<a href="https://en.wikipedia.org/wiki/XML">XML</a>, vous reconnaîtrez la syntaxe d'une déclaration d'espace de nom XML (<a href="#f3">3</a>).</p><p>Cet exemple nous donne un accès aux listes de termes du vocabulaire Dublin Core, grâce au préfixe "dc". Dublin Core contient de nombreux termes (<a href="#f4">4</a>), nous utiliserons ici "creator" et "created", avec le préfixe :</p><ul><li>dc:creator</li>
<li>dc:created</li>
</ul><p>Maintenant les choses sont claires, "dc:creator" n'est pas la même chose que "xyz:creator".</p><p>Pour que cela fonctionne, il faut déclarer quelque part en haut du document que l'on pointe vers ce vocabulaire. Dans notre exemple, cela pourrait se faire dans l'élément body ou html. L'exemple complet devient :</p><pre class="language-html">&lt;html xmlns:dc="http://purl.org/dc/terms/"&gt;
  &lt;head&gt;
    &lt;title&gt;RDFa: Tout le monde peut avoir une API&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;RDFa: Tout le monde peut avoir une API&lt;/h1&gt;
    Author:
    &lt;em property="dc:creator" content="Mark Birbeck"&gt;Mark Birbeck&lt;/em&gt;
    Published:
    &lt;em property="dc:created" content="2009-05-09"&gt;May 9th, 2009&lt;/em&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p>Les vocabulaires sont nombreux et vous pouvez même inventer le vôtre pour votre société, organisation, groupe d'intérêts. S'il n'existe pas d'organisation centralisée, il existe en revanche de bonnes pratiques. Le pouvoir impose des responsabilités, alors renseignez-vous bien avant de vous lancer dans la rédaction d'un nouveau vocabulaire.</p><p>Avant de revenir à notre exemple, je voudrais ajouter encore une chose à propos des vocabulaires. Vous vous demandez certainement pourquoi <code>@rel="license"</code> n'a pas eu le même traitement que <code>@rel="author"</code> et requiert un préfixe. La réponse est que HTML vient déjà avec des valeurs pré-construites à utiliser avec <code>@rel</code> (comme "next" et "prev") et RDFa en ajoute quelques autres. L'une d'elles est "license". Mais une fois que vous sortez de cette liste de valeurs — par exemple en utilisant un terme du vocabulaire Dublin Core comme "<a href="https://www.dublincore.org/specifications/dublin-core/dcmi-terms/">replaces</a>" ou un terme de FOAF comme "knows" — alors vous devez utiliser un préfixe comme nous l'avons fait pour <code>@property</code>.</p><p>Par exemple, admettons que notre article remplace un autre document, une relation que nous pouvons exprimer avec l'expression Dublin Core "replaces" :</p><pre class="language-html">&lt;html xmlns:dc="http://purl.org/dc/terms/"&gt;
  &lt;head&gt;
    &lt;title&gt;RDFa: Tout le monde peut avoir une API&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;RDFa: Tout le monde peut avoir une API&lt;/h1&gt;
    Author:
    &lt;em property="dc:creator" content="Mark Birbeck"&gt;Mark Birbeck&lt;/em&gt;
    Created:
    &lt;em property="dc:created" content="2009-05-09"&gt;May 9th, 2009&lt;/em&gt;
    License:
    &lt;a
      rel="license"
      href="http://creativecommons.org/licenses/by-sa/3.0/"
      &gt;CC Attribution-ShareAlike&lt;/a
    &gt;
    Previous version:
    &lt;a
      rel="dc:replaces"
      href="http://la-cascade.ghost.io/rdfa.0.8.html"
      &gt;version 0.8&lt;/a
    &gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p>Maintenant que nous comprenons les vocabulaires, revenons à notre exemple principal.</p><h3>Valeur texte d'une propriété</h3><p>Dans l'exemple précédent, la duplication du texte "Mark Birbeck", dans l'attribut <code>@content</code> et dans le texte est problématique. Nous pouvons supprimer <code>@content</code> si le texte contient la valeur de la métadonnée :</p><pre class="language-html">Author: &lt;em property="dc:creator"&gt;Mark Birbeck&lt;/em&gt;</pre><h4>Règle n°5 :</h4><p>S'il n'y a pas d'attribut <code>@content</code>, la valeur de la propriété sera celle du texte inline.</p><p>Cette façon de faire peut être considérée comme la pratique par défaut, l'insertion d'une valeur <code>@content</code> pouvant être une façon d'outrepasser la valeur textuelle si celle-ci ne dit pas exactement ce que vous souhaitez. Elle donne plus de liberté d'action aux auteurs quant au texte qu'ils veulent donner aux lecteurs, tout en étant précis dans les métadonnées. La date de publication illustre bien ce cas. Toutes les données qui suivent ont la même signification, dans des présentations très différentes :</p><pre class="language-html">&lt;span property="dc:created" content="2009-05-14"&gt;May 14th, 2009&lt;/span&gt;
&lt;span property="dc:created" content="2009-05-14"&gt;May 14th&lt;/span&gt;
&lt;span property="dc:created" content="2009-05-14"&gt;14 Mai&lt;/span&gt;
&lt;span property="dc:created" content="2009-05-14"&gt;14/05/09&lt;/span&gt;
&lt;span property="dc:created" content="2009-05-14"&gt;demain&lt;/span&gt;
&lt;span property="dc:created" content="2009-05-14"&gt;hier&lt;/span&gt;
&lt;span property="dc:created" content="2009-05-14"&gt;14 Mai, 2009&lt;/span&gt;
&lt;span property="dc:created" content="2009-05-14"
  &gt;14 maggio, 2009&lt;/span
&gt;</pre><h4>Règle n°6 :</h4><p>Si l'attribut <code>@content</code> est présent, c'est son contenu qui établit la valeur de la propriété, et non pas le texte inline de l'élément.</p><h3>Ajouter des propriétés à une image</h3><p>Nous pouvons également ajouter des propriétés à une image. Par exemple, pour indiquer sa date de création, nous pouvons écrire :</p><pre class="language-html">&lt;img
  src="http://la-cascade.io/image1.png"
  property="dc:created"
  content="2009-03-22"
/&gt;
&lt;img
  src="http://la-cascade.io/image2.png"
  property="dc:created"
  content="2009-05-01"
/&gt;</pre><h4>Règle n°7 :</h4><p>Le HTML ordinaire permet d'établir des propriétés de la page, RDFa permet en outre d'établir des propriétés pour les URL d'images.</p><p>RDFa permet également d'exprimer une propriété et une relation pour la même image :</p><pre class="language-html">&lt;img
  src="http://la-cascade.ghost.io/image1.png"
  rel="license"
  href="http://creativecommons.org/licenses/by-sa/3.0/"
  property="dc:created"
  content="2009-05-01"
/&gt;</pre><h3>Ajouter des métadonnées à n'importe quel objet</h3><p>En suivant l'évolution d'un HTML basique vers RDFa, nous avons fait trois pas importants :</p><ol><li>Nous avons noté que n'importe quelle métadonnée exprimée dans le <code>head</code> d'un document peut être utilisée dans son <code>body</code> — moyennant le changement de l'attribut <code>@name</code> en <code>@property</code>.</li>
<li>Nous avons vu comment RDFa permet d'utiliser des vocabulaires clairement définis.</li>
<li>Nous avons appris que RDFa permet d'exprimer des propriétés et des relations à propos d'images ou à propos du document courant.</li>
</ol><p>Puisque nous pouvons ajouter des propriétés et des relations à des images, pourquoi pas généraliser ? Si je peux indiquer la licence de ce document et la licence des images, pourquoi pas indiquer les licences de tout ce à quoi je me réfère dans ma page web ?</p><p>Par exemple, admettons que j'aie quelques liens vers des présentations SlideShare sur RDFa :</p><pre class="language-html">&lt;a href='http://www.slideshare.net/fabien_' gandon/rdfa-in-a-nutshell-v1"&gt;RDFa in a nutshell&lt;/a&gt;
&lt;a href='http://www.slideshare.net/mark.birbeck/the-5-minute-guide-to-rdfain-only-6-minutes-40-seconds' &gt;The 5-minute guide to RDFa… in only 6 minutes and 40 seconds&lt;/a&gt;</pre><p>Si vous regardez ces pages sur SlideShare, vous verrez que les informations relatives à la licence sont clairement affichées. Mais quid si nous voulions ajouter cette information au document en cours, de façon à ce qu'un navigateur intelligent puisse en faire quelque chose ? (La page pourrait être, par exemple, un ensemble de résultats de recherche, nous pourrions vouloir afficher les licences de façon à aider l'internaute à choisir les documents).</p><p>Nous pourrions penser qu'il suffit d'utiliser <code>@rel="license"</code> sur ces ancres, comme d'habitude, mais rappelez-vous que cela implique que le document courant ait une licence identifiée par l'item dans l'attribut <code>@href</code>. Dans le cas présent, l'autre document est une page SlideShare, pas une licence.</p><p>Pour rendre possible l'insertion d'informations additionnelles à propos de n'importe quelle ressource, RDFa ajoute un nouvel attribut appelé <code>@about</code>. Il est calqué sur le modèle de l'attribut <code>@src</code> dans les images, c'est à dire qu'il peut contenir des informations <code>@rel</code> et <code>@property</code>, mais il peut être utilisé sur n'importe quel élément HTML. Voici comment utiliser <code>@about</code> pour nous aider à ajouter des informations relatives aux licences de nos slides. Notre premier lien :</p><pre class="language-html">&lt;a
  href="http://www.slideshare.net/fabien_gandon/rdfa-in-a-nutshell-v1"
  &gt;RDFa in a nutshell&lt;/a
&gt;</pre><p>...est enrichi ainsi :</p><pre class="language-html">&lt;a
  about="http://www.slideshare.net/fabien_gandon/rdfa-in-a-nutshell-v1"
  rel="license"
  href="http://creativecommons.org/licenses/by/2.5/"
  &gt;CC BY&lt;/a
&gt;.</pre><p>Notez bien au passage que du point de vue du processeur RDFa cette information peut figurer n'importe où dans le document, elle n'a pas besoin d'apparaître à côté du lien. Pour les humains bien sûr, c'est plus logique.</p><p>La deuxième présentation :</p><pre class="language-html">&lt;a
  href="http://www.slideshare.net/mark.birbeck/the-5-minute-guide-to-rdfain-only-6-minutes-40-seconds"
  &gt;The 5-minute guide to RDFa…in only 6 minutes and 40 seconds&lt;/a
&gt;</pre><p>...reçoit sa licence en ajoutant le balisage suivant :</p><pre class="language-html">&lt;a
  about="http://www.slideshare.net/mark.birbeck /the-5-minute-guide-to-rdfain-only-6-minutes-40-seconds"
  rel="license"
  href="http://creativecommons.org/licenses/by-sa/2.5/"
  &gt;CC BY SA&lt;/a
&gt;.</pre><p>Là encore, ce balisage pourrait apparaître n'importe où.</p><p>Notez que la référence à chaque licence reste un lien cliquable, donc du point de vue de l'utilisateur rien ne change lorsqu'on ajoute <code>@about</code> à l'ancre. Mais du point de vue des métadonnées, chaque licence est maintenant appliquée à un document externe qui contient une présentation, plutôt qu'au document courant.</p><p>Bien sûr, dans un exemple réel les liens cliquables contiendraient probablement les icônes Creative Commons :</p><pre class="language-html">&lt;a
  about="http://www.slideshare.net/mark.birbeck/the-5-minute-guide-to-rdfain-only-6-minutes-40-seconds"
  rel="license"
  href="http://creativecommons.org/licenses/by-sa/2.5/"
  &gt;&lt;img src="http://i.creativecommons.org/l/by-sa/2.5/80x15.png"
/&gt;&lt;/a&gt;</pre><p>Vous l'avez sans doute déjà compris, nous pouvons aussi ajouter <code>@property</code> et <code>@content</code> aux ressources référencées par <code>@about</code>. Par exemple si nous voulions ajouter des informations sur le créateur de la présentation, nous pourrions écrire :</p><pre class="language-html">&lt;a
  about="http://www.slideshare.net/fabien_gandon/rdfa-in-a-nutshell-v1"
  rel="license"
  href="http://creativecommons.org/licenses/by/2.5/"
  property="dc:creator"
  content="Fabien Gandon"
  &gt;&lt;img src="http://i.creativecommons.org/l/by/2.5/80x15.png"
/&gt;&lt;/a&gt;</pre><h4>Règle n°8 :</h4><p>Propriétés et relations peuvent être spécifiées pour n'importe quelle ressource en utilisant l'attribut <code>@about</code> de RDFa.</p><h3>Utiliser @about</h3><p>Quelle technique utiliser pour attribuer plusieurs propriétés avec <code>@about</code> ? Jusqu'ici, nos exemples ne comportaient qu'une seule propriété et une seule relation pour chaque objet, parce que c'est la limite imposée par la structure d'HTML : dans un élément, chaque attribut doit avoir un nom unique, il n'est donc pas possible de spécifier des valeurs ou des relations multiples.</p><p>La réponse est très simple. En RDFa, l'attribut <code>@about</code> utilisé dans un élément établit le contexte par rapport auquel se situe les éléments "enfants". Rappelons-nous notre dernier exemple :</p><pre class="language-html">&lt;a
  about="http://www.slideshare.net/fabien_gandon/rdfa-in-a-nutshell-v1"
  rel="license"
  href="http://creativecommons.org/licenses/by/2.5/"
  property="dc:creator"
  content="Fabien Gandon"
  &gt;&lt;img src="http://i.creativecommons.org/l/by/2.5/80x15.png"
/&gt;&lt;/a&gt;</pre><p>Ce balisage dit deux choses, d'abord que "la présentation SlideShare visionnable à l'URL spécifiée comporte une licence CC BY", ensuite que "la présentation SlideShare visionnable à l'URL spécifiée a été créée par Fabien Gandon".</p><p>Pour rendre plus tangible le probème que nous cherchons à résoudre, imaginons que nous voulions aussi ajouter la date à laquelle la présentation a été publiée — sachant que nous ne sommes pas autorisés à ajouter un deuxième attribut <code>@property</code> à notre ancre.</p><p>La façon la plus simple d'y parvenir est de créer un élément qui contienne le contexte dans lequel nous voulons qu'opèrent tous nos RDFa, dans ce cas c'est l'adresse de la présentation :</p><pre class="language-html">&lt;div
  about="http://www.slideshare.net/fabien_gandon/rdfa-in-a-nutshell-v1"
&gt;
  ...
&lt;/div&gt;</pre><p>Une fois que nous avons ceci, nous pouvons ajouter toutes les propriétés que nous voulons :</p><pre class="language-html">&lt;div
  about="http://www.slideshare.net/fabien_gandon/rdfa-in-a-nutshell-v1"
&gt;
  &lt;h1&gt;RDFa in a Nutshell&lt;/h1&gt;
  &lt;ul&gt;
    &lt;li&gt;Author:&lt;em property="dc:creator"&gt;Fabien Gandon&lt;/em&gt;&lt;/li&gt;
    &lt;li&gt;
      Created:&lt;em property="dc:created" content="2007-01-01"
        &gt;Jan 1st, 2007&lt;/em
      &gt;
    &lt;/li&gt;
    &lt;li&gt;
      License:
      &lt;a
        rel="license"
        href="http://creativecommons.org/licenses/by/2.5/"
        &gt;&lt;img src="http://i.creativecommons.org/l/by/2.5/80x15.png"
      /&gt;&lt;/a&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;</pre><p>Si ce layout vous semble familier, c'est parce que c'est exactement celui que nous avons vu lorsque nous avons ajouté des propriétés au "document courant" :</p><pre class="language-html">&lt;html xmlns:dc="http://purl.org/dc/terms/"&gt;
  &lt;head&gt;
    &lt;title&gt;RDFa: Tout le monde peut avoir une API&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;RDFa: Tout le monde peut avoir une API&lt;/h1&gt;
    &lt;ul&gt;
      &lt;li&gt;Author: &lt;em property="dc:creator"&gt;Mark Birbeck&lt;/em&gt;&lt;/li&gt;
      &lt;li&gt;
        Created:
        &lt;em property="dc:created" content="2009-05-09"
          &gt;May 9th, 2009&lt;/em
        &gt;
      &lt;/li&gt;
      &lt;li&gt;
        License:
        &lt;a
          rel="license"
          href="http://creativecommons.org/licenses/by-sa/3.0/"
          &gt;CCAttribution-ShareAlike&lt;/a
        &gt;
      &lt;/li&gt;
      &lt;li&gt;
        Version précédente:
        &lt;a
          rel="dc:replaces"
          href="http://la-cascade.ghost.io/rdfa.0.8.html"
          &gt;version 0.8&lt;/a
        &gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p>La seule différence est que le contexte de toutes les propriétés et relations que nous avons ajoutées est défini par <code>@about</code>, alors que dans le premier exemple le contexte était simplement le document lui-même.</p><h4>Règle n°9 :</h4><p>La propriété <code>@about</code> établit le contexte de toutes les propriétés et relations contenues. S'il n'y a pas de valeur définie avec <code>@about</code>, toutes les propriétés et relations feront référence au document courant.</p><p>Cette technique est sans doute ce qui fait la différence essentielle entre RDFa et les autres méthodes de structuration de données dans HTML, telles que les Microformats et eRDF.</p><hr /><p>Notes du traducteur :</p><p><small>    <strong id="f1">1</strong> - Cet article date de 2009. Google, Yahoo! et Bing utilisent aujourd'hui les microdonnées (microdata) pour enrichir le contenu, dans le cadre d'un schéma commun, <a href="https://schema.org/">schema.org</a>.<br />Voici ce que dit Google à son propos :<br />À l'origine, trois formats de balisage des données structurées sont compatibles : les microdonnées, les microformats et RDFa. Pour schema.org, nous avons décidé de nous concentrer sur un seul format, afin d'éviter que les webmasters ne soient obligés de faire un choix difficile. De plus, un format unique permet d'améliorer la cohérence entre les moteurs de recherche qui se basent sur ces données. Chacun des formats présente des avantages particuliers, mais nous avons trouvé que les microdonnées offraient un juste équilibre entre la capacité d'extension de RDFa et la simplicité des microformats. C'est pour cette raison que nous avons choisi ce format.<br />Comme le rappelle Google, RDFa est un langage plus riche et extensible que les microdonnées, et il est compatible avec les outils de mise en valeur du contenu (rich snippets et autres) des moteurs de recherche. Vous pouvez combiner RDFa et les microdonnées dans votre HTML pour avoir un contenu parfaitement sémantique !</small> <a href="#a1">↩</a></p><p><small>    <strong id="f2">2</strong> - En anglais, le terme country peut désigner le pays, ou la campagne par opposition à la ville.</small> <a href="#a2">↩</a></p><p><small>    <strong id="f3">3</strong> - xmlns: espace de nom (Name Space = ns) XML, et dc = Dublin Core</small> <a href="#a3">↩</a></p><p><small>    <strong id="f4">4</strong> - Dublin Core lui-même en contient très peu (comme son nom l'indique), il s'agit des 15 termes considérés comme essentiels. Dublin Core 'qualified' en ajoute de plus spécifiques.</small> <a href="#a4">↩</a></p>]]></description>
      <link>https://la-cascade.io/articles/introduction-a-rdfa</link>
      <guid>https://la-cascade.io/articles/introduction-a-rdfa</guid>
      <pubDate>Wed, 15 Jan 2014 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Do's & Don'ts de la Typographie]]></title>
      <description><![CDATA[<p><em>L'essentiel du contenu disponible sur le web est du texte, il est donc fondamental de comprendre les principes de base de toute bonne typographie. Cette connaissance permet aux designers de communiquer plus efficacement, de créer de meilleurs sites web, plus faciles à utiliser.</em></p><div class="articleContent"><p>Pour les designers expérimentés, la mise en forme du texte peut paraître naturelle, mais pour ceux qui commencent dans ce domaine, j'ai dressé une liste des choses à faire (Do's) et à ne pas faire (Don'ts). Ce sera un bon outil pour apprendre, mais aussi une checklist à garder sous le coude pour vos futurs projets. Allons-y :</p><h2>Do: établir une hiérarchie typographique</h2><p>On peut établir une hiérarchie typographique par divers moyens, que ce soit la taille de la police (font-size), sa graisse (font-weight), la couleur et le contraste. Son but est donner une structure à la page et de guider l'utilisateur à travers le contenu. Notre regard parcourt rapidement un texte tel un scan pour en comprendre la structure, et sans une claire hiérarchie, le texte devient beaucoup plus difficile à scanner et donc à lire. Dans l'exemple ci-dessous, le texte de gauche est établi dans une taille et une graisse uniques, du coup on fait difficilement la distinction entre le titre et le corps du texte. Le même texte à droite fait apparaître une hiérarchie typographique claire qui rend aisée la distinction entre ses différents composants. Ici, je n'ai utilisé que la taille et la graisse pour établir une hiérarchie, mais vous pouvez aussi expérimenter la couleur et le contraste.</p><figure role="group"><img src="https://la-cascade.io/images/hierarchy.jpg" alt="" /></figure><h2>DON'T: N'utilisez pas un texte trop petit</h2><p>Tout le monde n'a pas 10/10 chez l'ophtalmo, il faut vous assurer que votre texte est suffisamment grand pour pouvoir être lu confortablement. Personnellement je recommanderais de ne pas descendre en-dessous de 14pt. (<a href="#f1">1</a>)</p><figure role="group"><img src="https://la-cascade.io/images/text_size.jpg" alt="" /></figure><h2>DO: Choisissez une police appropriée pour le corps du texte</h2><p>c'est un autre facteur important pour la lisibilité de votre texte. Une police comme Satisfy pourrait être en accord avec l'esthétique de votre site, mais son utilisation pour le corps de votre texte aura un impact négatif sur vos utilisateurs parce qu'elle est beaucop plus difficile à lire que votre police sérif ou sans-sérif habituelle. Regardez les exemples ci-dessous et vous remarquerez que la lecture du texte de gauche vous demande plus d'effort que celle du texte de droite.</p><figure><img src="https://la-cascade.io/images/font_choice.jpg" alt="" /></figure><h2>DON'T: n'utilisez pas trop de polices dans une même page</h2><p>Ce n'est pas parce que des services comme Typekit ou Google Fonts vous donnent accès à des milliers de polices que vous devez les utiliser sans discernement. Comme le montre l'exemple suivant, si elle n'est pas réalisée à bon escient l'utilisation de polices multiples peut brouiller un message. Je recommande habituellement de ne pas en utiliser plus de 2 ou 3.</p><figure><img src="https://la-cascade.io/images/too_many_fonts.jpg" alt="" /></figure><h2>DO: faites respirer votre texte</h2><p>L'absence d'espace entre les lignes de votre texte affecte sa lisibilité car le parcours de vos yeux d'une ligne à l'autre est plus difficile. Ce problème est aisément résolu en augmentant la hauteur de ligne (line-height), mais attention à ne pas exagérer car trop d'espace entre les lignes complique également la lecture.</p><figure><img src="https://la-cascade.io/images/line_height.jpg" alt="" /></figure><h2>DON'T: n'utilisez pas les majuscules en continu</h2><p>Les gens ne sont pas habitués à lire de longs morceaux de textes en majuscules, c'est en réalité plus difficile à lire. De plus, un texte tout en lettres capitales a une connotation agressive ou bruyante (QUELQU'UN QUI CRIE !) et si vous l'utilisez dans un email il sera considéré comme un spam. Il est donc important de bien considérer comment et quand vous utilisez les mots en majuscules et de ne le faire qu'avec modération.</p><figure><img src="https://la-cascade.io/images/all_caps.jpg" alt="" /></figure><h2>DO: Essayez de limiter vos paragraphes à 40-60 caractères par ligne</h2><p>Si une ligne est trop longue, le lecteur perd progressivement sa concentration et peut avoir des difficultés à passer d'une ligne à l'autre. Si elle est trop courte, l'oeil fait des allers-retours trop fréquents ce qui crée un mauvais rythme. Le lecteur peut aussi commencer à lire la ligne suivante trop tôt et perdre des mots en cours de route. C'est pour cela que l'on considère que la longueur de ligne optimale se situe entre 40 et 60 caractères par ligne. (<a href="#f2">2</a>)</p><figure><img src="https://la-cascade.io/images/charactersperline.jpg" alt="" /></figure><h2>DON'T: n'utilisez pas trop de textes centrés</h2><p>Un texte centré est difficile à lire parce que les bords de chaque ligne sont inégaux et du coup plus compliqués à scanner par l'oeil car chaque ligne commence à un endroit différent. Les blocs de texte centré sont également plus compliqués à aligner avec d'autres objets dans la page et sont souvent considérés un peu amateurs. Tout comme les textes en majuscules, il faut donc les utiliser avec modération et choisir plutôt le texte aligné à gauche comme votre standard.</p><figure><img src="https://la-cascade.io/images/centered_text.jpg" alt="" /></figure><h2>DO: assurez-vous d'avoir un contraste suffisant entre texte et background</h2><p>Le contraste est un aspect de la typographie qui affecte la lisibilité. S'il n'y a pas suffisamment de contraste entre votre texte et le background, le contenu peut devenir illisible.</p><figure><img src="https://la-cascade.io/images/contrast.jpg" alt="" /></figure><hr /><p>    <strong>1</strong> - 14pt correspondent à 19px. On voit souvent recommander 16px comme taille idéale, parfois 18px. En tout cas, ne descendez jamais en-deçà de 14px ! NdT: <em>Voyez aussi <a href="https://la-cascade.io/articles/une-taille-de-police-enfantine">Une taille de police enfantine</a>, qui milite pour des tailles de police plus lisible</em>. <a href="#a1">↩</a></p><p><small>    <strong>2</strong> - Certains auteurs considèrent plutôt la fourchette 45-75 comme la longueur idéale du texte par ligne.</small> <a href="#a2">↩</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/dos-and-donts-de-la-typographie</link>
      <guid>https://la-cascade.io/articles/dos-and-donts-de-la-typographie</guid>
      <pubDate>Tue, 31 Dec 2013 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[De la Typographie Web]]></title>
      <description><![CDATA[<p><em>Être designer demande une compréhension profonde de la typographie et de la sélection et de l'association des polices de caractères. Le grand Jason Santa Maria l'explique avec intelligence et sensibilité.</em></p><div class="articleContent"><p>On trouve beaucoup de livres et d’articles sur la Typographie, mais très peu explorent la question de la sélection et de l’association des polices de caractères. Les vannes étant sur le point de s’ouvrir <sup><a href="#1">(1)</a></sup> et les polices promises à une prochaine liberté d’utilisation sur les sites web, savoir choisir la bonne police est en passe de devenir un nouveau défi pour les designers. Par où commencer ?</p><p>Jusqu’à présent, l’utilisation de polices de caractères autres que celles installées par défaut sur nos ordinateurs impliquait de recourir à des images, à Flash ou à des solutions de contournement. Les navigateurs ont mis la balle dans notre camp avec la mise en oeuvre de la propriété CSS <code>@font-face</code> qui permet aux designers de faire un lien vers n’importe quelle police pour l’importer dans une page.</p><p>Cela a jeté une lumière crue sur la grande préoccupation des fonderies : la plupart des fabricants de polices ont longtemps refusé d’accorder des licences pour l’utilisation de leurs polices de caractères sur le net, craignant un piratage massif. L’implémentation de <code>@font-face</code> a permis d’exposer clairement ce problème et a poussé les parties concernées à trouver une solution positive pour tout le monde. Depuis, des solutions existent ou sont en construction, qui vont d’accords de license accordés aux utilisateurs jusqu’à des services tiers tels que <a href="https://typekit.com">Typekit</a>, <a href="https://www.typotheque.com/blog/typotheque_launches_its_web_fonts_service">Typotheque</a> et <a href="http://kernest.com">Kernest</a>. Les designers ont maintenant l’embarras du choix et les fabricants de polices peuvent gagner de l’argent avec leurs créations. Problème résolu, donc ? Plus ou moins.</p><h2>Le meilleur des mondes</h2><p>Nous avons été gâtés. Jusqu’à présent, il est probable que si vous éditiez du texte sur une page web dans une police de caractères système et à une taille raisonnable, le résultat était lisible. De plus, nous connaissons les avantages et les défauts des polices que nous avons été forcés d’utiliser. Mais de nombreuses polices auxquelles nous aurons bientôt accès n’ont jamais été pensées pour les écrans, d’où des soucis à se faire en termes d’esthétique ou de lisibilité.</p><p>Les problèmes techniques liés aux polices pour le web sont bien réels, depuis l’incohérence du rendu selon les navigateurs et les plateformes jusqu’aux problèmes inhérents au chargement de fichiers de polices ou de familles de polices : le poids des pages peut monter facilement à plus de 100k. Mais supposons pour l’instant que ces problèmes seront résolus sous peu, et concentrons-nous sur ce que nous aurons à faire après.</p><p>Il y a une possibilité sérieuse qu’avec cet accès aux bibliothèques de polices nous n’ouvrions la boîte de Pandore. Beaucoup de gens ont <em>quelques</em> connaissances en matière de typographie, mais mon intuition est que de nombreux designers resteront perplexes face aux nouveaux défis auxquels ils sont confrontés.</p><h2>Contexte et signification</h2><p>Être designer web demandera bientôt une compréhension plus profonde de la typogaphie et de la façon dont fonctionnent les polices de caractères. Les options seront sans doute limitées au commencement, mais leur nombre va aller croissant et comme on le sait, un grand pouvoir impose de grandes responsabilités. Ce n’est pas parce que vous <em>pouvez</em> utiliser cette police qui a l’air d’avoir des pattes d’éléphant que vous le <em>devez</em>.</p><p>Les polices système que nous utilisons communément, telles que Georgia, Verdana et Arial sont devenues tellement omniprésentes qu’il n’est presque plus imaginable de les utiliser en dehors du web. L’expression esthétique qu’il nous était impossible de réaliser en raison d’un choix insuffisant nous laissait le temps de peaufiner la lisibilité. Cela a fait du web un univers du “set it and forget it” (installez le et n’y pensez plus), en raison de la rapidité de publication, mais aussi de l’absence de contrôle précis sur la typographie, tel qu’il existe pour l’impression classique.</p><h2>Exigence</h2><p>On peut utiliser une police parce qu’elle a l’air intéressante et cela peut donner des résultats acceptables, mais pratiquer l’art de la typographie implique de comprendre réellement les polices et ce qu’elles signifient. Le choix d’une police acceptable n’est pas compliqué, mais choisir celle qui convient parfaitement, dans un contexte technique et social donné, peut s’avérer difficile.</p><p>La célèbre designer de polices <a href="http://fr.wikipedia.org/wiki/Zuzana_Licko">Zuzana Licko</a> a dit un jour que “nous lisons le mieux ce que nous lisons le plus”. Cette notion sonne juste s’agissant d’un comportement acquis, elle révèle aussi le principal défi du typographe : la lecture est un acte personnel et relatif. Lire un long passage en écriture <a href="http://fr.wikipedia.org/wiki/%C3%89criture_gothique">gothique</a>, qui était considéré “lisible” il y a quelques siècles, nous demanderait aujourd’hui un effort bien plus considérable que si nous le lisions dans une police <a href="http://fr.wikipedia.org/wiki/Empattement_(typographie)">sérif</a> ou <a href="http://fr.wikipedia.org/wiki/Lin%C3%A9ale">sans sérif</a>, sur papier ou en ligne.</p><p>Au-delà de la question de la lisibilité, les considérations sur la typographie se réduisent pour l’essentiel à des questions de contraste et de forme. Les détails d’une police injectent du sens dans un design : des lignes douces et l’épaisseur du trait par exemple peuvent servir un contenu délicat ou lui donner élégance et dignité. Ces mêmes attributs peuvent être juxtaposés avec un contenu inattendu pour produire un effet ironique.</p><p>Voici maintenant une liste de qualités et quelques méthodes à garder à l’esprit quand vous vous lancerez dans le monde toujours plus vaste des polices de caractères pour le web.</p><h2>Le guide à tomber par terre pour choisir et associer des polices</h2><p>Cherchez en premier lieu des polices lisibles — celles que nous utilisons et lisons quotidiennement.</p><h3>Contraste</h3><p>Le contraste est probablement ce que nous devons avoir d’abord à l’esprit. Quand on associe des polices, il est important d’être capable de les distinguer mais le contraste a d’autres fonctions. Des polices très différentes peuvent jouer l’une avec l’autre de façon complémentaire ou au contraire résister l’une à l’autre en créant une certaine tension, alors que des polices qui semblent trop similaires peuvent affaiblir le message et embrouiller le langage du design visuel.</p><h3>Les basiques du corps de texte</h3><figure role="group"><img src="https://la-cascade.io/images/bobulate.png" alt="exemple de page bien faite, Bobulate" /><figcaption><a href="http://bobulate.com">Bobulate.com</a> utilise <a href="https://typekit.com/fonts/skolar-web">Skolar</a>, à travers <a href="https://typekit.com">Typekit</a>.</figcaption></figure><p>Lorsque je choisis des polices, j’aime commencer par celle que j’utiliserai dans mon corps de texte, car c’est sur elle que le lecteur passera le plus de temps. Préférez des polices robustes et lisibles même dans une taille réduite, et ayant un bon contraste entre les caractères.</p><p>Les meilleures polices de texte ont de la personnalité, mais pas suffisamment pour nous distraire du contenu. Les polices à forte personnalité conviennent mieux à l’affichage, car elles peuvent devenir lourdes dans de longs passages.</p><h3>Lisez-moi</h3><figure role="group"><img src="https://la-cascade.io/images/legible.png" alt="Deux textes identiques dans deux polices différentes" /><figcaption>Quand le texte s’amenuise, hauteur d’x et contraste sont utiles.</figcaption></figure><p>Les conventions habituelles concernant le choix des polices s’appliquent pour l’écran, mais en raison de l’écart de qualité entre l’écran et l’imprimerie, ces conventions devraient être suivies de façon encore plus stricte pour l’écran, et même de manière légèrement exagérée. De grandes <a href="http://fr.wikipedia.org/wiki/Hauteur_d%27x">hauteurs d’x</a> et un corps de caractère robuste rendront votre texte lisible, même à taille réduite. Par exemple, <a href="http://fr.wikipedia.org/wiki/Verdana">Verdana</a> et <a href="http://fr.wikipedia.org/wiki/Georgia_(police_d%27%C3%A9criture)">Georgia</a>, toutes deux des polices éprouvées pour l’écran, ont une grande hauteur d’x et un peu plus d’espace entre les lettres ce qui fait que le texte reste clair même lorsqu’il est de petite taille.</p><h3>Quel est le message ?</h3><figure role="group"><img src="https://la-cascade.io/images/grindhouse.jpeg" alt="Un pastiche d’affiche de film des années 70" /><figcaption>Cette affiche de film utilise beaucoup de polices et de types, à l’imitation des affiches emblématiques des années 70.</figcaption></figure><p>Une bonne façon de comprendre ce dont vous réalisez le design est de rédiger une description générale des qualités du message que vous souhaitez faire passer, puis de chercher les polices qui incarnent ces qualités. Si vous êtes dans un design sérieux, une police d’affichage fantaisiste écrite à la main (<a href="http://fr.wikipedia.org/wiki/Scripte_(typographie)">scripte</a>) ne conviendra sans doute pas. Mais une police robuste comme <a href="http://www.myfonts.com/fonts/adobe/franklin-gothic/roman/">Franklin Gothic</a> pourra transmettre un sentiment de stabilité et de force tout en conférant un air d’importance.</p><p>Une seule police peut être assez pour dire ce que vous avez à dire, deux est généralement beaucoup. Si vous en utilisez plus, il faut que ce soit pour de bonnes raisons — comme d’essayer de retrouver l’esthétique de vieilles affiches de <a href="https://www.google.com/search?q=boxing+poster&amp;tbm=isch">boxe</a>, de films ou de musique par exemple.</p><h3>Une sans, une sérif</h3><figure role="group"><img src="https://la-cascade.io/images/bodoni_futura.png" alt="Le texte ’Hello’ dans deux polices d’affichage différentes" /><figcaption>Bodoni et Futura ont des formes de lettres très différentes, mais leur structure est basée sur les mêmes principes géométriques.</figcaption></figure><p>Un des moyens les plus simples pour créer un équilibre et un contraste en typographie est de choisir une association serif / sans-serif. C’est une combinaison simple et facile à gérer qui peut donner un aspect très cohérent à votre texte si vous choisissez les bonnes polices.</p><p>Sans que ce soit une règle absolue, les polices du même designer fonctionnent généralement bien ensemble. Comme dans deux toiles d’un même artiste, vous pouvez parfois voir la main du designer dans deux polices qu’il a réalisées. <a href="http://www.myfonts.com/fonts/adobe/perpetua/regular/">Perpetua</a> et <a href="http://www.myfonts.com/fonts/adobe/gill-sans/regular/">Gill Sans</a> d’Eric Gill fonctionnent bien ensemble car elles partagent les mêmes traits et les mêmes courbes. De la même façon, des polices conçues pour être appariées, comme <a href="http://www.fontshop.com/fontlist/super_families/ff_meta_sans_ff_meta_serif/">Meta Sans</a> et <a href="http://metaserif.com">Meta Serif</a>, s’associent bien.</p><p>Utiliser plus d’une police d’<a href="http://en.wikipedia.org/wiki/Typeface#Display_type">affichage</a> ou <a href="http://fr.wikipedia.org/wiki/Scripte_(typographie)">scripte</a> est en général une mauvaise idée. Il y a des exceptions à chaque règle, mais ces polices ont une telle personnalité qu’une seule suffit et deux ne feraient qu’apporter de la confusion.</p><p>Cherchez des polices conçues avec les mêmes principes. Par exemple, bien que d’aspect très différent, <a href="http://fr.wikipedia.org/wiki/Futura_(police_d%27%C3%A9criture)">Futura</a> et <a href="http://en.wikipedia.org/wiki/Bodoni">Bodoni</a> forment une superbe association parce qu’elles ont été inspirées par les mêmes formes géométriques simples.</p><figure role="group"><img src="https://la-cascade.io/images/baskerville_futura.png" alt="Deux polices contrastées" /><figcaption>Baskerville et Futura, "vieux" et "nouveau".</figcaption></figure><p>Sinon, il est possible d’associer deux polices divergentes pour créer un nouveau sens ou une juxtaposition intéressante, à condition que le contraste soit fort. Combiner une <a href="http://en.wikipedia.org/wiki/Baskerville">police transitionnelle</a> comme <a href="http://www.myfonts.com/fonts/adobe/itc-new-baskerville/roman/">Baskerville</a> avec une police moderne comme Futura peut créer un expression forte à partir de l’idée de vieux vs nouveau.</p><h3>Explorez des styles différents</h3><figure role="group"><img src="https://la-cascade.io/images/proxima_nova.png" alt="Les composantes d’une famille de police" /><figcaption>Des familles de polices comme <a href="http://www.marksimonson.com/fonts/view/proxima-nova">Proxima Nova</a> de Mark Simonson contiennent des graisses variées, ouvrant un champ de possibilités typographiques.</figcaption></figure><p>Choisir des familles de polices comportant une bonne sélection de <a href="http://fr.wikipedia.org/wiki/Graisse_(typographie)">graisses</a> et de styles vous donne plus de flexibilité sans avoir à recourir à d’autres polices. Utilisez un gras pour contraster avec une police extra-légère ou italique, essayez des majuscules ou des petites capitales avec un peu de d’espacement entre les lettres pour un sous-titre. Si vous choisissez des polices qui ne contiennent qu’une seule graisse, il sera plus difficile de créer le contraste requis pour distinguer visuellement les sections d’un texte.</p><h3>À la bibliothèque !</h3><p>Beaucoup de polices ont un lien avec une période culturelle ou une sous-culture. Selon ce que vous créez, cela peut être un avantage ou un désavantage. Il est toujours bon d’en savoir plus sur une police en s’informant sur le lieu, l’époque, les raisons pour lesquelles elle a été créée. Parfois une police peut avoir le bon “look” mais évoquer des connotations erronées. Par exemple <a href="http://www.myfonts.com/fonts/adobe/trajan/trajan/">Trajan</a> a été utilisée pour des films épiques, policiers, romantiques, pour des comédies et... pour <a href="http://vimeo.com/432490">n’importe quel film</a>, bien qu’étant romaine et agée de 1900 ans. Les polices en écriture gothique ont longtemps servi aux groupes de heavy metal ou à tout ce qui devait être “inquiétant” ou “dark”. Il faut comprendre ces implications culturelles pour les éviter, ou au contraire en faire un bon usage.</p><h3>Money, honey</h3><p>Nous avons été tellement habitués aux polices système que de nombreux professionnels rechignent à l’idée de payer pour des polices. Mais même quand vous utilisez les polices que vous trouvez sur votre ordinateur, vous utilisez des polices que vous avez payées, leur prix est inclus dans celui de votre système d’exploitation. Il y a beaucoup de polices gratuites, mais la plupart le sont pour une bonne raison : il leur manque souvent beaucoup de choses, crénage, ligatures, etc. et elles ne sont pas suffisamment robustes pour être utilisées sérieusement. Les polices solides, comme à peu près tout ce qui est de qualité, coûtent généralement quelque chose.</p><h3>Suivez votre instinct</h3><p>Parfois une paire de polices semble aller bien ensemble, même si vous ne savez pas pourquoi. Les lignes qui précèdent sont des guides, pas des lois : il y a une myriade de polices et de styles, et vous serez parfois surpris de voir des polices s’associer à l’encontre de toute logique.</p><h3>Toujours plus loin !</h3><p>Le nombre de polices disponibles augmente chaque jour. Si votre police favorite n’est pas encore là, elle le sera bientôt, même si le problème des licences n’est pas résolu de sitôt.</p><p>Avec l’arrivée de polices toujours plus nombreuses, nous devons comprendre comment elles peuvent servir au mieux nos designs et les choisir sur des critères autres que la seule nouveauté. Si l’essentiel du web est constitué de texte — ce qu’il est — la typographie peut être en effet un outil très puissant.</p><hr /><p>(1) Cet article en avance sur son temps date de 2009.   <a href="#backto1" class="c1">↩︎</a></p></div>]]></description>
      <link>https://la-cascade.io/articles/de-la-typographie-web</link>
      <guid>https://la-cascade.io/articles/de-la-typographie-web</guid>
      <pubDate>Sun, 22 Dec 2013 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Emmet, un turbo dans votre CSS]]></title>
      <description><![CDATA[<p><em>Josh Medeski se concentre ici sur Emmet pour CSS : comment Emmet transforme instantanément de simples abréviations en snippets de code CSS complexes.</em></p><div class="articleContent"><p>La plupart des articles sur Emmet traitent de son <a href="https://la-cascade.io/articles/goodbye-zen-coding-hello-emmet/">utilisation pour HTML</a>, mais ici nous allons nous concentrer sur CSS. Prêt à mettre un turbo dans votre CSS ? On y va !</p><h2>Emmet, qu'est-ce que c'est ?</h2><p>Emmet est un ensemble d'abréviations qui s'étendent en html/xml/css, comme des snippets de textes. Vous pouvez installer Emmet sur votre éditeur de texte en allant sur <a href="http://emmet.io/download/">la page download</a>.</p><p>Une fois Emmet installé, tapez une abréviation puis la touche qui déclenchera l'action - dans <a href="http://www.sublimetext.com/">Sublime Text</a> c'est la touche <code>tab</code>.</p><h2>Pourquoi utiliser Emmet ?</h2><p>Emmet (qui s'appelait autrefois Zen Coding) utilise des abréviations facilement mémorisables pour faciliter votre travail de codeur. Il vous aidera plus ou moins, en fonction du temps que vous investirez pour apprendre sa syntaxe (simple).</p><p>Non seulement il vous fera gagner du temps, mais il rend plus <em>fun</em> le travail d'écriture : il y a quelque chose de magique à regarder quelques caractères se transformer en un code parfaitement formaté !</p><p>Je me suis rendu compte qu'Emmet me permettait de mémoriser le code plus facilement. Une abréviation comme <code>text-transform</code> devient "tt" et <code>text-align: justify</code> devient "taj". Super simple et utile, non ? Petit à petit vous apprendrez de nouvelles propriétés CSS et n'aurez à mémoriser que leur abréviation. Pas besoin de se soucier des ":" et des espaces, Emmet s'en charge.</p><h2>Emmet et CSS</h2><p>Regardons maintenant les composants de base des abréviations Emmet, leur fonctionnement et la façon dont il vont accélérer et simplifier votre travail.</p><h3>Propriétés</h3><p>Dans CSS vous donnez des valeurs à des propriétés telles que <code>font-size</code> , <code>margin</code> , <code>padding</code> , etc.</p><figure role="group"><img src="https://la-cascade.io/images/css_best_property_value.png" alt="exemple de couples propriété-valeur dans css" /></figure><p>Emmet a créé une abréviation pour chacune des propriétés CSS : <code>border-bottom</code> est <code>bdb</code> , <code>border-top</code> est <code>bdt</code>. Ci-dessous, un exemple en action avec <code>font-size</code> qui est <code>fz</code> .</p><p>Une fois tapé l'abréviation, appuyez sur la touche 'tabulation' (ou une autre touche, cela dépend de votre éditeur de texte), Emmet transforme celle-ci en CSS valide et place le curseur là où vous en avez besoin :</p><figure role="group"><img src="https://la-cascade.io/images/emmet_css_property-1.gif" alt="exemple gif de transformation de fz en font-size" /></figure><h3>Valeurs</h3><p>Maintenant que nous avons vu comment fonctionnent les propriétés, il est temps d'ajouter une valeur. Pour cela, il suffit de taper la propriété abrégée et la valeur. Par exemple, <code>fz18</code> donnera <code>font-size: 18px;</code> . Pas besoin de taper "px" car Emmet l'ajoute par défaut. Si une propriété n'a pas d'unité (comme <code>font-weight</code> ), Emmet n'en ajoute pas.</p><figure role="group"><img src="https://la-cascade.io/images/emmet_css_value.gif" alt="exemple gif de transformation de fz16 en font-size: 16px" /></figure><h3>Unités</h3><p>Et si vous utilisez autre chose que des pixels ? Les unités <code>em</code> , <code>rem</code> , <code>%</code> , <code>ex</code> , et <code>px</code> sont toutes disponibles dans Emmet. Chaque unité a même sa forme abrégée :</p><ul><li><code>px</code> → par défaut</li>
<li><code>p</code> → <code>%</code></li>
<li><code>e</code> → <code>em</code></li>
<li><code>r</code> → <code>rem</code></li>
<li><code>x</code> → <code>ex</code></li>
</ul><p>Pour utiliser une unité, il suffit de l'ajouter à votre valeur. L'exemple ci-dessous définit une taille de police en <code>em</code> .</p><figure role="group"><img src="https://la-cascade.io/images/emmet_css_unit.gif" alt="exemple gif de transformation de fz1e en font-size: 1em" /></figure><h3>Unités multiples</h3><p>Certaines propriétés, comme <code>margin</code> , peuvent avoir plusieurs valeurs. Dans Emmet, la syntaxe abrégée utilise un tiret séparateur. L'exemple ci-dessous montre comment définir quatre valeurs pour une marge :</p><figure role="group"><img src="https://la-cascade.io/images/emmet_css_multiple_units.gif" alt="exemple gif de transformation de m10-20-30-40 en margin: 10px 20px 30px 40px" /></figure><h3>Couleurs</h3><p>Pour les couleurs, il y a plusieurs façons d'écrire (au choix), qui donnent les résultats suivants :</p><ul><li><code>#1</code> → <code>#111</code></li>
<li><code>#e0</code> → <code>#e0e0e0</code></li>
<li><code>#fc0</code> → <code>#ffcc00</code></li>
</ul><figure role="group"><img src="https://la-cascade.io/images/emmet_css_colors.gif" alt="exemple gif de transformation de 'c#2' en color: '#222'" /></figure><h3>!important</h3><p>Même si le tag <code>!important</code> ne doit être utilisé que de manière parcimonieuse et avisée, Emmet a prévu une abréviation, au cas où. Il suffit d'ajouter un point d'exclamation à votre déclaration :</p><figure role="group"><img src="https://la-cascade.io/images/emmet_css_important.gif" alt="exemple gif de transformation de p0! en padding: 0 !important" /></figure><h3>Propriétés multiples</h3><p>Maintenant que nous connaissons les bases des fonctions CSS dans Emmet, il est temps de les mettre en oeuvre ensemble. De même que pour les fonctions HTML, on peut ajouter un signe <code>+</code> pour chaque déclaration. Et rappelez-vous que si vous vous êtes embrouillé, il suffit de revenir en arrière (Cmd+Z ou Ctrl+Z), corriger la syntaxe et taper <code>tab</code> à nouveau.</p><p>Voici un exemple où je définis diverses marges et padding dans <code>body</code> :</p><figure role="group"><img src="https://la-cascade.io/images/emmet_css_multiple_properties.gif" alt="exemple gif de transformation de mb10+pt20 en margin bottom: 10px et padding-top: 20px" /></figure><h3>Exemple</h3><p>Vous pouvez utiliser toutes ces abréviations ensemble ou séparément, selon ce qui vous semble le plus simple et vous facilite la vie. Pour terminer cette courte présentation, voici un dernier exemple récapitulatif :</p><figure role="group"><img src="https://la-cascade.io/images/emmet_css_example.gif" alt="exemple gif de transformation de tous les exemples précédents" /></figure><h2>Conclusion</h2><p>Emmet est un outil puissant qui vous permet d'économiser du temps sur du code répétitif, sans avoir à créer manuellement vos propres snippets. Il peut être utilisé avec les principaux éditeurs de texte.</p><p>Comme pour tout nouvel outil, il y a un temps d'apprentissage, il est court, n'approfondissez pas trop dans un premier temps, apprenez d'abord ce dont vous aurez tout de suite besoin puis visitez régulièrement la documentation. Emmet propose une <a href="http://docs.emmet.io/cheat-sheet/">anti-sèche</a> avec toutes les fonctions possibles.</p><h3>Pour aller plus loin</h3><p><a href="http://docs.emmet.io/css-abbreviations/">Documentation Emmet</a><br /><a href="http://docs.emmet.io/cheat-sheet/">Anti-sèche Emmet (syntaxe, HTML, CSS)</a><br /><a href="http://webdesign.tutsplus.com/tutorials/applications/build-bootstrap-in-minutes-using-emmet/">Bootstrap en quelques minutes avec Emmet</a> (en anglais)<br /><a href="https://la-cascade.io/articles/goodbye-zen-coding-hello-emmet/">Goodbye, Zen Coding. Hello, Emmet</a> !<br /><a href="https://la-cascade.io/articles/une-liste-de-raccourcis-emmet/">Raccourcis et astuces Emmet</a>, par Matt MacFadyen et Jordan Moore</p></div>]]></description>
      <link>https://la-cascade.io/articles/emmet-un-turbo-dans-votre-css</link>
      <guid>https://la-cascade.io/articles/emmet-un-turbo-dans-votre-css</guid>
      <pubDate>Sat, 21 Dec 2013 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Goodbye, Zen Coding. Hello, Emmet!]]></title>
      <description><![CDATA[<p><em>Emmet, anciennement connu comme Zen Coding, est le plugin d'éditeur de texte qui vous fera gagner le plus de temps.</em></p><div class="articleContent"><p><a href="http://emmet.io/">Emmet</a>, anciennement connu comme Zen Coding, est le plugin d'éditeur de texte qui vous fera gagner le plus de temps, ceci en transformant instantanément de simples abréviations en snippets de code complexes.</p><p>Si vous préférez regarder une vidéo (en anglais) plutôt que de lire, voici <a href="http://www.youtube.com/watch?feature=player_embedded&amp;v=sxW-V24MTXI">un résumé de mes astuces préférées</a>. (NdT: et pour un article plus centré sur Emmet et CSS, consultez <a href="https://la-cascade.io/articles/emmet-un-turbo-dans-votre-css/">un turbo dans votre CSS</a>).</p><h2>Comment ça marche ?</h2><p>Il faut bien l'admettre, écrire en HTML demande du temps, avec toutes ces balises, ces attributs, guillemets, parenthèses, etc. La plupart des éditeurs de texte proposent une complétion de code, qui est certes très utile, mais il reste encore beaucoup à taper. Emmet transforme de simples abréviations en code complexe.</p><h2>Abréviations HTML</h2><h3>Initialiser</h3><p>Commencer avec un nouveau document HTML prend moins d'une seconde. Il suffit de taper <code>!</code> ou <code>html:5</code> puis faire "tabulation" ou "enter" selon votre éditeur de texte (dans un document vierge préalablement enregistré avec une extension <code>.html</code> ) et vous verrez apparaître un doctype HTML5 structuré avec quelques éléments de base.</p><figure><img src="https://la-cascade.io/images/01initializers.gif" alt="exemple gif de transformation de raccourcis en code" /></figure><ul><li><code>html:5</code> ou <code>!</code> pour un doctype HTML5</li>
<li><code>html:xt</code> pour un doctype transitionnel XHTML</li>
<li><code>html:4s</code> pour un doctype strict HTML4</li>
</ul><h3>Ajouter des classes, id, texte et attributs</h3><p>La syntaxe d'Emmet pour décrire les éléments reprend les sélecteurs CSS, il est donc facile de s'y habituer. Essayez de combiner un nom d'élément (p.ex. <code>p</code> ) et un identifiant (p.ex. <code>p#description</code> ).</p><figure><img src="https://la-cascade.io/images/02classes_ids.gif" alt="exemple gif de transformation de p#foo en p id='foo' et p.foo en p class='foo'" /></figure><p>Vous pouvez mixer classes et id, p.ex. <code>p.bar#foo</code> donnera :</p><pre>&lt;p class="bar" id="foo"&gt;&lt;/p&gt;</pre><p>Voyons maintenant comment définir le contenu et les attributs de vos balises HTML. Pour le contenu on utilise des accolades, <code>h1{foo}</code> est transformé en :</p><pre>&lt;h1&gt;foo&lt;/h1&gt;</pre><p>Les attributs sont indiqués entre crochets, <code>a[href=#]</code> donnera :</p><pre>&lt;a href="#"&gt;&lt;/a&gt;</pre><figure><img src="https://la-cascade.io/images/03texts_attrs.gif" alt="exemple gif de transformation de h1{foo} en h1 et le titre foo" /></figure><h3>Emboîtements</h3><p>En emboîtant nos abréviations, nous pouvons construire une page entière de code en n'écrivant qu'une seule ligne. L'opérateur "descendant" (child), représenté par <code>&gt;</code> vous permet d'emboîter les éléments. L'opérateur sibling (pour les éléments de même niveau dans le DOM), représenté par <code>+</code> vous permet de placer les éléments les uns à côté des autres. Enfin, l'opérateur ascensionnel, représenté par <code>^</code> vous permet de remonter d'un niveau dans l'arbre.</p><figure><img src="https://la-cascade.io/images/04nesting.gif" alt="h1+h2 donnent deux éléments consécutifs, p&gt;span donnent deux éléments emboîtés" /></figure><p>Dans les exemples ci-dessus,</p><ul><li><code>h1</code> et <code>h2</code> se suivent, j'utilise donc <code>+</code></li>
<li><code>span</code> est enchâssé dans <code>p</code> , j'utilise donc <code>&gt;</code></li>
<li>après avoir emboîté <code>span</code> dans <code>p</code> , je veux continuer à écrire mon code sur une seule ligne, je dois sortir de l'emboîtement, ce que je fais en utilisant <code>^</code></li>
</ul><h3>Regroupements</h3><p>Pour profiter vraiment des emboîtements sans que votre code ne devienne une bouillie d'opérateurs, le mieux est de les regrouper - comme en mathématiques - en utilisant des parenthèses. Par exemple <code>(.foo&gt;h1)+(.bar&gt;h2)</code> est traduit ainsi :</p><pre>&lt;div class="foo"&gt;
        &lt;h1&gt;&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="bar"&gt;
        &lt;h2&gt;&lt;/h2&gt;
&lt;/div&gt;</pre><figure><img src="https://la-cascade.io/images/05grouping.gif" alt="exemple gif de transformation des éléments complexes ci-dessus" /></figure><h3>Noms d'éléments implicites</h3><p>Pour déclarer un élément et une classe, il suffit de taper <code>div.item</code> ce qui génèrera <code>&lt;div class="item"&gt;&lt;/div&gt;</code>.</p><p>Autrefois, on pouvait omettre le nom d'élément pour un <code>div</code> , il n'y avait qu'à taper <code>.item</code> et cela générait <code>&lt;div class="item"&gt;&lt;/div&gt;</code>. Emmet est plus intelligent. Il va chercher le nom de l'élément parent à chaque fois que vous utilisez un nom d'élément implicite. Si vous déclarez <code>.item</code> à l'intérieur d'une <code>&lt;ul&gt;</code> , il génèrera <code>&lt;li class="item"&gt;&lt;/li&gt;</code> au lieu de <code>&lt;div class="item"&gt;&lt;/div&gt;</code>.</p><figure><img src="https://la-cascade.io/images/06implicit_tags.gif" alt="exemple gif de transformation des éléments ci-dessus, selon le contexte" /></figure><p>Voici une liste de noms d'éléments implicites :</p><ul><li><code>li</code> pour <code>ul</code> et <code>ol</code></li>
<li><code>tr</code> pour <code>table</code> , <code>tbody</code> , <code>thead</code> et <code>tfoot</code></li>
<li><code>td</code> pour <code>tr</code></li>
<li><code>option</code> pour <code>select</code> et <code>optgroup</code></li>
</ul><h3>Multiplication</h3><p>Vous pouvez choisir le nombre de fois qu'un élément doit apparaître, en utilisant l'opératuer <code>*</code>. Ainsi, <code>ul&gt;li*3</code> est traduit par :</p><pre>&lt;ul&gt;
        &lt;li&gt;&lt;/li&gt;
        &lt;li&gt;&lt;/li&gt;
        &lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;</pre><figure><img src="https://la-cascade.io/images/07multiplication.gif" alt="exemple gif de transformation des éléments ci-dessus ul et li" /></figure><h3>Numérotation</h3><p>Et si l'on voulait ajouter une numérotation ? Il suffit d'insérer l'opérateur <code>$</code> dans le nom de l'élément ou de l'attribut, ou dans la valeur de l'attribut, pour obtenir cette numérotation. Si vous tapez <code>ul&gt;li.item$*3</code> , le résultat sera :</p><pre>&lt;ul&gt;
        &lt;li class="item1"&gt;&lt;/li&gt;
        &lt;li class="item2"&gt;&lt;/li&gt;
        &lt;li class="item3"&gt;&lt;/li&gt;
&lt;/ul&gt;</pre><figure><img src="https://la-cascade.io/images/08numbering.gif" alt="exemple gif de transformation des éléments ci-dessus ul et li numérotés" /></figure><hr /><h2>Abréviations CSS</h2><h3>Valeurs</h3><p>Emmet vous aide également pour CSS. Vous pouvez injecter des valeurs directement dans des abréviations CSS. Imaginons que vous vouliez définir une largeur. Tapez <code>w100</code> et cela vous donnera :</p><pre>width: 100px;</pre><figure><img src="https://la-cascade.io/images/09values.gif" alt="exemple gif de transformation des éléments margin, width, height" /></figure><p>Il y a d'autres unités que les pixels. Tapez <code>h10p+m5e</code> et voici ce qui sera affiché :</p><pre>height: 10%;
margin: 5em;</pre><h3>Opérateurs additionnels</h3><p>Vous connaissez déjà de nombreuses abréviations intuitives, telles que <code>@f</code> qui donne :</p><pre>@font-face {
  font-family:;
  src: url();
}</pre><p>Certaines propriétés, comme <code>background</code>, <code>background-image</code> , <code>border-radius</code> , <code>font</code> , <code>@font-face</code> , <code>text-outline</code> , <code>text-shadow</code> possèdent quelques options supplémentaires que vous pouvez activer en utilisant le signe <code>+</code>. Par exemple, <code>@f+</code> donnera :</p><pre>@font-face {
  font-family: 'FontName';
  src: url('FileName.eot');
  src: url('FileName.eot?#iefix') format('embedded-opentype'),
  url('FileName.woff') format('woff'),
  url('FileName.ttf') format('truetype'),
  url('FileName.svg#FontName') format('svg');
  font-style: normal;
  font-weight: normal;
}</pre><figure><img src="https://la-cascade.io/images/10extra.gif" alt="exemple gif de transformation des éléments ci-dessus, deux caractères tapés donnent une liste impressionnante" /></figure><p>Amusez-vous à voir ce que ça donne avec d'autres propriétés en tapant leur abréviation et <code>+</code> : par exemple <code>bg+</code> etc.</p><h3>Recherche floue</h3><p>Le module CSS utilise les correspondances partielles pour retrouver des abréviations inconnues. Lorsque vous tapez une abréviation inexistante, Emmet essaie de trouver la définition de snippet la plus proche, par exemple <code>ov:h</code> , <code>ov-h</code> , <code>ovh</code> et <code>oh</code> génèreront le même résultat :</p><pre>overflow: hidden;</pre><figure><img src="https://la-cascade.io/images/11fuzzy_search.gif" alt="exemple gif de transformation des éléments ci-dessus, plusieurs versions donnent le même résultat" /></figure><h3>Préfixes constructeurs</h3><p>CSS est génial, mais ces préfixes constructeurs sont une vraie plaie. Enfin, plus maintenant : Emmet a des abréviations pour eux aussi. Par exemple, l'abréviation <code>trs</code> donnera :</p><pre>-webkit-transform: ;
-moz-transform: ;
-ms-transform: ;
-o-transform: ;
transform: ;</pre><figure><img src="https://la-cascade.io/images/12vendor_prefixes.gif" alt="exemple gif de transformation des éléments ci-dessus, ajout de préfixes constructeurs" /></figure><p>Vous pouvez également ajouter des préfixes à n'importe quel élément, il suffit d'utiliser le préfixe <code>-</code>. Ainsi, <code>-super-foo</code>sera traduit par :</p><pre>-webkit-super-foo: ;
-moz-super-foo: ;
-ms-super-foo: ;
-o-super-foo: ;
super-foo: ;</pre><p>Et si vous ne voulez pas tous ces préfixes mais seulement certains. Pas de problème, vous pouvez définir exactement la compatibilité navigateur souhaitée. Par exemple, <code>-wm-trf</code> donnera :</p><pre>-webkit-transform: ;
-moz-transform: ;
transform: ;</pre><p>avec :</p><ul><li>w → -webkit-</li>
<li>m → -moz-</li>
<li>s → -ms-</li>
<li>o → -o-</li>
</ul><h3>Dégradés</h3><p>Puis en est à ces caractéristiques ennuyeuses de CSS, nous ne pouvons pas ne pas parler des dégradés. Ces longues définitions peuvent être facilement remplacées par une abréviation concise et à toute épreuve. Tapez <code>lg(left, #fff 50%, #000)</code> , et voilà ce que obtiendrez :</p><pre>background-image: -webkit-gradient(linear, 0 0, 100% 0, color-stop(0.5, #fff), to(#000));
background-image: -webkit-linear-gradient(left, #fff 50%, #000);
background-image: -moz-linear-gradient(left, #fff 50%, #000);
background-image: -o-linear-gradient(left, #fff 50%, #000);
background-image: linear-gradient(left, #fff 50%, #000);</pre><figure><img src="https://la-cascade.io/images/13gradient.gif" alt="exemple gif de transformation des éléments complexes ci-dessus" /></figure><h2>Extras</h2><h3>Lorem ipsum</h3><p>Plus besoin de ces services tiers qui génèrent du texte "Lorem ipsum", vous pouvez maintenant le faire directement dans votre éditeur de texte. Utilisez les abréviations <code>lorem</code> ou <code>ipsum</code> . Vous pouvez même spécifier le nombre de mots dont vous avez besoin, par exemple <code>lorem10</code> génèrera :</p><pre>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Libero delectus.</pre><figure><img src="https://la-cascade.io/images/14lorem.gif" alt="exemple gif de transformation des éléments ci-dessus, lorem ipsum de longueur variable" /></figure><p>Lorem peut être concaténé avec les autres éléments, ainsi <code>p*3&gt;lorem5</code> génèrera :</p><pre>&lt;p&gt;Lorem ipsum dolor sit amet.&lt;/p&gt;
&lt;p&gt;Voluptates esse aliquam asperiores sunt.&lt;/p&gt;
&lt;p&gt;Fugiat eaque laudantium explicabo omnis!&lt;/p&gt;</pre><h2>Customization</h2><p>Emmet propose tout un tas de réglages fins, vous pouvez utiliser trois fichiers pour cela :</p><ul><li>Pour mettre à jour un snippet ou pour en ajouter un de votre cru, éditez <a href="http://docs.emmet.io/customization/snippets/">snippets.json</a>.</li>
<li>Pour changer le comportement des filtres et actions d'Emmet, essayez avec <a href="http://docs.emmet.io/customization/preferences/">preferences.json</a>.</li>
<li>Pour définir comment vous souhaitez qu'apparaisse le HTML ou le XML généré, éditez <a href="http://docs.emmet.io/customization/syntax-profiles/">syntaxProfiles.json</a>.</li>
</ul><h2>Et plus encore !</h2><p>Ce n'est que le début. Emmet offre bien d'autres fonctions, comme <a href="http://docs.emmet.io/actions/base64/">l'encodage et le décodage d'images</a>, <a href="http://docs.emmet.io/actions/update-image-size/">l'ajout ou la mise à jour des attributs <code>width</code> et <code>height</code>pour les images</a>, <a href="http://docs.emmet.io/actions/inc-dec-number/">l'incrementation de nombres</a> etc.</p><p>Visitez le <a href="http://emmet.io/">site</a>, consultez la <a href="http://docs.emmet.io/">documentation</a> et l'<a href="http://docs.emmet.io/cheat-sheet/">anti-sèche</a> bien pratique.</p><h2>Compatibilité éditeurs de texte</h2><p>Si vous vous demandez "est-ce que ça marchera avec mon éditeur de texte", la réponse est "Oui mon ami", un grand nombre d'éditeurs de texte sont compatibles et j'espère que le vôtre se trouve dans la liste :</p><ul><li><a href="https://github.com/sergeche/emmet-sublime">Sublime Text 2</a></li>
<li><a href="https://github.com/emmetio/Emmet.tmplugin">TextMate 1.x</a></li>
<li><a href="https://github.com/emmetio/emmet-eclipse">Eclipse/Aptana</a></li>
<li><a href="https://github.com/emmetio/Emmet.codaplugin">Coda 1.6 et 2.x</a></li>
<li><a href="https://github.com/emmetio/Emmet.sugar">Espresso</a></li>
<li><a href="https://github.com/sergeche/emmet.chocmixin">Chocolat</a> (disponible via la boîte de dialogue “Install Mixin”)</li>
<li>Komodo Edit/IDE (disponible via Tools → Add-ons)</li>
<li>Notepad++</li>
<li>PSPad</li>
<li><a href="https://github.com/emmetio/codemirror">CodeMirror2/3</a></li>
<li><a href="https://github.com/emmetio/brackets-emmet">Brackets</a></li>
<li>Textarea</li>
<li><a href="http://www.jetbrains.com/phpstorm/">phpstorm</a></li>
</ul><h3>Liens utiles</h3><p><a href="http://docs.emmet.io/css-abbreviations/">Documentation Emmet</a><br /><a href="http://docs.emmet.io/cheat-sheet/">Anti-sèche Emmet (syntaxe, HTML, CSS)</a><br /><a href="http://webdesign.tutsplus.com/tutorials/applications/build-bootstrap-in-minutes-using-emmet/">Bootstrap en quelques minutes avec Emmet</a> (en anglais)<br /><a href="https://la-cascade.io/articles/emmet-un-turbo-dans-votre-css/">Emmet, un turbo dans votre CSS</a>, par Josh Medeski<br /><a href="https://la-cascade.io/articles/une-liste-de-raccourcis-emmet/">Raccourcis et astuces Emmet</a>, par Matt MacFadyen et Jordan Moore</p></div>]]></description>
      <link>https://la-cascade.io/articles/goodbye-zen-coding-hello-emmet</link>
      <guid>https://la-cascade.io/articles/goodbye-zen-coding-hello-emmet</guid>
      <pubDate>Fri, 20 Dec 2013 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Le web, 95% de typographie]]></title>
      <description><![CDATA[<p><em>Un bref rappel par Oliver Reichenstein, fondateur d'Information Architects, de l'importance de la typographie dans le web, ce qu'elle est et ce qu'elle n'est pas. Simple, direct, éclairant et inspirant.</em></p><div class="articleContent"><p>95% de l’information sur le web est écrite. En bonne logique tout designer web devrait avoir de solides connaissances dans la principale discipline consacrée à donner forme à l’information écrite, à savoir la Typographie.</p><p>En 1969, le célèbre typographe suisse <a href="http://fr.wikipedia.org/wiki/Emil_Ruder">Emil Ruder</a> écrivait au sujet des matériaux imprimés de son époque ce qu'on pourrait dire de nos sites web contemporains :</p><blockquote cite="">
<p>De nos jours, nous sommes inondés par un tel flot d'information imprimée que la valeur du travail individuel a été dépréciée, nos contemporains harassés n'étant plus à même de suivre tout ce qui est imprimé aujourd’hui. C’est la tâche du typographe de diviser, d’organiser et d’interpréter cette masse d'information imprimée pour faire en sorte que le lecteur trouve ce qui l’intéresse.</p>
<p><cite><a href="http://fr.wikipedia.org/wiki/Emil_Ruder">Emil Ruder</a></cite></p>
</blockquote><p>Avec un peu d’imagination (remplacez imprimé par web), cela ressemble à la description de poste d’un designer de l’information. C’est le rôle d’un tel designer de “diviser et d’organiser et d’interpréter cette masse d'information imprimée pour faire en sorte que le lecteur trouve ce qui l’intéresse”.</p><h2>Micro-Typographie vs Macro-Typographie</h2><p>Les typographes distinguent la macro-typographie et la micro-typographie. La micro typographie traite des aspects détaillés des caractères et de l'espacement, en se concentrant sur la lisibilité du texte :</p><ul><li>Le suivi et la largeur des glyphes</li>
<li>Protrusion, crénage de marge ou <a href="https://en.wikipedia.org/wiki/Hanging_punctuation">exdentation</a></li>
<li>Augmentation ou diminution ponctuelle de l'espacement des mots</li>
<li>Le découpage des mots par l'espacement des mots ou d'autres espaces blancs.</li>
</ul><p>Alors que la micro-typographie est difficile à contrôler dans un support <em>liquide</em> et sans format comme le Web, la macro-typographie couvre de nombreux aspects de ce que nous appelons aujourd'hui la conception Web :</p><ul><li>Le format : Les dimensions de base dans lesquelles nous plaçons les caractères</li>
<li>La grille : La taille des caractères, la proportion des colonnes</li>
<li>La hiérarchie : Comment les différentes tailles de caractères et le formatage sont liés les uns aux autres.</li>
</ul><p>Ainsi, la macro-typographie (structure générale d’un texte) par contraste avec la micro-typographie (aspects détaillés des caractères et de l’espacement des mots) couvre beaucoup d’aspects du “design de l’information”.</p><p>Aujourd’hui, les designers de l’information font pour ainsi dire les tâches que réalisaient les typographes il y a 30 ans :</p><blockquote>
<p><em>La typographie a un objectif simple, qui est de transmettre l’information par écrit. Il n’existe pas d’argument ou de considération qui puisse absoudre la typographie de ce devoir. Un document imprimé qui ne peut être lu est un produit sans objet</em>.</p>
</blockquote><p>Optimiser la typographie consiste à optimiser la lisibilité, l’accessibilité, l’usabilité, l’équilibre graphique général. Organiser des blocs de textes et les combiner avec des images, n’est-ce pas ce font que les graphistes, les spécialistes de l’usabilité, les architectes de l’information ? Alors pourquoi est-ce un sujet aussi négligé ?</p><h2>Trop peu de polices ? Une résolution trop faible ?</h2><p>Le principal argument – ou la principale récrimination – contre la discipline typographique en ligne est qu’il y a trop peu de polices de caractères disponibles. Le deuxième argument est que la résolution de l’écran est trop faible, ce qui rend difficile la lecture d’un texte pixélisé ou de polices anticrénelées.</p><p>Le premier argument est dénué de pertinence : à l’époque de la Renaissance italienne, les typographes n’avaient qu’une seule fonte pour travailler, et pourtant cette période a produit quelques-unes des plus belles réalisations typographiques :</p><figure><img src="https://la-cascade.io/images/garamond-specimen-compressor.jpeg" alt="une magnifique typographie" /></figure><p>Le typographe ne devrait pas trop s’en faire quant au choix de polices dont il dispose. En fait, ce choix ne devrait pas être sa préoccupation principale. Il devrait utiliser ce qui est disponible et faire au mieux.</p><h2>Choisir une police n’est pas de la typographie</h2><p>Le second argument ne vaut pas mieux. Au commencement de l’imprimerie, la qualité des caractères d’impression était bien pire que ce que nous voyons sur les écrans actuels. En outre, si elles sont utilisées professionnellement, les polices numériques sont tout à fait lisibles.</p><p>Le design d’information ne consiste pas à utiliser de bonnes polices mais à utiliser une bonne typographie - ce qui est très différent. N’importe qui peut utiliser des polices, quelques-uns savent en choisir de bonnes, mais rares sont ceux qui maîtrisent la typographie.</p><h2>Considérez le texte comme une interface utilisateur</h2><p>C’est vrai, la diversité de rendu des polices selon les navigateurs et les plateformes est agaçante et, oui, les problèmes de résolution rendent toute concentration problématique au delà de cinq minutes. Mais enfin, cela fait partie du travail d’un designer de rendre les textes faciles et agréables à lire sur la plupart des navigateurs et des plateformes. Un interlignage correct, un bon espacement des caractères et des mots, des espaces blancs et l’utilisation parcimonieuse de la couleur, tout ceci aide à la lisibilité. Mais ce n’est pas tout. Un grand designer web sait comment travailler avec un texte, pas seulement en tant que contenu mais aussi comme <a href="http://www.cameronmoll.com/archives/001266.html">une interface utilisateur</a>. Jetez un coup d’œil au site de <a href="http://www.subtraction.com">Khoi Vinh</a>, et vous comprendrez ce que je veux dire ( <em>NdT: la nouvelle version du site est encore plus parlante !</em>) :</p><figure><img src="https://la-cascade.io/images/koih-compressor.gif" alt="Le site de Khoi Vinh" /></figure><p>Des exemples plus célèbres de sites <a href="http://fr.wikipedia.org/wiki/Ornement_et_Crime">non ornementaux</a> qui traitent le texte comme une interface sont : <a href="http://www.google.com">Google</a>, <a href="http://www.ebay.fr">Ebay</a>, <a href="http://www.craigslist.fr">Craigslist</a>, <a href="http://www.youtube.com">Youtube</a>, <a href="http://www.flickr.com">Flickr</a>, <a href="http://digg.com">Digg</a>, <a href="http://www.reddit.com">Reddit</a>, <a href="https://delicious.com">Delicious</a>. Contrôler la typographie n’est pas seulement une nécessité de base du design, savoir comment traiter un texte comme une interface utilisateur est un facteur-clé de succès pour un site web. Ceux qui réussissent ont su créer à la fois une interface simple ET une identité forte. Mais c’est un autre sujet.</p><hr /><h4>Suggestions de lectures :</h4><p><strong>Robert Bringhurst</strong> <a href="https://www.amazon.com/gp/product/0881792128/ref=as_li_tl?ie=UTF8&amp;tag=informationar-20&amp;camp=1789&amp;creative=9325&amp;linkCode=as2&amp;creativeASIN=0881792128&amp;linkId=a7034de643a3a98ca8083ac9a22e6cf3">The Elements of Typographic Style</a> : le célèbre typographe Robert Bringhurst apporte de la clarté à l'art de la typographie avec ce guide de style magistral. L'endroit idéal pour commencer votre voyage dans les trous de lapin de la typographie.<br /><strong>Emil Ruder</strong>, <a href="http://www.amazon.fr/Typographie-Emil-Ruder/dp/3721200438/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1375821709&amp;sr=1-1&amp;keywords=emil+ruder">Typographie</a> : une bible pour des générations de typographes et de graphistes qui y ont appris les fondamentaux. Ruder, l'un des grands typographes du XXe siècle était un pionnier. Il abandonna les règles conventionnelles de sa discipline et les remplaça par de nouvelles règles qui satisfaisaient aux exigences de la nouvelle typographie.<br /><strong>Kimberly Elam</strong>, <a href="http://www.amazon.com/o/ASIN/1568984650">Grid Systems : Principles of Organizing Type</a> (en anglais) : les systèmes de grilles sont le fondement de tout design typographique, et pourtant ils passent souvent pour des solutions rigides et convenues. Peu de designers comprennent réellement la complexité et les richesses potentielles de la composition à partir de grilles (éventuellement subverties...)<br /><strong>Muller-Brockmann</strong>, <a href="http://www.amazon.com/Systems-Graphic-Design-Josef-Muller-Brockmann/dp/3721201450/sr=1-2/qid=1162128429?ie=UTF8&amp;s=books">Grid Systems : A visual communication manual for graphic designers, typographers and three dimensional designers</a> (en anglais et allemand). Par un professionnel pour les professionnels, voici l'ouvrage définitif sur l'utilisation de systèmes de grilles pour les graphistes. Bien qu'écrite en 1961, cette interprétation est toujours utile aujourd'hui, même pour le design assisté par ordinateur.<br /><strong>Gerrit Noordzij</strong>, <a href="https://www.amazon.fr/gp/product/0907259308/ref=as_li_tl?ie=UTF8&amp;tag=informationar-20&amp;camp=1789&amp;creative=9325&amp;linkCode=as2&amp;creativeASIN=0907259308&amp;linkId=956f8abcec1264b9629dd257c98d52b8">The Stroke: Theory of Writing</a>, The Stroke propose une véritable théorie de l'écriture, c'est-à-dire des concepts qui se cachent derrière les lettres sur la page, qu'elles soient écrites au stylo, au crayon ou au pinceau. The Stroke ne s'intéresse pas à la calligraphie d'art et aux belles formes, c'est une description du phénomène des lettres et de la manière dont elles sont réalisées dans l'écriture. Partant de principes de base, Gerrid Noordzij commence par l'espace blanc qui crée la définition en entourant les lettres. Puis, à l'aide de concepts géométriques simples, il décrit dans les moindres détails comment les traits de l'écriture peuvent être formés.</p></div>]]></description>
      <link>https://la-cascade.io/articles/le-web-95-de-typographie</link>
      <guid>https://la-cascade.io/articles/le-web-95-de-typographie</guid>
      <pubDate>Wed, 11 Dec 2013 07:00:00 +0100</pubDate>
    </item>
    <item>
      <title><![CDATA[Box-sizing pour les nuls]]></title>
      <description><![CDATA[<p><em>Box-sizing est une alternative au modèle de boîte standard. Elle est très simple et peut réellement changer votre travail. Une très bonne introduction par Paula Borowska.</em></p><div class="articleContent"><p>Box-sizing est une solution alternative au modèle de boîte standard que nous offre CSS. Pour bien comprendre la propriété box-sizing, il faut d'abord bien comprendre le modèle de boîte. En pratique, ils fonctionnent de la même manière mais il y a une différence essentielle — que nous allons approfondir tout à l'heure. Pour l'instant, revoyons notre bon vieux modèle de boîte.</p><h2>Le modèle de boîte</h2><p>Ce modèle découle du fait que les éléments HTML sont pour la plupart des boîtes et que CSS utilise ces boîtes pour les agencer dans votre mise en page. Un élément HTML typique comporte une largeur et une hauteur qui définissent la surface de son contenu, et cette surface est elle-même enveloppée dans des padding, des bordures et des marges, comme on le voir sur cette illustration :</p><figure role="group"><img src="https://la-cascade.io/images/boxmodel-1-compressor.png" alt="Le modèle de boîte classique" /></figure><p>Notez la relation entre ces propriétés : nous avons d'abord le contenu (Content), défini par sa largeur et sa hauteur, que cette dernière soit automatique ou spécifiée, elle est toujours là. Puis il y a le padding, suivi de la bordure, suivi de la marge. Voici une définition plus précise de chacun de ces éléments :</p><p><strong>Content</strong> : le contenu, c'est à dire le texte ou l'image<br /><strong>Padding</strong> : crée un espace autour du contenu. Cet espace a le même background que la boîte Content.<br /><strong>Border</strong> : une bordure qui entoure le contenu et son padding. Elle peut avoir elle-même son propre background, son épaisseur, sa texture, ses motifs.<br /><strong>Margin</strong> : la marge crée un espace autour des éléments précédents, cet espace est toujours transparent et n'est jamais affecté par les background de ces éléments.</p><p>Quand nous définissons les dimensions d'un élément, nous ne définissons en fait que les largeur et hauteur du contenu. Pour calculer la largeur et la hauteur totales de cet élément, nous devons aussi inclure le padding, la bordure et la marge.</p><p>Voici un exemple :</p><pre>//Exemple de dimension d'un élément
.box {
   width: 100px;
   padding: 10px;
   border: 5px solid black;
   margin: 10px;
}</pre><p>La largeur du contenu est de 100px, toutefois l'élément dans son ensemble a une largeur de 150px car nous devons intégrer les dimensions des autres composantes. Attention, il faut compter deux fois la largeur du padding, de la bordure et de la marge puisqu'elles sont de chaque côté de la boîte du contenu.</p><p>Dans l'exemple précédent, nous aurions donc :<br />100px (largeur du contenu) + 10px (padding gauche) + 10px (padding droite) + 5px (bordure gauche) + 5px (bordure droite) + 10px (marge gauche) + 10px (marge droite) = 150px (largeur totale de l'élément).</p><h2>En quoi Box-Sizing est-il différent ?</h2><p>CSS Box-sizing suit le modèle de boîte dans la mesure où il intègre la surface du contenu d'abord, puis le padding, puis la bordure, MAIS IL N'INCLUT PAS LES MARGES.</p><p>Cependant, nous devons définir la largeur ou la hauteur de notre élément, qui est maintenant la largeur ou la hauteur de l'élément <strong>dans son ensemble</strong>. Donc au lieu d'ajouter le padding et la bordure, vous devez les soustraire pour obtenir les dimensions du contenu :</p><p>Largeur = la largeur totale de l'élément et Largeur - padding - bordure = largeur du contenu</p><p>Dans l'exemple précédent, nous aurions : 100px (largeur totale de l'élément) - 10px (padding gauche) - 10px (padding droite) - 5px (bordure gauche) - 5px (bordure droite) = 70px (largeur du contenu).</p><p>La logique est donc inversée, et pour mieux la comprendre voici les deux modèles mis côte à côte :</p><figure role="group"><img src="https://la-cascade.io/images/boxsizing-1-compressor.png" alt="comparaison de box model et box sizing" /></figure><h2>Comment utiliser Box-Sizing</h2><p>Pour faire fonctionner box-sizing, il nous faut écrire quelques lignes de code afin de “l'activer”. Ces lignes peuvent être appliquées à un élément en particulier ou à l'ensemble de votre document. Il faut garder à l'esprit les limitations des navigateurs et utiliser les préfixes constructeurs spécifiques, nous y reviendrons plus tard.</p><pre>//Déclaration initiale
.box {
   box-sizing: border-box; /* Opera/IE 8+ */
/* box-sizing est appliqué seulement à cette classe */
}
* {
 box-sizing: border-box;
/* box-sizing est appliqué à tous les éléments */
}</pre><h2>Syntaxe</h2><p>Syntaxe de base de box-sizing :</p><pre>{box-sizing: content-box|border-box|inherit;}</pre><p>La syntaxe de base de box-sizing est très simple. Passons en revue les trois valeurs qu'elle peut prendre.</p><p><strong>Content-box</strong> : c'est la valeur par défaut, elle spécifie que les largeur et hauteur définies s'appliquent aux largeur et hauteur du contenu seul, et que le padding, la bordure et les marges sont en dehors de ces dimensions.<br /><strong>Border-box</strong> : les largeur et hauteur spécifiées sont celles de l'élément dans son ensemble, en conséquence les dimensions du padding ou des bordures viennent diminuer les dimensions du contenu.<br /><strong>Inherit</strong> : comme pour toute valeur héritée, la valeur de box-sizing peut dépendre de celle de son élément parent.</p><p>NB : Pour compléter cet article, La Cascade a publié un article plus récent intitulé <a href="https://la-cascade.io/articles/controler-le-modele-de-boite/">Contrôler le modèle de boîte</a> par Ire Aderinokun, lecture conseillée !</p><h2>Support navigateurs</h2><p>À ce jour, box-sizing est compatible avec tous les principaux navigateurs. Si vous voulez connaître tous les détails, vous pouvez consulter le site <a href="http://caniuse.com/css3-boxsizing">Can I use</a> qui est toujours à jour.</p><p>Les navigateurs actuels sont compatibles avec box-sizing, mais les versions anciennes ne le sont pas, c'est pourquoi, si vous voulez cibler large, il est important d'utiliser les préfixes ! (NdT: les choses évoluent vite, pour être sûr d'utiliser les bons préfixes constructeurs, le mieux est d'utiliser Autoprefixer, pour tout savoir sur cet outil super pratique <a href="https://openclassrooms.com/fr/courses/6106181-simplifiez-vous-le-css-avec-sass/6612156-utilisez-autoprefixer-pour-creer-du-code-adapte-a-tous-les-navigateurs">voir l'article</a> dans openclassroom).</p><p>Voici comment écrire le code :</p><pre>//Snippet pour les préfixes de box-sizing
.box {
   box-sizing: border-box; /* Opera/IE 8+ */
   -moz-box-sizing: border-box; /* Firefox, autres Gecko */
   -webkit-box-sizing: border-box; /* Safari/Chrome, autres WebKit */
}</pre><h2>Min/Max</h2><p>Si les préfixes max- et min- ne vous sont pas encore familiers, ils doivent le devenir. Pour en savoir plus vous pouvez cliquer <a href="http://www.w3schools.com/cssref/pr_dim_min-width.asp">ici</a>. Comme vous l'avez deviné, min- et max- peuvent être appliqués à la hauteur et à la largeur d'un élément pour définir la taille minimum et maximum de cet élément. Et box-sizing fonctionne avec ces propriétés aussi.</p><h2>Alors, pourquoi l'utiliser ?</h2><p>Si vous avez utilisé le modèle de boîte et si vous y êtes habitués, ce nouveau modèle peut vous paraître étrange. Cependant, si vous ne comprenez pas ou si vous n'aimez pas le modèle de boîte, box-sizing est pour vous.</p><p>Et il y a encore un grand avantage à l'utiliser : box-sizing est idéal pour les mises en page fluides.</p><p>Prenons un exemple simple. Notre mise en page comprend deux éléments div qui devraient avoir pour dimension 50%. Parfait, mais il nous faut encore soustraire 10% de padding pour séparer les deux. Nous faisons donc le calcul et nous changeons les chiffres. Avec box-sizing rien de tout cela ! Nous définissons notre largeur et notre padding et le tour est joué.</p><p>En conclusion et pour le dire simplement : les mises en pages ne sont pas toujours simples et s'avèrent souvent des casse-tête. Box-sizing vous fera gagner du temps et vous aidera à coder plus efficacement.</p></div>]]></description>
      <link>https://la-cascade.io/articles/box-sizing-pour-les-nuls</link>
      <guid>https://la-cascade.io/articles/box-sizing-pour-les-nuls</guid>
      <pubDate>Tue, 10 Dec 2013 07:00:00 +0100</pubDate>
    </item>
  </channel>
</rss>
