Les dernières actualités d'Alsacreations.com
Le « vibe coding » est une expression inventée par Andrej Karpathy au début de l'année 2025. Il désigne une nouvelle façon de programmer, en déléguant entièrement l'écriture du code à l'intelligence artificielle d'un agent. Le terme est controversé et sa définition est floue. Dans ce tutoriel, nous montrons comment utiliser l'agent IA comme un outil afin de générer du code de manière solide et maîtrisée.
À qui s'adresse ce tutoriel ? Aux développeurs sous Visual Studio Code, avec un abonnement GitHub Copilot payant.
Le plan gratuit ne suffit pas car nous aurons besoin des derniers modèles d'Anthropic ou d'OpenAI. En outre, mieux vaut avoir un système de gestion de versions (comme Git).
Si ce n'est pas déjà fait, ouvrez la barre latérale du chat en cliquant sur son icône en haut à droite du champ de recherche. En bas de cette barre latérale, passez en mode Agent et sélectionnez un modèle — les derniers modèles d'Anthropic ou d'OpenAI feront l'affaire.
Même si cela n'est pas obligatoire, je recommande au développeur qui connaît bien son travail d'essayer le mode « auto-approve ». Votre VS Code et les plugins de Copilot doivent être à jour. Voici la configuration :
"chat.agent.maxRequests": 1000,
"chat.tools.global.autoApprove": true,
Attention : cela fait passer l'agent IA de VS Code dans un mode « auto-approve » efficace, mais aussi risqué. Vous devrez désormais le surveiller durant son travail et systématiquement utiliser votre système de gestion de versions afin de pouvoir revenir à une version antérieure en cas de problème.
Petit point de vocabulaire pour distinguer modèles de langage et agents. On peut voir un modèle de langage (ou « LLM », pour Large Language Model) comme une capacité de raisonnement sur étagère. Des exemples de LLM : Claude Sonnet, GPT, Gemini pro. Ils n'ont pas les mêmes points forts. Un agent de programmation IA est un programme doté d'un chat qui utilise un ou plusieurs modèles pour accomplir des tâches de programmation. Des exemples d'agents : Claude Code, l'agent de GitHub Copilot, celui de Cursor, Gemini CLI, OpenAI Codex. Ces solutions ne se valent pas, les coûts diffèrent aussi. Il ne faut pas hésiter à les essayer et à les réessayer régulièrement car le paysage évolue rapidement.
VS Code propose plusieurs modes accessibles depuis le sélecteur en bas de la barre latérale du chat :
Un agent de programmation IA doit être traité comme un perpétuel nouveau venu. À chaque session de travail, il redécouvre le projet depuis zéro. En pratique, une session ne dure que quelques minutes ou dizaines de minutes.
Démarrez toujours une nouvelle session du chat (« ï¼ ») pour chaque nouvelle tâche. Cela évite de polluer le contexte avec des informations issues d'une tâche précédente.
La fenêtre de contexte représente la quantité maximale de texte que l'agent peut traiter simultanément. Elle contient tout : les instructions, la discussion, le code lu, écrit, corrigé, relu etc. Sa taille est limitée. Lorsqu'elle est remplie, il faut redémarrer avec un agent tout neuf. C'est pourquoi il est important de ne pas la surcharger et de commencer une session propre pour chaque tâche.
Nous utilisons les derniers modèles premium. Il y a une limite mensuelle de requêtes premium, il faut donc surveiller la consommation. Cliquez sur l'icône du chat en bas de la barre latérale. Repérez le pourcentage de requêtes premium restantes pour le mois en cours.

