<?xml version="1.0" encoding="UTF-8" ?>
    <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/layout/content/">
    <channel>
      <title>Lionel Péramo (en)</title>
      <link>https://lionel-peramo.com/</link>
      <description>A blog about web development and technology.</description>
      <language>en</language>
      <atom:link href="https://lionel-peramo.com/rss.xml" rel="self" type="application/rss+xml" />
      <item>
            <title>Web optimization: removing dead code with the Chrome Coverage tab</title>
            <link>https://lionel-peramo.com/posts/remove-unused-css-js-chrome-devtools-coverage/</link>
            <guid>https://lionel-peramo.com/posts/remove-unused-css-js-chrome-devtools-coverage/</guid>
            <pubDate>Thu, 26 Mar 2026 14:30:00 +0000</pubDate>
            <description>Learn how to identify unused JavaScript and CSS. This detailed technical guide helps you lighten your pages to boost your performance and SEO.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 8 min</p>
              
<p>The modern web is becoming increasingly heavy. Sites load massive files. Yet, a large part of this code is never used.
Developers often use complete libraries. They only use a small fraction of the functions. This surplus of data slows
down navigation. It consumes battery on mobile. It wastes bandwidth.</p>
<p>Google Chrome offers a very powerful integrated tool. It is called the <strong>Coverage</strong> tab. This tool analyzes your code as
you browse. It shows what is executed. Most importantly, it shows what remains inactive. Removing this dead code is a
priority for performance. It is essential for improving your <strong>Core Web Vitals</strong>.</p>
<h2>Why is dead code dangerous?</h2>
<p>Every byte sent has a technical cost. The browser follows a strict process to display a page.</p>
<h3>The impact on CSS rendering</h3>
<p>CSS blocks the page display. The browser must read the entire file before drawing. If your file is 200 KB but only 10 KB
are useful, you are wasting time. The user sees a white screen. This increases the <strong>LCP (Largest Contentful Paint)</strong>
score. A fast site retains its visitors better.</p>
<h3>The cost of JavaScript</h3>
<p>JavaScript is very expensive for the processor. The browser must download the file. Then, it must decompress it. Then,
it must parse and compile it. This work uses a lot of resources. On an old smartphone, this creates stutters. The
Coverage tool helps you reduce the <strong>TBT (Total Blocking Time)</strong>.</p>
<h2>How to open the Coverage tab?</h2>
<p>The tool is hidden in Chrome’s advanced options. Here are the steps to access it:</p>
<ol>
<li>Open your website in Chrome.</li>
<li>Open the developer tools with the <code>F12</code> key.</li>
<li>Press <code>Ctrl + Shift + P</code> (or <code>Cmd + Shift + P</code> on Mac).</li>
<li>A search bar appears.</li>
<li>Type the word “<strong>Coverage</strong>”.</li>
<li>Select the “<strong>Show Coverage</strong>” option.</li>
</ol>
<p>A new panel opens at the bottom of your window. To start the analysis, click the reload button. It is the icon with a
circular arrow. The page will refresh. The tool will then record every line of code used.</p>
<h2>Understanding data visualization</h2>
<p>The Coverage tab presents a complete table. Each row corresponds to a loaded file.</p>
<ul>
<li><strong>URL:</strong> The name and address of the file. This includes your scripts and styles.</li>
<li><strong>Type:</strong> Indicates whether it is JS or CSS.</li>
<li><strong>Total Bytes:</strong> The total weight of the file.</li>
<li><strong>Unused Bytes:</strong> The amount of code that was not used.</li>
<li><strong>Usage Visualization:</strong> A very useful horizontal bar.</li>
</ul>
<h3>Analyzing colors</h3>
<p>In this tool, the colors are simple to understand. The <strong>red</strong> bar represents code that has never been executed. The
grey bar represents useful code.</p>
<p>If you see a bar that is almost entirely red, the file is a problem. In the image above, some files show <strong>100% unused
code</strong>. This is a total loss of efficiency. This often happens with icon fonts or old tracking scripts.</p>
<h2>Detailed analysis in sources</h2>
<p>Click on a row in the table. The file opens in the <strong>Sources</strong> tab. Look to the left of the line numbers. Color strips
appear.</p>
<ul>
<li>A <strong>grey</strong> strip means the line was read by the browser.</li>
<li>A <strong>red</strong> strip means the line is ignored.</li>
</ul>
<h2>The human factor: interaction</h2>
<p>The Coverage tool is a live recorder. It cannot guess the future. When the page loads, everything related to dropdown
menus or pop-ups will be red. This is normal. The code has not been used yet.</p>
<p><strong>To obtain a reliable report:</strong></p>
<ol>
<li>Start the recording.</li>
<li>Browse your entire page.</li>
<li>Click on all the buttons.</li>
<li>Open the menus.</li>
<li>Scroll to the footer.</li>
</ol>
<p>You will see the red bars turn grey in real time. The code you really need reveals itself little by little.</p>
<h2>How to eliminate unnecessary code?</h2>
<p>Once the diagnosis is complete, you must act. Here are three methods to clean your project.</p>
<h3>1. Manual removal</h3>
<p>This is the simplest method for CSS. If the tool shows that entire styles are red across the whole site, delete them. It
is often old, forgotten code.</p>
<h3>2. Code splitting</h3>
<p>Do not load the code for your “Contact” page on your “Home” page. Split your scripts into small pieces. Only load them
when necessary. This is very easy to do with modern frameworks.</p>
<p>Here is an example of conditional loading in JavaScript:</p>
<pre><code class="language-js">const feedbackBtn = document.querySelector('.js-feedback');

if (feedbackBtn)
{
  import('./modules/feedback.js').then(module =&gt;
  {
    module.init();
  });
}
</code></pre>
<h3>3. Tree Shaking</h3>
<p>This is an automatic technique. It removes dead code during the site’s creation. For this, use tools like Vite or
Webpack. They analyze your code and remove what is not called.</p>
<pre><code class="language-js">// We only import what is useful
import {computeTotal} from './math-library.js';

const result = computeTotal(10, 20);
console.log(result);

// The multiply() function in math-library.js will remain unused
// It will not be included in the final file
</code></pre>
<h2>Browser extensions and the Coverage tab</h2>
<p>The image of the Coverage tab often shows lines starting with <code>chrome-extension://</code>. This is not your site’s code. These
are the scripts from your own extensions (like uBlock or LastPass).</p>
<p><strong>Warning:</strong> Do not confuse these files with your own assets. Focus only on files that start with <code>http://</code> or
<code>https://</code> with your domain name. Extensions consume a lot of resources. They can distort your performance tests. Always
test your site in <strong>Incognito</strong> mode to avoid this.</p>
<h2>Benefits for SEO and indexing</h2>
<p>A light site ranks better on Google. The search engine analyzes speed. If your JS files are too heavy, the Google bot
will spend less time indexing your pages. This is called the <strong>crawl budget</strong>.</p>
<p>By reducing dead code:</p>
<ul>
<li>The site loads faster.</li>
<li>User experience improves.</li>
<li>Bounce rate decreases.</li>
<li>Your Lighthouse score increases.</li>
</ul>
<h2>Conclusion</h2>
<p>The Coverage tab is a vital diagnostic tool. It allows you to see the invisible. In a few clicks, you identify the
culprits of slowness. Cleaning your code is a mark of respect for the user.</p>
<p>Start today. Open your tools. Launch an analysis. Every red line removed makes the web faster and greener.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Is it possible to reach 0% unused code?</summary>
It is almost impossible. A site needs code to handle errors. It needs code for future interactions. A rate of 20% unused
code is already an excellent result.
</details>
<details>
<summary>Does the Coverage tool work on Firefox?</summary>
Firefox has similar tools, but Chrome's Coverage tab is the most complete. It offers the most precise line-by-line
visualization.
</details>
<details>
<summary>Is dead code dangerous for security?</summary>
Yes. The more code you have, the more risk of vulnerabilities you have. Removing unnecessary code reduces the attack
surface. This is a good security practice.
</details>
<details>
<summary>Why is my CSS file 100% red on mobile?</summary>
It is probably a file dedicated to the desktop version (like <code>print.css</code>). The Coverage tool helps you see
that you are loading unnecessary files for certain screens.
</details>

            ]]></content:encoded>
        </item><item>
            <title>CSS corner-shape: The Complete Guide to Sculpting Your Interfaces</title>
            <link>https://lionel-peramo.com/posts/css-corner-shape-ultimate-guide/</link>
            <guid>https://lionel-peramo.com/posts/css-corner-shape-ultimate-guide/</guid>
            <pubDate>Tue, 24 Mar 2026 21:30:00 +0000</pubDate>
            <description>Learn how to use corner-shape to create beveled corners, notches, and superellipses. A simple technical guide to boost your performance and design.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 7 min</p>
              
<p>For a long time, the Web used only one shape for corners: the circular arc. While the <code>border-radius</code> property is
extremely useful, it is limited. It cannot create clipped right angles (bevels) or more complex shapes without external
help.</p>
<p>The <code>corner-shape</code> property changes this. It allows you to choose the <strong>shape</strong> of the corner without changing its *
<em>size</em>*. This is a performance revolution because everything is handled natively by the browser.</p>
<h2>Why use <code>corner-shape</code>?</h2>
<p>Previously, to create a beveled corner, we used images or complex masks. These methods slow down the site.
<code>corner-shape</code> offers three advantages:</p>
<ol>
<li><strong>Speed</strong>: The browser draws the shape directly.</li>
<li><strong>Lightweight</strong>: Less code and no images to load.</li>
<li><strong>Flexibility</strong>: The shape automatically adapts to the block size.</li>
</ol>
<p>Here is an example of fluid and high-performance code:</p>
<pre><code class="language-scss">.card {
  background-color : #1a1a1a;
  border-radius    : clamp(1rem * $font-size, 5vi, 3rem * $font-size);
  corner-shape     : bevel;
  inline-size      : 100%;
  padding          : 2rem * $font-size;
}
</code></pre>
<h2>The Four Basic Shapes</h2>
<p>The <code>corner-shape</code> property offers four simple keywords. Each keyword changes how the corner is traced.</p>
<h3>1. Round Mode</h3>
<p>This is the default value. The browser draws a quarter circle. This is exactly what <code>border-radius</code> does on its own.</p>
<h3>2. Bevel Mode</h3>
<p>The bevel cuts the corner with a straight line. It’s ideal for modern or industrial designs. The calculation is very
simple for the Graphics Processing Unit (GPU), making the rendering instantaneous.</p>
<h3>3. Scoop Mode</h3>
<p><code>Scoop</code> mode creates an inward curve. Imagine removing a circular piece from the corner of the block. This is very
difficult to achieve without this property.</p>
<h3>4. Notch Mode</h3>
<p>The notch creates a stair-shaped cutout. The corner consists of two straight lines meeting inside the block.</p>
<h2>The Superellipse: The Secret of High-End Design</h2>
<p>The <code>superellipse()</code> function is the most technical part of <code>corner-shape</code>. It allows for very smooth curves, often
called “squircles.”</p>
<h3>What is a Superellipse?</h3>
<p>It is a mathematical shape between a square and a circle. Unlike a circle, the curve starts very gently. There is no
visible break between the straight line and the start of the corner. Apple uses this shape extensively for its icons and
products.</p>
<pre><code class="language-scss">.premium-box {
  aspect-ratio  : 1 / 1;
  border-radius : 20%;
  corner-shape  : superellipse(2.5);
  inline-size   : min(20rem * $font-size, 80vi);
}
</code></pre>
<p>In this code, the number <code>2.5</code> is the mathematical exponent.</p>
<ul>
<li>If the number is <strong>2</strong>, it’s a perfect circle.</li>
<li>As the number increases, the corner becomes “fuller” and approaches a square.</li>
</ul>
<h2>How the Browser Renders These Shapes</h2>
<p>To ensure maximum performance, it is important to understand what happens inside the browser.</p>
<h3>The Rendering Pipeline</h3>
<p>When you use <code>corner-shape</code>, the browser follows these steps:</p>
<ol>
<li><strong>Layout Calculation</strong>: It defines the block size (the rectangle).</li>
<li><strong>Painting Phase</strong>: It draws the border with the chosen shape.</li>
</ol>
<p>The advantage of <code>corner-shape</code> is that it does not affect the <strong>layout</strong> stage. The block remains the same size
regardless of the corner shape. This prevents the browser from recalculating positions if the shape changes, for
example, during a hover effect.</p>
<h3>Hardware Acceleration</h3>
<p>Tracing shapes like bevels or superellipses is sent directly to the GPU. The GPU is designed to draw vectors very
quickly. This is much more efficient than using JavaScript filters or masks.</p>
<h2>Accessibility and Visual Comfort</h2>
<p>Good code must be readable by everyone, including assistive tools.</p>
<h3>Focus Indicators</h3>
<p>A major problem with old techniques was that the selection ring (when using the Tab key) remained rectangular. With
<code>corner-shape</code>, the browser adapts the focus ring to the shape of the corner.</p>
<pre><code class="language-scss">.interactive-element:focus-visible {
  outline        : .2rem * $font-size solid #4a90e2;
  outline-offset : .4rem * $font-size;
}
</code></pre>
<h3>Fluid Units</h3>
<p>We use <code>rem</code> and the <code>$font-size</code> variable so that the corners adapt to the user’s text size. If a person increases the
font size in their browser to read better, the corners will remain proportional, and the interface will stay clean.</p>
<h2>Summary for Developers</h2>
<p>To optimize your interface with <code>corner-shape</code>, remember these points:</p>
<ul>
<li><strong>Use bevel</strong> for a technical look and maximum performance.</li>
<li><strong>Use superellipse</strong> for a soft, luxury look.</li>
<li><strong>Use relative units</strong> (<code>rem</code>) to ensure the design is accessible.</li>
<li><strong>Avoid corner images</strong> to save precious milliseconds during loading.</li>
</ul>
<p><code>corner-shape</code> is the perfect tool for combining complex design with incredible loading speeds. It is the future of
high-performance web design.</p>
<p>The following demo is by Amit Sheen.</p>
<div class=video-facade>
  
  <video controls height=660 preload=none src=corner-shape-demo-660.m4v width=660>
    Your browser does not support video playback.
  </video>
</div>
<hr>
<h3>Frequently Asked Questions (FAQ)</h3>
<details>
<summary>Does <code>corner-shape</code> work with <code>box-shadow</code>?</summary>
Yes. The shadow follows the corner shape exactly. If you use a notch, the shadow will also have a notch. It is automatic
and very fast.
</details>
<details>
<summary>Does this replace <code>border-radius</code>?</summary>
No. They work together. <code>border-radius</code> defines the size of the corner area, and <code>corner-shape</code>
defines the drawing style within that area.
</details>
<details>
<summary>Why is performance better than with SVG?</summary>
Because the browser's CSS engine treats <code>corner-shape</code> as a primitive drawing instruction. An SVG file must
be read, parsed, and rasterized, which takes more time and memory.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Mastering contenteditable=plaintext-only: The Technical Guide for Clean and Secure Input</title>
            <link>https://lionel-peramo.com/posts/mastering-contenteditable-plaintext-only/</link>
            <guid>https://lionel-peramo.com/posts/mastering-contenteditable-plaintext-only/</guid>
            <pubDate>Wed, 18 Mar 2026 18:00:00 +0000</pubDate>
            <description>Say goodbye to HTML pollution in your input areas. Discover how `contenteditable=&quot;plaintext-only&quot;` radically transforms user input management for better security and performance.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 7 min</p>
              
<p>In modern interface development, managing user input is a constant challenge. You have likely encountered this problem:
a user copies and pastes rich text from a web page or a Word document into your comment area, and suddenly your layout
explodes, polluted by useless <code>&lt;span&gt;</code> tags, inline styles, or even malicious scripts.</p>
<p>For a long time, we used <code>textarea</code> for its simplicity, at the cost of complex auto-expansion management. Or, we forced
<code>contenteditable</code> by developing complex JavaScript “gas factories” to clean data on the fly.</p>
<p>There is now a native, robust, and extremely high-performance solution: the <code>contenteditable=&quot;plaintext-only&quot;</code>
attribute.</p>
<h2>What is contenteditable=“plaintext-only”?</h2>
<p>It is a specific value for the HTML <code>contenteditable</code> attribute. When applied to an element (usually a <code>div</code> or a
<code>span</code>), the browser strictly restricts input and pasting behavior.</p>
<p>Unlike the classic <code>contenteditable=&quot;true&quot;</code> mode which allows the creation of complex DOM structures (text nodes,
formatting tags, images), the <code>plaintext-only</code> mode imposes a strong constraint: <strong>only text characters and line breaks
are accepted</strong>.</p>
<p>Any pasted rich content is immediately converted to raw text by the browser’s rendering engine before it even reaches
your event handler.</p>
<h2>Why is it a strategic lever?</h2>
<h3>1. Security by design</h3>
<p>The first argument is security. By allowing rich text via <code>contenteditable=&quot;true&quot;</code>, you potentially expose yourself to
XSS (Cross-Site Scripting) vulnerabilities if your sanitization process is incomplete or bypassed.</p>
<p>With <code>plaintext-only</code>, the attack surface is drastically reduced. The browser does not interpret inserted HTML tags. An
attacker trying to inject <code>&lt;script&gt;alert(1)&lt;/script&gt;</code> will see these characters displayed as literal text, without any
execution. This is the principle of defense in depth through technological choice.</p>
<h3>2. Performance and User Experience (UX)</h3>
<p>In a context where every millisecond counts, avoiding heavy JavaScript processing is crucial.</p>
<ul>
<li><strong>DOM Reduction:</strong> No more need to parse complex DOM trees generated by malicious copy-pastes.</li>
<li><strong>Native Auto-expansion:</strong> By using a <code>div</code> with <code>contenteditable=&quot;plaintext-only&quot;</code>, you natively benefit from an area
that adapts to the content height, without complex JavaScript <code>input</code> event listeners to recalculate height (as was
the case for auto-adjusting <code>textarea</code>).</li>
</ul>
<h3>3. Content Consistency</h3>
<p>Your databases will receive uniform data. No more mixed fonts, disparate colors, and unexpected DOM structures that make
display or backend processing (like PDF generation or exporting) unpredictable.</p>
<h2>Technical Implementation</h2>
<p>Implementation is trivial but requires careful attention to CSS styling to maintain the appearance of an input area.</p>
<pre><code class="language-css">.input-field {
  /* Using clamp for fluid and reactive width */
  inline-size    : clamp(18.75rem, 50%, 50rem);
  min-block-size : 1.5em;
  padding        : .625rem;
  border         : .0625rem solid #ccc;
  /* Ensure readable typography */
  font-family    : sans-serif;

  /* Avoiding useless overrides with :not */

  &amp;:not([contenteditable='plaintext-only']) {
    border-color : red;
  }
}
</code></pre>
<p>Here is how to structure your HTML component:</p>
<pre><code class="language-html">
&lt;div
  class=&quot;input-field&quot;
  contenteditable=&quot;plaintext-only&quot;
  role=&quot;textbox&quot;
  aria-multiline=&quot;true&quot;
  placeholder=&quot;Enter your text here...&quot;&gt;
