<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="https://chierchia.fr/wp-content/plugins/pretty-rss-feeds/xslt/pretty-feed.xsl" type="text/xsl" media="screen" ?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>javascript - Ange Chierchia</title>
	<atom:link href="https://chierchia.fr/tag/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>https://chierchia.fr/tag/javascript/</link>
	<description>Développeur Web full-stack</description>
	<lastBuildDate>Sun, 08 Feb 2026 16:11:25 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://chierchia.fr/wp-content/uploads/cropped-16350293-SSDKVqo3-32x32.jpg</url>
	<title>javascript - Ange Chierchia</title>
	<link>https://chierchia.fr/tag/javascript/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
					<title>Menu horizontal CSS : les sprites, c’était malin en 2009, beaucoup moins en 2026</title>
					<link>https://chierchia.fr/2026/02/menu-horizontal-css-sprites-2026/</link>
					<comments>https://chierchia.fr/2026/02/menu-horizontal-css-sprites-2026/#respond</comments>
		
		<dc:creator><![CDATA[<span class='p-author h-card'>Ange Chierchia</span>]]></dc:creator>
		<pubDate>Mon, 16 Feb 2026 06:45:00 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://chierchia.fr/?p=8600</guid>

					<description><![CDATA[En 2009, les sprites CSS optimisaient les menus horizontaux. En 2026, Flexbox, SVG et CSS modernes permettent des menus accessibles, responsives et maintenables.]]></description>
										<content:encoded><![CDATA[<div class='e-content'>
<p>La technique des sprites CSS a longtemps été une excellente solution pour optimiser les menus à base d&rsquo;image, mais en plus de 15 ans, le Web a bien évolué. En 2026, on peut (on doit <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f914.png" alt="🤔" class="wp-smiley" style="height: 1em; max-height: 1em;" />) construire des menus horizontaux plus souples, responsives et accessibles. Dans cet article, on va voir comment recréer l&rsquo;idée d&rsquo;un « <a href="https://chierchia.fr/2009/06/creer-un-menu-horizontal-avec-des-sprites-css/" type="post" id="1417">menu horizontal avec sprites CSS</a> » en utilisant des techniques modernes, en gardant les mêmes objectifs qu&rsquo;à l&rsquo;époque : esthétique et performance.</p>



<span id="more-8600"></span>



<h2 class="wp-block-heading">Pourquoi les sprites CSS ne sont plus la solution par défaut</h2>



<p>La technique des sprites consistait à regrouper tous les états graphiques (normal, survol, actif) dans une seule grande image, puis à afficher la bonne portion via <code>background-position</code>. Ça réduisait le nombre de requêtes HTTP nécessaires, ce qui était crucial avant l&rsquo;arrivée de HTTP/2.</p>



<p>Aujourd&rsquo;hui, cette approche a plusieurs limites pour un menu de navigation, même si elle fonctionne toujours :</p>



<ul class="wp-block-list">
<li>Maintenance lourde : chaque changement de pictogramme ou de texte implique de recalculer les positions.</li>



<li>Mauvaise adaptation aux écrans haut densité (Retina, 4K), sauf en multipliant les versions d&rsquo;images.</li>



<li>Accessibilité limitée : le texte est souvent masqué au profit d&rsquo;images purement décoratives.</li>



<li>Utilité réduite : HTTP/2, les formats d&rsquo;image modernes (WebP, SVG) rendent ce gain de requêtes moins critique.</li>
</ul>



<p>La technique des sprites reste pertinente pour certains cas (animations, jeux en HTML5), mais pour un simple menu de navigation, des alternatives modernes font clairement mieux le job aujourd&rsquo;hui.</p>



<h2 class="wp-block-heading">Structure HTML moderne</h2>



<p>La base n&rsquo;a pas fondamentalement changé depuis 2009 : une liste non ordonnée reste un excellent choix pour construire une navigation. En revanche, on va profiter d&rsquo;HTML5, des attributs ARIA et des bonnes pratiques en matière d&rsquo;accessibilité.</p>



<pre class="wp-block-code"><code>&lt;nav class="main-nav" aria-label="Navigation principale"&gt;
    &lt;a class="main-nav__logo" href="/"&gt;
        &lt;span class="sr-only"&gt;Retour à l'accueil&lt;/span&gt;
        &lt;!-- Logo SVG inline ou image --&gt;
        &lt;svg aria-hidden="true" viewBox="0 0 100 20"&gt;
            &lt;!-- ... --&gt;
        &lt;/svg&gt;
    &lt;/a&gt;
    
    &lt;button class="main-nav__toggle" aria-expanded="false" aria-controls="main-menu"&gt;
        &lt;span class="sr-only"&gt;Ouvrir le menu&lt;/span&gt;
        &lt;span class="main-nav__toggle-bar"&gt;&lt;/span&gt;
        &lt;span class="main-nav__toggle-bar"&gt;&lt;/span&gt;
        &lt;span class="main-nav__toggle-bar"&gt;&lt;/span&gt;
    &lt;/button&gt;

    &lt;ul id="main-menu" class="main-nav__list"&gt;
        &lt;li class="main-nav__item"&gt;
            &lt;a class="main-nav__link is-active" href="/" aria-current="page"&gt;Home&lt;/a&gt;
        &lt;/li&gt;
        &lt;li class="main-nav__item"&gt;
            &lt;a class="main-nav__link" href="/services"&gt;Services&lt;/a&gt;
        &lt;/li&gt;
        &lt;li class="main-nav__item"&gt;
            &lt;a class="main-nav__link" href="/references"&gt;Références&lt;/a&gt;
        &lt;/li&gt;
        &lt;li class="main-nav__item"&gt;
            &lt;a class="main-nav__link" href="/contact"&gt;Contact&lt;/a&gt;
        &lt;/li&gt;
    &lt;/ul&gt;
&lt;/nav&gt;</code></pre>



<p>Quelques points importants : </p>



<ul class="wp-block-list">
<li>Utilisation de <code>&lt;nav&gt;</code> et <code>aria-label</code> pour expliciter le rôle de la zone.</li>



<li>Un bouton de type « hamburger » pour le mobile, relié à la liste via <code>aria-controls</code>.</li>



<li>Une classe <code>is-active</code> pour gérer l&rsquo;onglet actif côté CSS.</li>
</ul>



<h2 class="wp-block-heading">Mise en page avec Flexbox (bye-bye <code>float</code> !)</h2>



<p>Là où mon article d&rsquo;origine utilisait <code>float: left</code> sur les <code>&lt;li&gt;</code>, on peut aujourd&rsquo;hui aligner le menu avec Flexbox. Plus simple et plus&#8230; flexible ! (ouais, je suis un marrant <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f923.png" alt="🤣" class="wp-smiley" style="height: 1em; max-height: 1em;" />).</p>



<pre class="wp-block-code"><code>.main-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
    padding: 0.75rem 1.5rem;
    background: linear-gradient(90deg, #1f2933, #111827);
    color: #ffffff;
}

.main-nav__logo {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    color: inherit;
}

.main-nav__list {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.main-nav__link {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0;
    font-weight: 500;
    color: #e5e7eb;
    text-decoration: none;
    transition: color 200ms ease-out;
}</code></pre>



<p>Ici, la liste devient une simple rangée flex, ce qui rend l&rsquo;ajout ou la suppression d&rsquo;éléments beaucoup plus naturel que la gestion de coordonnées de sprites. On peut aussi, si besoin, passer sur CSS Grid pour gérer un en-tête plus complexe.</p>



<h2 class="wp-block-heading">Effets de survol modernes</h2>



<p>Au lieu de gérer les états normal/hover/actif via une image sprite, on peut recréer des effets visuels sophistiqués en pur CSS : soulignement animé, fond dégradé, « pill » qui se déplace, etc.</p>



<h3 class="wp-block-heading">Exemple : soulignement animé avec un pseudo-élément</h3>



<pre class="wp-block-code"><code>.main-nav__link::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -0.2rem;
    width: 100%;
    height: 2px;
    border-radius: 999px;
    background: linear-gradient(90deg, #f59e0b, #ec4899);
    transform-origin: center;
    transform: scaleX(0);
    transition: transform 0.2s ease-out;
}

.main-nav__link:hover::after,
.main-nav__link:focus-visible::after,
.main-nav__link.is-active::after {
    transform: scaleX(1);
}

.main-nav__link:hover,
.main-nav__link:focus-visible,
.main-nav__link.is-active {
    color: #fff;
}</code></pre>



<p>Avec cette approche, on reproduit l&rsquo;idée d&rsquo;un état survolé distinct, sans aucune image et avec un rendu parfaitement net sur tous les écrans. On améliore aussi l&rsquo;accessibilité en stylant <code>:focus-visible</code> pour la navigation au clavier.</p>



<h2 class="wp-block-heading">Icônes : du sprite bitmap au SVG</h2>



<p>Autre gros virage : la façon d’intégrer des icônes. Là où l&rsquo;on utilisait auparavant une sprite PNG, on privilégie maintenant :</p>



<ul class="wp-block-list">
<li>une « Icon Font » (de moins en moins recommandée),</li>



<li>des SVG inline (avec <code>&lt;svg&gt;</code> dans le HTML),</li>



<li>ou une sprite SVG via <code>&lt;symbol&gt;</code> et <code>&lt;use&gt;</code></li>
</ul>



<h3 class="wp-block-heading">Exemple avec une sprite SVG</h3>



<pre class="wp-block-code"><code>&lt;svg aria-hidden="true" style="display:none"&gt;
    &lt;symbol id="icon-home" viewBox="0 0 24 24"&gt;
        &lt;!-- … --&gt;
    &lt;/symbol&gt;
    &lt;symbol id="icon-services" viewBox="0 0 24 24"&gt;
        &lt;!-- … --&gt;
    &lt;/symbol&gt;
&lt;/svg&gt;

&lt;nav class="main-nav" aria-label="Navigation principale"&gt;
    &lt;ul class="main-nav__list"&gt;
        &lt;li class="main-nav__item"&gt;
            &lt;a class="main-nav__link is-active" href="#home"&gt;
                &lt;svg class="main-nav__icon" aria-hidden="true"&gt;
                    &lt;use href="#icon-home"&gt;&lt;/use&gt;
                &lt;/svg&gt;
                &lt;span&gt;Home&lt;/span&gt;
            &lt;/a&gt;
        &lt;/li&gt;
        &lt;!-- … --&gt;
    &lt;/ul&gt;
&lt;/nav&gt;</code></pre>



<pre class="wp-block-code"><code>.main-nav__icon {
    width: 1.1rem;
    height: 1.1rem;
    margin-right: 0.4rem;
    flex-shrink: 0;
}
</code></pre>



<p>Les avantages sont nombreux : un rendu vectoriel, une couleur facilement personnalisable en CSS (via <code>fill</code> et optionnellement <code>currentColor</code>), et plus aucune gymnastique de <code>background-position</code> !</p>



<h2 class="wp-block-heading">Rendre le menu responsive</h2>



<p>Un menu horizontal moderne doit s&rsquo;adapter à toutes les tailles de fenêtre. On peut combiner CSS à un petit peu de JavaScript pour gérer l&rsquo;ouverture et la fermeture du menu sur mobile.</p>



<h3 class="wp-block-heading">CSS : basculer en mode « hamburger » sur mobile</h3>



<pre class="wp-block-code"><code>.main-nav__toggle {
    display: none;
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 0.25rem;
}

.main-nav__toggle-bar {
    display: block;
    width: 1.5rem;
    height: 2px;
    margin: 0.2rem 0;
    border-radius: 999px;
    background-color: #e5e7eb;
    transition: transform 0.2s ease-out, opacity 0.2s ease-out;
}

/* Mobile */
@media (max-width: 768px) {
    .main-nav {
        flex-wrap: wrap;
        align-items: center;
        row-gap: 0;
    }

    .main-nav__toggle {
        display: flex;
        flex-direction: column;
        margin-left: auto;
    }

    .main-nav__list {
        flex-basis: 100%;
        flex-direction: column;
        align-items: flex-start;
        gap: 0.75rem;
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.25s ease-out;
    }

    .main-nav__list.is-open {
        max-height: unset;
        overflow: initial;
    }
}</code></pre>



<h3 class="wp-block-heading">JavaScript : gestion de l&rsquo;état « ouvert »</h3>



<pre class="wp-block-code"><code>const navToggle = document.querySelector('.main-nav__toggle');
const navList = document.querySelector('#main-menu');

if (navToggle &amp;&amp; navList) {
    navToggle.addEventListener('click', () =&gt; {
        const isOpen = navToggle.getAttribute('aria-expanded') === 'true';
        navToggle.setAttribute('aria-expanded', String(!isOpen));
        navList.classList.toggle('is-open', !isOpen);
    });
}</code></pre>



<p>Ce petit script suffit amplement pour un menu responsive classique, tout en respectant les attributs ARIA pour les lecteurs d&rsquo;écran. Des implémentations plus avancées peuvent gérer le focus, l&rsquo;échappement au clavier ou les sous-menus (dropdown, mega menu, etc.)</p>



<h2 class="wp-block-heading">Accessibilité et UX, à ne surtout plus ignorer</h2>



<p>Si mon article d&rsquo;origine se concentrait surtout sur la technique des sprites et l&rsquo;optimisation des requêtes HTTP, un menu moderne doit aussi intégrer de vraies bonnes pratiques d&rsquo;accessibilité (et on aurait dû s&rsquo;en rendre compte déjà à l&rsquo;époque des mises en page en&nbsp;<code>&lt;table&gt;</code>&nbsp;<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f631.png" alt="😱" class="wp-smiley" style="height: 1em; max-height: 1em;" />).</p>



<p>Quelques points clés :</p>



<ul class="wp-block-list">
<li>Utiliser des textes visibles plutôt que de les masquer derrière une image.</li>



<li>Prévoir des styles de <code>:focus-visible</code> suffisamment contrastés pour la navigation clavier.</li>



<li>S&rsquo;assurer que le contraste texte/fond est suffisant pour une lecture confortable.</li>



<li>Gérer l&rsquo;état actif (<code>aria-current="page"</code>) pour que l&rsquo;utilisateur sache où il se trouve.</li>
</ul>



<h2 class="wp-block-heading">17 ans de progrès en un menu</h2>



<p>En 2009, les sprites CSS étaient une astuce magique pour booster les performances d&rsquo;un menu horizontal un peu « design ». Aujourd&rsquo;hui, grâce à Flexbox, SVG, des CSS modernes et un peu de JavaScript (bye jQuery ! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f92d.png" alt="🤭" class="wp-smiley" style="height: 1em; max-height: 1em;" />), on obtient un résultat plus performant, plus accessible et infiniment plus maintenable. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f60e.png" alt="😎" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="wBWYPdP" data-pen-title="Untitled" data-user="nighcrawl" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
      <span>See the Pen <a href="https://codepen.io/nighcrawl/pen/wBWYPdP">
  Untitled</a> by Ange Chierchia (<a href="https://codepen.io/nighcrawl">@nighcrawl</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
      </p>
      <script async src="https://public.codepenassets.com/embed/index.js"></script>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://chierchia.fr/2026/02/menu-horizontal-css-sprites-2026/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
					<title>Creating CSS Theme Variables from a JS file</title>
					<link>https://chierchia.fr/2025/08/20250820190407/</link>
					<comments>https://chierchia.fr/2025/08/20250820190407/#respond</comments>
		
		<dc:creator><![CDATA[<span class='p-author h-card'>Ange Chierchia</span>]]></dc:creator>
		<pubDate>Thu, 21 Aug 2025 05:00:00 +0000</pubDate>
				<category><![CDATA[Bookmarks]]></category>
		<category><![CDATA[Notes]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://chierchia.fr/?p=4660</guid>

					<description><![CDATA[Bookmarked CSS { In Real Life } &#124; Creating CSS Theme Variables from a JS file. Les design tokens, c’est la promesse d’une cohérence. Mais dans la pratique, on se retrouve souvent avec un fichier SCSS, un fichier JS, un fichier Figma… et des incohérences qui s’accumulent. L’idée proposée ici est toute bête mais super [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class='e-content'>
<div class="wp-block-indieblocks-bookmark"><div class="u-bookmark-of h-cite"><p><i>Bookmarked <a class="u-url p-name" href="https://css-irl.info/creating-css-variables-from-a-js-file/">CSS { In Real Life } | Creating CSS Theme Variables from a JS file</a>.</i></p></div></div>



<p>Les design tokens, c’est la promesse d’une cohérence. Mais dans la pratique, on se retrouve souvent avec un fichier SCSS, un fichier JS, un fichier Figma… et des incohérences qui s’accumulent. L’idée proposée ici est toute bête mais super efficace : un seul fichier JavaScript, qui définit tes tokens (couleurs, tailles, etc.), et qui crache directement des variables CSS prêtes à l’emploi. Plus besoin de jongler, tout le monde boit à la même source.</p>



<p>Ce que j’aime, c’est la simplicité. Pas besoin de grosse usine à gaz ni de tooling lourd façon “style dictionary”. Tu écris tes valeurs une fois, tu génères les :root { &#8211;variable: valeur }, et basta. Côté dev, tu consommes les tokens en JS et en CSS sans jamais les dédoubler.</p>



<p>Ça ne remplacera pas une infra complète pour une grosse équipe produit, mais pour un projet à taille humaine, c’est pile le bon compromis : un point de vérité unique, une synchro JS/CSS sans douleur, et une dette technique évitée dès le départ. Bref, ça mérite d’être testé sur ton prochain side project.</p>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://chierchia.fr/2025/08/20250820190407/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
					<title>Web Components: Working With Shadow DOM</title>
					<link>https://chierchia.fr/2025/08/20250808155219/</link>
					<comments>https://chierchia.fr/2025/08/20250808155219/#respond</comments>
		
		<dc:creator><![CDATA[<span class='p-author h-card'>Ange Chierchia</span>]]></dc:creator>
		<pubDate>Mon, 11 Aug 2025 05:30:00 +0000</pubDate>
				<category><![CDATA[Bookmarks]]></category>
		<category><![CDATA[Notes]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web component]]></category>
		<guid isPermaLink="false">https://chierchia.fr/?p=4607</guid>

					<description><![CDATA[Bookmarked Web Components: Working With Shadow DOM — Smashing Magazine. Je suis longtemps passé à côté du Shadow DOM. Trop abstrait, trop “spec moderne” pour mes besoins du quotidien. Mais cet article m’a recadré. Il explique comment le Shadow DOM te permet d’encapsuler un composant comme un vrai bloc isolé : pas de fuite de [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class='e-content'>
<div class="wp-block-indieblocks-bookmark"><div class="u-bookmark-of h-cite"><p><i>Bookmarked <a class="u-url p-name" href="https://www.smashingmagazine.com/2025/07/web-components-working-with-shadow-dom/">Web Components: Working With Shadow DOM — Smashing Magazine</a>.</i></p></div></div>



<p>Je suis longtemps passé à côté du Shadow DOM. Trop abstrait, trop “spec moderne” pour mes besoins du quotidien.</p>



<p>Mais cet article m’a recadré.</p>



<p>Il explique comment le Shadow DOM te permet d’encapsuler un composant comme un vrai bloc isolé : pas de fuite de styles, pas de conflits de noms, pas de comportements JS qui partent en sucette.</p>



<p>Et ça, dans une époque où chaque lib veut imposer sa logique, ça fait du bien de voir un truc standard qui tient la route.</p>



<p>On n’est pas obligés de tout reconstruire avec Web Components demain matin, mais piger comment le Shadow DOM fonctionne, c’est clairement un level-up pour écrire du code plus robuste — et plus pérenne</p>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://chierchia.fr/2025/08/20250808155219/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
					<title>Les composants Web pour les nuls</title>
					<link>https://chierchia.fr/2024/01/les-composants-web-pour-les-nuls/</link>
					<comments>https://chierchia.fr/2024/01/les-composants-web-pour-les-nuls/#respond</comments>
		
		<dc:creator><![CDATA[<span class='p-author h-card'>Ange Chierchia</span>]]></dc:creator>
		<pubDate>Mon, 08 Jan 2024 19:39:03 +0000</pubDate>
				<category><![CDATA[Bookmarks]]></category>
		<category><![CDATA[Notes]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web component]]></category>
		<guid isPermaLink="false">https://nighcrawl.com/blog/2024/01/les-composants-web-pour-les-nuls</guid>

					<description><![CDATA[En parcourant mon Feedbin ce midi je suis tombé par hasard sur un article d’Eric Meyer concernant les composants Web et grâce à lui j’ai compris comment ils fonctionnent et tout me parait un peu moins flou maintenant. Si comme moi vous n’aviez pas encore pu saisir leur intérêt, je vous conseille vivement d’aller le [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class='e-content'>
<div class="wp-block-indieblocks-bookmark"><div class="u-bookmark-of h-cite"><p><i>Bookmarked <a class="u-url" href="https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the-light-dom/">https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the-light-dom/</a>.</i></p></div><div class="e-content">
<p>En parcourant mon Feedbin ce midi je suis tombé par hasard sur <a href="https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the-light-dom/">un article d’Eric Meyer concernant les composants Web</a> et grâce à lui j’ai compris comment ils fonctionnent et tout me parait un peu moins flou maintenant.</p>



<p>Si comme moi vous n’aviez pas encore pu saisir leur intérêt, je vous conseille vivement d’aller le lire ! J’espère pouvoir appliquer ça dans un futur projet au boulot et me faire les dents dessus <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Je n’ai rien d’autre à ajouter. Juste, lisez le.</p>
</div></div>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://chierchia.fr/2024/01/les-composants-web-pour-les-nuls/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
					<title>Modifier l’état d’une checkbox en fonctions de ses checkboxes filles</title>
					<link>https://chierchia.fr/2024/01/modifier-letat-dune-checkbox-en-fonctions-de-ses-checkboxes-filles/</link>
					<comments>https://chierchia.fr/2024/01/modifier-letat-dune-checkbox-en-fonctions-de-ses-checkboxes-filles/#respond</comments>
		
		<dc:creator><![CDATA[<span class='p-author h-card'>Ange Chierchia</span>]]></dc:creator>
		<pubDate>Sat, 06 Jan 2024 13:10:05 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://nighcrawl.com/blog/2024/01/modifier-letat-dune-checkbox-en-fonctions-de-ses-checkboxes-filles</guid>

					<description><![CDATA[Cette semaine je travaillais sur un projet dans lequel une page affiche une liste de documents que l’on peut filtrer à l’aide de checkboxes. Dans cet article je vais vous exposer un cas d’usage que j’ai rencontré et comment je l’ai solutionné. La fonctionnalité que j’avais a créer était un genre d’arborescence de checkboxes. En [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class='e-content'>
<p>Cette semaine je travaillais sur un projet dans lequel une page affiche une liste de documents que l’on peut filtrer à l’aide de checkboxes. Dans cet article je vais vous exposer un cas d’usage que j’ai rencontré et comment je l’ai solutionné.</p>



<span id="more-1300"></span>



<p>La fonctionnalité que j’avais a créer était un genre d’arborescence de checkboxes. En d’autres termes, l’un des filtres présentait une liste d’options avec des sous-options, chacune pouvant être cochée ou non. Si une option «&nbsp;mère&nbsp;» est cochée, toutes les sous options qui lui appartiennent doivent être cochées automatiquement. À l’inverse, si on ne coche pas toutes les options «&nbsp;filles&nbsp;», l’état de l’option «&nbsp;mère&nbsp;» doit être indéfini.</p>



<p>Voici le résultat final <a href="https://codepen.io/nighcrawl/pen/gOEPdzR">est visible sur Codepen</a>.</p>



<h2 class="wp-block-heading" id="structure-html">Structure HTML</h2>



<p>La structure HTML que j’ai utilisé est plutôt basique, ce sont simplement des <code class="language-plaintext highlighter-rouge">&lt;input type="checkbox"&gt;</code> regroupez dans une <code class="language-plaintext highlighter-rouge">&lt;div class="children"&gt;&lt;/div&gt;</code> pour les checkboxes «&nbsp;filles&nbsp;». L’attribut <code class="language-plaintext highlighter-rouge">id</code> de la checkbox «&nbsp;mère&nbsp;» va nous permettre de la cibler plus facilement en JavaScript.</p>



<div class="language-plaintext highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code>&lt;div class="options"&gt;
  &lt;div class="input input--checkbox"&gt;
    &lt;input type="checkbox" name="parent" id="checkAll"&gt;
    &lt;label for="checkAll"&gt;Tout sélectionner&lt;/label&gt;
  &lt;/div&gt;
  &lt;div class="children"&gt;
    &lt;div class="input input--checkbox"&gt;
      &lt;input type="checkbox" name="child[]" id="child1"&gt;
      &lt;label for="child1"&gt;Option 1&lt;/label&gt;
    &lt;/div&gt;

    &lt;div class="input input--checkbox"&gt;
      &lt;input type="checkbox" name="child[]" id="child2"&gt;
      &lt;label for="child2"&gt;Option 2&lt;/label&gt;
    &lt;/div&gt;

    &lt;div class="input input--checkbox"&gt;
      &lt;input type="checkbox" name="child[]" id="child3"&gt;
      &lt;label for="child3"&gt;Option 3&lt;/label&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre>
</div>
</div>



<p>Passons maintenant au JavaScript.</p>



<h2 class="wp-block-heading" id="ajouter-un-écouteur-dévènement-sur-les-checkboxes">Ajouter un écouteur d’évènement sur les checkboxes</h2>



<p>Nous allons d’abord créer un écouteur pour le clic sur les checkboxes. Pour plus de simplicité, notre écouteur exécutera une fonction que l’on nomme <code class="language-plaintext highlighter-rouge">changeOptionsHandler()</code> et dans laquelle on traitera les changement d’état de chaque checkbox. Voici comment ajouter l’’écouteur sur nos checkboxes:</p>



<pre class="wp-block-code"><code>document.querySelectorAll('&#91;type="checkbox"]').forEach((input) => {
  input.addEventListener("click", (event) => {
    changeOptionsHandler(event.target);
  });
});</code></pre>



<p>D’abord on cible tous les checkboxes avec <code class="language-plaintext highlighter-rouge">document.querySelectorAll('[type="checkbox"]')</code> puis on attache l’écouteur d’évènement <code class="language-plaintext highlighter-rouge">click</code> sur chacune d’elle.</p>



<pre class="wp-block-code"><code>forEach((input) => {
  input.addEventListener("click", (event) => {
    // …
  })
}</code></pre>



<p>Passons maintenant à la fonction <code class="language-plaintext highlighter-rouge">changeOptionsHandler()</code>.</p>



<h2 class="wp-block-heading" id="gérer-les-changement-détat-des-checkboxes">Gérer les changement d’état des checkboxes</h2>



<p>D’abord on gérer le clic sur la checkbox dont l’id est «&nbsp;checkAll&nbsp;», puis dans une fonction différente on gèrera le clic sur les checkboxes «&nbsp;filles&nbsp;» et leur conséquences sur la checkbox «&nbsp;mère&nbsp;»</p>



<pre class="wp-block-code"><code>if (input.id === "checkAll") {
  if (input.checked === true) {
    input
      .closest(".options")
      .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]')
      .forEach((child) => {
        child.checked = true;
      });
  } else {
    input
      .closest(".options")
      .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]')
      .forEach((child) => {
        child.checked = false;
      });
  }</code></pre>



<p>Si la checkbox est cochée, alors on récupères toutes les checkboxes contenues dans la <code class="language-plaintext highlighter-rouge">&lt;div&gt;&lt;/div&gt;</code> dont l’attribut <code class="language-plaintext highlighter-rouge">class</code> contient «&nbsp;options&nbsp;», puis pour chaque on modifie l’attribut<code class="language-plaintext highlighter-rouge">checked</code>avec la même valeur (<code class="language-plaintext highlighter-rouge">true</code>).</p>



<pre class="wp-block-code"><code>if (input.checked === true) {
  input
    .closest(".options")
    .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]')
    .forEach((child) => {
      child.checked = true;
    });
}</code></pre>



<p>Puis on fait la même chose si la checkbox est décochée. Ici ‘false’.</p>



<p>Maintenant on va s’intéresser aux différents états que pourra avoir la checkbox «&nbsp;mère&nbsp;» lors d’un clic sur l’une de ses «&nbsp;filles&nbsp;».</p>



<h2 class="wp-block-heading" id="gérer-les-états-de-la-checkbox-mère">Gérer les états de la checkbox «&nbsp;mère&nbsp;»</h2>



<p>La checkbox «&nbsp;mère&nbsp;» pourra avoir trois états :</p>



<ul class="wp-block-list">
<li>coché</li>



<li>décoché</li>



<li>indéterminé</li>
</ul>



<p>Pour déterminer sont état, il faudra que l’on compte le nombre d’options disponibles et le nombre de «&nbsp;filles&nbsp;» cochées. Si le total d’options est égal au nombre d’options cochées, alors l’état de la checkbox «&nbsp;mère&nbsp;» est «&nbsp;coché&nbsp;». Si le nombre d’options décochées est égal au total d’options, alors celle-ci sera «&nbsp;décochée&nbsp;». Dans tout les autres cas, la checkbox «&nbsp;mère&nbsp;» sera dans un état «&nbsp;indéterminé&nbsp;».</p>



<p>Voilà comment cela se traduit en code :</p>



<pre class="wp-block-code"><code>let checkAllState = (input) => {
  let countOptions = input
    .closest(".options")
    .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]').length;
  let checkedOptions = input
    .closest(".options")
    .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]:checked').length;
  let checkAll = input.closest(".options").querySelector("#checkAll");

  if (countOptions !== checkedOptions) {
    if (checkedOptions == 0) {
      checkAll.indeterminate = false;
      checkAll.checked = false;
    } else {
      checkAll.indeterminate = true;
      checkAll.checked = false;
    }
  } else {
    checkAll.indeterminate = false;
    checkAll.checked = true;
  }
};</code></pre>



<p>Et voilà ! Je vous met ici le code JavaScript complet.</p>



<pre class="wp-block-code"><code>let changeOptionsHandler = (input) => {
  if (input.id === "checkAll") {
    if (input.checked === true) {
      input
        .closest(".options")
        .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]')
        .forEach((child) =&amp;gt; {
          child.checked = true;
        });
    } else {
      input
        .closest(".options")
        .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]')
        .forEach((child) =&amp;gt; {
          child.checked = false;
        });
    }
  }
  checkAllState(input);
};

let checkAllState = (input) => {
  let countOptions = input
    .closest(".options")
    .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]').length;
  let checkedOptions = input
    .closest(".options")
    .querySelectorAll('&#91;type="checkbox"]&#91;name="child&#91;]"]:checked').length;
  let checkAll = input.closest(".options").querySelector("#checkAll");

  if (countOptions !== checkedOptions) {
    if (checkedOptions == 0) {
      checkAll.indeterminate = false;
      checkAll.checked = false;
    } else {
      checkAll.indeterminate = true;
      checkAll.checked = false;
    }
  } else {
    checkAll.indeterminate = false;
    checkAll.checked = true;
  }
};

document.querySelectorAll('&#91;type="checkbox"]').forEach((input) => {
  input.addEventListener("click", (event) =&amp;gt; {
    changeOptionsHandler(event.target);
  });
});</code></pre>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p>Grâce à un peu de magie JavaScript, on a réussi à créer une petite danse entre une checkbox « mère » et ses petites « filles », tout ça pour rendre notre interface utilisateur encore plus cool et intuitive.</p>



<p>Si vous avez des astuces, des idées pour améliorer cette petite méthode ou même si vous avez juste envie de partager vos expériences, n’hésitez pas à me répondre sur Mastodon. J’adorerais entendre vos retours et idées.</p>



<p><em><a href="https://ma.tt/2024/01/birthday-gift/">Happy Birthday Matt!</a> Hope you like your gift</em> <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p></p>
</div>]]></content:encoded>
					
					<wfw:commentRss>https://chierchia.fr/2024/01/modifier-letat-dune-checkbox-en-fonctions-de-ses-checkboxes-filles/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
					<title>Mettre en place un « dark mode » simplement</title>
					<link>https://chierchia.fr/2023/09/mettre-en-place-un-dark-mode-simplement/</link>
					<comments>https://chierchia.fr/2023/09/mettre-en-place-un-dark-mode-simplement/#respond</comments>
		
		<dc:creator><![CDATA[<span class='p-author h-card'>Ange Chierchia</span>]]></dc:creator>
		<pubDate>Wed, 20 Sep 2023 21:13:36 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[dark mode]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://nighcrawl.com/blog/2023/09/mettre-en-place-un-dark-mode-simplement</guid>

					<description><![CDATA[Cela fait un moment que j’avais mis en place la possibilité de choisir entre un thème sombre et un thème clair pour lire mon blog. Et ça fait presque aussi longtemps qu’il était éclaté au sol, dans le sens où même si on choisissait l’un des modes, les préférences du système prenaient de nouveau le [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class='e-content'>Cela fait un moment que j’avais mis en place la possibilité de choisir entre un thème sombre et un thème clair pour lire mon blog. Et ça fait presque aussi longtemps qu’il était éclaté au sol, dans le sens où même si on choisissait l’un des modes, les préférences du système prenaient de nouveau le dessus au rechargement de page. On va voir ensemble ce qui n’allait pas et donc ce qu’il ne faut pas faire.<span id="more-1314"></span></p>
<h2 id="conditionner-le-mode-sombre-en-javascript-et-via-les-styles-css">Conditionner le mode sombre en JavaScript ET via les styles CSS</h2>
<p>Si il y a bien une chose à éviter, c’est celle-ci. En effet, il est préférable de décider qui, de JavaScript ou CSS, va gérer le mode sombre et de s’y tenir, afin d’éviter que des conditions définies en JavaScript soient écrasées par une feuille de style. C’est le soucis que j’avais ici : je définissais à la fois des règles CSS ciblées par un attribut <code class="language-plaintext highlighter-rouge">html[data-theme="dark"]</code> qui était ensuite modifié via JavaScript ainsi que des règles ciblées par une media query <code class="language-plaintext highlighter-rouge">@media (prefers-color-scheme: dark)</code>.</p>
<div class="language-css highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code><span class="nt">html</span><span class="o">[</span><span class="nt">data-theme</span><span class="o">=</span><span class="s1">"dark"</span><span class="o">]</span> <span class="nt">body</span> <span class="p">{</span>
    <span class="nl">background-color</span><span class="p">:</span> <span class="m">#222222</span><span class="p">;</span>
    <span class="nl">color</span><span class="p">:</span> <span class="m">#ffffff</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">@media</span> <span class="p">(</span><span class="n">prefers-color-scheme</span><span class="p">:</span> <span class="n">dark</span><span class="p">)</span> <span class="p">{</span>
  <span class="nt">body</span> <span class="p">{</span>
    <span class="nl">background-color</span><span class="p">:</span> <span class="m">#222222</span><span class="p">;</span>
    <span class="nl">color</span><span class="p">:</span> <span class="m">#ffffff</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
</div>
<p>Et voici ce que je faisais en JavaScript :</p>
<p>Je sauvegardais dans un booléen <code class="language-plaintext highlighter-rouge">isDarkMode</code> le résultat de la condition media query <code class="language-plaintext highlighter-rouge">(prefers-color-scheme: dark)</code> ou de l’attribut <code class="language-plaintext highlighter-rouge">[data-theme="dark"]</code>.</p>
<p>Au chargement de la page, le thème était défini sur “dark” ou “light” suivant la valeur du booléen <code class="language-plaintext highlighter-rouge">isDarkMode.</code> Puis lorsque un changement au niveau de la media query était détecté, j’appelai à nouveau ma fonction <code class="language-plaintext highlighter-rouge">switchTheme()</code>.</p>
<div class="language-javascript highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code><span class="kd">var</span> <span class="nx">themeToggle</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">.site-theme-switcher</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">useDark</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">matchMedia</span><span class="p">(</span><span class="dl">"</span><span class="s2">(prefers-color-scheme: dark)</span><span class="dl">"</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">isDarkMode</span> <span class="o">=</span> <span class="nx">useDark</span><span class="p">.</span><span class="nx">matches</span> <span class="o">||</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">html</span><span class="dl">'</span><span class="p">).</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-theme</span><span class="dl">'</span><span class="p">)</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">dark</span><span class="dl">"</span><span class="p">;</span>

<span class="kd">var</span> <span class="nx">switchTheme</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">darkModeState</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span> <span class="p">(</span><span class="nx">darkModeState</span><span class="p">)</span> <span class="p">{</span>
		<span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">html</span><span class="dl">'</span><span class="p">).</span><span class="nx">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-theme</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">dark</span><span class="dl">'</span><span class="p">);</span>
		<span class="nx">themeToggle</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-switch-theme</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">light</span><span class="dl">'</span><span class="p">);</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">html</span><span class="dl">'</span><span class="p">).</span><span class="nx">removeAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-theme</span><span class="dl">'</span><span class="p">);</span>
		<span class="nx">themeToggle</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-switch-theme</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">dark</span><span class="dl">'</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">};</span>

<span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">DOMContentLoaded</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
	<span class="nx">switchTheme</span><span class="p">(</span><span class="nx">isDarkMode</span><span class="p">);</span>
	<span class="nx">useDark</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
		<span class="nx">switchTheme</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">matches</span><span class="p">);</span>
	<span class="p">});</span>
<span class="p">});</span>
</code></pre>
</div>
</div>
<p>En soit, cette méthode n’est pas mauvaise, mais à aucun moment elle ne prend en compte la volonté de l’utilisateur de visionner votre site Web en version sombre ou non. C’est le système d’exploitation de l’ordinateur qui prend la main.</p>
<h2 id="ne-pas-utiliser-de-cookie">Ne pas utiliser de cookie</h2>
<p>Une autre erreur à ne pas faire, si on veut que l’utilisateur garde la main, c’est de ne pas enregistrer son choix. C’est tout bête, mais je ne m’en suis rendu compte que ce soir en me penchant enfin sur le problème…</p>
<p>La correction est simple à mettre en place, il suffit de modifier la fonction <code class="language-plaintext highlighter-rouge">switchTheme()</code> comme suit :</p>
<div class="language-javascript highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code><span class="kd">var</span> <span class="nx">switchTheme</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">darkModeState</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span> <span class="p">(</span><span class="nx">darkModeState</span><span class="p">)</span> <span class="p">{</span>
		<span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">html</span><span class="dl">'</span><span class="p">).</span><span class="nx">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-theme</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">dark</span><span class="dl">'</span><span class="p">);</span>
		<span class="nx">themeToggle</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-switch-theme</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">light</span><span class="dl">'</span><span class="p">);</span>
		<span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">darktheme=true; expires=Fri, 31 Dec 9999 23:59:59 GMT;</span><span class="dl">"</span><span class="p">;</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">html</span><span class="dl">'</span><span class="p">).</span><span class="nx">removeAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-theme</span><span class="dl">'</span><span class="p">);</span>
		<span class="nx">themeToggle</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="dl">'</span><span class="s1">data-switch-theme</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">dark</span><span class="dl">'</span><span class="p">);</span>
		<span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">darktheme=false; expires=Fri, 31 Dec 9999 23:59:59 GMT;</span><span class="dl">"</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">};</span>
</code></pre>
</div>
</div>
<p>Il conviendra ensuite de modifier l’écouteur de l’évènement <code class="language-plaintext highlighter-rouge">DOMContentLoaded</code> comme ceci :</p>
<div class="language-javascript highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code><span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">DOMContentLoaded</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">"</span><span class="s2">;</span><span class="dl">"</span><span class="p">).</span><span class="nx">some</span><span class="p">((</span><span class="nx">item</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">item</span><span class="p">.</span><span class="nx">trim</span><span class="p">().</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">darktheme=true</span><span class="dl">"</span><span class="p">)))</span> <span class="p">{</span>
		<span class="nx">switchTheme</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
	<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="dl">"</span><span class="s2">;</span><span class="dl">"</span><span class="p">).</span><span class="nx">some</span><span class="p">((</span><span class="nx">item</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">item</span><span class="p">.</span><span class="nx">trim</span><span class="p">().</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">darktheme=false</span><span class="dl">"</span><span class="p">)))</span> <span class="p">{</span>
		<span class="nx">switchTheme</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="nx">switchTheme</span><span class="p">(</span><span class="nx">useDark</span><span class="p">.</span><span class="nx">matches</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
</div>
<p>Et voilà !</p></div>
]]></content:encoded>
					
					<wfw:commentRss>https://chierchia.fr/2023/09/mettre-en-place-un-dark-mode-simplement/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
					<title>Une présentation vidéo en HTML, CSS et JS</title>
					<link>https://chierchia.fr/2015/11/presentation-video-html-css-js/</link>
					<comments>https://chierchia.fr/2015/11/presentation-video-html-css-js/#respond</comments>
		
		<dc:creator><![CDATA[<span class='p-author h-card'>Ange Chierchia</span>]]></dc:creator>
		<pubDate>Mon, 30 Nov 2015 07:15:07 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://nighcrawl.com/blog/2015/11/presentation-video-html-css-js</guid>

					<description><![CDATA[Il y a déjà quelques mois, j’ai eu la tâche de trouver un moyen de présenter différent aspects d’une application que mes collègues et moi développons chez Ibakus Europe. L’idée était de faire une sorte de présentation vidéo expliquant les différents menus de l’application et que l’on puisse « naviguer » dans celle-ci, un peu comme une sorte de [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class='e-content'>Il y a déjà quelques mois, j’ai eu la tâche de trouver un moyen de présenter différent aspects d’une application que mes collègues et moi développons chez <a href="https://www.ibakus.com">Ibakus Europe</a>.</p>
<p>L’idée était de faire une sorte de présentation vidéo expliquant les différents menus de l’application et que l’on puisse « naviguer » dans celle-ci, un peu comme une sorte de PowerPoint vidéo.<span id="more-1345"></span></p>
<h2 id="premièreidée-à-chaud">Première idée, à chaud</h2>
<p>Au départ, mon idée était de réaliser un screencast en suivant un scénario d’utilisation de l’application puis d’utiliser un logiciel de montage vidéo, du genre After Effects pour placer les différentes info-bulles.</p>
<p>Mais ça voulait dire perdre la possibilité de modifier les textes des info-bulles une fois la vidéos montée, encodée et tout le toutim.</p>
<h2 id="ma-solution-presque-parfaite">Ma solution (presque parfaite)</h2>
<p>Je me suis alors demandé comment je pouvais bien faire pour garder la possibilité de modifier les info-bulles a posteriori.</p>
<p>Voilà où je suis arrivé : le principe était de réaliser plusieurs petits screencasts pour chaque menu dans lesquels on suivait le scénario et de les inclure dans un document HTML à l’aide de balises <code class="language-plaintext highlighter-rouge">&lt;video&gt;</code>.</p>
<p>Pour lire chaque morceaux de vidéos et afficher les info-bulles aux bons moments, on a utilisé JavaScript et CSS.</p>
<h3 id="structure-de-la-page-html">Structure de la page HTML</h3>
<p>Dans notre page HTML, nous allons créer un <code class="language-plaintext highlighter-rouge">&lt;div&gt;</code> auquel au ajoutera l’attribut <code class="language-plaintext highlighter-rouge">class="wrapper"</code>. Ce <code class="language-plaintext highlighter-rouge">div.wrapper</code> contiendra deux éléments &lt;div&gt;; le premier encapsulera nos info-bulles (<code class="language-plaintext highlighter-rouge">div.bubbles-holder</code>) et le second regroupera nos vidéos (<code class="language-plaintext highlighter-rouge">div.medias-holder</code>).</p>
<div class="language-plaintext highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code>&lt;div class="wrapper"&gt;
  &lt;a href="#step-1" id="start" data-media="1"&gt;Start&lt;/a&gt;
  &lt;div class="bubbles-holder"&gt;
    &lt;!-- ici, nos info-bulles --&gt;
  &lt;/div&gt;

  &lt;div class="medias-holder"&gt;
    &lt;!-- ici, nos vidéos --&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre>
</div>
</div>
<h4 id="les-info-bulles">Les info-bulles</h4>
<p>Chaque info-bulle est composée d’un paragraphe explicatif et de boutons permettant la navigation entre les vidéos.</p>
<p>Pour afficher l’info-bulle adéquate via JavaScript, elles auront toute une ID unique, du style <code class="language-plaintext highlighter-rouge">#step-X</code>.</p>
<p>Chaque bouton de navigation aura un attribut <code class="language-plaintext highlighter-rouge">data-media</code> qui permettra de savoir quelle vidéo doit être jouée lorsqu’on clique dessus.</p>
<p>Voici ce que ça donne.</p>
<div class="language-plaintext highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code>&lt;div class="bubbles-holder"&gt;
  &lt;div id="step-1" class="bubble"&gt;
    &lt;div class="bubble__content"&gt;
      &lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sapiente, eos.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="bubble__navigation"&gt;
      &lt;a data-media="1" href="#step-1" class="navigation__btn--replay"&gt;Replay&lt;/a&gt;
      &lt;a data-media="2" href="#step-2" class="navigation__btn--next"&gt;Next&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;!-- Les info-bulles suivantes --&gt;
&lt;/div&gt;
</code></pre>
</div>
</div>
<h4 id="les-vidéos">Les vidéos</h4>
<p>Pour les vidéos, rien de bien fou, simplement un ID qui nous servira dans le JavaScript et deux formats différents comme sources pour ainsi couvrir la majorité des navigateurs Web actuels.</p>
<div class="language-plaintext highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code>&lt;div class="medias-holder"&gt;
  &lt;div class="media" id="media-1"&gt;
    &lt;video class="media--video" id="video-1"&gt;
      &lt;source src="video-1.webm" type="video/webm"&gt;
      &lt;source src="video-1.mp4" type="video/mpeg"&gt;
    &lt;/video&gt;
  &lt;/div&gt;

  &lt;!-- les autres vidéos --&gt;
&lt;/div&gt;
</code></pre>
</div>
</div>
<h3 id="la-feuille-de-styles-css">La feuille de styles CSS</h3>
<p>Lorsque la page s’affiche on ne souhaite afficher que la première vidéo et un bouton « Start » qui permettra de jouer la présentation vidéo. Tout le reste doit être caché et ne sera affiché qu’au moment voulu, via JavaScript.</p>
<p>Voici ce que ça donne.</p>
<div class="language-plaintext highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code>.wrapper {
  height: 720px;
  margin: 0 auto;
  position: relative;
  width: 1080px;
}

.bubbles-holder,
.medias-holder  {
  display: block;
  position: absolute;
}

.bubbles-holder .bubble,
.medias-holder .media {
  display: none;
  position: absolute;
}

.medias-holder .media:fist-child {
  display: block;
}
</code></pre>
</div>
</div>
<p>Le reste de la feuille de styles CSS n’est pas important ici, il suffira juste d’ajouter des règles pour l’esthétisme de la page et de l’interface.</p>
<h3 id="gestion-des-évènements-enjavascript">Gestion des évènements en JavaScript</h3>
<p>Pour plus de facilité avec la gestion des évènements, j’utilise jQuery. Ce que l’on souhaite, c’est lancer la lecture d’une vidéo lorsqu’on clique sur un bouton de navigation (« Start », « Replay », « Next », « Prev »), et afficher l’info-bulle qui s’y rapporte.</p>
<div class="language-plaintext highlighter-rouge">
<div class="highlight">
<pre class="highlight"><code>$(document).on('click', 'a', function (event) {
  event.preventDefault(); // Permet d'annuler l'action normal d'un clic sur un lien hypertexte

  // On affiche uniquement la vidéo voulue  
  var media = $(this).attr('data-media');
  if (media !== undefined) {
    $('.media').hide(); // On cache tous les .media en display: block
    $('#media-' + media).show();
    
    // On force la vidéo à être jouée depuis le début (utile pour le clic sur 'Replay'
    var video = document.getElementById('video-' + media);
    video.pause();
    video.currentTime = 0;
    video.play();
  }

  // Si le clic ne s'est pas fait sur un bouton 'Replay', on cache toutes les info-bulles et on affiche seulement celle de la vidéo jouée
  var step = $(this).attr('href');
  if (href.length &gt; 0 &amp;&amp; $(this).hasClass('navigation__btn--replay') != true) {
    $('.bubble)"fadeOut('fast');
    $(href).delay(ac__getDelay(step)).fadeIn();
  }

  // Si on clic sur le bouton 'Start', on le cache en fondue
  if ($(this).attr('id') == "start")
    $(this).fadeOut('fast');
});
</code></pre>
</div>
</div>
<p>Et voilà ! Au clic sur un bouton de navigation (ou sur le bouton « Start »), on affiche la vidéo dont la référence est passée dans l’attribut <code class="language-plaintext highlighter-rouge">data-media</code> du bouton, puis on affiche l’info-bulle qui s’y rapporte dont la référence est passée dans l’attribut <code class="language-plaintext highlighter-rouge">href</code> du bouton.</p>
<p>Vous remarquerez l’appel de la fonction <code class="language-plaintext highlighter-rouge">ac__getDelay()</code> lors de l’affichage des info-bulles, je ne la détaillerai pas ici, mais c’est une fonction qui me permet de retourner un nombre de milli-secondes différent en fonction de l’info-bulle passée en paramètre.</p>
<h2 id="mission-accomplie-">Mission accomplie !?</h2>
<p>Je ne sais pas si avec mes collègues on a fait le bon choix en partant sur cette solution, mais le fait est que ça marche et que le rendu est plutôt sympa.</p>
<p>Par contre, si le contenu de la présentation vidéo est amené à changer régulièrement, ça peut-être fastidieux, car il faut enregistrer les screencasts, caler les délais d’affichage des info-bulles sur la vidéo, etc.</p>
<p>En tout cas, je pose ça là et vous en faites ce que vous voulez.</p>
<p>Tchô !</p>
<p>&nbsp;</p></div>
]]></content:encoded>
					
					<wfw:commentRss>https://chierchia.fr/2015/11/presentation-video-html-css-js/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