Implémenter une fonctionnalité, cela commence par la rédaction de spécifications. Lorsque cela est fait, n'oublions pas qu'un agent de programmation IA est, à chaque nouvelle session, un nouveau venu. Même après qu'il ait lu la documentation, on ne lâche pas un nouveau venu sur une base de code existante en lui disant de faire comme il le sent. On lui demande comment il envisage de traiter le problème (c'est le plan d'implémentation), on en discute avec lui. Ensuite on le laisse travailler. À la fin, on vérifie le travail.
Ce processus est adapté aux tickets complexes. Il n'y a aucune raison d'être rigide sur quoi que ce soit. Mais dans le cadre de ce tutoriel, suivons toutes les étapes.
Quelques lignes ou phrases suffisent pour décrire ce que l'on veut obtenir. Expliquer ce que l'on a au départ et ce que l'on souhaite obtenir. Si l'on sait quels fichiers sources sont concernés, on peut le mentionner. Mais à cette étape, le prompt n'a pas besoin d'être très solide. Il sera complété à l'étape suivante.
Pour ma part, je rédige ce genre de prompts dans un éditeur de texte à part. C'est plus confortable.
Passez en mode Plan dans le sélecteur en bas de la barre latérale du chat. Ce mode est conçu pour que l'agent explore le code et propose un plan structuré avant de toucher à quoi que ce soit.
Donnez-lui un prompt qui l'invite à investiguer, poser des questions, proposer des approches et leurs compromis. C'est une collaboration : le développeur corrige, clarifie, tranche. N'hésitez pas à challenger l'agent. Vous pouvez glisser-déposer des fichiers pertinents dans le chat pour lui fournir du contexte supplémentaire.
Voici un exemple de prompt :
[ICI_VOTRE_BESOIN]
Investigate the codebase to understand how it currently works. Then discuss with me: present your findings, what needs to change, possible approaches and their trade-offs. Ask clarifying questions. Once we agree on an approach, write a step-by-step implementation plan with file paths and function names. Do not start coding.
Le principe ici est d'inciter l'agent à poser des questions afin de passer dans un mode collaboratif. L'idée est d'éviter que l'agent ne se précipite vers une solution. Et réfléchir avec lui sur les différents choix de conception dans un premier temps.
Lors de cette étape de conception, on peut demander à l'agent de faire des recherches sur le web. En ce qui concerne les bibliothèques de programmation, le MCP Context7 vous sera d'une grande utilité, il contient de la documentation prête à emploi pour les agents. Une fois Context7 installé, c'est une bonne idée de demander à l'agent de l'utiliser avant d'écrire le plan. Bien entendu, Context7 est une source externe et donc un risque d'injection de prompts. C'est pourquoi le meilleur moment pour s'en servir est lors de la conception du plan, alors que nous (humains) sommes présents et interagissons avec l'agent.
J'écris mes prompts en anglais, mais le français marchera très bien.
Le mode Plan de Visual Studio Code produit un plan structuré. Le relire attentivement. Demander des ajustements si nécessaire. Ne pas hésiter à itérer.
Mettez une attention particulière sur les structures de données. N'espérez jamais qu'un problème complexe puisse se résoudre correctement comme par magie sans que vous n'ayez à comprendre comment !
Obtenir de bonnes spécifications est certainement au cœur de la programmation avec IA. Ce savoir-faire devient essentiel à notre métier, et je ne doute pas qu'il fera l'objet d'une attention croissante des acteurs du développement logiciel dans les prochains mois et années. Sur ce sujet, une vidéo d'un chercheur de OpenAI :
Depuis le mode Plan, l'agent propose d'implémenter. On peut aussi copier le plan et ouvrir un nouveau chat en mode Agent.
Pensez à faire une sauvegarde du projet (git commit) avant de lancer l'implémentation. Cela permet de revenir en arrière en cas de problème et de comparer le code avant et après.
Gardez un œil sur l'agent pendant qu'il travaille. Le cas échéant, interrompez-le dès que vous vous apercevez qu'il va dans une mauvaise direction. Expliquez-lui ce qui ne va pas, il continuera sa session en prenant en compte votre message.
Relancez de préférence une nouvelle session de l'agent avant d'exécuter un plan. D'abord pour éviter la contamination des informations entre tâches. Ensuite parce que l'agent IA devient parfois moins fiable lorsque sa fenêtre de contexte se remplit.
Astuce : pendant que l'agent travaille, mettez ce temps à profit pour discuter du plan suivant dans une autre session en parallèle. Toutefois, gardez un œil sur ce que fait votre agent.
Parfois ça fonctionne du premier coup — et c'est fun ! Mais il est impératif de vérifier la qualité du code produit. Les agents sont têtus sur certains choix. Ils ont tendance à dupliquer paresseusement et à complexifier le code plutôt qu'à refactoriser, quand bien même ils en seraient parfaitement capables.
Passez en revue le code généré. Ne laissez rien passer. N'acceptez pas un code qui serait moins bon que ce que vous auriez écrit vous-même.
Si vous ne comprenez pas le code généré : si vous vous êtes aventuré loin de votre zone de confort, c'est peut-être le moment d'apprendre ? La responsabilité du développeur reste entière : de même que le conducteur d'un véhicule est toujours responsable — en cas d'accident, le comportement de la voiture n'est pas une bonne excuse.
Lorsque vous modifiez à la main le résultat du travail de l'agent sans prendre la peine de lui expliquer pourquoi, considérez que la session de l'agent devient inutilisable et démarrez-en une neuve. Autrement il restera sur ses idées initiales.
Rappelez-vous que nous avons désactivé des protections à l'étape de configuration : l'agent peut exécuter des commandes potentiellement dangereuses dans le terminal. Il peut aussi se retrouver bloqué dans une boucle infinie en cherchant une solution, et consommer une grande partie — voire la totalité — de vos requêtes premium.
Le système de gestion de versions est un filet de sécurité, mais gardez à l'esprit que l'agent sait aussi l'utiliser.
Méfiez-vous des prompts malintentionnés. Ne lancez jamais votre agent sur un projet inconnu. Et soyez vigilant à chaque fois que vous lui demandez de rechercher des informations sur Internet.
Les principes vus dans ce tutoriel : discuter avant de coder, découpler la conception d'un plan de son implémentation, sont généraux. Vous trouverez qu'ils s'appliquent aussi en dehors de la programmation.
Il existe un autre axe qui augmente considérablement la qualité du travail de l'agent, c'est la documentation interne du projet. En 2026, la documentation technique devrait être écrite sous la forme de « skills ». Les Agent Skills sont une nouvelle norme créée par Anthropic et adoptée par la plupart des agents. Bien que cette norme soit loin d'être aboutie et sera amenée à évoluer, elle est opérationnelle et répond au double besoin de partager des instructions réutilisables entre plusieurs projets, et de rédiger de la documentation interne spécifique à un projet.
Pour ceux qui seraient intéressés, j'ai créé AlignFirst sous la forme d'un skill open source (github.com/paleo/alignfirst). Le but est de faire écrire le code tel que nous l'aurions écrit. Sans magie ni fioritures, juste l'essentiel. Ce qui est particulièrement adapté aux développeurs qui aiment le code bien écrit.
Happy Vibe Coding !
Mise à jour du 14 août 2025 — Ajout de GPT-5. La section sur les spécifications techniques a été enrichie. La partie « Documenter le projet » a été complètement réécrite.
Mise à jour du 20 septembre — Mise à jour des prompts.
Mise à jour du 30 septembre — Suppression du prompt de refactoring automatique.
Mise à jour du 8 décembre — Modification des étapes, pour mettre l'accent sur les spécifications plus que le(s) plan(s).
Mise à jour du 18 février 2026 — Réécriture complète du tutoriel. La documentation sort du tutoriel, car, depuis fin 2025, elle est un sujet à part entière, à écrire sous la forme de « skills ». Le tutoriel est recentré sur la production de code. Les lecteurs qui auraient appliqué une ancienne version du tutoriel sont invités à passer aux skills en exécutant ce prompt.
Retrouvez l'intégralité de ce tutoriel en ligne sur Alsacreations.com
La gestion de la portée des styles est un défi historique en CSS. Des méthodologies comme BEM aux solutions techniques comme le Shadow DOM ou les CSS Modules, nous avons toujours cherché à éviter que le style d'un composant ne se propage sur ses voisins. L'arrivée de la règle @scope change la donne en offrant une solution native, flexible et puissante.
@scopeLa règle @scope permet de cibler des éléments dans un fragment spécifique du DOM.
Dans cet exemple simple, seuls les <h2> à l'intérieur des éléments portant la classe .card seront colorés en hotpink. Les styles n'affecteront pas les autres <h2> de la page :
@scope (.card) {
/* Cible les h2 uniquement dans .card */
h2 {
color: hotpink;
}
}
Dans cet autre exemple sont ciblés uniquement les <h2> à l'intérieur des éléments portant la classe .card contenant un élément .title :
@scope (.card:has(.title)) {
/* Cible les h2 uniquement dans .card qui contient .title */
h2 {
color: hotpink;
}
}
Voici le tableau de compatibilité de @scope, que vous pouvez également consulter sur Caniuse.com :
:scope et l'esperluette &À l'intérieur d'un bloc @scope, le navigateur a besoin d'un moyen de désigner l'élément racine lui-même (celui qui porte la classe ou l'attribut de départ). Il existe deux façons de procéder :
:scope : Une pseudo-classe qui référence logiquement l'élément racine. C'est le cœur technique du dispositif.& (Esperluette) : Comme dans le nesting classique, elle permet de coller des états à la racine (ex: &:hover).Dans la plupart des cas, l'usage du & pour les états interactifs est recommandé pour sa simplicité.
Par exemple, si on souhaite que son composant .card ait un fond gris, mais que ses éléments internes aient leurs propres styles, on va se servir de :scope :
@scope (.card) {
/* Cible l'élément .card lui-même */
:scope {
background: var(--surface);
border: 1px solid var(--border-light);
}
}
Pour les éléments hautement réutilisables comme les boutons, :scope associé à & (esperluette) permettent de centraliser la logique interactive (hover, focus, active) en utilisant les variables CSS.
@scope (.btn) {
:scope {
/* Variables par défaut */
--button-background-color: var(--form-background, Field);
--button-text-color: var(--on-form, ButtonText);
background-color: var(--button-background-color);
color: var(--button-text-color);
transition: all var(--transition-duration);
}
/* Logique interactive unique pour toutes les variantes */
&:hover, &:focus-visible {
background-color: oklch(from var(--button-background-color) calc(l * 0.9) c h);
}
&:disabled {
opacity: 0.8;
cursor: not-allowed;
}
/* Variantes : On ne change que les valeurs, pas la logique */
&.btn-primary {
--button-background-color: var(--primary);
--button-text-color: var(--on-primary);
}
}
.card .title ou .card > .title ?C'est bien vrai ça, on pourrait croire que @scope ne sert qu'à nous compliquer la vie. Alors que… pas du tout !
@scope, c'est la racine la plus proche de l'élément dans le DOM qui l'emporte. C'est idéal pour les thèmes imbriqués..card .title a une spécificité de (0,2,0). À l'intérieur d'un @scope, le sélecteur .title reste à (0,1,0), facilitant les surcharges sans utiliser !important.>) est fragile. Si on ajoute une div intermédiaire pour du layout, le style casse. @scope tolère n'importe quelle profondeur tant que la limite n'est pas franchie.En outre, grâce à la priorité par proximité, @scope permet d'imbriquer des thèmes sans conflit, peu importe l'ordre des CSS.
@scope (.theme-dark) {
:scope { background: #1a1a1a; color: white; }
.title { color: var(--color-pink-300); }
}
@scope (.theme-light) {
:scope { background: white; color: #1a1a1a; }
.title { color: var(--color-blue-600); }
}
Contrairement aux sélecteurs descendants classiques, @scope introduit deux concepts majeurs :
Dans l'exemple suivant, le navigateur cherche .card pour y colorer les h2 en rose. Cependant, dès qu'il rencontre un élément .content, il cesse d'appliquer les styles à ses descendants :
@scope (.card) to (.content) {
/* Cible les .title dans .card mais s'arrête à .content */
.title {
color: hotpink;
}
}
C'est l'atout majeur de @scope : la capacité de définir un périmètre d'exclusion via la clause to. Cela permet de protéger des zones de contenu riche (WYSIWYG, slots) ou des composants imbriqués qui ne doivent pas être affectés par les styles du parent.
BEM est une convention efficace mais verbeuse, et elle repose entièrement sur votre discipline de nommage et nécessite des noms de classes uniques (.card__title, .hero__title--alternate).
Avec @scope, vous pouvez garder des noms plus simples et réutilisables, tout en garantissant que les styles restent confinés à leur contexte : le HTML est épuré des préfixes répétitifs et grâce au to (.content), un titre de card situé dans un élément .content sera jamais affecté par le style de la carte, car il est "hors limite".
L'adoption de @scope marque une étape vers la fin de l'ère "tout BEM" au profit d'une approche plus sémantique et structurelle.
Dans un projet concret, BEM, @layer et @scope peuvent cependant coexister :
On ne va pas se mentir : l'intégration de @scope dans un projet utilisant déjà un framework utilitaire comme Tailwind peut sembler redondante au premier abord.
Il existe cependant quelques cas d'usage où @scope peut apporter une valeur ajoutée significative, notamment pour les composants complexes et les zones de contenu dynamique qui ne sont pas facilement gérables avec les classes utilitaires seules.
Par exemple, dans Tailwind, styler du HTML brut (venant d'un CMS) nécessite souvent l'utilisation du plugin @tailwindcss/typography (classe .prose). Cependant, ce plugin est parfois trop rigide. Avec @scope, on peut créer des "bulles" de styles spécifiques pour son contenu sans polluer le reste du site et sans créer de classes complexes :
@layer components {
@scope (.prose-custom) to (.content) {
/* On style les balises nues uniquement dans ce contexte */
h2 { @apply text-2xl font-bold mb-4 text-primary; }
p { @apply leading-relaxed mb-6; }
/* Les limites protègent les composants Tailwind imbriqués */
}
}
Si l'on devait résumer les avantages de @scope en quelques points clés :
.card-header__title. On utilise des classes simples (.title, .media, .header, .content) et faciles à retenir.to pour définir une limite haute et basse et garantir que les utilitaires appliqués à un composant enfant ne seront jamais écrasés par les styles du parent.@scope apparaît clairement, permettant de voir immédiatement quelle racine applique le style, plutôt que de chercher l'origine dans une pile de sélecteurs descendants complexes..card .btn) qui augmentent la spécificité, @scope maintient une spécificité faible. Cela permet à ses classes utilitaires (ex: p-4) de rester prioritaires et faciles à surcharger si besoin.Si l'on ne devait en retenir qu'un seul, il s'agirait sans aucun doute de Conflits de nommage réduits. En effet, des noms de classes génériques comme .title peuvent être utilisées dans plusieurs scopes sans risque de conflit, car elles ne s'appliquent qu'à leur propre scope. Et tout le monde sait que nommer les choses c'est… compliqué.
@scope ne remplace pas les outils actuels, il complète avantageusement l'outillage natif déjà mis en place par CSS (cascade, @layer, :where(), etc.).
Totalement inadapté pour les styles globaux (reset, typographie de base, utilitaires) qui doivent se propager partout, il devient en revanche un allié précieux pour les styles de composants et les zones de contenu dynamique.
Utilisons-le dans notre @layer(components) pour isoler nos "organismes" (cartes, headers, modales). C'est la fin du "CSS qui bave" et le début d'une architecture plus proche de la structure réelle de vos pages.
Note : Le support navigateur est désormais excellent dans les versions récentes de Firefox, Chrome, Edge et Safari. Pour les projets nécessitant un support legacy, une stratégie de Progressive Enhancement via @supports (scope: html) est préconisée.
L'événement scrollend est une nouvelle API standardisée pour détecter la fin du défilement dans une page web.
Durant des années nous avons du jongler avec moult événements, astuces JavaScript et calculs pour attraper l'action de scroll, notamment le combiner à un debounce : cette approche consistait à déclencher un timer à chaque événement de défilement et à considérer que le scroll était terminé si aucun nouvel événement ne survenait pendant un certain délai, typiquement 100 à 200 millisecondes, selon la lourdeur de la page et la réactivité attendue.
Les inconvénients étaient des faux positifs lors de pauses qui n'en étaient pas vraiment, la consommation de ressources (processeur, carte graphique), et le délai choisi restait approximatif. De plus, on ne prenait pas en compte les animations de défilement fluide ou les gestes tactiles avec inertie.
// Approche classique/ancienne avec debounce â ï¸
let scrollTimer = null;
window.addEventListener('scroll', function() {
// Annuler le timer précédent si le scroll continue
if (scrollTimer !== null) {
clearTimeout(scrollTimer);
}
// Définir un nouveau timer
scrollTimer = setTimeout(function() {
// Code exécuté "à la fin" du scroll
console.log('Scroll terminé (probablement)');
// Exemple : charger plus de contenu
loadMoreContent();
// Exemple : enregistrer la position de lecture
trackScrollDepth();
}, 150); // Délai arbitraire de 150ms
}, false);
Désormais scrollend (disponible dans tous les navigateurs) est aussi simple à utiliser que n'importe quel événement natif du navigateur. Il suffit d'ajouter un écouteur sur l'élément défilable concerné, que ce soit la fenêtre principale ou un conteneur spécifique.
// Avec scrollend â
window.addEventListener('scrollend', function() {
// Code exécuté réellement à la fin du scroll
console.log('Scroll terminé');
// Exemple : charger plus de contenu
loadMoreContent();
// Exemple : enregistrer la position de lecture
trackScrollDepth();
});
L'événement se déclenche de manière fiable dans tous les scénarios de défilement : que l'utilisateur utilise la molette de la souris, fasse glisser la barre de défilement, utilise les touches du clavier, effectue un geste tactile sur mobile/tablette, ou même lorsqu'un défilement programmé via scrollTo() ou scrollIntoView() se termine.
Pour le lazy-loading cet événement permet de déclencher le chargement de nouvelles données uniquement lorsque l'utilisateur a réellement terminé son défilement, y compris en infinite scroll, évitant ainsi des requêtes prématurées. On peut aussi parfaitement l'utiliser pour afficher des indicateurs de position de lecture qui se mettent à jour de façon plus pertinente, même si on peut le faire de manière encore plus élégante en CSS : Les Animations liées au scroll avec CSS.
Enfin pour les adeptes du tracking, scrollend permet de savoir jusqu'où les internautes défilent réellement dans une page, plutôt que de se baser sur des approximations.
D'après Can I Use : scrollend on est plutôt à l'aise car tous les navigateurs majeurs le supportent (Chrome, Edge, Firefox, Safari). Nul besoin de polyfill.
Pendant plus d'une décennie, nous avons traité le Web comme une collection d'affiches statiques imprimées sur du papier de verre : une pour mobile, une pour tablette, une pour desktop. Mais le Web n'est pas une série de tailles d'écrans fixes. C'est un fluide continu.
Bienvenue dans l'ère de l'Intrinsic Web Design (ou Design Intrinsèque), un terme introduit Jen Simmons en 2018 où le contenu dicte la mise en page, et non l'inverse. L'objectif est de créer des composants qui s'adaptent à leur contexte, qu'ils soient dans une sidebar réduite ou dans un header très large.
Le CSS moderne nous offre un vocabulaire de précision pour définir comment les boîtes doivent se comporter face à leur contenu et leur conteneur :
auto : L'ancien roi. Contextuel, imprévisible parfois, il laisse le navigateur calculer la taille selon le modèle de boîte standard (display).min-content : "Je veux être aussi petit que possible." Le navigateur va essayer de réduire la boîte jusqu'à ce que le mot le plus long ou l'élément le plus large force la largeur minimale. C'est le "soft wrapping" ultime.max-content : "Je prends toute la place dont j'ai besoin." La boîte s'élargit pour contenir tout le texte sans aucun retour à la ligne, quitte à provoquer un scroll horizontal (à utiliser avec prudence !).fit-content : Le compromis parfait. C'est mathématiquement équivalent à min(max-content, available-space). La boîte s'adapte au contenu, mais s'arrête poliment si elle touche le bord du conteneur parent.stretch : L'élément s'étire pour remplir l'axe disponible. C'est souvent le comportement par défaut des flex-items ou des grid-items.clamp(), min() et max()Fini le temps où l'on devait déclarer font-size: 16px puis le changer à 18px au breakpoint tablette, et 20px sur desktop.
Avec les fonctions mathématiques CSS, la fluidité est native. La fonction clamp() est sans doute la plus polyvalente d'entre elles. Elle permet de définir une valeur minimale, une valeur idéale (fluide) et une valeur maximale.
h1 {
/* Taille min: 2rem, Idéale: 5% du viewport, Max: 4rem */
font-size: clamp(2rem, 5vw + 1rem, 4rem);
}
Contrairement à une approche type Tailwind (qui demande souvent d'empiler des préfixes text-m md:text-l lg:text-xl), clamp() gère l'interpolation mathématique tout seul. Plus de breakpoints figés, plus d'effets de saut lors du redimensionnement de la fenêtre.
ð§ L'outil Alsacréations : Pour générer ces formules sans avoir un doctorat en mathématiques, notre outil maison Elastic est toujours là pour vous servir.

Vous utilisez déjà Flexbox et Grid, mais exploitez-vous vraiment leurs capacités intrinsèques ? Ces modules ont été conçus pour gérer l'espace restant et l'espace manquant sans Media Queries.
Flexbox brille sur un axe. Ses propriétés de base sont des moteurs de fluidité :
flex-wrap: wrap : La base du responsive. Si ça ne rentre pas, ça passe à la ligne.flex-grow: 1 : "Prends tout l'espace vide disponible".flex-shrink: 1 : "Si on manque de place, réduis-toi".
Grid introduit l'unité fr (fraction), qui distribue l'espace libre après le calcul des tailles fixes.
Mais la véritable puissance réside dans minmax(). Cette fonction permet de générer des colonnes occupant une largeur minimale (300px) tout en s'étirant pour remplir l'espace disponible : grid-template-columns: minmax(300px, 1fr)
Le nom d'usage "RAM" (pour "Repeat Auto Minmax") est usuellement donné au snippet magique qui génère une grille responsive automatique sans aucun breakpoint :
.grid-auto {
display: grid;
/* 1. repeat: Répète les colonnes...
2. auto-fit: ...autant de fois que possible dans le conteneur...
3. minmax: ...avec une taille min de 250px et max de 1fr.
*/
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
Résultat : Sur desktop, vous avez 4 colonnes. Sur tablette, 2 ou 3. Sur mobile, 1 seule. Nul besoin de @media ni de breakpoints pour cela.
Plutôt que de repartir d'une page blanche et de se battre avec les calculs de fr ou de minmax, le projet d'Alsacréations nommé Bretzel propose des styles utilitaires neutres et réutilisables qui exploitent ces concepts de design intrinsèque.
Contrairement aux frameworks lourds, Bretzel offre des solutions légères qui s'adaptent sans Media Queries pour bon nombre d'entre elles. On y retrouve notamment :
repeat(auto-fill, minmax(...)) pour des listes de cartes qui se réorganisent d'elles-mêmes.Ces patterns sont "incassables" car ils ne dépendent pas d'une largeur d'écran arbitraire mais des limites physiques imposées à leurs conteneurs.

C'est ici que tout bascule : tandis que les Media Queries interrogent l'écran (le Viewport), les Container Queries interrogent un ancêtre ou le parent direct de l'élément.
Cela permet de créer des composants réellement agnostiques. Une "Card" placée dans une sidebar étroite s'affichera en mode "compact", et la même "Card" dans le contenu principal s'affichera en mode "étendu".
Mise en pratique :
/* 1. On définit le conteneur */
.card-wrapper {
container-type: inline-size; /* Surveille la largeur */
container-name: card; /* Optionnel, pour cibler spécifiquement */
}
/* 2. Styles de base du composant */
.card {
display: flex;
flex-direction: column; /* Mobile-first (ou plutôt Small-container-first) */
gap: 1rem;
}
.card-image {
aspect-ratio: 16/9;
object-fit: cover;
}
/* 3. Les styles s'adaptent si le CONTENEUR > 500px */
@container card (width > 500px) {
.card {
flex-direction: row; /* On passe à l'horizontale */
align-items: center;
}
.card-image {
width: 30cqi; /* 30% de la largeur du CONTENEUR (Container Query Inline unit) */
max-width: 200px;
}
.card-content {
flex: 1;
font-size: clamp(1rem, 3cqi + 1rem, 2rem); /* Typo fluide basée sur le conteneur */
}
}
Notez l'unité cqi : Comme vw mais relative au conteneur. Indispensable pour une typographie contextuelle parfaite.
Et pour les plus audacieux, l'association avec :has() permet de transformer automatiquement un parent en conteneur si un certain enfant est présent :
/* Si l'élément .box contient un composant .card, il devient un conteneur */
.box:has(> .card) {
container-type: inline-size;
}
Ou encore plus fort :
/* Le parent de .card, quel qu'il soit devient un conteneur */
.card {
*:has(> &) {
container-type: inline-size;
}
}
ð Pour en savoir plus sur ce sujet, n'hésitez pas à consulter notre article détaillé "Les Container Queries en CSS"
Aujourd'hui, @container interroge la taille. Demain, avec les Style Queries, nous interrogerons la valeur d'une propriété ou d'une variable CSS.
Imaginez un composant qui change d'aspect non pas selon sa taille, mais selon son "thème" défini par une variable parente :
/* Conditionner le style selon une variable CSS */
@container style(--variant: highlighted) {
.card {
background: gold;
border: 5px solid black;
animation: shake 0.5s;
}
}
Cela ouvre la porte à une logique conditionnelle directement en CSS, séparant totalement la présentation de la structure HTML.
Si vous pensiez qu'on avait atteint le sommet, détrompez-vous. Voici ce qui arrive (et qui est déjà testable, notamment sous Firefox derrière des flags) :
À ce jour, les variables CSS ne fonctionnent pas dans les Media Queries, il est donc nécessaire de répéter systématiquement les mêmes requêtes @media (width > 48rem) à chaque fois que nécessaire.
Bientôt, vous pourrez scripter vos environnements :
/* Définition (bientôt natif) */
@custom-media --tablet (max-width: 48rem);
@custom-media --dark-mode (prefers-color-scheme: dark);
/* Utilisation */
@media (--tablet) {
/* ... */
}
Le Responsive ne concerne pas que la taille. Il concerne aussi les préférences utilisateur. La fonction light-dark() simplifie drastiquement la gestion du Dark Mode, sans avoir à envelopper tout votre CSS dans des blocs @media (prefers-color-scheme: dark).
:root {
/* Le navigateur choisit la bonne couleur automatiquement */
color-scheme: light dark;
--surface: light-dark(var(--color-white), var(--color-gray-900));
--on-surface: light-dark(var(--color-gray-900), var(--color-gray-100));
}
body {
background-color: var(--surface);
color: var(--on-surface);
}
En 2026, faire du responsive ne consiste plus à boucher les trous entre deux breakpoints. C’est accepter qu’on n'est pas là pour faire de l'impression papier, mais pour construire des systèmes qui s'adaptent à de multiples contraintes.
En adoptant l’Intrinsic Web Design, on redonne au navigateur son rôle d’outil intelligent capable d'interpréter nos intentions plutôt que d'exécuter des ordres rigides. Moins de Media Queries, c’est plus de robustesse, moins de dette technique et, surtout, un Web qui respire enfin et qui résistera au prochain device pliable en forme de triangle.
L'API Web Share est un agrément de l'expérience utilisateur permettant de s'affranchir des dizaines de scripts tiers (parfois lourds et intrusifs) à ajouter à une page pour chaque réseau social.
C'est très facile à mettre en place et à cerner, on peut le constater en survolant la spécification W3C Web Share API qui ne pèse pas plusieurs dizaines de pages.
Historiquement, pour permettre à un utilisateur de partager un article, nous devions intégrer des boutons spécifiques pour chaque plateforme (Twitter, Facebook, LinkedIn, etc.). Cela impliquait souvent le chargement de bibliothèques JavaScript externes, réseau par réseau, ou des solutions groupées telles que addThis, allouridssant la page, posant des problèmes de performance et de respect de la vie privée.
L'API Web Share change la donne en permettant aux sites web d'utiliser le mécanisme de partage natif du système d'exploitation. C'est donc la même popup (ou popin) qui s'ouvre lorsque vous partagez une photo depuis votre galerie.

Le bénéfice est triple :
(On rappelle qu'il vaut mieux utiliser un bouton pour une action en restant sur la même page, et un lien pour une action provoquant un changement de contexte/page).
Bien que l'API soit standardisée, le comportement visuel varie selon la plateforme :
| Caractéristique | Mobile (iOS / Android) | Desktop (Windows / macOS) |
|---|---|---|
| Interface | Popup de partage native | Menu contextuel du système ou fenêtre dédiée |
| Intérêt | Usage naturel | Pratique mais moins évident (souvent limité à l'email ou AirDrop) |
| Support | Quasi universel | Bon sur Chromium, Safari, Edge ; pas Firefox |
ð L'API Web Share ne fonctionne que dans un contexte sécurisé, c'est-à-dire sur HTTPS, et doit impérativement être déclenchée par une action volontaire de l'utilisateur (un clic ou un appui) sinon ce sera bloqué.

Si le support s'est largement généralisé, surtout sur mobile, certains environnements comme Firefox sur certains OS desktop ne l'ont pas encore appliqué alors même que la version mobile de Firefox le reconnaît.
On va donc penser amélioration progressive :
navigator.share existe.mailto:, liens directs vers les réseaux, etc).D'un point de vue technique, l'objet passé à la méthode navigator.share() est flexible mais chaque clé répond à des contraintes spécifiques définies par la spécification W3C.
titleIl s'agit d'une chaîne de caractères représentant le titre du document ou de l'élément partagé. On va le retrouver comme sujet de l'e-mail si l'utilisateur choisit une application de messagerie ou comme titre de l'aperçu. Ce n'est pas du HTML, uniquement du texte brut.
textC'est le corps descriptif du partage, en général on y place un résumé ou un message personnalisé. Dans le cas d'un partage via SMS ou WhatsApp, c'est ce contenu qui remplira le champ de saisie.
urlUne chaîne de caractères représentant une URL valide (absolue ou relative). Le navigateur résout automatiquement les URL relatives par rapport à l'URL de la page courante avant de les envoyer au système.
filesC'est l'ajout le plus complexe. : un tableau d'objets File (généralement créés via un constructeur new File() ou récupérés depuis un <input type="file">). Avant de partager des fichiers, il est impératif d'utiliser la méthode navigator.canShare({ files: mesFichiers }), elle va renvoyer un booléen indiquant si le système accepte le format et le poids des fichiers. En général on accepte couramment les images, les pdf, audio et vidéo mais pas les exécutables (.exe, .js) qui seront bloqués
Voici un exemple de code utilisant les promesses.
const shareBtn = document.querySelector('#btn-partage');
// On ne montre le bouton que si l'API est supportée
if (navigator.share) {
shareBtn.style.display = 'block'; // Ou un équivalent
shareBtn.addEventListener('click', async () => {
try {
await navigator.share({
title: 'Le titre de l\'article',
text: 'Une courte description',
url: window.location.href
});
console.log('Contenu partagé avec succès !');
} catch (err) {
// L'utilisateur a annulé ou le partage a échoué
console.log(`Erreur ou annulation : ${err}`);
}
});
} else {
// Optionnel : afficher une autre solution (ex: copier le lien)
console.log("Web Share API non supportée sur ce navigateur.");
}
Attention désormais dans les frames (<iframe> en réalité, ce qui est le cas de la démo ci-dessus hébergée par codepen) vous devez autoriser spécifiquement cette API pour des raisons de sécurité avec l'attribut allow="web-share".