&lt;/div&gt;
</code></pre>
<h3>The role of accessibility</h3>
<p>It is essential to add <code>role=textbox</code> and <code>aria-multiline=true</code> so that assistive technologies understand that this is a
textual input field. Without this, the element is not correctly interpreted as a form control.</p>
<h2>Comparison with alternatives</h2>
<table>
<thead>
<tr>
<th align="left">Approach</th>
<th align="left">Security</th>
<th align="left">Performance</th>
<th align="left">Dev Effort</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>textarea</code></td>
<td align="left">High</td>
<td align="left">High</td>
<td align="left">Medium (auto-resize)</td>
</tr>
<tr>
<td align="left"><code>contenteditable=true</code></td>
<td align="left">Low</td>
<td align="left">Low</td>
<td align="left">Very High (sanitizing)</td>
</tr>
<tr>
<td align="left"><code>contenteditable=plaintext-only</code></td>
<td align="left">High</td>
<td align="left">High</td>
<td align="left">Very Low</td>
</tr>
</tbody>
</table>
<h2>Limitations and Best Practices</h2>
<p>While powerful, this mode has its limits:</p>
<ol>
<li><strong>Browser Support:</strong> It is widely supported in modern browsers (Chromium, WebKit). Always check compatibility if you
target very specific environments.</li>
<li><strong>Event Management:</strong> Even if the text is “clean,” you still need to handle <code>input</code> or <code>blur</code> events to capture the
data and send it to your backend.</li>
<li><strong>Placeholder:</strong> <code>contenteditable</code> does not support the <code>placeholder</code> attribute natively. You will need to use a CSS
trick with the <code>:empty</code> pseudo-class to display help text when the field is empty.</li>
</ol>
<pre><code class="language-css">[contenteditable='plaintext-only']:empty::before {
  content : attr(data-placeholder);
  color   : #888;
}
</code></pre>
<h2>Conclusion</h2>
<p>Switching to <code>contenteditable=&quot;plaintext-only&quot;</code> is not just a syntactic improvement. It is a paradigm shift that places
security and performance at the heart of your interface design. By delegating the formatting constraint to the browser,
you free up development time for higher value-added features while ensuring a consistent and fast user experience.</p>
<p>Do not wait to audit your current input fields and migrate to this native approach.</p>
<hr>
<h3>FAQ</h3>
<details>
<summary>Can I still allow emojis?</summary>
Yes. Emojis are standard Unicode characters. <code>plaintext-only</code> allows them perfectly because they do not
constitute HTML formatting.
</details>
<details>
<summary>How to retrieve the value with JavaScript?</summary>
You access the content exactly like any other element: use <code>element.innerText</code> or
<code>element.textContent</code> to retrieve the raw text.
</details>
<details>
<summary>What happens if the user tries to paste text with links?</summary>
The browser will automatically extract only the string from the link, without keeping the <code>&lt;a&gt;</code> tag or
the <code>href</code> attribute. The link will become non-clickable raw text.
</details>
<details>
<summary>Can I use this in a complex form?</summary>
Yes, but be careful: a <code>div</code> is not submitted automatically with the form like an <code>input</code> or
<code>textarea</code>. You must capture the content in JavaScript and inject it into a <code>hidden</code> field during
form submission.
</details>

            ]]></content:encoded>
        </item><item>
            <title>content-visibility and contain-intrinsic-size: Slash rendering time by 10 with two lines of CSS</title>
            <link>https://lionel-peramo.com/posts/css-rendering-performance-content-visibility-contain-intrinsic-size/</link>
            <guid>https://lionel-peramo.com/posts/css-rendering-performance-content-visibility-contain-intrinsic-size/</guid>
            <pubDate>Wed, 11 Mar 2026 17:40:00 +0000</pubDate>
            <description>Discover how content-visibility and contain-intrinsic-size revolutionize web performance by limiting rendering to visible content, boosting your Core Web Vitals.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 7 min</p>
              
<p>In the frantic race for web performance, every millisecond saved on the <strong>Main Thread</strong> is a victory. While we have long
relied on complex JavaScript libraries to manage lazy rendering, modern CSS brings a native solution of formidable
efficiency: <code>content-visibility</code>.</p>
<p>The problem is simple: the heavier a DOM page is, the more time the browser spends calculating the layout and painting
elements, even those located 5000 pixels below the fold. By using <code>content-visibility</code>, you instruct the browser to skip
the rendering work for off-screen elements.</p>
<h2>The hidden cost of invisible rendering</h2>
<p>When a browser loads a page, it performs a series of critical steps: building the DOM, the CSSOM, then calculating
style, layout (geometry), and finally the “paint” (drawing pixels). On a page containing thousands of nodes, this stage
can paralyze the processor for several hundred milliseconds.</p>
<p>This is where the concept of <strong>containment</strong> comes in. Historically, the <code>contain</code> property allowed isolating parts of
the DOM to prevent the recalculation of a small component from triggering a recalculation of the entire page.
<code>content-visibility</code> is the logical and automated evolution of this concept.</p>
<h2>1. <code>content-visibility: auto</code>, the smart rendering engine</h2>
<p>The <code>auto</code> value is the most powerful. It allows the browser to determine whether an element is in the viewport (the
visible area) or not. If the element is far from the user’s view, the browser:</p>
<ul>
<li>Does not calculate the layout of its children.</li>
<li>Does not paint its content.</li>
<li>Treats it as if it had strict “containment”.</li>
</ul>
<p>As soon as the user scrolls and approaches the element, the browser triggers rendering just in time.</p>
<h3>Technical implementation</h3>
<p>Here is how to apply this optimization to page sections smoothly, using <code>clamp()</code> to adapt dynamically to screen size
without media queries.</p>
<pre><code class="language-css">.optimized-section {
  content-visibility     : auto;
  /* Using clamp for fluid management of reserved space */
  contain-intrinsic-size : auto clamp(25rem, 60vh, 75rem);
}

/* Avoiding unnecessary overrides on already visible sections */
.optimized-section:not([data-priority='high']) {
  margin-block : clamp(1rem, 5%, 3rem);
}
</code></pre>
<h2>2. The scroll jump problem: <code>contain-intrinsic-size</code></h2>
<p>Using <code>content-visibility: auto</code> alone has one major flaw: the browser assumes the unrendered element has a height of
<strong>0px</strong>. As the user scrolls, the element is rendered, its actual height is calculated, and all content below it “jumps”
abruptly.</p>
<p>This is a disaster for <strong>CLS (Cumulative Layout Shift)</strong>, a key Google indicator for SEO.</p>
<p>To fix this, we use <code>contain-intrinsic-size</code>. This property acts as a placeholder or fallback size. It tells the
browser: “Even if you don’t render this element, reserve this space”.</p>
<h3>Modern and precise syntax</h3>
<p>It is now possible to use <code>auto</code> combined with a size value. If the browser has already rendered the element once, it
will remember its actual size instead of using the estimated value, making the scroll perfectly fluid.</p>
<pre><code class="language-css">.dynamic-card-container {
  content-visibility     : auto;
  /* Defining intrinsic width and height */
  contain-intrinsic-size : auto 100% auto clamp(15.625rem, 30vh, 31.25rem);
}
</code></pre>
<h2>3. SEO and Accessibility: What impact?</h2>
<p>This is the question all SEO experts ask: if the content is not rendered, can Google see it?</p>
<p>The answer is <strong>yes</strong>. <code>content-visibility: auto</code> does not hide DOM content the same way <code>display: none</code> does. The
content remains accessible in the render tree for search engines and screen readers. However, since the content is not “
painted”, it is recommended not to use it on critical text elements for immediate accessibility (like the main
navigation menu).</p>
<h3>Why it is good for your SEO</h3>
<ol>
<li><strong>LCP (Largest Contentful Paint):</strong> By freeing the processor from useless rendering tasks, the browser can focus on
the main element of the page.</li>
<li><strong>INP (Interaction to Next Paint):</strong> Less rendering work means a main thread that is more responsive to user clicks
and interactions.</li>
</ol>
<h2>4. Advanced optimization strategies</h2>
<p>To maximize performance, you should not apply these properties to every small element. The trick is to target “chunks”
or logical sections of your page.</p>
<pre><code class="language-css">main &gt; section:not(:first-child) {
  content-visibility     : auto;
  contain-intrinsic-size : auto 50rem;
}
</code></pre>
<p>In this example, we leave the first section (often above the fold) alone for immediate rendering, while optimizing all
subsequent sections.</p>
<h2>5. Comparison: CSS vs JavaScript (Intersection Observer)</h2>
<p>Before this property, we used the <code>IntersectionObserver</code> API to add or remove CSS classes. Here is why the native method
is superior:</p>
<ul>
<li><strong>Raw performance:</strong> CSS runs at the rendering engine level, not in the JavaScript virtual machine.</li>
<li><strong>Zero delay:</strong> The browser knows exactly when to start rendering to avoid white flashes, which is very difficult to
synchronize perfectly in JS.</li>
<li><strong>Lightness:</strong> Less JS means less code to download, parse, and execute.</li>
</ul>
<h2>Conclusion: A giant leap for web performance</h2>
<p>Implementing <code>content-visibility</code> and <code>contain-intrinsic-size</code> represents one of the most cost-effective optimizations
in terms of “effort / gain” ratio. With just a few lines of code, you can transform a heavy, stuttering page into a
fluid, app-grade experience.</p>
<p>This is the essence of modern engineering: delegating intelligence to the browser to focus on the added value of your
interface.</p>
<hr>
<h3>FAQ</h3>
<details>
<summary>Does <code>content-visibility</code> work on all browsers?</summary>
The property has been supported by Chrome, Edge, and Opera since version 85. Safari recently integrated it. For
incompatible browsers, it is ignored without breaking your site (Progressive Enhancement).
</details>
<details>
<summary>Can <code>content-visibility</code> be used to hide content intentionally?</summary>
Yes, the <code>hidden</code> value is similar to <code>display: none</code> but it keeps the rendering state in memory,
allowing for much faster reappearance. It is ideal for tab systems.
</details>
<details>
<summary>How to choose the right value for <code>contain-intrinsic-size</code>?</summary>
Use the inspector (F12) to measure the average height of your sections on desktop and mobile. Using <code>clamp()</code>
allows providing an estimate that adapts to the viewport width.
</details>
<details>
<summary>Is it risky for CLS?</summary>
Only if you forget <code>contain-intrinsic-size</code>. Without it, the scrollbar can "jump", which degrades the user
experience and penalizes your SEO score.
</details>

            ]]></content:encoded>
        </item><item>
            <title>CompressionStream API: Optimize Your Data Transfers Natively</title>
            <link>https://lionel-peramo.com/posts/compression-stream-api-native-performance/</link>
            <guid>https://lionel-peramo.com/posts/compression-stream-api-native-performance/</guid>
            <pubDate>Sun, 08 Mar 2026 18:10:00 +0000</pubDate>
            <description>Learn how to reduce data weight without bloating your code. A complete guide to the native compression API for faster web applications.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 8 min</p>
              
<p>On the modern web, speed is a priority. Every byte sent between a server and a user impacts loading time. Heavier data
makes applications feel slow, especially on mobile devices or poor connections.</p>
<p>Until recently, client-side data compression required importing massive third-party libraries
like <a href="https://github.com/nodeca/pako">pako</a> or <a href="https://github.com/nodejs/node/blob/main/lib/zlib.js">zlib.js</a>. These
tools add weight to your application before it even starts working. Today, a built-in solution exists: the
<strong>CompressionStream API</strong>.</p>
<h2>Why compress data on the client side?</h2>
<p>Most developers think compression is a task reserved for the server. This is often true for downloading pages. However,
in data-rich applications, the client (the browser) often needs to send large amounts of information to the server.</p>
<p>Here are some situations where native compression is useful:</p>
<ol>
<li><strong>Sending logs:</strong> If your application sends detailed error reports.</li>
<li><strong>Saving documents:</strong> For online text or drawing editors.</li>
<li><strong>Local storage:</strong> To save more information in the browser database (IndexedDB) without saturating the user’s disk
space.</li>
</ol>
<h2>What is the CompressionStream API?</h2>
<p>This programming interface (API) allows you to compress and decompress data streams natively. “Native” means the code is
already present in the browser. You do not need to download anything extra.</p>
<p>It uses streams. A stream is a way to process data bit by bit, like water flowing through a pipe, rather than waiting
for the entire bucket to be full. This prevents using too much memory (RAM) on the user’s device.</p>
<h2>Available algorithms</h2>
<p>The API offers three main formats to transform your data:</p>
<ul>
<li><strong>GZIP</strong>: The most common format on the Internet. It offers an excellent balance between final file size and
calculation speed.</li>
<li><strong>DEFLATE</strong>: A very fast basic algorithm.</li>
<li><strong>DEFLATE-RAW</strong>: A version of Deflate without header information, used for specific technical needs.</li>
</ul>
<h2>Practical application: compressing data</h2>
<p>To use this API, we create a compression stream. Here is how to transform simple text into compressed data.</p>
<pre><code class="language-js">/**
 * Compresses a string into GZIP
 * @param {string} inputData
 * @returns {Promise&lt;Uint8Array&gt;}
 */
async function compressData(inputData)
{
  const
    encoder = new TextEncoder(),
    rawData = encoder.encode(inputData),

    // Create a stream from raw data
    stream = new Blob([rawData]).stream(),
    compressionStream = new CompressionStream('gzip'),

    // Pass data through the compressor
    compressedStream = stream.pipeThrough(compressionStream),

    response = new Response(compressedStream),
    buffer = await response.arrayBuffer();

  return new Uint8Array(buffer);
}
</code></pre>
<h2>Doing the opposite: decompression</h2>
<p>If you receive compressed data from the server or your local database, you must make it readable again.</p>
<pre><code class="language-js">/**
 * Decompresses GZIP data to get text
 * @param {Uint8Array} compressedData
 * @returns {Promise&lt;string&gt;}
 */
async function decompressData(compressedData)
{
  const
    decompressionStream = new DecompressionStream('gzip'),

    // Create a readable stream for the decompressor
    stream = new ReadableStream(
      {
        start(controller)
        {
          controller.enqueue(compressedData);
          controller.close();
        }
      }),

    decompressedStream = stream.pipeThrough(decompressionStream),
    response = new Response(decompressedStream);

  return await response.text();
}
</code></pre>
<h2>The importance of streaming</h2>
<p>The strength of this API lies in its ability to process huge files without freezing the computer. If you try to compress
a 1 GB file all at once, the browser might close the tab due to lack of memory.</p>
<p>With the <code>pipeThrough</code> system, data flows in small segments. This is called backpressure management. The system
automatically adapts to the processing speed of the device.</p>
<h2>Design optimization and accessibility</h2>
<p>Technical performance is not enough. The user must understand what is happening. If compression takes time, a fluid
progress bar should be displayed.</p>
<p>Let’s use modern CSS to create an indicator that adapts to all screen sizes using fluid properties.</p>
<pre><code class="language-css">.progress-container {
  /* Use clamp for fluid and responsive width without media queries */
  inline-size      : clamp(15rem, 50vw + 2rem, 100%);
  background-color : #f0f0f0;
  border-radius    : .5rem;
  padding          : .25rem;
}

.progress-bar {
  block-size       : 1rem;
  background-color : #007bff;
  border-radius    : .25rem;
  /* Optimization: Only apply transition if the user doesn't prefer reduced motion */
  transition       : width .2s ease-in-out;
}

/* Use :not to avoid CSS overrides and keep the code clean */
@media (prefers-reduced-motion : reduce) {
  .progress-bar:not(.static) {
    transition : none;
  }
}
</code></pre>
<h2>Impact on SEO</h2>
<p>Google and other search engines use robots to analyze your site. These robots reward sites that are lightweight and
resource-efficient.</p>
<ol>
<li><strong>Reduction in total weight</strong>: Less JavaScript code to download means a better “Core Web Vitals” score.</li>
<li><strong>Interaction speed</strong>: By compressing outgoing data, you free up the user’s bandwidth faster, making the application
more responsive.</li>
<li><strong>Mobile experience</strong>: A site that saves its users’ mobile data is better ranked and more appreciated.</li>
</ol>
<h2>When to avoid using this API?</h2>
<p>There are cases where compression is useless or even counterproductive:</p>
<ul>
<li><strong>Already compressed files</strong>: Images (JPG, PNG), videos (MP4), and PDF files are already compressed. Trying to
compress them again with GZIP can sometimes make the file larger.</li>
<li><strong>Small data</strong>: If your text is less than 100 bytes, compression will add structure information that will make the
final result larger than the original.</li>
</ul>
<h2>Browser compatibility</h2>
<p>The CompressionStream API is available on almost all recent browsers (Chrome, Firefox, Safari, Edge). However, for older
systems, it is important to check if the tool exists before using it.</p>
<pre><code class="language-js">console.log(
  ('CompressionStream' in window)
    ? 'Native compression is available!'
    : 'Using a slower alternative method.'
);
</code></pre>
<h2>Conclusion: a step towards a cleaner web</h2>
<p>Using the CompressionStream API is a smart decision for any performance-conscious developer. It allows for removing
unnecessary dependencies, reducing memory consumption, and improving the overall user experience.</p>
<p>In 2026, the quality of an application is not only measured by its features, but by its ability to be lightweight and
respectful of the user’s resources. Native compression is one of the best tools to achieve this goal.</p>
<hr>
<h3>Frequently Asked Questions (FAQ)</h3>
<details>
<summary>Does compression slow down the user's CPU?</summary>
Any compression requires effort from the processor. However, the native API is optimized by browser creators. It is much faster and more battery-efficient than old libraries manually written in JavaScript.
</details>
<details>
<summary>Can I compress multiple files into one?</summary>
No, the CompressionStream API compresses one data stream at a time. To create an archive containing multiple files (like a .zip), you will need to use an additional data structure to organize your files before compressing them.
</details>
<details>
<summary>Is GZIP the best format?</summary>
It is the most compatible. If you send data to a standard web server, GZIP is often automatically recognized. It is therefore the safest choice for most projects.
</details>

            ]]></content:encoded>
        </item><item>
            <title>OKLCH: The Ultimate Guide to Mastering Perceptual Colors in CSS</title>
            <link>https://lionel-peramo.com/posts/oklch-css-ultimate-guide-perceptual-colors/</link>
            <guid>https://lionel-peramo.com/posts/oklch-css-ultimate-guide-perceptual-colors/</guid>
            <pubDate>Wed, 04 Mar 2026 22:30:00 +0000</pubDate>
            <description>HSL is dead, long live OKLCH. Learn why this format changes everything for accessibility, performance, and modern web interface design.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 8 min</p>
              
<p>Web development is a quest for precision. We optimize our scripts. We reduce image weight. Yet, we often use obsolete
color tools. The RGB format dates back to the first tube monitors. The HSL format was created to simplify mathematical
calculations. None of these formats understand how your eyes work.</p>
<p><strong>OKLCH</strong> changes everything. It is not just a new syntax. It is a new way to calculate light in the browser. In this
guide, we will explore in depth why you must adopt it today.</p>
<h2>Why HSL Has Always Fooled Us</h2>
<p>You might think that changing lightness in HSL is enough. This is a common mistake. In HSL, the ‘Lightness’ (L) value is
relative to the mix of primary colors. It does not account for the sensitivity of the human retina.</p>
<h3>The Yellow and Blue Experiment</h3>
<p>Let us perform a simple test. Take a pure yellow (<code>hsl(60, 100%, 50%)</code>). Take a pure blue (<code>hsl(240, 100%, 50%)</code>). Both
have a lightness of 50%. However, if you turn this image into black and white, the yellow will look almost white. The
blue will look almost black.</p>
<p>Why? Because the human eye perceives yellow as naturally brighter than blue. If you create an interface with these two
colors in HSL, your contrasts will be wrong. You will have to correct each color by hand. This is a huge waste of time
for a developer.</p>
<h2>The Solution: OKLCH and Human Perception</h2>
<p>The OKLCH color space is ‘perceptually uniform’. This means the numbers match what you see. If two colors have an ‘L’
(Lightness) of ‘0.7’, they will have exactly the same clarity to a human.</p>
<h3>Understanding the Three Components</h3>
<ol>
<li><strong>L (Lightness):</strong> The clarity. It goes from ‘0’ (total black) to ‘1’ (pure white). Unlike HSL, ‘0.5’ in OKLCH is
always perceived as a perfect medium gray.</li>
<li><strong>C (Chroma):</strong> The strength of the color. It starts at ‘0’. The higher the number, the more vivid the color. It is
more precise than saturation because it does not depend on lightness.</li>
<li><strong>H (Hue):</strong> The tint. It is the angle on the color wheel from ‘0’ to ‘360’.</li>
</ol>
<pre><code class="language-css">/* Using variables for optimal performance */
:root {
  --hue-brand   : 260;
  --chroma-main : .12;

  /* We define lightness fluidly based on screen size */
  --light-fluid : clamp(.4, 2vw + .1, .8);
}

.main-container *:not(footer) {
  background-color : oklch(var(--light-fluid) var(--chroma-main) var(--hue-brand));
}
</code></pre>
<h2>Performance and Code Optimization</h2>
<p>In a high-performance context, CSS structure is vital. OKLCH allows writing less code to achieve more results.</p>
<h3>Automatic and Predictable Dark Mode</h3>
<p>In HSL, switching to dark mode is a headache. You change the ‘L’, but the color often becomes too saturated or shifts
hue visually. In OKLCH, you simply lower the ‘L’. The hue and purity remain strictly identical.</p>
<pre><code class="language-css">[data-theme='dark'] {
  /* We halve the lightness without altering the color */
  --light-fluid : .2;
}

.article-content {
  color : oklch(var(--light-fluid) var(--chroma-main) var(--hue-brand));
}
</code></pre>
<h3>Optimizing Color Animation Fluidity</h3>
<p>The browser calculates OKLCH colors natively. By using CSS Variables with OKLCH, you avoid heavy recalculations. The GPU
can interpolate these values very quickly during transitions. This ensures a 60 frames per second (FPS) rendering.</p>
<h2>Impact on SEO and Accessibility</h2>
<p>Google uses algorithms to check if your text is readable. If your contrasts are poor, your SEO score drops.</p>
<h3>Towards the WCAG 3 Standard (APCA)</h3>
<p>Future accessibility standards (APCA) will favor models like OKLCH. Why? Because they are closer to physical reality. By
using OKLCH today, you prepare your site for tomorrow’s standards.</p>
<h3>Simplified Contrast Algorithm</h3>
<p>With OKLCH, you no longer need complex tools to check your colors. You can define a simple rule for your team: ‘The text
must always have an L that differs by 0.5 from the background’. This rule will work for ALL colors in the spectrum. This
is a major productivity gain.</p>
<pre><code class="language-css">.badge {
  /* Light background */
  background-color : oklch(.9 .05 var(--hue-brand));

  /* Dark text guaranteed readable on 0.9 background */
  color            : oklch(.2 .05 var(--hue-brand));
}
</code></pre>
<h2>The P3 Gamut: Pushing Screen Limits</h2>
<p>Most developers remain stuck in ‘sRGB’. It is an old, limited color space. Recent screens (OLED, Retina) support *
<em>Display P3</em>*.</p>
<p>OKLCH is the bridge to this universe. It allows you to declare colors that do not exist in RGB or HSL. These colors are
more vibrant and deeper. They draw the eye to your Call to Action (CTA) buttons.</p>
<h3>A Risk-Free Transition</h3>
<p>If the user has an old screen, the browser performs the calculation. It finds the closest possible color. This is called
progressive enhancement. You offer the best to modern users without breaking the experience for others.</p>
<h2>Methodology: How to Migrate an Existing Project?</h2>
<p>Switching to OKLCH requires a rigorous method to maintain performance.</p>
<ol>
<li><strong>Identify Hues:</strong> List your current colors (Hex or HSL).</li>
<li><strong>Convert:</strong> Use converters to find the OKLCH equivalent.</li>
<li><strong>Parameterize:</strong> Create variables for Hue (H) and Chroma (C).</li>
<li><strong>Adjust:</strong> Use Lightness (L) to create your shades (hover, active, focus).</li>
</ol>
<pre><code class="language-css">.button-action {
  /* Avoid media queries with clamp */
  --btn-width      : clamp(6.25rem, 15vw, 16.25rem);

  width            : var(--btn-width);
  background-color : oklch(.6 .2 150);
}

.button-action:hover {
  /* Simple and clean clarity increase */
  background-color : oklch(.7 .2 150);
}
</code></pre>
<h2>Conclusion: Modern Code Craftsmanship</h2>
<p>OKLCH is not an option. It is a necessity for any developer who cares about software quality. It provides:</p>
<ul>
<li>Mathematical and reliable <strong>accessibility</strong>.</li>
<li>Optimal rendering <strong>performance</strong>.</li>
<li>Increased <strong>maintainability</strong> through logical variables.</li>
<li>Strengthened <strong>SEO</strong> via perfect contrasts.</li>
</ul>
<p>In 2026, the web must be inclusive and fast. By mastering OKLCH, you regain total control over the light in your
interfaces. Your sites will not just be more beautiful. They will be more accurate.</p>
<hr>
<h3>Frequently Asked Questions (FAQ)</h3>
<details>
<summary>Does OKLCH completely replace the HEX format?</summary>
Yes. The HEX format is a relic of the past. It is hard for a human to read and does not support transparency natively in
a simple way. OKLCH is superior in every way for modern development.
</details>
<details>
<summary>Why is Chroma (C) sometimes a small number like 0.1?</summary>
Chroma is not a percentage. It is a measure of intensity. For most web interfaces, a value between 0.01 and 0.3 is more
than enough. Beyond 0.4, you enter extremely vivid colors that may not display on all screens.
</details>
<details>
<summary>How to handle support for old browsers?</summary>
Support is excellent (90%+ of users). For remaining browsers, you can use an automatic fallback via PostCSS or write a
simple rule: <code>color: rgb(0, 100, 0); color: oklch(0.5 0.2 150);</code>. The browser will ignore the second line if
it does not understand it.
</details>
<details>
<summary>Can OKLCH be used with gradients?</summary>
Absolutely. OKLCH gradients are magnificent. They do not pass through the 'dead gray' in the middle of the gradient like
RGB gradients do. The transition is organic and vibrant.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Web Compatibility and Accessibility: The Guide to 5 Technical Tools</title>
            <link>https://lionel-peramo.com/posts/web-compatibility-accessibility-tools/</link>
            <guid>https://lionel-peramo.com/posts/web-compatibility-accessibility-tools/</guid>
            <pubDate>Tue, 03 Mar 2026 19:00:00 +0000</pubDate>
            <description>Learn how to use CanIUse, CanIEmail, A11y Support, CanInclude, and Can I PHP. This guide helps you code without errors on all platforms.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 7 min</p>
              
<p>Web development is a complex job. Creating a site is not enough. Your code must work everywhere. It must work on all
screens. It must work for all users.</p>
<p>There are many different browsers. There are many email applications. Some servers use old technologies. These
differences create errors. We call these compatibility problems.</p>
<p>A technical error drives your customers away. It also blocks people with disabilities. It prevents search engines from
reading your site.</p>
<p>To succeed, you must check your code. Here are 5 tools to code with precision.</p>
<h2>1. CanIUse: Checking Web Browsers</h2>
<p><strong>Link:</strong> <a href="https://caniuse.com/">https://caniuse.com/</a></p>
<p>CanIUse is a huge database. It lists web features. It shows which browsers accept your code. It covers Chrome, Firefox,
Safari, and Edge.</p>
<h3>Why Use This Tool?</h3>
<p>Browsers do not evolve at the same speed. A feature might work on Chrome but not on Safari. CanIUse displays color
tables.</p>
<ul>
<li><strong>Green:</strong> The code works well.</li>
<li><strong>Red:</strong> The code does not work.</li>
<li><strong>Yellow:</strong> The code works sometimes.</li>
</ul>
<h3>Technical CSS Code Example</h3>
<p>Modern CSS allows you to write fewer lines. We use mathematical functions for element sizes. We also use selectors to
exclude objects.</p>
<p>Here is a very high-performance code example:</p>
<pre><code class="language-css">/* Container with fluid width */
.main-wrapper {
  width         : min(100% - 2rem, 75rem);
  margin-inline : auto;
}

/* Text size adapts to the screen */
.main-title {
  font-size : clamp(1.25rem, 4vw + 1rem, 2.5rem);
}

/* Style only elements that are not disabled */
.action-link:not(.is-disabled) {
  color           : '#05f';
  text-decoration : underline;
}
</code></pre>
<p>Before copying this code, go to CanIUse. Type <code>min</code>, <code>clamp</code>, or <code>:not</code>. The tool gives you the percentage of compatible
users. If the score is high, you can code. If the score is low, you must change your method. This avoids breaking the
display for your customers.</p>
<h2>2. CanIEmail: Email Compatibility</h2>
<p><strong>Link:</strong> <a href="https://www.caniemail.com/">https://www.caniemail.com/</a></p>
<p>Sending an HTML email is very difficult. Email applications are old. They do not read code like a browser. Outlook is
the most difficult application. It uses the Microsoft Word engine to display emails.</p>
<h3>The Dangers of Code in Emails</h3>
<p>Many CSS properties are forbidden in emails. CanIEmail tests over 50 applications. It also tests over 170 features.</p>
<p>If you use bad code, the email will be unreadable. The user will delete your message. CanIEmail saves you time. It shows
you what is safe. Often, you must use HTML tables for the structure. It is an old but very solid technique. The tool
helps you choose between design and compatibility.</p>
<h2>3. A11y Support: The Accessibility Tool</h2>
<p><strong>Link:</strong> <a href="https://a11ysupport.io/">https://a11ysupport.io/</a></p>
<p>Web accessibility allows disabled people to use the internet. Blind people use screen readers. This software reads the
code aloud. But not all screen readers read the same thing.</p>
<h3>Why Check A11y Support?</h3>
<p>A code can be correct for the W3C. Yet, software might not understand it. A11y Support lists these problems. It compares
browsers and screen readers.</p>
<p>The tool tests ARIA attributes. It also tests HTML roles.</p>
<ul>
<li>It prevents making a site invisible to a blind person.</li>
<li>It ensures your buttons are usable with a keyboard.</li>
<li>It makes your site truly inclusive.</li>
</ul>
<p>Always check your interactive components on this tool. It is a mandatory step for quality.</p>
<h2>4. CanInclude: Validating HTML Structure</h2>
<p><strong>Link:</strong> <a href="https://caninclude.glitch.me/">https://caninclude.glitch.me/</a></p>
<p>The HTML language has precise rules. We call this semantics. Some tags cannot go inside other tags. CanInclude checks
these rules for you.</p>
<h3>The Risks of a Bad Structure</h3>
<p>Nesting your tags incorrectly creates bugs. The browser must make efforts to fix your errors. This slows down the page
display.</p>
<p>A bad structure also loses Google robots. Google uses HTML to understand your topic. If the HTML is wrong, your SEO
drops. CanInclude is very simple. You provide the parent tag. You provide the child tag. The tool answers ‘Yes’ or ‘No’.
It is fast and efficient.</p>
<h2>5. Can I PHP: Server Compatibility</h2>
<p><strong>Link:</strong> <a href="https://caniphp.com/">https://caniphp.com/</a></p>
<p>PHP code runs on the server. PHP changes versions often. Each version brings new functions. If your server is old, your
recent code will crash.</p>
<h3>Securing Your Backend</h3>
<p>A PHP error stops the entire site. The user sees a white page. We call this a fatal error. This is very bad for your
business.</p>
<p>Can I PHP gives you the minimum version for each function. Here is an example of modern PHP code:</p>
<pre><code class="language-php">&lt;?php

/* Check a string with a modern function in PHP
 * This requires PHP 8.0 or higher */
function check_user_access(string $role)
{
  if (str_contains($role, 'admin'))
    return 'Access granted';

  return 'Access denied';
}
</code></pre>
<p>Go to Can I PHP. Type <code>str_contains</code>. The tool will tell you: ‘PHP 8.0’. If your server uses PHP 7.4, the code will
break. You will have to use an old function like <code>strpos</code>. This tool protects your server against crashes.</p>
<h2>Conclusion</h2>
<p>Performance depends on compatibility. A good developer always checks their tools.</p>
<ul>
<li><strong>CanIUse</strong> secures your styles and scripts.</li>
<li><strong>CanIEmail</strong> makes your emails readable everywhere.</li>
<li><strong>A11y Support</strong> opens your site to everyone.</li>
<li><strong>CanInclude</strong> validates your HTML structure.</li>
<li><strong>Can I PHP</strong> protects your server from errors.</li>
</ul>
<p>Use these tools every day. Your code will be stronger. Your users will be happier. Your site will be faster.</p>
<hr>
<h3>Frequently Asked Questions (FAQ)</h3>
<details>
<summary>Are these tools free?</summary>
Yes. All these tools are free. they are maintained by volunteer experts.
</details>
<details>
<summary>Which tool is the most important?</summary>
All are important. But CanIUse is the one used most often. It is the base of the developer profession.
</details>
<details>
<summary>Why test accessibility?</summary>
It is a legal obligation in many countries. It is also an ethical choice to leave no one behind.
</details>
<details>
<summary>Can I use these tools on mobile?</summary>
Yes. All these sites work on smartphones. You can check a function anywhere.
</details>

            ]]></content:encoded>
        </item><item>
            <title>PHP on the Desktop: Mastering BosonPHP for Ultra-High Performance Native Applications</title>
            <link>https://lionel-peramo.com/posts/php-desktop-native-applications-bosonphp/</link>
            <guid>https://lionel-peramo.com/posts/php-desktop-native-applications-bosonphp/</guid>
            <pubDate>Thu, 26 Feb 2026 15:00:00 +0000</pubDate>
            <description>BosonPHP (v0.19.5) turns PHP into a formidable alternative to Electron. Explore the FFI architecture, framework integration via Bridges, and memory management to build native desktop apps.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 10 min</p>
              
<p>For over twenty years, PHP has reigned supreme over the web backend. Its execution model was immutable: an HTTP request
comes in, a process is born, generates a response, and then dies. But those days are over. The introduction and
maturation of the <strong>FFI (Foreign Function Interface)</strong> extension have opened a breach into which new architectures are
flooding.</p>
<p>Today, the <strong>BosonPHP</strong> project stands as the new frontier of the ecosystem. It is not just a localized web server, but
a true open-source runtime (MIT licensed) designed to run PHP code as a native desktop application. Gone is the
excessive weight of Chromium and Node.js inherent to the Electron ecosystem. Welcome to direct, ultra-lightweight, and
lightning-fast execution.</p>
<h2>BosonPHP 0.19.5: Anatomy of a Desktop Kernel</h2>
<p>The project’s official slogan on GitHub perfectly summarizes its philosophy: <em>“Because it’s not an Electron!”</em>.</p>
<p>The traditional approach to building desktop apps with web technologies involves embedding a full browser within each
application. The result? A basic app often consumes over 200 MB of RAM at rest and carries significant weight on the
disk.</p>
<p>BosonPHP takes the opposite path. In its current version <strong>0.19.5</strong>, the system relies on high-level bindings to
<strong>Saucer v6.0</strong>, an ultra-lightweight C++ library dedicated to creating smart WebView windows. BosonPHP wraps your code
in the native WebView engine provided by the operating system (Edge WebView2 on Windows, WebKit on macOS and Linux). The
final compiled application weighs only a few dozen megabytes.</p>
<h3>The Strategic Choice of PHP 8.4</h3>
<p>You might wonder if BosonPHP already uses PHP 8.5, which is starting to be discussed. The answer is no. Currently, the
reactor’s core remains firmly anchored on <strong>PHP 8.4</strong> (as confirmed by the <code>php84</code> technical tag in their official
repository).</p>
<p>Why stick to version 8.4? Because creating native interfaces via FFI requires complex manipulation of memory pointers in
C. PHP 8.4 offers extremely well-documented stability regarding the asynchronous <strong>Garbage Collector</strong> and typed
structures—vital elements to avoid memory leaks in a long-running process. Moving to a higher minor version would
require revalidating the reliability of all underlying memory bridges.</p>
<h2>The ‘Zero HTTP Overhead’ Architecture and Framework Bridges</h2>
<p>The real revolution of BosonPHP lies in the absence of a network. In previous attempts to port PHP to the desktop, a
micro-web server was launched in the background, and the interface communicated with it via TCP requests on <code>localhost</code>.</p>
<p>With BosonPHP, the GUI communicates directly with the PHP process in memory. Events trigger PHP methods directly. But
how can we use our favorite frameworks if the whole concept of an HTTP request has disappeared?</p>
<h3>The Bridge System</h3>
<p>This is where BosonPHP demonstrates its engineering prowess. The team has developed an ecosystem of <strong>Bridges</strong> that
emulate HTTP behavior directly in RAM, without ever opening a network port.</p>
<p>The project offers official components to integrate your frameworks without modification:</p>
<ul>
<li><code>boson-php/laravel-provider</code> and <code>boson-php/laravel-http-bridge</code></li>
<li><code>boson-php/symfony-bundle</code> and <code>boson-php/symfony-http-bridge</code></li>
<li><code>boson-php/spiral-bridge</code></li>
<li><code>boson-php/psr-http-bridge</code> (for any PSR-7 compatible router)</li>
</ul>
<p>When your application’s WebView attempts to load an internal URL or submit a form, the Boson Bridge intercepts the call,
builds a native request object (e.g., an <code>Illuminate\Http\Request</code> for Laravel), and injects it into the framework in
memory. The response is generated and returned to the WebView instantly.</p>
<h2>Developing with BosonPHP: A Practical Case</h2>
<p>BosonPHP’s software structure is highly modular. To add native features, you install specific extensions via Composer.</p>
<p>Let’s take an example of an application that monitors network and battery status. We will use the
<code>boson-php/webview-ext-battery</code> and <code>boson-php/app-ext-alert</code> components.</p>
<pre><code class="language-php">&lt;?php

use Boson\App;
use Boson\Window;
use Boson\Extensions\Alert\AlertExtension;
use Boson\Extensions\Battery\BatteryExtension;

class SystemMonitor
{
  private App $app;
  private Window $window;

  public function __construct()
  {
    $this-&gt;app = new App();
    
    // We register native extensions into the Kernel
    $this-&gt;app-&gt;register(new AlertExtension());
    $this-&gt;app-&gt;register(new BatteryExtension());
  }

  public function boot(): void
  {
    $this-&gt;window = new Window(
      title: 'Boson System Monitor',
      width: 800,
      height: 600
    );

    $this-&gt;window-&gt;on('ready', function (Window $win)
    {
      $this-&gt;checkBatteryStatus($win);
    });

    $this-&gt;app-&gt;run();
  }

  private function checkBatteryStatus(Window $win): void
  {
    // Calling the native Battery API via FFI bindings
    $battery = $win-&gt;native-&gt;getBatteryInfo();
    
    if ($battery-&gt;percent &lt; 20 &amp;&amp; !$battery-&gt;isCharging)
    {
      // Calling native OS message box without HTML/JS
      $win-&gt;native-&gt;alert(
        title: 'Warning',
        message: 'Battery level is critically low.'
      );
    }

    // Pushing data to the WebView DOM
    $win-&gt;executeJS('updateBatteryUI(' . $battery-&gt;percent . ');');
  }
}

$monitor = new SystemMonitor();
$monitor-&gt;boot();
</code></pre>
<p>In this code, we see the power of the API. The <code>app-ext-alert</code> extension does not create a fake HTML dialog box. It
calls the actual <code>MessageBox</code> API of the OS on Windows or the <code>NSAlert</code> API on macOS via FFI bindings.</p>
<h2>Critical Memory Management in a Desktop Context</h2>
<p>This is the major friction point for a backend developer transitioning to BosonPHP. In classic PHP (PHP-FPM), memory
cleanup is not your primary concern because the process dies at the end of the request.</p>
<p>In BosonPHP, your application can stay open in the background for weeks. The development rules change:</p>
<ol>
<li><strong>Ban Infinite Global State:</strong> Arrays stored in <code>$GLOBALS</code> or static class properties that accumulate over time will
cause a fatal memory leak.</li>
<li><strong>Master Weak References:</strong> Boson provides the <code>boson-php/weak-types</code> component to manage data. A weak reference
allows you to associate metadata with an object without preventing the Garbage Collector from destroying it when it
is no longer used elsewhere.</li>
<li><strong>Force Cyclic Cleanup:</strong> In complex applications, it is often wise to bind the <code>gc_collect_cycles()</code> function to an
internal timer or a change in application state (such as minimizing the window to the taskbar).</li>
</ol>
<h2>The Workflow: From Writing to Compilation</h2>
<p>The project excels in its fluid deployment process. The Developer Experience (DX) is designed to be as simple as
possible.</p>
<p>You initialize your project with:</p>
<pre><code class="language-bash">composer create-project boson-php/app my-app
</code></pre>
<p>During development, you test the application by simply running:</p>
<pre><code class="language-bash">php index.php
</code></pre>
<p>Once development is complete, the <code>boson-php/compiler</code> component comes into play. It consolidates your source code,
front-end assets, and the internal PHP engine into a single, standalone executable.</p>
<pre><code class="language-bash">php vendor/bin/boson compile
</code></pre>
<p>The generated executable contains everything needed. The end user <strong>absolutely does not need to have PHP installed</strong> on
their machine. It is total plug-and-play.</p>
<h2>Conclusion</h2>
<p>BosonPHP is no longer just an experiment. With a stable architecture based on PHP 8.4, the integration of Saucer v6.0,
and robust framework support via native asynchronous bridges, version 0.19.5 offers high-level industrial tooling.</p>
<p>Capitalizing on BosonPHP means using your current technical knowledge to deploy ultra-lightweight and high-performance
software on any desktop operating system. The elephant language is no longer just the king of the server; it now has a
place on your desktops.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Can I use a local database with a BosonPHP application?</summary>
Yes. The recommended technology for the desktop is <strong>SQLite</strong>. PHP's native <code>PDO_SQLITE</code>
extension integrates perfectly because it requires no external daemon or service. Read and write operations are
performed directly on a local file within the application's storage space.
</details>
<details>
<summary>Does BosonPHP support asynchronous code or multithreading?</summary>
PHP is fundamentally single-threaded. However, Boson's event architecture uses the OS's internal event loop. For
complex asynchronous tasks (like heavy network calls without freezing the UI), you can use native PHP 8.1+
<strong>Fibers</strong> or resort to compatible background processing libraries.
</details>
<details>
<summary>Are BosonPHP applications secure against code injection?</summary>
Since the PHP code is executed locally and packaged in a binary, the risk of server-side injection (Remote Code
Execution) disappears. However, the risk of client-side XSS vulnerabilities (WebView) remains. It is imperative to
sanitize all data sent to the <code>executeJS()</code> method to prevent a user from injecting malicious scripts into
the application interface.
</details>
<details>
<summary>Can I manipulate the host system's files?</summary>
Yes, the application has the same read and write permissions as the operating system user who launched it. Unlike a
traditional browser (which is sandboxed), BosonPHP allows you to freely manipulate entire directories using native
functions like <code>file_put_contents()</code> or <code>scandir()</code>.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Native Gradient Interpolation: Mastering the CSS Houdini @property API</title>
            <link>https://lionel-peramo.com/posts/native-gradient-interpolation-css-houdini/</link>
            <guid>https://lionel-peramo.com/posts/native-gradient-interpolation-css-houdini/</guid>
            <pubDate>Thu, 19 Feb 2026 18:00:00 +0000</pubDate>
            <description>A technical analysis of transitioning from opacity hacks to native interpolation. Learn how to use typed variables to animate gradients without DOM complexity.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 7 min</p>
              
<p>Browser rendering engines have historically treated CSS gradients as generated images. Since an image is a complex value
rather than a simple numerical unit, the browser cannot calculate a smooth transition between two <code>background-image</code>
states. Without intervention, switching from one color configuration to another is binary and instantaneous, lacking any
fluid interpolation.</p>
<p>The <strong>CSS Houdini API</strong>, specifically through the <code>@property</code> rule, transforms this constraint. It allows developers to
declare typed variables that the CSS engine can interpolate mathematically. This document details how to leverage this
technology to fluidize interfaces while optimizing the rendering pipeline.</p>
<h2>The Architecture of Typed Variables</h2>
<p>A standard CSS variable (Custom Property) is a string of characters with no semantic meaning for the browser. To enable
animation, the nature of the data must be explicitly defined. <code>@property</code> associates a type (<code>syntax</code>) with a variable,
such as an angle or a color.</p>
<h3>Declaration and Registration of Properties</h3>
<p>Property registration must be precise. The <code>inherits: false</code> parameter is critical for performance. It prevents the
variable from unnecessarily propagating down the DOM tree, thereby limiting the scope of style calculations during
transition phases.</p>
<pre><code class="language-css">/* Registration of the animation tokens */
@property --gradient-angle {
  syntax        : '&lt;angle&gt;';
  inherits      : false;
  initial-value : 45deg;
}

@property --gradient-start {
  syntax        : '&lt;color&gt;';
  inherits      : false;
  initial-value : #00f;
}

@property --gradient-end {
  syntax        : '&lt;color&gt;';
  inherits      : false;
  initial-value : #09f;
}

.surface {
  /* Fluid sizing via arithmetic functions, eliminating media queries */
  height             : clamp(15rem, 30vh + 5rem, 40rem);
  width              : 100%;
  margin-block-start : clamp(1rem, 5vw, 3rem);
  position           : relative;
  cursor             : pointer;

  background         : linear-gradient(var(--gradient-angle), var(--gradient-start), var(--gradient-end));
  transition         : --gradient-angle .7s cubic-bezier(.4, 0, .2, 1),
                       --grad-start .7s cubic-bezier(.4, 0, .2, 1),
                       --grad-end .7s cubic-bezier(.4, 0, .2, 1);

  /* Layer isolation for painting optimization */
  contain     : layout paint style;
  will-change : transform;
}

.surface:hover {
  --gradient-angle : 225deg;
  --gradient-start : #f00;
  --gradient-end   : #f70;
}
</code></pre>
<h2>Rendering Pipeline Optimization</h2>
<p>Choosing this technique directly impacts the Critical Rendering Path. Unlike opacity animation, which runs on the
<strong>Compositor (GPU)</strong>, animating gradient properties triggers a <strong>repaint</strong>.</p>
<h3>Managing the Repaint Cycle</h3>
<p>At each frame of the animation, the browser recalculates the pixels of the background image. Although more costly than a
simple layer merge, this process is optimized by two factors:</p>
<ol>
<li><strong>Semantic Isolation:</strong> By declaring <code>inherits: false</code>, you reduce the cost of style recalculation. The browser knows
that modifying the variable does not affect child nodes.</li>
<li><strong>DOM Tree Reduction:</strong> This method eliminates the need for pseudo-elements (<code>::after</code>) or extra tags. A lighter DOM
accelerates all phases of rendering, from parsing to layout.</li>
</ol>
<h2>Responsive Arithmetic and Fluidity</h2>
<p>The use of <code>clamp()</code> allows for the removal of traditional Media Queries. Every <code>@media</code> rule forces the browser to
re-evaluate the CSS cascade during window resizing. By using mathematical functions, size calculation becomes a dynamic
operation performed during the Layout phase.</p>
<p>This approach ensures constant visual stability. It also reduces the total size of the CSS file, speeding up download
and analysis time by the main thread.</p>
<h2>Accessibility and Motion Compliance</h2>
<p>Animating colors and angles can impact users suffering from vestibular disorders or motion sensitivity. Respecting
system preferences is both a technical and ethical necessity.</p>
<pre><code class="language-css">@media (prefers-reduced-motion : reduce) {
  .surface {
    transition : none;
  }
}
</code></pre>
<p>Integrating this media query ensures compliance with international accessibility standards (EAA 2025 / WCAG). It ensures
that the aesthetic of the interface does not become a barrier to navigation.</p>
<h2>SEO Impact and Core Web Vitals</h2>
<p>Perceived and real performance is a major ranking criterion. The use of <code>@property</code> optimizes several key metrics:</p>
<ul>
<li><strong>Largest Contentful Paint (LCP):</strong> Rendering is immediate because it does not depend on loading an external
resource (image). The gradient is generated natively by the graphics engine.</li>
<li><strong>Cumulative Layout Shift (CLS):</strong> Fluid dimension definition via <code>clamp</code> prevents abrupt layout shifts during style
loading.</li>
<li><strong>Total Blocking Time (TBT):</strong> Since the CSS code is more concise and lacks JavaScript logic for animation, the main
thread remains available for user interactions.</li>
</ul>
<h2>Deployment Strategy and Support</h2>
<p>As of 2025, support for <code>@property</code> is widespread across Blink (Chrome, Edge), WebKit (Safari), and Gecko (Firefox)
engines. For environments that do not support Houdini, the browser simply ignores the transition. The user benefits from
a static gradient that changes instantly on hover. This principle of progressive enhancement ensures that the interface
remains functional everywhere while providing a superior experience on modern browsers.</p>
<h2>Conclusion</h2>
<p>The CSS Houdini API redefines how we design graphic transitions. By moving from a hack based on overlapping elements to
a native interpolation of typed variables, we clean up the source code and optimize system resource usage. Mastering
<code>@property</code> allows for the marriage of surgical CSS engineering precision with a fluid and high-performance user
experience.</p>
<hr>
<h3>Technical FAQ</h3>
<details>
<summary>Why is the <code>inherits: false</code> syntax preferable?</summary>
It prevents the browser from checking every child element to see if it uses the modified variable. This saves
significant calculation cycles on pages with a complex DOM.
</details>
<details>
<summary>What is the advantage of <code>will-change: transform</code> here?</summary>
Although we are not directly animating the transform, this property often forces the browser to place the element on
its own GPU layer, isolating "repaint" operations from the rest of the page.
</details>
<details>
<summary>Can gradients with more than two colors be animated?</summary>
Yes. Simply register as many typed properties as necessary and integrate them into the linear-gradient function.
Interpolation will occur on each variable simultaneously.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Animated Border and Glow Effect: How to Code an Ultra-Fast Premium Button</title>
            <link>https://lionel-peramo.com/posts/high-performance-animated-glow-border-css/</link>
            <guid>https://lionel-peramo.com/posts/high-performance-animated-glow-border-css/</guid>
            <pubDate>Wed, 18 Feb 2026 17:30:00 +0000</pubDate>
            <description>Learn how to create a rotating border with a glow effect using pure CSS. A method optimized for performance, SEO, and accessibility without any JavaScript.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 8 min</p>
              
<p>Website design should never slow down the user.
A button is the most critical element for conversion.
If it looks good, users want to click.
If it is fast, users feel confident.</p>
<p>Often, light effects (Glow) require many computer resources.
If the code is poorly written, the animation stutters.
We will see how to create a rotating luminous border.
This code uses only CSS to remain ultra-performant.</p>
<h2>The Problem with Poorly Designed Buttons</h2>
<p>Many developers make the mistake of using images or JavaScript to make a button shine.
This causes three problems:</p>
<ol>
<li><strong>Weight</strong>: An animated image is heavy to download.</li>
<li><strong>Readability</strong>: If the effect passes in front of the text, it becomes unreadable.</li>
<li><strong>Slowness</strong>: JavaScript uses the browser’s main processor.</li>
</ol>
<p>Our solution uses <strong>hardware rendering</strong>.
This means the work is done by the graphics card (GPU).
The main processor (CPU) remains free for other site tasks.</p>
<h2>HTML Structure: Simplicity and Efficiency</h2>
<p>For the browser to work fast, it needs simple code.
We use a box (<code>div</code> or <code>button</code>) and a container for the text.
This allows the visual effect to be separated from the actual content.</p>
<pre><code class="language-html">
&lt;div class=box&gt;
  &lt;div class=content&gt;
    &lt;h1&gt;Glowing border&lt;/h1&gt;
    &lt;p&gt;Hover your mouse to animate the border&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>Here, we do not use quotes for simple classes like <code>class=box</code>.
This is an optimization that slightly reduces the HTML file size.
Modern browsers understand this code perfectly.</p>
<h2>Step 1: Declaring an Intelligent Variable</h2>
<p>In CSS, we often use variables.
But here, we use a “typed” variable.
We tell the browser that <code>--angle</code> is a unit of rotation measurement.</p>
<pre><code class="language-css">@property --angle {
  syntax        : &quot;&lt;angle&gt;&quot;;
  initial-value : 76deg;
  inherits      : false;
}
</code></pre>
<p><strong>Why is this important?</strong>
Without this, the browser does not know how to smoothly transition from 0 to 360 degrees.
Thanks to <code>@property</code>, the animation is handled mathematically.
This allows for 120 frames per second without any effort.</p>
<h2>Step 2: Fluid Design with <code>clamp</code> and <code>min</code></h2>
<p>We want our box to look good everywhere.
We do not use fixed sizes in pixels.
Instead, we use <code>min()</code> and <code>clamp()</code> functions.</p>
<pre><code class="language-css">.box {
  position    : relative;
  display     : grid;
  place-items : center;
  /* Width adapts between 90% on mobile and 25rem on desktop */
  width       : min(90vw, 25rem);
  height      : auto;
  background  : #012;
  /* Fluid spacing */
  padding     : clamp(.625rem, calc(1.136vw + .3978rem), 1.25rem);
  margin      : 1.25rem;
}
</code></pre>
<p><code>clamp()</code> automatically calculates the best size.
There is no need for complex rules for mobile phones.
This is a win for performance and code maintenance.</p>
<h2>Step 3: Creating Light Layers</h2>
<p>We use two invisible layers behind the box: <code>::before</code> and <code>::after</code>.
The secret is to use a <strong>conic gradient</strong>.</p>
<ol>
<li><strong>The <code>::before</code> layer</strong>: This is the sharp border. It is placed right behind the background.</li>
<li><strong>The <code>::after</code> layer</strong>: This is the glowing halo. It is placed even further back (<code>z-index: -2</code>) and is blurred.</li>
</ol>
<pre><code class="language-css">.box::before, .box::after {
  content    : &quot;&quot;;
  position   : absolute;
  inset      : -3px; /* Border thickness */
  z-index    : -1;
  background : conic-gradient(from var(--angle), #56e0a6, #060c21, #11b9d1, #060c21, #56e0a6);
}

.box::after {
  z-index : -2;
  filter  : blur(20px);
}
</code></pre>
<p>By using <code>inset: -3px</code>, we ask the gradient to slightly overlap the box.
This creates the colored border.</p>
<h2>Step 4: Interaction and Animation</h2>
<p>The effect only activates when the user hovers over the box.
This saves energy.
We use two animations at the same time.
The first rotates the angle.
The second adds a <code>sepia</code> filter to make the light more intense.</p>
<pre><code class="language-css">&amp;:hover::before, &amp;:hover::after {
  animation : glowing-border 3.5s linear infinite;
}

&amp;:hover::after {
  animation-name : glowing-border, blur-effect;
}

@keyframes glowing-border {
  to { --angle : 436deg }
  /* 76deg + 360deg for a full rotation */
}

@keyframes blur-effect {
  to { filter : blur(15px) sepia(.3) }
}
</code></pre>
<p>The <code>sepia</code> filter is very clever.
It slightly changes the hue of the colors.
This gives a more “vivid” and warm look to the button during clicks or hovers.</p>
<h2>Why is this Technique the Fastest?</h2>
<p>There are several ways to draw a border.
But most of them force the browser to recalculate the page’s shape.
This is called <strong>Layout Shift</strong>.</p>
<p>Our method uses only the final <strong>Rendering Process</strong> (Composite).
Since we only modify one variable (<code>--angle</code>) and one filter (<code>blur</code>), the browser does not redo position calculations.
This is the least tiring method for the computer.</p>
<h2>SEO Impact and Core Web Vitals</h2>
<p>SEO is not just text.
It is also the technical quality of your components.
Here is how this button helps your ranking:</p>
<ol>
<li><strong>LCP (Largest Contentful Paint)</strong>: The button is lightweight. It does not block the display of the rest of the page.</li>
<li><strong>INP (Interaction to Next Paint)</strong>: The hover response is instantaneous because it is handled by the GPU. Google
loves fast interactions.</li>
<li><strong>CLS (Cumulative Layout Shift)</strong> : By using <code>aspect-ratio</code> or calculated sizes (<code>height: auto</code>), content does not
jump during loading.</li>
</ol>
<h2>Accessibility: Readability and Movement</h2>
<p>A button must be readable for everyone.
In our example, the text is in a separate layer (<code>.content</code>).
It always remains white on a dark background.
The contrast is excellent, which is vital for visually impaired users.</p>
<p>We must also think of people sensitive to movement.
Some people may feel dizzy with rotating lights.
CSS allows us to automatically disable the animation for them.</p>
<pre><code class="language-css">@media (prefers-reduced-motion : reduce) {
  .box::before, .box::after {
    animation  : none;
    background : #11b9d1; /* A fixed and calm border */
  }
}
</code></pre>
<h2>Performance Optimization: Avoiding Overrides</h2>
<p>In our code, we do not use complicated selectors.
We use CSS nesting (<code>&amp;::before</code>).
This allows the browser to read the code faster.
If you need multiple variants, use <code>:not()</code>.
For example: <code>.box:not(.no-animation)</code>.
This avoids forcing the browser to cancel styles that have already been calculated.</p>
<h2>Conclusion: The Power of Modern CSS</h2>
<p>Creating “Premium” interfaces does not require heavy libraries.
With a few well-thought-out lines of CSS, you get:</p>
<ul>
<li>Fluid animation at 120 FPS.</li>
<li>A perfect performance score on Lighthouse.</li>
<li>A pleasant and interactive user experience.</li>
</ul>
<p>Performance is not the enemy of design.
It is the engine that allows design to be appreciated by everyone.
Every millisecond of calculation saved is a victory for your SEO and the planet.</p>
<hr>
<h3>Frequently Asked Questions (FAQ)</h3>
<details>
<summary>Why use 436deg in the animation?</summary>
We start at 76deg. To make a full 360deg turn, we must reach 436deg (76 + 360 = 436). This allows for a perfect loop
without a visual jump.
</details>
<details>
<summary>Does the sepia filter slow down the site?</summary>
No, because it is only applied during hover. The rest of the time, the browser performs no calculations on this filter.
</details>
<details>
<summary>Can I put long text in this box?</summary>
Yes. Thanks to <code>height: auto</code> and fluid <code>padding</code>, the box will grow with your text without
breaking the border effect.
</details>
<details>
<summary>How do I change the border color?</summary>
Simply change the color codes in the <code>conic-gradient</code>. You can put as many colors as you want to create a
rainbow or bicolor effect.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Optimizing Conversion: The Complete Guide to the HTML autocomplete Attribute</title>
            <link>https://lionel-peramo.com/posts/optimizing-conversion-autocomplete-html-guide/</link>
            <guid>https://lionel-peramo.com/posts/optimizing-conversion-autocomplete-html-guide/</guid>
            <pubDate>Mon, 16 Feb 2026 17:45:00 +0000</pubDate>
            <description>Discover how the autocomplete attribute transforms your forms. A technical guide focused on HTML to reduce friction, improve accessibility, and boost your sales by 20%.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 9 min</p>
              
<p>On the internet, friction is the number one enemy. Every field a user must fill manually is an opportunity for them to
leave your site. This is called form abandonment. For an e-commerce site or an online service, this represents a direct
loss of money.</p>
<p>However, there is a free, native, and extremely high-performance technical solution: the <code>autocomplete</code> attribute.
According to figures from <a href="https://www.zuko.io/blog/does-browser-autofill-affect-form-conversion-rate">Zuko</a>, <strong>correctly using auto-completion increases form success rates from 59% to 71%</strong>.</p>
<p>This guide explains how to transform your forms using only HTML.</p>
<h2>Why autocomplete changes everything?</h2>
<p>Filling out a form requires significant effort, especially on a mobile phone. The user must click the field, wait for
the keyboard to appear, type their information without mistakes, and then move to the next field.</p>
<p>The <code>autocomplete</code> attribute allows the browser to do all this work for the user. In a fraction of a second, the browser
identifies the data stored in its system and offers to fill the entire form at once.</p>
<h3>The difference between “heuristic” and “semantic”</h3>
<p>If you don’t use the <code>autocomplete</code> attribute, the browser tries to guess what it should fill. This is called
<strong>heuristics</strong>. It looks at the field name (<code>name=prenom</code>) or the surrounding text. But browsers often make mistakes,
especially if your site is translated into several languages.</p>
<p>By adding <code>autocomplete</code>, you provide a <strong>semantic</strong> instruction. You tell the browser: “This field is exactly for the
first name.” There is no more room for error. The performance gain is immediate because the browser no longer needs to
analyze your code to guess your intentions.</p>
<h2>1. User Identity</h2>
<p>This is the basis of every form. For the browser to suggest the correct information, you must use standard tokens.</p>
<p>Here is a code example optimized for identity:</p>
<pre><code class="language-html">
&lt;div class=form-group&gt;
  &lt;label for=first-name&gt;First Name&lt;/label&gt;
  &lt;input id=first-name name=fname type=text autocomplete=given-name required&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=last-name&gt;Last Name&lt;/label&gt;
  &lt;input id=last-name name=lname type=text autocomplete=family-name required&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=nickname&gt;Username&lt;/label&gt;
  &lt;input id=nickname name=user type=text autocomplete=nickname&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=job-title&gt;Job Position&lt;/label&gt;
  &lt;input id=job-title name=position type=text autocomplete=organization-title&gt;
&lt;/div&gt;
</code></pre>
<h3>Why separate first and last names?</h3>
<p>Some forms use a single “Full Name” field. This is an error for auto-completion performance. Browsers often store first
and last names separately. By using <code>given-name</code> and <code>family-name</code>, you guarantee perfect filling.</p>
<h2>2. Contact details</h2>
<p>Typing errors in email addresses or phone numbers are the leading causes of account creation failure. Auto-completion
eliminates this risk.</p>
<pre><code class="language-html">&lt;!-- Contact details optimized for mobile interaction --&gt;
&lt;div class=form-group&gt;
  &lt;label for=user-email&gt;Email Address&lt;/label&gt;
  &lt;input id=user-email name=email type=email autocomplete=email required&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=user-phone&gt;Phone Number&lt;/label&gt;
  &lt;input id=user-phone name=phone type=tel autocomplete=tel&gt;
&lt;/div&gt;
</code></pre>
<p><strong>Technical note:</strong> Always use <code>type=email</code> and <code>type=tel</code> in addition to autocomplete. This allows smartphones to
display the correct keyboard (numeric keypad for phone), which further increases input speed.</p>
<h2>3. Shipping Address: The e-commerce challenge</h2>
<p>The address is the longest part to fill. It often contains five or six different fields. This is where the impact on
conversion is strongest.</p>
<pre><code class="language-html">&lt;!-- Shipping address tokens for e-commerce performance --&gt;
&lt;div class=form-group&gt;
  &lt;label for=street&gt;Street Address&lt;/label&gt;
  &lt;input id=street name=addr1 type=text autocomplete=&quot;shipping street-address&quot;&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=city&gt;City&lt;/label&gt;
  &lt;input id=city name=city type=text autocomplete=&quot;shipping address-level2&quot;&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=zip&gt;Zip Code&lt;/label&gt;
  &lt;input id=zip name=zip type=text autocomplete=&quot;shipping postal-code&quot;&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=country&gt;Country&lt;/label&gt;
  &lt;input id=country name=country type=text autocomplete=&quot;shipping country&quot;&gt;
&lt;/div&gt;
</code></pre>
<p>By adding the word <code>shipping</code> before the token (e.g., <code>shipping postal-code</code>), you indicate to the browser that this is
the delivery address. If it is the billing address, use <code>billing</code>. This allows the browser to offer two different
addresses if the user has saved them.</p>
<h2>4. Payments and Security</h2>
<p>Filling in credit card numbers is stressful for the user. By automating this step, you reduce anxiety and speed up the
payment.</p>
<pre><code class="language-html">&lt;!-- Payment fields with secure native autocomplete --&gt;
&lt;div class=form-group&gt;
  &lt;label for=card-num&gt;Card Number&lt;/label&gt;
  &lt;input id=card-num name=cnum type=text autocomplete=cc-number&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=card-name&gt;Name on Card&lt;/label&gt;
  &lt;input id=card-name name=cname type=text autocomplete=cc-name&gt;
&lt;/div&gt;

&lt;div class=form-group&gt;
  &lt;label for=card-exp&gt;Expiry Date&lt;/label&gt;
  &lt;input id=card-exp name=cexp type=text autocomplete=cc-exp&gt;
&lt;/div&gt;
</code></pre>
<p>Contrary to popular belief, this is <strong>more secure</strong>. The user does not need to take out their card in a public place.
The browser protects this data with a password or fingerprint (TouchID/FaceID).</p>
<h2>5. Password Management</h2>
<p>This is one of the most critical points. Poor autocomplete configuration can block a user trying to log in.</p>
<ul>
<li><strong>For Login</strong>: Use <code>autocomplete=current-password</code>.</li>
<li><strong>For Registration</strong>: Use <code>autocomplete=new-password</code>.</li>
</ul>
<p>This tells the password manager whether to suggest an old code or generate a new one securely.</p>
<h2>6. Accessibility (WCAG): A right for everyone</h2>
<p>Web accessibility is not just for the blind. It also concerns people with motor impairments (difficulty typing) or
cognitive impairments (difficulty remembering their own information).</p>
<p>The <strong>WCAG 2.1</strong> standard requires identifying the purpose of the input (criterion 1.3.5). The <code>autocomplete</code> attribute
is the official solution to comply with this rule. Without it, your site may be considered non-compliant with
accessibility laws.</p>
<h2>7. Performance: Why native always wins?</h2>
<p>Many sites use heavy JavaScript scripts to help with input (address search via API). While these tools are useful, they
slow down the page. They require time to load the script and execute the code.</p>
<p>The HTML <code>autocomplete</code> attribute has a performance cost of <strong>zero</strong>.</p>
<ol>
<li>No additional network request.</li>
<li>No CPU calculation time.</li>
<li>Works even if the network is slow or if JavaScript is blocked.</li>
</ol>
<h2>Absolute mistakes to avoid</h2>
<ul>
<li><strong>Abuse of autocomplete=off</strong>: Some developers think they increase security by forbidding auto-completion. It’s the
opposite. You force the user to use simple passwords to remember them.</li>
<li><strong>Fancy field names</strong>: If you use <code>name=field_1</code>, the browser will struggle to understand without the <code>autocomplete</code>
attribute. Always be explicit.</li>
</ul>
<h2>Conclusion</h2>
<p>Form optimization is not about adding complex features, but about the intelligent use of web standards. The
<code>autocomplete</code> attribute is the most powerful tool to improve user experience without any compromise on performance.</p>
<p>As a developer or site manager, your mission is to reduce your visitors’ effort. A form that fills itself is a form that
converts.</p>
<hr>
<h3>FAQ</h3>
<details>
<summary>Is autocomplete available on all browsers?</summary>
Yes, it is a standard supported by all modern browsers (Chrome, Safari, Edge, Firefox). Even very old browsers simply ignore the attribute without ever crashing the site.
</details>
<details>
<summary>Can autocomplete fill dropdown menus (select)?</summary>
Yes, perfectly! You can add the <code>autocomplete</code> attribute to a <code>select</code> tag, for example, for the choice of country or state.
</details>
<details>
<summary>Can the user disable this feature?</summary>
Yes, the user always maintains control in their browser settings. But the vast majority of internet users use it because it makes their lives easier.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Mastering AbortController in JavaScript: The Guide to High-Performance Requests</title>
            <link>https://lionel-peramo.com/posts/mastering-javascript-abortcontroller-high-performance-requests/</link>
            <guid>https://lionel-peramo.com/posts/mastering-javascript-abortcontroller-high-performance-requests/</guid>
            <pubDate>Thu, 12 Feb 2026 12:00:00 +0000</pubDate>
            <description>Learn how to use AbortController to cancel fetch requests, handle native timeouts, and optimize the memory of your JS applications.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 9 min</p>
              
<p>Modern <strong>web</strong> development relies almost exclusively on asynchrony. Whether fetching data via an API, loading modules on
the fly, or managing streaming flows, the <code>fetch()</code> function has become the universal tool. However, a crucial question
is often ignored: what happens when the user leaves a page before the loading finishes?</p>
<p>Without control, you create “zombie requests.” These processes continue to consume bandwidth and processor resources (
CPU) in the background, even if the result is no longer needed. This is where <strong>AbortController</strong> comes in.</p>
<p>In this expert guide, we will break down how this API transforms the management of your requests to achieve an optimal
level of <strong>performance</strong> and digital sobriety.</p>
<h2>The Problem of Orphaned Requests</h2>
<p>Imagine a “search-as-you-type” interface. For every character typed, a <code>fetch()</code> request is launched. If the user
types “JavaScript” quickly, seven or eight requests can be sent to the server. If the early requests arrive after the
last one, they might overwrite the most recent data in your interface (a <em>race condition</em> problem).</p>
<p>Previously, canceling a promise was complex, if not impossible to do cleanly. The introduction of <strong>AbortController</strong> in
2018 radically changed the game by providing a standardized way to interrupt any asynchronous process.</p>
<h2>Anatomy of AbortController</h2>
<p>The object consists of two distinct but linked parts:</p>
<ol>
<li><strong>The Controller:</strong> The object that holds the power to cancel.</li>
<li><strong>The Signal:</strong> The token passed to asynchronous functions so they know when to stop.</li>
</ol>
<p>Here is the simplest implementation:</p>
<pre><code class="language-js">const
  controller = new AbortController(),
  signal = controller.signal;

// Triggers cancellation
controller.abort();
</code></pre>
<h2>Canceling a <code>fetch</code> Request: A Practical Case</h2>
<p>To cancel a <code>fetch()</code>, simply pass the <code>signal</code> in the request’s options object.</p>
<pre><code class="language-js">async function fetchData(url)
{
  const controller = new AbortController();

  try
  {
    const response = await fetch(url, {signal: controller.signal});
    return await response.json();
  } catch (error)
  {
    if (error.name === 'AbortError')
      console.warn('Fetch request was cancelled by the user.');
    else
      console.error('A network error occurred:', error);
  }
}
</code></pre>
<h3>Why Is It Vital for Performance?</h3>
<p>By calling <code>abort()</code>, the <strong>browser</strong> immediately cuts the TCP connection. You instantly save battery on mobile devices
and free up RAM that won’t be used to process a useless response.</p>
<h2>Native Timeout Management: Goodbye Manual <code>setTimeout</code></h2>
<p>One of the greatest recent advancements (Baseline 2023) is the static <code>AbortSignal.timeout()</code> method. It allows you to
set a time limit for an operation without having to manage complex counters yourself.</p>
<pre><code class="language-js">async function fetchWithTimeout(url, ms)
{
  try
  {
    // Automatically aborts after 'ms' milliseconds
    const response = await fetch(url, {signal: AbortSignal.timeout(ms)});
    return await response.json();
  } catch (error)
  {
    if (error.name === 'TimeoutError')
      console.error('The request took too long and timed out.');
  }
}
</code></pre>
<p>This approach is much more robust than old “hacks” using <code>Promise.race()</code>, because it actually cancels the network
request instead of simply ignoring its result.</p>
<h2>Advanced Usage: AbortSignal.any()</h2>
<p>In 2026, we often have to handle cancellations from multiple sources (a “Cancel” button AND an automatic timeout). The
<code>AbortSignal.any()</code> method allows combining several signals. The first signal to activate triggers the global
cancellation.</p>
<pre><code class="language-js">async function robustFetch(url)
{
  const
    userController = new AbortController(),
    timeoutSignal = AbortSignal.timeout(5000),
    // Combine signals: aborts if user clicks OR if 5s elapse
    combinedSignal = AbortSignal.any([
      userController.signal,
      timeoutSignal
    ]);

  return fetch(url, {signal: combinedSignal});
}
</code></pre>
<h2>State Management and User Feedback</h2>
<p>Canceling an asynchronous task should not come at the expense of clarity. An interface that remains frozen after
clicking “Cancel” is a UX error. The logic resides in state transitions driven by JavaScript and reflected by robust *
<em>CSS</em>*.</p>
<pre><code class="language-js">async function handleActionWithFeedback(controller)
{
  const btn = document.getElementById('action-btn');
  btn.classList.add('is-loading');

  try
  {
    await performHeavyTask(controller.signal);
  } catch (err)
  {
    if (err.name === 'AbortError')
      btn.classList.replace('is-loading', 'is-cancelled');
  }
}
</code></pre>
<p>To accompany this logic, I use a fluid design that ensures my status indicators remain readable on any screen, without
multiplying media queries:</p>
<pre><code class="language-css">.status-indicator {
  /* Fluid typography: min 14px, max 20px based on viewport width */
  font-size : clamp(0.875rem, 1.2vw + 0.5rem, 1.25rem);
  padding   : clamp(0.5rem, 2vh, 1.5rem);

  /* Target only end states without overriding the base */
  &amp;:not(.is-loading, .is-success) {
    background-color : var(--background-soft);
    filter           : grayscale(1);
    opacity          : 0.7;
  }
}
</code></pre>
<h2>AbortController Beyond the Network: Event Listeners</h2>
<p><strong>AbortController</strong> is not reserved for network requests. You can use it to clean up your Event Listeners all at once.
This is a major technique for avoiding memory leaks in Single Page Applications (SPA).</p>
<pre><code class="language-js">const menuController = new AbortController();

window.addEventListener('resize', handleResize, {signal: menuController.signal});
window.addEventListener('scroll', handleScroll, {signal: menuController.signal});

// Clean up everything at once
function destroyComponent()
{
  menuController.abort();
}
</code></pre>
<h2>Performance and Eco-design: The Virtuous Circle</h2>
<p>On this blog, I often advocate for <strong>digital sobriety</strong>. <strong>AbortController</strong> is one of its best technical ambassadors:</p>
<ul>
<li><strong>Server Traffic Reduction:</strong> Fewer useless requests processed by your PHP or Node.js backend.</li>
<li><strong>Data Economy:</strong> Crucial for users with limited plans or in low network coverage areas (3G/Edge).</li>
<li><strong>Display Fluidity:</strong> By cutting useless processing (JSON parsing, DOM manipulations), you avoid jank and allow the
browser to maintain a smooth 60 FPS rendering.</li>
</ul>
<h2>SEO Strategy and Accessibility</h2>
<p>While request cancellation is a background task, it indirectly impacts your <strong>SEO</strong>. Google analyzes the visual
stability and response speed of your pages (Core Web Vitals). A site that doesn’t manage its zombie requests ends up
lagging, degrading the <strong>LCP (Largest Contentful Paint)</strong> score.</p>
<p>On the accessibility side, ensure that when an operation is canceled by a timeout, the user is informed via an
<code>aria-live</code> region.</p>
<pre><code class="language-js">const statusEl = document.getElementById('status-message');

if (error.name === 'AbortError')
{
  statusEl.textContent = 'Loading interrupted.';
  statusEl.setAttribute('aria-live', 'polite');
}
</code></pre>
<h2>Conclusion: Toward Responsible Code</h2>
<p><strong>AbortController</strong> is not an option; it is a necessity for any developer aiming for technical excellence. It allows you
to move from code that suffers from asynchrony to code that directs it. In 2026, the quality of an application is judged
not only by what it displays but by the cleanliness with which it handles what it no longer displays.</p>
<p>Take back control, cancel the superfluous, and build a faster, more human web.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Is the cancellation reversible?</summary>
No. Once a signal has transitioned to the "aborted" state, it cannot go back. To restart an operation, you must create a new instance of <strong>AbortController</strong>.
</details>
<details>
<summary>Can I cancel synchronous code with this API?</summary>
Not natively. <strong>AbortController</strong> is designed for asynchronous APIs that accept an <code>AbortSignal</code>. For synchronous code (like a massive <code>for</code> loop), you must manually check the <code>signal.aborted</code> property at each iteration.
</details>
<details>
<summary>What is the browser support in 2026?</summary>
Support is at <strong>95.78%</strong> (data as of <time datetime="2026-02-11T18:00:00+00:00">February 11, 2026</time>, subject to change). You can check the current support status on <a href="https://caniuse.com/?search=abortController">CanIUse</a>. All modern browsers (Chrome, Firefox, Safari, Edge) as well as Node.js and Deno support AbortController natively. For very old environments, lightweight polyfills exist.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Web Accessibility Audit: A Critical Guide to 11 Essential Tools (WCAG &amp; EAA 2025)</title>
            <link>https://lionel-peramo.com/posts/web-accessibility-audit-tools/</link>
            <guid>https://lionel-peramo.com/posts/web-accessibility-audit-tools/</guid>
            <pubDate>Wed, 11 Feb 2026 11:30:00 +0000</pubDate>
            <description>Critical and detailed analysis of 11 accessibility tools (Axe, WAVE, NVDA, Stark). Understand their strengths, weaknesses, and their role in WCAG and EAA 2025 compliance.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 11 min</p>
              
<p>Accessibility is not just a checkbox; it is a <strong>software quality</strong> assurance process. Even the best intentions can fail
if they are not backed by rigorous tools and a clear audit methodology.</p>
<p>An audit tool does only one thing: it helps you validate the technical application of <strong>WCAG</strong> rules. It will never
replace your <strong>developer</strong> judgment. For this reason, it is essential to know the strengths and limits of each
instrument.</p>
<p>This guide is a critical examination of the <strong>11 essential tools</strong> to ensure the compliance of your projects, especially
in view of the <strong>European Accessibility Act (EAA 2025)</strong>.</p>
<h2>1. Automated Analysis Tools (CI/CD Integration)</h2>
<h3>A. Axe Accessibility (Deque Systems) — The Industrial Standard</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left"><strong>Browser</strong> extension (DevTools), <strong>Node.js</strong> library (<code>axe-core</code>).</td>
</tr>
<tr>
<td align="left"><strong>Site</strong></td>
<td align="left"><a href="https://www.deque.com/axe/">deque.com/axe</a></td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left"><strong>Extremely reliable.</strong> Almost zero false positives. Focuses on clear technical issues (e.g., misspelled <strong>ARIA</strong> roles).</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left"><strong>Limited coverage (~40% of WCAG).</strong> Misses issues requiring human judgment (e.g., meaningful <code>alt</code> text).</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left">Integrate <code>axe-core</code> into tests to block the deployment of non-compliant components.</td>
</tr>
</tbody>
</table>
<h3>B. WAVE (WebAIM) — The Educational Evaluation Tool</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left"><strong>Browser</strong> extension and online web service.</td>
</tr>
<tr>
<td align="left"><strong>Site</strong></td>
<td align="left"><a href="https://wave.webaim.org/">wave.webaim.org</a></td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left"><strong>Instant visualization.</strong> Overlays icons directly on your <strong>page</strong> to spot errors (missing titles, <strong>forms</strong> without labels).</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left">Less precise than Axe. Can produce too many “Structure” or “Best Practice” alerts.</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left"><strong>Quick check</strong> to raise team awareness or verify the visual flow of the <strong>page</strong>.</td>
</tr>
</tbody>
</table>
<h3>C. Lighthouse (Chrome DevTools) — The Global Score Audit</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left">Native tab integrated into Chrome and Edge development tools (F12).</td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left"><strong>360° Vision.</strong> The only tool linking accessibility, <strong>performance</strong> (Core Web Vitals), and <strong>SEO</strong> in one report.</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left"><strong>Less granular.</strong> Uses the Axe engine but with fewer options. Scores can be misleading if manual barriers remain.</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left"><strong>Sanity Check.</strong> Use it to ensure no major regressions across performance and accessibility before launch.</td>
</tr>
</tbody>
</table>
<h2>2. Manual Testing Tools</h2>
<h3>A. Screen Readers (NVDA and VoiceOver)</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left"><strong>NVDA</strong> (Free software for Windows), <strong>VoiceOver</strong> (Built into macOS/iOS).</td>
</tr>
<tr>
<td align="left"><strong>Site</strong></td>
<td align="left"><a href="https://www.nvaccess.org/">NVDA</a> &amp; <a href="https://www.apple.com/accessibility/vision/">VoiceOver</a></td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left"><strong>The ultimate test.</strong> Only way to verify if the meaning of your <strong>HTML</strong> and <strong>ARIA</strong> tags is truly understood by the user.</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left">Learning curve for <strong>developers</strong>. Audit time is significantly longer.</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left"><strong>Mandatory</strong> for testing complex widgets (menus, <strong>combobox</strong>, modal windows).</td>
</tr>
</tbody>
</table>
<h3>B. Keyboard Navigation (The Tab Key)</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left">Native to any <strong>browser</strong>.</td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left"><strong>Zero tools required.</strong> Validates logical navigation order and identifies elements unreachable via keyboard.</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left">Provides no information about what is read by a screen reader.</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left">Manage focus movement with <code>tabindex</code> and the <strong><code>inert</code></strong> attribute for modals.</td>
</tr>
</tbody>
</table>
<h2>3. Design and Contrast Validation Tools</h2>
<h3>A. Color Contrast Analyzer (TPGi)</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left">Simple desktop application (includes an eyedropper).</td>
</tr>
<tr>
<td align="left"><strong>Site</strong></td>
<td align="left"><a href="https://www.tpgi.com/color-contrast-checker/">tpgi.com/color-contrast-checker</a></td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left">Measures exact contrast ratios anywhere on your screen (web page or Figma mockups).</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left"><strong>Manual check</strong>: cannot scan a whole site at once; each color combination must be tested individually.</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left">Final validation of <strong>4.5:1 (WCAG AA)</strong> contrast ratio for text.</td>
</tr>
</tbody>
</table>
<h3>C. Stark (Figma/Sketch Plugin) — Design Integration</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left">Plugin for Figma, Sketch, or Adobe XD.</td>
</tr>
<tr>
<td align="left"><strong>Site</strong></td>
<td align="left"><a href="https://www.getstark.co/">getstark.co</a></td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left"><strong>Anticipation.</strong> Check contrast <em>while</em> designing mockups, before any <strong>development</strong> begins.</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left">Some advanced features require a paid subscription.</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left">Build an accessibility culture from the very start of the project.</td>
</tr>
</tbody>
</table>
<h2>4. Journey Audit Tools</h2>
<h3>A. Tanaguru — User Journey Audit</h3>
<table>
<thead>
<tr>
<th align="left">Feature</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><strong>Format</strong></td>
<td align="left">Online platform (free and paid options).</td>
</tr>
<tr>
<td align="left"><strong>Site</strong></td>
<td align="left"><a href="https://tanaguru.com/">tanaguru.com</a></td>
</tr>
<tr>
<td align="left"><strong>Strengths</strong></td>
<td align="left"><strong>Comprehensive analysis.</strong> Tests a sequence of actions across multiple pages. Ideal for checkout or registration flows.</td>
</tr>
<tr>
<td align="left"><strong>Weaknesses</strong></td>
<td align="left">Requires more setup time than browser extensions.</td>
</tr>
<tr>
<td align="left"><strong>Pro usage</strong></td>
<td align="left">Verification of <strong>EAA 2025</strong> compliance for critical user journeys.</td>
</tr>
</tbody>
</table>
<h2>Conclusion: Accessibility is a Quality Metric</h2>
<p>Mastering these <strong>tools</strong> allows you to offload low-level validation from <strong>development</strong> to focus on <strong>complex
semantics</strong> and <strong>UX</strong>. By combining automation (Axe) with manual testing (NVDA), you guarantee not only <strong>WCAG</strong>
compliance but also a truly superior experience for every user.</p>
<p>In 2026, accessibility is the new indicator of <strong>performance</strong> and technical rigor.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Which tool should be integrated into a CI/CD pipeline for accessibility?</summary>
The <strong><code>axe-core</code></strong> library is the standard choice. It is ultra-fast and designs its tests for
minimum false positives, guaranteeing that the <em>build</em> will only be broken in case of a proven technical error on
the <strong>HTML</strong> or <strong>ARIA</strong>.
</details>
<details>
<summary>How to test LCP (Largest Contentful Paint) for accessibility?</summary>
LCP is a <strong>performance</strong> metric. Accessibility techniques encourage the use of native <strong>semantic
HTML</strong> rather than heavy <strong>JavaScript</strong>. This native sobriety mechanically leads to better LCP
scores. Use <strong>Lighthouse</strong> for measurement.
</details>
<details>
<summary>Is the HTML inert attribute supported everywhere?</summary>
The <strong><code>inert</code></strong> attribute has been part of the "Baseline" since 2024 and is now widely supported
by modern <strong>browsers</strong> (Chrome, Edge, Safari, Firefox). It is safe to use to improve
<strong>accessibility</strong> and keyboard <strong>focus</strong> without external scripts.
</details>

            ]]></content:encoded>
        </item><item>
            <title>CSS Media Queries and Accessibility: The Complete Guide for an Inclusive Web</title>
            <link>https://lionel-peramo.com/posts/css-media-queries-accessibility/</link>
            <guid>https://lionel-peramo.com/posts/css-media-queries-accessibility/</guid>
            <pubDate>Mon, 02 Feb 2026 21:30:00 +0000</pubDate>
            <description>Learn how to use CSS media queries to build sites that adapt to everyone. A simple, high-performance guide to respecting your users&#039; preferences.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 8 min</p>
              
<p>Web accessibility is often seen as a technical chore. We tend to think it is only about complying with laws like the
<strong>EAA 2025</strong>. In reality, accessibility is a mark of quality. An accessible site is better built and faster for
everyone.</p>
<p>In 2026, we have precision tools to help users: <strong>Preference Media Queries</strong>. These lines of code detect settings chosen
by users on their phones or computers. The site can then change its look automatically.</p>
<p>In this guide, we will explore 7 essential media queries. We will learn how to code for maximum performance while
remaining compatible with all browsers.</p>
<h2>A Golden Rule: Progressive Enhancement</h2>
<p>Before coding, you must understand an important rule. Do not build a heavy site and then try to “fix” it for people with
disabilities. Do the opposite.</p>
<p>Use the <strong>Progressive Enhancement</strong> logic:</p>
<ol>
<li>First, create a simple, static, and easy-to-read base. This is the version for everyone.</li>
<li>Add animations or visual effects only if the user has not requested restrictions.</li>
</ol>
<p>To achieve this, we often use the <code>no-preference</code> value.</p>
<h2>1. <code>prefers-reduced-motion</code>: mastering movement</h2>
<p>Some people experience dizziness or nausea when there is too much movement on the screen. These are called vestibular
disorders. About 35% of adults over 40 are affected by these disorders, according to a
<a href="https://pubmed.ncbi.nlm.nih.gov/19468085/">study published by the National Institutes of Health</a>.</p>
<p>Unfortunately, since support is currently limited on some browsers, we cannot condition everything via this media query.
If a browser does not support it, no style will be applied. To avoid this, we define a static base and then add the
animation inside the media query block. We will therefore have two contradictory orders when the value is
“no-preference,” but that is the price of compatibility.</p>
<h3>The high-performance method:</h3>
<pre><code class="language-css">/* Static and lightweight base for everyone */
.my-title {
  transform: none;
}

/* Animation is only enabled if the user accepts movement */
@media (prefers-reduced-motion: no-preference) {
  .my-title {
    animation: 1s slide-in forwards;
  }
  
  :root {
    scroll-behavior: smooth;
  }
}
</code></pre>
<h2>2. <code>prefers-color-scheme</code>: native dark mode</h2>
<p>This is likely the most well-known media query. It detects whether the user has chosen a light or dark theme in their
device settings.</p>
<p>Using <code>prefers-color-scheme</code> is essential for visual comfort. It is also a gesture for the planet: on modern (OLED)
screens, displaying black consumes less energy.</p>
<h3>Optimize with light-dark()</h3>
<p>To go further and simplify your code, you can combine this query with the new <code>light-dark()</code> function. It allows you to
manage two colors in a single line of code.</p>
<p>To understand how to use it and boost your rendering performance, read my
<a href="/posts/css-light-dark-mode-guide/">complete guide on the light-dark() function and eco-design</a>.</p>
<h2>3. <code>prefers-contrast</code>: visual clarity</h2>
<p>Not everyone perceives contrasts the same way. With age or certain vision conditions (like cataracts), light gray text
on a white background becomes unreadable.</p>
<h3>Implementation:</h3>
<pre><code class="language-css">.my-card {
  border: 1px solid #ccc;
}

@media (prefers-contrast: more) {
  .my-card {
    border: 2px solid #000; /* Thicker, black border */
    box-shadow: none;       /* Remove shadows that blur vision */
  }
}
</code></pre>
<h2>4. <code>forced-colors</code>: visual survival mode</h2>
<p>On Windows, “High Contrast” mode replaces your colors with a palette chosen by the system. In this case, your background
colors disappear. You must ensure that your elements remain visible through their borders.</p>
<p>It is useless to fight against this mode. You must embrace it by using system color keywords.</p>
<pre><code class="language-css">@media (forced-colors: active) {
  .action-button {
    /* Force a border that adapts to system colors */
    outline: 2px solid ButtonText;
    border: 1px solid ButtonText;
  }
}
</code></pre>
<p>To see all available codes, check the
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/system-color">system colors list on MDN</a>. This
guarantees that your buttons will never be invisible.</p>
<h2>5. <code>inverted-colors</code>: respecting system inversion</h2>
<p>Some visually impaired users invert all their screen colors to read better (white becomes black, blue becomes orange).
The problem is that your photos also become unreadable “negatives.” The <code>inverted-colors</code> query allows you to fix this.</p>
<pre><code class="language-css">@media (inverted-colors: inverted) {
  img, video {
    /* Re-invert images to make them look natural again */
    filter: invert(100%);
  }
}
</code></pre>
<h2>6. <code>prefers-reduced-transparency</code>: avoiding visual fatigue</h2>
<p>Blur effects (Glassmorphism) are pretty but tire the brains of people with attention disorders or reading difficulties.
Text becomes blurry on a transparent background.</p>
<p>Since Firefox does not yet handle this option, we use the same logic as for movement: a solid base style, and the visual
effect added only for those without restrictions.</p>
<pre><code class="language-css">/* Base: solid, opaque background for easy reading */
.nav-menu {
  background: #ffffff;
}

/* Visual effect added only if the user has no restriction */
@media (prefers-reduced-transparency: no-preference) {
  .nav-menu {
    background: rgba(255, 255, 255, 0.7);
    backdrop-filter: blur(5px);
  }
}
</code></pre>
<h2>7. The <code>speech</code> media query: the web for ears</h2>
<p>Accessibility is also for those who listen to the web. Blind users use software that reads the site aloud. The <code>speech</code>
query allows you to adapt the text specifically for these tools.</p>
<pre><code class="language-css">@media speech {
  .decorative-spacer, .ads-banner {
    display: none;
  }
}
</code></pre>
<h2>Performance and SEO: why code this way?</h2>
<p>Using these techniques is not just an ethical act. It is a software quality strategy:</p>
<ol>
<li><strong>Zero JavaScript:</strong> CSS is handled natively by the browser, which is much faster than detection scripts.</li>
<li><strong>LCP Score:</strong> Rendering is more stable because media queries are resolved instantly during CSS parsing.</li>
<li><strong>Technical SEO:</strong> Google favors sites that respect web standards and provide a smooth experience for all user
profiles.</li>
</ol>
<h2>Conclusion: a more human web</h2>
<p>Learning accessibility media queries is the mark of an expert developer in 2026. It’s not just extra code; it’s
better-thought-out code. An accessible site is a universal site, performant and ready for the future.</p>
<p>Inclusion is the ultimate form of optimization.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Do I have to test all these media queries?</summary>
Yes, and it's easy! In <strong>Chrome DevTools</strong>, go to the "Rendering" tab. You can simulate every user
preference with one click.
</details>
<details>
<summary>Why does <code>forced-colors</code> break my gradients?</summary>
That is intentional. The goal of this mode is readability, not aesthetics. The system simplifies everything so the user
can read effortlessly.
</details>
<details>
<summary>Is native dark mode enough for accessibility?</summary>
No. It is a good start for comfort, but accessibility also requires checking contrasts and keyboard navigation.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Mastering Dark Mode in 2026: The Expert Guide to light-dark() and Eco-design</title>
            <link>https://lionel-peramo.com/posts/css-light-dark-mode-guide/</link>
            <guid>https://lionel-peramo.com/posts/css-light-dark-mode-guide/</guid>
            <pubDate>Wed, 28 Jan 2026 10:00:00 +0000</pubDate>
            <description>Dark mode is used by 82% of internet users. Learn how to use native light-dark() and color-scheme functions for a fast, energy-efficient website.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 8 min</p>
              
<p>Dark mode is no longer just a trend. It is a mandatory ergonomic standard. According to a study on <a href="https://thesmallbusinessblog.com/dark-mode-users/">Dark Mode usage by
82% of users</a>, this setting has become the norm. It now dictates how I design my interfaces.</p>
<p>However, many websites still use outdated methods. These methods slow down the browser. They create unpleasant flashes
of light during page load. In 2026, I must use native CSS tools. This guide explains how to combine technical
performance with visual comfort.</p>
<h2>Why dark mode is a strategic priority</h2>
<p>A dark theme is not just “pretty.” It is a powerful lever for three pillars: health, energy, and performance.</p>
<h3>1. Accessibility and eye health</h3>
<p>Dark mode reduces eye strain. This is especially true in dark environments. It also helps people sensitive to bright
light (photophobia).</p>
<p>However, I must be careful with contrasts. Dark gray on a black background is unreadable. I follow <strong>WCAG 2.1</strong>
standards. This ensures my content remains accessible to everyone.</p>
<h3>2. Eco-design and battery life</h3>
<p>This is where technology meets ecology. On OLED screens, a black pixel is a pixel turned off. A turned-off pixel
consumes no energy.</p>
<p>According to <a href="https://dl.acm.org/doi/10.1145/3458864.3467682">a study published by the ACM</a>, dark mode can save up to <strong>47% of battery</strong>. This gain is highest when
screen brightness is high. At 50% brightness, the saving drops to around 9%. Dark mode is a concrete <strong>digital
sobriety</strong> tool for mobile users.</p>
<h3>3. Rendering performance</h3>
<p>Old methods used a lot of JavaScript. JavaScript must be loaded and executed. This increases <strong>Total Blocking Time
(TBT)</strong>.</p>
<p>Native CSS is handled directly by the browser’s rendering engine. It is faster. It uses less processor (CPU) power. It
is the best choice for web performance.</p>
<h2>The <code>color-scheme: light dark</code> revolution</h2>
<p>For a long time, developers used classes like <code>.dark-mode</code> on the <code>&lt;body&gt;</code> tag. It was heavy. It required syncing
JavaScript and CSS.</p>
<p>The first modern step is to declare theme support to the browser:</p>
<pre><code class="language-css">:root {
  /* Tell the browser that I support both themes */
  color-scheme: light dark;
}
</code></pre>
<p>This line is magic. It automatically changes native elements of the page:</p>
<ul>
<li>Scrollbars.</li>
<li>Buttons and form fields.</li>
<li>Default system background colors.</li>
</ul>
<h2>The elegance of the CSS <code>light-dark()</code> function</h2>
<p>The <code>light-dark()</code> function is a major new feature. It allows defining two values in a single property. It is much
cleaner than repeating media queries everywhere.</p>
<h3>Syntax and implementation</h3>
<p>Here is how I centralize my colors:</p>
<pre><code class="language-css">:root {
  color-scheme: light dark;

  /* light-dark(light-value, dark-value) */
  --bg-primary: light-dark(#f4f4fa, #16191a);
  --text-main: light-dark(#333333, #eeeeee);
  --accent: light-dark(#005398, #4dabf7);
}

body {
  background-color: var(--bg-primary);
  color: var(--text-main);
}
</code></pre>
<p><strong>The major benefit:</strong> The code is shorter. The CSS tree is simplified. The browser decides which value to use instantly.</p>
<h2>Managing images in dark mode</h2>
<p>A very bright image can blind a user in dark mode. This breaks the user experience. There are two technical solutions.</p>
<h3>1. Darken via CSS filters</h3>
<p>I can apply a global filter. It is fast and effective for photos:</p>
<pre><code class="language-css">@media (prefers-color-scheme: dark) {
  img:not([src$=&quot;.svg&quot;]) {
    /* Lower brightness and boost contrast for better visibility */
    filter: brightness(.85) contrast(1.1);
  }
}
</code></pre>
<h3>2. Use the <picture> element for diagrams</h3>
<p>Sometimes, a simple brightness drop is not enough. This applies to charts or logos. In that case, I use two versions of
the image:</p>
<pre><code class="language-html">&lt;picture&gt;
  &lt;source srcset=&quot;chart-dark.avif&quot; media=&quot;(prefers-color-scheme: dark)&quot;&gt;
  &lt;img src=&quot;chart-light.avif&quot; alt=&quot;Technical architecture diagram&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;
&lt;/picture&gt;
</code></pre>
<h2>Avoiding Flash of Unstyled Content (FOUC)</h2>
<p>The light “flash” (FOUC) happens when JavaScript takes too long to execute. The user sees the light mode for a fraction
of a second before the dark mode activates. This is a serious UX error.</p>
<p><strong>The high-performance solution:</strong>
By using <code>prefers-color-scheme</code> and <code>light-dark()</code>, the browser knows the theme before displaying the first pixel.</p>
<ol>
<li>No JavaScript to load.</li>
<li>No preference to read from a database.</li>
<li>No visual flash.</li>
</ol>
<p>This is the approach I use in <strong>EcoComposer</strong>. The library detects user preferences declaratively. This ensures a smooth
experience, even on slow connections.</p>
<h2>Dark design pitfalls</h2>
<p>A successful dark mode requires subtlety. Here are three common mistakes I avoid.</p>
<h3>1. Pure black (#000)</h3>
<p>I never put pure white text on a pure black background. High contrast tires the eyes. It creates a “halation” effect. I
prefer very dark grays like <code>#121212</code>.</p>
<h3>2. Color saturation</h3>
<p>A bright color is perfect on a white background. On a dark background, it can become “electric” and aggressive. <strong>I
desaturate my accent colors</strong> for dark mode. Users will appreciate it.</p>
<h3>3. Depth and elevation</h3>
<p>In light mode, I use drop shadows to create depth. In dark mode, shadows are invisible. To show that an element is in
the foreground (like a modal), I use a slightly lighter background color.</p>
<ul>
<li>Page background: <code>#121212</code>.</li>
<li>Elevated element: <code>#1e1e1e</code>.</li>
</ul>
<h2>Impact on SEO and Core Web Vitals</h2>
<p>Google loves fast sites. Native dark mode directly helps your scores:</p>
<ul>
<li><strong>LCP (Largest Contentful Paint):</strong> Less JavaScript means faster display.</li>
<li><strong>CLS (Cumulative Layout Shift):</strong> Avoiding late CSS classes prevents layout shifts.</li>
</ul>
<p>A comfortable site keeps users longer. This improves your bounce rate. It is a positive signal for your SEO.</p>
<h2>Conclusion: responsible code craftsmanship</h2>
<p>Mastering dark mode is proof of professionalism. By using <code>light-dark()</code> and <code>color-scheme</code>, I show that I master modern
tools. I build a lighter, more accessible, and more sustainable web.</p>
<p>I don’t let technical constraints dictate my work. I use them to offer the best possible experience.</p>
<hr>
<h3>FAQ</h3>
<details>
<summary>Is light-dark() supported everywhere?</summary>
Yes, the function is supported by all modern browsers since late 2024. It is a "baseline" feature. For old browsers, I
use standard CSS variables as a fallback.
</details>
<details>
<summary>Does dark mode really save energy on all screens?</summary>
No. It only works on OLED and AMOLED screens. On standard LCD screens, the backlight is always on, even for black areas.
But since OLED is the mobile standard, the global gain is real.
</details>
<details>
<summary>Can I use light-dark() with images?</summary>
No, the function applies to CSS values (colors, lengths). For images, I use the <code>&lt;picture&gt;</code> element as
explained above.
</details>
<details>
<summary>What is the best contrast ratio for dark mode?</summary>
The AA standard requires a 4.5:1 ratio for text. In dark mode, aiming for a ratio between 7:1 and 10:1 is often more
comfortable to avoid eye fatigue.
</details>

            ]]></content:encoded>
        </item><item>
            <title>The HTML inert attribute: How to make an area inactive for a more accessible navigation</title>
            <link>https://lionel-peramo.com/posts/html-inert-attribute-make-area-inactive-accessibility/</link>
            <guid>https://lionel-peramo.com/posts/html-inert-attribute-make-area-inactive-accessibility/</guid>
            <pubDate>Tue, 27 Jan 2026 18:00:00 +0000</pubDate>
            <description>Learn how the HTML &#039;inert&#039; attribute allows you to make parts of your page inactive. Improve accessibility for people with disabilities and boost your performance.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 9 min</p>
              
<p>Creating a modern website often requires displaying overlapping elements, such as pop-up windows (modals) or slide-out
menus. But one question remains: how can you be sure that the user won’t click on a button left “behind” or navigate
with their keyboard in an area they can no longer see?</p>
<p>For a long time, this simple task was a nightmare for developers. It required writing very long and complicated
JavaScript scripts to prevent the cursor from moving anywhere. Today, there is a much simpler solution built directly
into the HTML language: the <strong><code>inert</code></strong> attribute.</p>
<p>In this guide, we will see how this tiny tool makes your sites faster, lighter, and above all, much simpler to use for
people with disabilities.</p>
<h2>What exactly is the <code>inert</code> attribute?</h2>
<p>The word “inert” means something that does not move or act. In web programming, when you add the <code>inert</code> attribute to a
part of your page (a <code>div</code>, a <code>section</code>, or a <code>main</code>), you tell the browser to consider that this area no longer exists
for the user.</p>
<p>It is not just a visual change. It is a deep “sleep mode” for the element. Here are the three main effects it produces
immediately:</p>
<ol>
<li><strong>No more clicking:</strong> Any links, buttons, or forms in the area become impossible to click with a mouse or touch on a</li>
<li>touchscreen.</li>
<li><strong>The keyboard ignores it:</strong> If a user uses the “Tab” key to move from one link to another, the browser will</li>
<li>directly skip the entire part marked as <code>inert</code>. This is a huge help for people with motor difficulties.</li>
<li><strong>Screen readers stay silent:</strong> Software used by blind people completely ignores the content of the area. This</li>
<li>prevents reading information that is not relevant at that moment.</li>
</ol>
<h3>A radically simple approach</h3>
<p>Unlike old methods that required modifying every button one by one, <code>inert</code> applies to a parent. If you set a box to
“inert,” everything inside it automatically becomes inert as well. This is called “shorthand” or “cascade” propagation.</p>
<h2>Why is it a revolution for accessibility?</h2>
<p>For a user who sees well and uses a mouse, it is easy to understand not to click on what is behind an open window. But
for a person with a disability, the situation is different.</p>
<h3>Protecting the user from “navigation errors”</h3>
<p>Imagine a blind person opening a navigation menu on their smartphone. If the developer hasn’t made the rest of the page
inactive, the screen reader will continue to suggest links from the footer or articles in the background, even though
the menu is still open. The user feels lost and no longer knows where they are on the site.</p>
<p>By using <code>inert</code>, you create a kind of “safety barrier.” You guide the user so they stay focused on the important action
of the moment (filling out a form, choosing an option in a menu) without risking leaving that area by mistake.</p>
<h3>Simplifying keyboard usage</h3>
<p>Many people use the keyboard instead of the mouse, either by habit or necessity (motor disability). Without the <code>inert</code>
attribute, these users sometimes have to press the “Tab” key 50 times to cross an entire page before reaching the
“Close” button of a window. With <code>inert</code>, you remove all unnecessary obstacles. Navigation becomes fluid and natural.</p>
<h2>How to use ‘inert’ in your code?</h2>
<p>One of the greatest advantages of this solution is its technical simplicity. You don’t need to be a programming expert
to use it.</p>
<h3>Practical example: the modal window</h3>
<p>This is the most common case. Here is how to structure your page so it works perfectly:</p>
<pre><code class="language-html">&lt;body&gt;
  &lt;!-- Wrap all main content in a div --&gt;
  &lt;div id=main-content&gt;
    &lt;header&gt;...&lt;/header&gt;
    &lt;main&gt;...&lt;/main&gt;
    &lt;footer&gt;...&lt;/footer&gt;
  &lt;/div&gt;

  &lt;!-- The window that pops up on top --&gt;
  &lt;div id=my-modal-window role=dialog aria-modal=true&gt;
    &lt;button onclick=&quot;close()&quot;&gt;Close&lt;/button&gt;
    &lt;p&gt;This is important information.&lt;/p&gt;
  &lt;/div&gt;
&lt;/body&gt;
</code></pre>
<p>When you display the window, you simply add the attribute to the area you want to make inactive:
<code>document.getElementById('main-content').setAttribute('inert', '');</code></p>
<p>And when you close the window, you remove the attribute:
<code>document.getElementById('main-content').removeAttribute('inert');</code></p>
<p>In a single line of <strong>code</strong>, you have solved all the interactivity problems on your page.</p>
<h2><code>Inert</code> vs <code>aria-hidden</code>: don’t get them confused anymore</h2>
<p>This is a very common confusion during <strong>development</strong>. Many sites use <code>aria-hidden=&quot;true&quot;</code>. It is a good intention, but
it is incomplete.</p>
<ul>
<li><strong><code>aria-hidden=&quot;true&quot;</code></strong>: Tells the screen reader not to read the area. But the user can still click on it or access</li>
<li>it with the Tab key on their keyboard. This is very confusing because you can interact with something that isn’t being</li>
<li>announced.</li>
<li><strong><code>inert</code></strong>: Blocks everything at the same time. Mouse, keyboard, and voice. It is the complete solution.</li>
</ul>
<h2>Performance and eco-design: code less to do more</h2>
<p>On this blog, I often talk about performance and respect for the digital environment (<strong>eco-design</strong>). The <code>inert</code>
attribute is an excellent example of this philosophy.</p>
<h3>Reducing page weight</h3>
<p>Previously, to manage navigation blocking, we downloaded JavaScript libraries (like <code>focus-trap</code>) that weighed several
dozen kilobytes. Multiplied by millions of visitors, this represents significant energy consumption for servers and
networks.</p>
<p>By using a native browser function, you remove these useless files. Your site loads faster, which improves your <strong>LCP
(Largest Contentful Paint)</strong> score. For Google, this is a positive signal that can help your <strong>SEO</strong>.</p>
<h3>Less work for the user’s computer</h3>
<p>Every script running in a browser consumes battery on a smartphone. <code>inert</code> is handled directly by the browser engine
(in very fast C++ language). It is much more energy-efficient than a JavaScript script that monitors every mouse
movement or every key press.</p>
<h2>A word on compatibility (Baseline 2024)</h2>
<p>For a few years, <code>inert</code> was an experimental novelty. That is no longer the case. Since 2024, it has been part of what
is called the “Baseline.” This means all modern browsers (Chrome, Firefox, Safari, Edge) support it perfectly.</p>
<p>If you still need to support very old browsers (which is increasingly rare), light “polyfills” (backup scripts) exist,
but for 96% of internet users, this will work natively without any extra effort on your part.</p>
<h2>Design tip: stylizing inactive zones</h2>
<p>To improve the <strong>user experience (UX)</strong>, it is recommended to visually show that the background content is no longer
available. You can use the <code>inert</code> attribute as a selector in your CSS file:</p>
<pre><code class="language-css">/* Reduce visibility of everything that is inert */
[inert] {
  opacity        : .4;
  filter         : blur(2px);
  user-select    : none;
  pointer-events : none;
}
</code></pre>
<p>This way, the user immediately understands, at a glance, that they must focus on the active window. It’s an elegant way
to marry design and technology.</p>
<h2>Conclusion: Toward responsible code craftsmanship</h2>
<p>Adopting the <code>inert</code> attribute is not just about saving the developer time. It is a sign of respect toward users. By
choosing native and lightweight solutions, we build a <strong>web</strong> that leaves no one behind, whether they are people with
disabilities or users with slow internet connections.</p>
<p>In 2026, the quality of a site is no longer measured by the complexity of its scripts, but by the relevance of its
technical choices. Use <code>inert</code>, simplify your code, and make accessibility a strength for your project.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Does the inert attribute also block forms?</summary>
Yes. If you apply <code>inert</code> to a form, the user will no longer be able to fill in fields or click the submit
button. This is very useful for preventing double form submission during loading.
</details>
<details>
<summary>Can I set the 'body' element to inert?</summary>
Technically yes, but it is discouraged because it would block absolutely the entire site, including the window you are
trying to display. It is better to target a container that holds everything except your modal window.
</details>
<details>
<summary>Does Google see inert content?</summary>
Yes. Search engine bots still read the HTML code. <code>inert</code> does not prevent the indexing of content; it only
prevents human interaction.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Visual Impairments and the Web: The Ultimate Guide to Inclusive Design</title>
            <link>https://lionel-peramo.com/posts/visual-impairments-inclusive-design/</link>
            <guid>https://lionel-peramo.com/posts/visual-impairments-inclusive-design/</guid>
            <pubDate>Mon, 26 Jan 2026 21:00:00 +0000</pubDate>
            <description>Over 2.2 billion people live with a vision impairment. Learn how to simulate, test, and code for inclusion without sacrificing your design.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 9 min</p>
              
<p>Web accessibility is often perceived as a purely technical constraint—a simple checkbox to comply with legal standards
like the <strong>EAA 2025</strong>. However, behind the algorithms and tags lies a massive human reality: according to the <a href="https://www.who.int/news-room/fact-sheets/detail/blindness-and-visual-impairment">World
Health Organization</a>, at least <strong>2.2 billion people</strong> suffer from near or far vision impairment.</p>
<p>For a developer or designer, ignoring this audience is not just an ethical lapse; it’s a major strategic mistake. An
unreadable site is a site that doesn’t convert. In this article, we will explore how to turn this “constraint” into a
lever for software quality by learning how to simulate these impairments and code robust CSS solutions.</p>
<h2>Understanding the Spectrum of Visual Impairments</h2>
<p>A common mistake is reducing vision impairment to total blindness. In reality, the spectrum is vast and impacts web
navigation in diverse ways:</p>
<ol>
<li><strong>Color Blindness (Dyschromatopsia):</strong> According to the <a href="https://www.colourblindawareness.org/colour-blindness/">Colour Blind Awareness
organization</a>, it affects approximately 8% of men and 0.5%
of women. Whether it’s protanopia (red), deuteranopia (green), or tritanopia (blue), the problem remains the same:
information transmitted solely through color is lost.</li>
<li><strong>Low Vision:</strong> This includes reduced visual acuity, blurred vision, or extreme sensitivity to light. These users
often rely on intensive zooming (up to 400%), an adaptation requirement now mandated by <a href="https://www.w3.org/WAI/WCAG21/Understanding/reflow.html">W3C WCAG standards</a>.</li>
<li><strong>Central or Peripheral Vision Loss:</strong> Conditions like macular degeneration (AMD) or glaucoma create “dead zones” in
the field of vision.</li>
<li><strong>Cataracts:</strong> This produces clouded vision and a drastic loss of contrast, making thin or light gray fonts
completely invisible.</li>
</ol>
<h2>Simulating to Better Understand: Browser Tools</h2>
<p>Before fixing, you must feel. Did you know that your <strong>Chrome DevTools</strong> (and Firefox) include real-time vision
simulators?</p>
<h3>How to Enable the Simulation?</h3>
<ol>
<li>Open the Inspector (F12).</li>
<li>Use the shortcut <code>Ctrl+Shift+P</code> (or <code>Cmd+Shift+P</code> on Mac) to open the command palette.</li>
<li>Type “<strong>Rendering</strong>” and select the tab.</li>
<li>Scroll down to the “<strong>Emulate vision deficiencies</strong>” section.</li>
</ol>
<p>Here, you can test your site through the eyes of someone with protanopia or blurred vision. It’s often a brutal
experience for a designer: you instantly realize that your “critical” red buttons on a dark background are invisible to
part of your users.</p>
<h2>CSS Strategies for an Inclusive Interface</h2>
<p>Once the observation is made, how do you act at the <strong>code</strong> level? Accessibility doesn’t mean making “ugly” or
black-and-white sites. It’s about resilient design.</p>
<h3>1. Contrast: The Golden Rule</h3>
<p>The WCAG 2.1 standard requires a contrast ratio of at least <strong>4.5:1</strong> for normal text and <strong>3:1</strong> for large text.</p>
<ul>
<li><strong>Technical Tip:</strong> Use tools like <code>color.review</code> to find combinations that work.</li>
<li><strong>Beyond Black and White:</strong> Avoid pure contrast (black #000 on white #FFF), which can cause eye strain (halation) in
people with dyslexia or photophobia. Prefer very dark grays on off-whites.</li>
</ul>
<h3>2. Typography: Abandon Pixels</h3>
<p>This is the most common <strong>frontend</strong> error. Using <code>px</code> for font sizes blocks the user’s ability to resize text via their
browser settings.</p>
<ul>
<li><strong>The Solution:</strong> Use the <code>rem</code> unit. It is based on the root size defined by the user.</li>
<li><strong>Line Height and Spacing:</strong> A <code>line-height</code> of at least 1.5 and generous paragraph spacing radically improve
reading for people with blurred vision.</li>
</ul>
<h3>3. Layout Robustness (The Zoom Test)</h3>
<p>A visually impaired user will zoom your page to 200% or even 400%. If your menu overlaps the content or columns clash,
the site is unusable.</p>
<ul>
<li><strong>Fluid Design:</strong> Use Flexbox and CSS Grid to allow content to reorganize naturally.</li>
<li><strong>Container Queries:</strong> This is the future. They allow a component to adapt to the space allocated to it, rather than
the total screen width, which is crucial during intensive zooming.</li>
</ul>
<h2>Media Queries: Give Control Back to the User</h2>
<p>Modern CSS offers tools to detect user preferences at the operating system level.</p>
<pre><code class="language-css">/* Detect &quot;High Contrast&quot; modes forced by the OS */
@media (forced-colors: active) {
  .button {
    /* We force a border because the background might disappear */
    border: 2px solid ButtonText;
    outline: 1px solid transparent;
  }
}

/* For light-sensitive users */
@media (prefers-color-scheme: dark) {
  body { background-color: #121212; color: #e0e0e0; }
}

/* For those who enabled &quot;High Contrast&quot; on Windows/macOS */
@media (prefers-contrast: more) {
  .button { border: 2px solid currentColor; }
}

/* Activate animations only if no reduction is requested */
@media (prefers-reduced-motion: no-preference) {
    .modal {
      animation: fadeIn 0.3s ease-in-out;
    }
    .link {
      transition: color 0.2s ease;
    }
}
</code></pre>
<p>These <strong>media queries</strong> allow you to offer a personalized experience without the user having to configure anything on
your site. This is the principle of <strong>Universal Design</strong>.</p>
<h2>SEO and Performance Impact: The Virtuous Circle</h2>
<p>Many don’t know it, but visual accessibility is a direct booster for your <strong>Organic Search (SEO)</strong>. Google behaves like
the most powerful “visually impaired” user in the world: it analyzes code to understand meaning, not pixels.</p>
<h3>Alt Attributes: Signal vs. Noise</h3>
<p>It’s often said that everything must be described. This is false.</p>
<ol>
<li><strong>Informative Image:</strong> (e.g., a technical diagram) Use a descriptive <code>alt</code>. It’s vital for the user and excellent</li>
<li>for Google Images.</li>
<li><strong>Decorative Image:</strong> (e.g., an abstract shape, a repetitive icon) **The <code>alt</code> attribute must be present but empty</li>
<li>(<code>alt=&quot;&quot;</code>)**. Why? Because an empty <code>alt</code> tells the screen reader to ignore the image. If it’s missing, the reader</li>
<li>will often read the file name (e.g., “bg-pattern-01.jpg”), which is useless noise.</li>
</ol>
<h3>LCP and Core Web Vitals</h3>
<p>An accessible page often avoids heavy JavaScript layout manipulations. By using native and robust CSS, you improve your
<strong>LCP (Largest Contentful Paint)</strong> and visual stability, two key factors for ranking in 2026.</p>
<h2>Conclusion: Toward Responsible Code Craftsmanship</h2>
<p>Accessibility is not a destination; it’s a continuous practice. By integrating visual impairment simulation from the
<strong>development</strong> phase, you create more robust, faster, and more human interfaces.</p>
<p>In 2026, the web can no longer afford to be exclusive. Take control of your contrasts, free your typography, and
remember that every millisecond of clarity gained is a victory for all your users.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Does visual accessibility make my site less aesthetic?</summary>
Absolutely not. Giants like Apple or Stripe have extremely polished designs that scrupulously respect contrast ratios.
"Beautiful" and "accessible" are not opposites; accessibility is simply a superior form of ergonomics.
</details>
<details>
<summary>What is the easiest tool to check my contrasts?</summary>
In addition to DevTools, the <strong><a href="https://color.review/">Color Review</a></strong> website is a gold
standard. It allows you to see in real-time if your text is readable according to AA and AAA standards, while suggesting
hue adjustments.
</details>
<details>
<summary>Is dark mode enough to make a site accessible?</summary>
No. While it helps people with photophobia, dark mode can cause contrast issues if not managed well. It should be seen
as a complement, not a universal solution.
</details>
<details>
<summary>Why is 400% zoom important?</summary>
It's a requirement of the <strong>WCAG 1.4.10 (Reflow)</strong> criterion. At 400% on a desktop screen, the site must
behave like a mobile version without data loss or horizontal scrolling. It's the ultimate test for your CSS flexibility.
</details>

            ]]></content:encoded>
        </item><item>
            <title>Mastering Web Printing with CSS: The Complete Guide to Perfect Pages</title>
            <link>https://lionel-peramo.com/posts/mastering-css-print/</link>
            <guid>https://lionel-peramo.com/posts/mastering-css-print/</guid>
            <pubDate>Sat, 24 Jan 2026 17:00:00 +0000</pubDate>
            <description>Discover how to use @media print in CSS to create perfect print layouts. Optimize UX, accessibility, and eco-design while saving paper and ink.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 13 min</p>
              
<p>In the all-digital era, the idea of printing a web page might seem outdated. Yet, it is an essential feature that is far
from dead. From <strong>cooking recipes</strong> to consult with your hands full, to <strong>assembly guides</strong> to follow away from the
screen, or <strong>plane tickets</strong> to keep safe, users still have many reasons to move from pixels to paper.</p>
<p>What if I told you that your <strong>CSS</strong> can not only make this experience pleasant but also save trees and strengthen your
brand image?</p>
<p>This comprehensive guide will show you how to master print styles to transform a chaotic web page into a clear,
professional, and environmentally friendly document.</p>
<h2>The Strategic Impact of a Print Stylesheet</h2>
<p>Many developers ignore the print stylesheet, considering it a minor detail. This is a strategic mistake. Proper print
management has direct impacts on user experience, accessibility, and even your brand image.</p>
<h3>1. User Experience (UX) and Professionalism</h3>
<p>When a user clicks “Print,” they expect a readable document. If the result is a page filled with navigation elements,
advertisements, and cut-off columns, the experience is frustrating. A site that offers a clean, well-formatted print
version shows attention to detail and high professionalism.</p>
<h3>2. Accessibility (a11y)</h3>
<p>Accessibility isn’t limited to screen readers. For many people, especially seniors or those suffering from eye strain,
reading a long document is more comfortable on paper. Providing a printable and readable version is an important facet
of inclusion.</p>
<h3>3. Eco-design and Savings</h3>
<p>A well-designed print stylesheet is a simple but powerful <strong>eco-design</strong> gesture. By hiding unnecessary images and
forcing a white background, you significantly reduce your users’ ink and paper consumption. It’s good for their wallets
and for the planet.</p>
<h2>The Basics: <code>@media print</code></h2>
<p>The heart of the magic lies in a simple CSS <em>media query</em>. Everything inside this block will only apply when the page
is printed.</p>
<pre><code class="language-css">@media print {
  /* Your print styles go here... */
}
</code></pre>
<p>This approach keeps your print styles completely separate from your screen styles, with no impact on site performance
during normal browsing.</p>
<h2>6 Steps to a Perfect Print Layout</h2>
<p>Optimizing for print isn’t complicated. Follow these steps to cover 99% of needs.</p>
<h3>Step 1: Clean Up the Unnecessary</h3>
<p>The first rule is to hide everything that doesn’t belong on a sheet of paper. This includes navigation, footers,
sidebars, ads, comment forms, and interactive buttons.</p>
<pre><code class="language-css">@media print {
  header,
  nav,
  footer,
  aside,
  form,
  .comments,
  .ads,
  .no-print {
    display: none;
  }
}
</code></pre>
<h3>How to ensure these rules apply without conflict?</h3>
<p>You might think of specificity wars or using <code>!important</code>. However, the cleanest and most robust solution is
architectural: <strong>isolating screen-specific styles</strong>.</p>
<p>The best practice is to wrap all your complex layout rules or styles that only concern the screen display in a
<code>@media screen</code> media query.</p>
<p><strong>Concrete Example:</strong></p>
<p>Instead of having a global style for your header:</p>
<pre><code class="language-css">/* Bad practice: global style that may conflict */
.main-header {
  display: flex;
  justify-content: space-between;
  background-color: #333;
}
</code></pre>
<p>Structure your CSS to clearly separate contexts:</p>
<pre><code class="language-css">/* Base styles, shared by screen and print */
.main-header {
  /* Ex: padding, etc. */
}

/* Styles ONLY for the screen */
@media screen {
  .main-header {
    display: flex;
    justify-content: space-between;
    background-color: #333;
  }
}

/* Styles ONLY for print */
@media print {
  .main-header {
    display: none;
  }
}
</code></pre>
<p>With this architecture, the rules for <code>@media screen</code> and <code>@media print</code> are mutually exclusive. The browser will never
apply screen styles during printing, thus eliminating any risk of specificity conflict. Your <code>display: none;</code> will work
every time without needing to override selectors or use <code>!important</code>.</p>
<p>This approach ensures cleaner, more predictable, and easier-to-maintain code in the long run.</p>
<h3>Step 2: Adapt Typography for Reading</h3>
<p>What is readable on a screen isn’t necessarily so on paper.</p>
<ul>
<li><strong>Font Family:</strong> Serif fonts, such as <em>Georgia</em> or <em>Times New Roman</em>, are often considered more readable for long
texts on paper.</li>
<li><strong>Font Size:</strong> Use points (<code>pt</code>) rather than pixels (<code>px</code>) or <code>rem</code>. A size of <code>12pt</code> is a comfortable standard.</li>
<li><strong>Color:</strong> To save ink and maximize contrast, force the text to pure black and the background to white.</li>
</ul>
<pre><code class="language-css">@media print {
  body {
    font-family: Georgia, 'Times New Roman', Times, serif;
    font-size: 12pt;
    color: #000;
    background: #fff;
  }
}
</code></pre>
<h3>Step 3: Guarantee a Linear Layout</h3>
<p>Unlike a screen, a sheet of paper is a fixed-width linear medium. The goal is therefore to ensure that your content
flows in a single column, from top to bottom, for maximum readability.</p>
<p>Modern layouts using <code>display: flex</code> or <code>display: grid</code> are powerful assets here. If your site is already responsive and
displays in a single column on mobile screens, you’ve already done most of the work.</p>
<p>However, to guarantee this behavior during printing, regardless of the screen size from which the user starts the print,
it is recommended to explicitly reset the layout. This also ensures that screen-specific properties, like <code>position: sticky</code>, are neutralized.</p>
<pre><code class="language-css">@media print {
  /* Basic reset for main containers */
  main, .container, article {
    width: 100%;
    min-width: 0;
    margin: 0;
    padding: 0;
    box-shadow: none;
    border: none;
  }

  /* Force flexbox containers into a single vertical column */
  .flex-container {
    flex-direction: column;
  }

  /* Transform CSS grids into a simple, single-column flow */
  .grid-container {
    display: block; /* The simplest and most robust solution */
  }
}
</code></pre>
<p>By forcing a vertical direction for your main containers and resetting their dimensions, you ensure that the content
will flow naturally, providing an optimal reading experience on paper.</p>
<h3>Step 4: Handle Links</h3>
<p>Hyperlinks are useless on paper. To keep them helpful, it is good practice to display the full URL next to the link
text. This can be done very simply with a CSS pseudo-element.</p>
<pre><code class="language-css">@media print {
  a::after {
    content: ' (' attr(href) ')';
    font-size: 9pt;
    color: #333;
  }

  /* Avoid displaying internal links or anchors */
  a[href^=&quot;#&quot;]::after,
  a[href^=&quot;javascript:&quot;]::after {
    content: '';
  }
}
</code></pre>
<h3>Step 5: Control Page Breaks</h3>
<p>This is where the magic really happens. CSS gives you control over where page breaks should (or should not) occur.</p>
<ul>
<li><code>break-inside: avoid;</code>: Prevents an element (like an image or a code block) from being split in two by a page break.</li>
<li><code>break-before: page;</code>: Forces a page break <em>before</em> an element. Very useful for starting a new section on a new page.</li>
<li><code>break-after: page;</code>: Forces a page break <em>after</em> an element.</li>
</ul>
<pre><code class="language-css">@media print {
  h2, h3 {
    break-after: avoid; /* Prevents a page break right after a heading */
  }

  figure, pre, table {
    break-inside: avoid; /* Protects figures and tables from being cut */
  }
}
</code></pre>
<h3>Step 6: Manage Page Margins with <code>@page</code></h3>
<p>The <code>@page</code> rule is specific to printing and allows you to define the margins of the printed document, much like in a
word processor.</p>
<pre><code class="language-css">@media print {
  @page {
    margin : 2cm;
  }

  /* You can even target the first page differently */
  @page :first {
    margin-block-start : 3cm;
  }
}
</code></pre>
<h2>Testing Your Print Styles</h2>
<p>No need to waste paper! All modern browsers include a print preview mode in their developer tools.</p>
<ol>
<li>Open developer tools (F12 or Ctrl+Shift+I).</li>
<li>Go to the “More tools” menu &gt; “Rendering”.</li>
<li>Look for the “Emulate CSS media type” option and select “print”.</li>
</ol>
<p>Your page will instantly display as if it were being printed, allowing you to adjust your styles in real time.</p>
<h2>Conclusion: Small Effort, Big Impact</h2>
<p>Optimizing print styles is an often-neglected task, but it demonstrates a high level of polish and respect for the user.
With just a few lines of <strong>CSS</strong>, you not only improve the <strong>user experience</strong> and <strong>accessibility</strong>, but you also make
a concrete gesture for digital <strong>eco-design</strong>.</p>
<p>It is proof that well-thought-out code can have benefits far beyond the screen.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Is print optimization still relevant in 2026?</summary>
Absolutely, and perhaps even more than we think. While uses like printing invoices are decreasing with digitalization,
many contexts where paper remains indispensable persist:
<ul>
<li>Practical guides and tutorials: A cooking recipe followed in the kitchen, a drawing guide, a sewing pattern, or a
furniture assembly plan. All these activities require consulting information while having your hands full, away from the screen.</li>
<li>Educational and dense content: Research articles, technical documentation, or course materials that one wishes to
physically annotate for better assimilation.</li>
<li>Accessibility and sharing: For people suffering from eye strain or to share information with a relative less
comfortable with digital tools.</li>
<li>Safety while traveling: Plane tickets, hotel reservations, or itineraries, where a paper copy remains a valuable
backup in case of battery or network issues.</li>
</ul>
<p>Ignoring printing means degrading the experience for all these use cases. Offering a clean printable version is a mark
of quality and respect for the end user.</p>
</details>
<details>
<summary>How do I handle frameworks like Bootstrap or Tailwind?</summary>
Most modern frameworks include utility classes for printing. For example, Bootstrap uses <code>d-print-none</code> to
hide an element during printing and <code>d-print-block</code> to show it. Tailwind offers a <code>print:</code>
modifier, such as <code>print:hidden</code>. You can combine these classes with your own <code>@media print</code>
stylesheet for total control.
</details>
<details>
<summary>What is the difference between creating a print stylesheet and generating a PDF?</summary>
It's true that most modern browsers allow you to "Save as PDF" directly from the print dialog box. In this case, the
<code>@media print</code> styles are indeed used to create the document.
<p>The real difference lies not in the output format (paper or PDF), but in the <strong>intent and the level of control</strong> of
the process:</p>
<ol>
<li><strong>Print style (<code>@media print</code>): Formatting initiated by the user.</strong></li>
</ol>
<ul>
<li><strong>Objective:</strong> Allow the user to obtain a clean version of the <em>current</em> page for their personal use (archiving,
offline reading, paper printing).</li>
<li><strong>Control:</strong> The <strong>user triggers the action</strong>. The final rendering may vary slightly depending on their browser and
settings. The document is a “snapshot” of the web page.</li>
<li><strong>Use case:</strong> Printing an article, a recipe, an itinerary.</li>
</ul>
<ol start="2">
<li><strong>PDF generation: A document controlled by the application.</strong></li>
</ol>
<ul>
<li><strong>Objective:</strong> Provide an official and standardized document, whose layout is <strong>identical for everyone</strong>, regardless
of the browser. This is often an explicit feature, like a “Download PDF” button.</li>
<li><strong>Control:</strong> The process is <strong>entirely mastered by the developer</strong>, via a server-side library (e.g.,
<code>FPDF</code> in PHP) or client-side (e.g., <code>jsPDF</code>). The developer precisely defines the structure,
headers, numbering, etc.</li>
<li><strong>Use case:</strong> Invoices, event tickets, financial reports, e-books. The PDF here is a product in itself, not just a
capture of the page.</li>
</ul>
<p>In summary:</p>
<ul>
<li>Use <strong><code>@media print</code></strong> to ensure that any page of your site is clean when the user decides to print or
save it.</li>
<li>Use <strong>dedicated PDF generation</strong> when you need to provide a specific, portable document whose format must be
perfectly controlled.</li>
</ul>
</details>

            ]]></content:encoded>
        </item><item>
            <title>WAI-ARIA: The Ultimate Guide to Mastering Web Accessibility Without Bloating Your Code</title>
            <link>https://lionel-peramo.com/posts/aria/</link>
            <guid>https://lionel-peramo.com/posts/aria/</guid>
            <pubDate>Wed, 21 Jan 2026 12:00:00 +0000</pubDate>
            <description>ARIA is not a magic wand; it is a surgical layer. Discover how to enrich your DOM for assistive technologies with expert precision.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 9 min</p>
              
<p>Web accessibility is often perceived as a compliance constraint—a checklist to avoid legal penalties. This is a narrow view. In reality, it is a pillar of software quality and <strong>code</strong> robustness.</p>
<p>In this article, we will dive deep into the world of <strong>WAI-ARIA</strong>. We won’t just talk about “doing the right thing,” but rather about data structures, rendering performance, and how the <strong>browser</strong> translates your tags for assistive technologies.</p>
<h2>The Birth of an Invisible Semantic Layer</h2>
<p>In the early days of the <strong>web</strong>, pages were simple static documents. A link was a link, a heading was a heading. But with the explosion of JavaScript and frameworks like React, Vue, or OTRA, we began simulating complex behaviors. A simple <code>&lt;div&gt;</code> can now become a dropdown menu, a modal window, or a price slider.</p>
<p>The problem? For a screen reader, a <code>&lt;div&gt;</code> remains a meaningless box. To bridge this gap, the <strong>WAI-ARIA</strong> (Web Accessibility Initiative - Accessible Rich Internet Applications) specification was created. It acts as an extension of HTML—a system of meta-information that changes nothing visually but redefines the object within the <strong>Accessibility Tree</strong>.</p>
<h3>The Concept of the Accessibility Tree</h3>
<p>Few developers realize that the browser does more than just build the DOM (Document Object Model) and the CSSOM (CSS Object Model). It also generates a third tree: the <strong>Accessibility Tree</strong>.</p>
<p>This tree filters DOM information to keep only what is useful for voice or braille navigation. When you use <strong>ARIA</strong> attributes, you directly modify the nodes of this tree. If you overload it with useless information, you create “semantic noise” that slows down the user. Performance, in this context, is measured by the speed at which the user understands the interface.</p>
<h2>The Three Pillars of the ARIA Specification</h2>
<p>To manipulate ARIA with surgical precision, you must understand its three components: roles, properties, and states.</p>
<h3>1. Roles (<code>role</code>)</h3>
<p>The role defines the element’s contract. Is it a button? A tab? A search area?</p>
<ul>
<li><strong>Structural Roles</strong>: <code>main</code>, <code>navigation</code>, <code>banner</code>, <code>contentinfo</code>. They help map out the <strong>page</strong>.</li>
<li><strong>Widget Roles</strong>: <code>dialog</code>, <code>tablist</code>, <code>tooltip</code>. They announce interactive behavior.</li>
<li><strong>Landmark Roles</strong>: They allow users to “jump” directly to a specific section.</li>
</ul>
<h3>2. Properties</h3>
<p>These describe characteristics that are generally stable. For example, <code>aria-labelledby</code> allows linking an element to its title via an ID. This is far more powerful than a simple title attribute because it allows for building a complex semantic hierarchy without duplicating text in the <strong>code</strong>.</p>
<h3>3. States (<code>states</code>)</h3>
<p>This is the most dynamic part of your <strong>development</strong>. States change based on user interaction:</p>
<ul>
<li><code>aria-expanded=&quot;true/false&quot;</code>: Indicates if a menu is open.</li>
<li><code>aria-busy=&quot;true&quot;</code>: Signals to the screen reader that a section is being updated (e.g., an AJAX load).</li>
<li><code>aria-invalid=&quot;true&quot;</code>: Indicates a real-time input error in a <strong>form</strong>.</li>
</ul>
<h2>The W3C Golden Rule: The Paradoxical “No ARIA”</h2>
<p>The number one rule in the official documentation is blunt: <strong>“If you can use a native HTML element that already has the semantics and behavior you need, then do not use ARIA.”</strong></p>
<h3>The Hidden Cost of “Custom CSS/JS”</h3>
<p>Take a checkbox for example.</p>
<ol>
<li><strong>Native Approach</strong>: <code>&lt;input type=&quot;checkbox&quot;&gt;</code>. Pros: Focus management, native keyboard support (Space), automatic “checked” state, maximum performance.</li>
<li><strong>ARIA Approach</strong>: <code>&lt;div role=&quot;checkbox&quot; aria-checked=&quot;false&quot; tabindex=&quot;0&quot;&gt;</code>. Cons: You must write JS to handle the click, JS to handle the Space key, and JS to toggle the state.</li>
</ol>
<p>Every line of JS added to compensate for a lack of native semantics is technical debt and an extra CPU load for the user’s device. By prioritizing native HTML, you practice <strong>eco-design</strong>: saving server resources (less code to send) and client resources (fewer scripts to run).</p>
<h2>Focus Management: The Heart of Interaction</h2>
<p>Accessibility isn’t just about text labels; it’s about movement. For a user navigating solely by keyboard, “focus” is their only means of action.</p>
<p>ARIA does not manage focus on its own. This is a common mistake. If you open a modal window with <code>role=&quot;dialog&quot;</code>, it is up to you as a <strong>developer</strong> to move the focus inside the window and implement a “Keyboard Trap” so it doesn’t escape into the background.</p>
<p>The <code>tabindex</code> attribute is your best ally here. <code>tabindex=&quot;0&quot;</code> inserts an element into the natural flow, while <code>tabindex=&quot;-1&quot;</code> allows an element to be focusable only via JavaScript. Mastering this mechanic is what differentiates an interface that is “accessible on paper” from one that is truly usable.</p>
<h2>Handling Dynamic Content with aria-live</h2>
<p>In modern <strong>web</strong> applications, content changes constantly without a page refresh. How does a blind person know that an error message just appeared at the top of the screen while they are filling out a field at the bottom?</p>
<p>The answer is: <strong>Live Regions</strong>. By using <code>aria-live</code>, you create a monitoring zone for the browser.</p>
<ul>
<li><code>aria-live=&quot;polite&quot;</code>: The announcement is made as soon as the user stops typing or navigating. This is the most UX-friendly approach.</li>
<li><code>aria-live=&quot;assertive&quot;</code>: The announcement interrupts the screen reader immediately. Use this with extreme caution for critical alerts only.</li>
</ul>
<h2>ARIA and Technical SEO: An Underestimated Alliance</h2>
<p>ARIA is often restricted to the realm of screen readers. People forget that search engine crawlers are also “non-visual users.” Google increasingly uses semantic signals to understand the structure of an application.</p>
<p>A site that correctly uses <code>main</code>, <code>search</code>, and <code>navigation</code> roles offers superior “semantic density.” By helping machines understand which button closes a window or which section is complementary (<code>role=&quot;complementary&quot;</code>), you indirectly assist Natural Language Processing (NLP) algorithms. High-performance <strong>SEO</strong> in 2026 is no longer just about keywords; it extends to the structural understanding of the <strong>code</strong>.</p>
<h2>Testing and Validation Strategies</h2>
<p>To guarantee the quality of your production <strong>version</strong>, automation is necessary but not sufficient.</p>
<ol>
<li><strong>Automated Tests</strong>: Use libraries like <code>axe-core</code> in your CI/CD pipelines. This catches about 40% of the most common errors (misspelled ARIA attributes, missing IDs).</li>
<li><strong>Manual Audit</strong>: Nothing replaces a walkthrough with a screen reader (NVDA or VoiceOver). Navigate with your eyes closed. If you feel lost, your ARIA architecture is failing.</li>
<li><strong>Browser Inspection</strong>: Chrome and Firefox dev tools now have an “Accessibility” tab. Use it to inspect the accessibility tree and verify that your attributes are correctly calculated.</li>
</ol>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>Can I use ARIA with deprecated tags?</summary>
Technically yes, but it is bad practice. ARIA is designed to enrich modern HTML (HTML5). Using ARIA on tags like <code>&lt;font&gt;</code> or <code>&lt;center&gt;</code> makes no sense because these tags should no longer exist in optimized code.
</details>
<details>
<summary>Does <code>aria-label</code> replace visible text?</summary>
Only for assistive technologies. For sighted users, the image or icon must be explicit. Warning: if a button contains text, <code>aria-label</code> will overwrite it completely. Ensure the label contains at least the visible text to avoid cognitive dissonance.
</details>
<details>
<summary>What is the most complex ARIA role to implement?</summary>
Undoubtedly the <code>combobox</code> role. It requires precise management of focus, the associated dropdown list, and selection announcements. It is the ultimate test for any accessibility expert.
</details>
<details>
<summary>Does ARIA impact JS performance?</summary>
The attributes themselves are passive. However, the JavaScript logic required to maintain ARIA states (e.g., syncing a menu opening with <code>aria-expanded</code>) can impact <strong>Total Blocking Time (TBT)</strong> if not optimized or if it triggers unnecessary reflows.
</details>
<details>
<summary>How should translations of ARIA attributes be handled?</summary>
This is crucial. Values for <code>aria-label</code> or <code>aria-valuetext</code> must be translated in every language **version** of your site, as they are read exactly as written by voice synthesizers.
</details>
<h2>Conclusion: Toward Responsible Code Craftsmanship</h2>
<p>Mastering <strong>WAI-ARIA</strong> is not about slapping labels everywhere. It is about understanding how information flows between your source <strong>code</strong> and the end user. It is an exercise in precision that requires rigor but transforms an ordinary website into a universal platform.</p>
<p>As developers, we have a responsibility to build a <strong>web</strong> that leaves no one behind. Take back control of your semantics, simplify your components, and make accessibility a driver of your performance.</p>

            ]]></content:encoded>
        </item><item>
            <title>Forgejo: Discover 6 keys to master this Git platform</title>
            <link>https://lionel-peramo.com/posts/forgejo-git-tool/</link>
            <guid>https://lionel-peramo.com/posts/forgejo-git-tool/</guid>
            <pubDate>Tue, 06 Jan 2026 16:30:00 +0000</pubDate>
            <description>Discover Forgejo, the lightweight open-source Git alternative. Learn how to manage every version of your code on a community-driven platform.</description>
            <content:encoded><![CDATA[
              <p>⏱️ Reading time: 9 min</p>
              
<p>Forgejo is a complete solution for hosting your source <strong>code</strong>.
It is a free tool that belongs to its developer community.
It allows managing IT projects in an ethical and sovereign way.</p>
<p>You too can set up your own instance on your server in a few minutes.
Discover why Forgejo has become essential for <strong>web</strong> professionals seeking independence.</p>
<h2>The history of software forges and the emergence of Forgejo</h2>
<p>To understand the importance of this tool, one must look at the history of collaborative development.
For a long time, developers used centralized tools like SourceForge.
Then, GitHub became the global standard for storing <strong>code</strong>.</p>
<p>However, GitHub is owned by a very large private corporation.
This raises questions about data ownership and freedom of choice technological.
It is in this context of needing sovereignty that tools like Gitea appeared.</p>
<h3>Project origins and the conflict with Gitea Ltd</h3>
<p>Forgejo was born from a specific event in the free software ecosystem.
Originally, the tool was named Gitea and was managed by passionate volunteers.
But in 2022, a company called Gitea Ltd was created to monetize the tool without everyone’s consent.</p>
<p>The community feared losing its technical independence to financial interests.
They decided to create a “fork”: a free and community-led copy of the project.
This is how Forgejo was born to protect the actual interests of users.</p>
<h3>Codeberg and digital sovereignty in Europe</h3>
<p>Today, the Codeberg e.V. association oversees the development of the project.
It is a non-profit organization based in Germany, subject to European laws.
It guarantees that the software will always remain free, open, and ad-free for everyone.</p>
<p>Forgejo’s source <strong>code</strong> is fully public and can be audited by anyone.
Every developer can suggest a bug fix or a new improvement.
To do this, you just need to fill out a contribution <strong>form</strong> on their official platform.</p>
<h3>A Git forge managed as a common good</h3>
<p>Unlike private platforms, Forgejo has no shareholders to satisfy.
Priority remains on <strong>software</strong> stability and contributor satisfaction.
This democratic structure prevents any takeover by a single entity.</p>
<p>The project uses its resources to improve essential <strong>developer</strong> functions.
This avoids adding useless features that often bloat modern tools.
It is this philosophy of “chosen sobriety” that makes Forgejo strong.</p>
<h2>Technical performance adapted to eco-design</h2>
<p>Forgejo’s strength is undoubtedly its lightness and digital sobriety.
Unlike GitLab, which requires a lot of RAM, Forgejo is optimized for efficiency.</p>
<h3>A lightweight infrastructure for every project version</h3>
<p>The software is written in the Go (Golang) language, known for its high <strong>performance</strong>.
This language allows compilation into a single binary, very easy to deploy.
You can track every <strong>version</strong> of your project without slowing down your server, even under heavy load.</p>
<p>Forgejo can run on very modest hardware without losing responsiveness.
It is capable of running on a Raspberry Pi with only 100 MB of available RAM.
This is a major advantage for reducing the electricity consumption of data centers.</p>
<h3>Advanced functions for daily collaborative work</h3>
<p>Forgejo is not just a passive storage space for your <strong>code</strong>.
It includes all the modern tools to organize a technical team’s work:</p>
<ul>
<li>Integrated Kanban boards to track task progress in real time.</li>
<li>A powerful ticketing system (Issues) to manage bugs and suggestions.</li>
<li>A complete Wiki to document every feature of your <strong>software</strong>.</li>
</ul>

<p>Each tool is designed to be fast and accessible, even with a slow connection.
The interface is minimalist to avoid distracting the user from their main task.
This also reduces page weight and speeds up overall display on the <strong>web</strong>.</p>
<h3>Modern automation with Forgejo Actions</h3>
<p>Modern development requires testing <strong>code</strong> with every modification.
Forgejo now integrates its own CI/CD system called Forgejo Actions.
This allows running automatic tests to ensure everything works as expected.</p>
<p>The system is compatible with GitHub Actions configuration files.
You can migrate your current automations to Forgejo without rewriting everything.
This greatly facilitates the switch to a more respectful and private infrastructure.</p>
<h3>Technical choice: Go language vs Ruby</h3>
<p>Why is Forgejo so fast compared to its competitors?
The answer lies in the choice of the Go language used for its <strong>development</strong>.
Go consumes far fewer resources than Ruby or Java.</p>
<p>This allows managing thousands of repositories on a standard server.
This raw efficiency reduces hosting costs for companies.
It also helps extend the life of old hardware.</p>
<h3>Constant evolution towards version 10.0 and beyond</h3>
<p>The project progresses very fast thanks to a global community of contributors.
The recent <strong>version</strong> 10.0 brought major visual and technical improvements.
The user interface is smoother, and permission management is more precise.</p>
<p>The software also integrates the latest security standards on the market.
It natively supports two-factor authentication and physical security keys.
This is a crucial point for protecting your work against unauthorized access.</p>
<h2>Why choose Forgejo for your projects in 2026?</h2>
<p>Choosing a Git forge is a strategic decision that impacts the longevity of a project.
Forgejo offers the best balance today between freedom, security, and power.</p>
<h3>An ethical alternative to web giants</h3>
<p>By using Forgejo, you take back total control over your digital assets.
Your files are no longer stored with a <strong>web</strong> giant with opaque terms of service.
It is a strong commitment toward a more decentralized and respectful IT world.</p>
<p>This autonomy protects you against sudden price changes in cloud services.
It also allows you to comply with data protection regulations (GDPR).
Your <strong>code</strong> stays on an infrastructure that you control from end to end.</p>
<h3>Performance gain for your development workflow</h3>
<p>A lightweight server is a server that responds faster to your requests.
By using sober tools like Forgejo, you optimize your entire production chain.
This is exactly the <strong>performance</strong> philosophy I share on this technical blog.</p>
<p>Every millisecond saved on your tools increases your productivity.
It also reduces the frustration related to heavy and slow interfaces.
The tool fades away to make room for creativity and pure logic.</p>
<h3>Impact on SEO and brand image</h3>
<p>My goal is to prove that good <strong>SEO</strong> starts with a quality infrastructure.
Choosing Forgejo is part of this quest for global and sustainable quality.
It shows your partners that you take care of your technical environment.</p>
<p>By using Forgejo, you join an ecosystem that values <strong>code</strong> craftsmanship.
You invest in a tool that respects the user as much as the machine.
It is the way to build a healthier and faster digital future.</p>
<hr>
<h3>Frequently Asked Questions</h3>
<details>
<summary>How to import a project from GitHub to Forgejo?</summary>
Forgejo has a very powerful automatic import tool. You just need to enter your repository URL and an access key. The software then retrieves your <strong>code</strong>, your branches, and the entire history in a few seconds.
</details>
<details>
<summary>Is Forgejo free for a company?</summary>
Yes. Forgejo is distributed under a free license (MIT/GPL). You can use it for personal or commercial projects without paying any royalties. This is a significant saving for a small structure.
</details>
<details>
<summary>Can the Forgejo interface be customized?</summary>
Absolutely. You can change the colors and the logo to match your identity. Since the <strong>code</strong> is free, you have total freedom over the appearance of your Git instance.
</details>

            ]]></content:encoded>
        </item>
    </channel>
    </rss>