feat(content): add a new article about CSS

This commit is contained in:
Bruno Carlin 2025-07-01 00:09:11 +02:00
parent cce7779c5a
commit 874def264c
Signed by: bcarlin
GPG key ID: 8E254EA0FFEB9B6D
3 changed files with 1086 additions and 0 deletions

View file

@ -36,6 +36,7 @@ outputFormats:
markup: markup:
highlight: highlight:
lineNumbersInTable: false
noClasses: false noClasses: false
goldmark: goldmark:
parser: parser:

View file

@ -0,0 +1,542 @@
---
# vim: spell spelllang=en
title: 'Embracing Modern CSS'
slug: '008-embracing-modern-css'
date: '2025-07-06T14:29:26+02:00'
draft: false
categories:
- dev
tags:
- CSS
summary: |
Where I write about my discoveries of recent CSS I was unaware of.
description: |
The article explores recent developments in CSS, such as nested rules, CSS
variables, and classless CSS, which allow for cleaner and more efficient
stylesheet writing. It also mentions future features like CSS mixins, custom
CSS properties, and CSS scopes, which promise to further enhance the way user
interfaces are styled.
---
I recently stumbled upon a note on a page of [Plain Vanilla] in which I learned
that nested CSS is a thing. It's a thing that's been around for quite some time,
but I did not know about it (I'm quite late in my RSS reader).
This allowed me to catch up on some of the recent evolutions of CSS.
[Plain Vanilla]: https://plainvanillaweb.com/pages/styling.html
## Nested CSS
Nesting CSS rules is one of the main reasons I've been using [SASS] for 15
years.
I've always preferred to write nested rules to group together coherent units of
CSS. For example,
```scss
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
header {
nav {
ul {
list-style: none;
li {
text-align: center;
}
}
}
}
```
makes more sense to me than
```css
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
header nav ul {
list-style: none;
}
header nav ul li {
text-align: center;
}
```
I have a few reasons for this:
* It's easier to read because selectors are sorter and the hierarchy is easier
to grasp;
* I can move around a group of selector without forgetting a declaration;
* I can use my IDE code folding based on indent to close a group and navigate
long CSS files.
Since the [CSS Nesting Module] is [Baseline Widely Available] and is supported
by [90% of users], It can be used to write nested CSS. So now, this is a thing in
CSS:
```css
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
header {
nav {
ul {
list-style: none;
li {
text-align: center;
}
}
}
}
```
The [CSS file] of this site has been rewritten using nested CSS.
[SASS]: https://sass-lang.com
[CSS Nesting Module]: https://drafts.csswg.org/css-nesting/
[Baseline Widely Available]: https://webstatus.dev/features/Nesting
[90% of users]: https://caniuse.com/css-nesting
[CSS file]: https://bcarlin.net/static/css/bcarlin.css
## CSS Variables
To me, variables are essential to ensure a coherent user interface. They allow to
reuse colors, sizes, spacing, and so on.
This is also a reason why I've been using [SASS]. It allowed me to write CSS
with reusable variables :
```scss
$color-error: red;
$color-success: green;
label {
&.error {
color: $color-error;
}
&.success {
color: $color-success;
}
}
.notification {
&.error {
background-color: $color-error;
}
&.success {
background-color: $color-success;
}
}
```
I missed the [CSS Custom Properties for Cascading Variables Module Level 1]
module from 2017, which allowed me to write the same thing in pure CSS:
```css
:root {
--color-error: red;
--color-success: green;
}
label {
&.error {
color: var(--color-error);
}
&.success {
color: var(--color-success);
}
}
.notification {
&.error {
background-color: var(--color-error);
}
&.success {
background-color: var(--color-success);
}
}
```
[CSS Custom Properties for Cascading Variables Module Level 1]: https://www.w3.org/TR/css-variables/
## Classless CSS
Maybe I an going backwards here, given the popularity of utility-first CSS
frameworks like [TailwindCSS].
This one is not really a CSS feature *per se*, but it is a way to write CSS,
where semantically correct HTML is automatically styled correctly. To some
extent, it is, however, backed by some [CSS Selectors Level 4] which are now
Widely implemented across browsers, such as `:has`, `:is`, `:where`, `:not` and
so on.
I used to use [BootstrapCSS] in my projects because it is complete and easy to
use, but I never liked the way it imposed a heavy CSS Structure on my source. For
this site, I was looking for something lighter and came across [PicoCSS] which
styles 90% of my site without changing anything to my templates.
I already had a meaningful semantic HTML base structure:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... -->
</head>
<body>
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
</header>
<main>
<article>
<header>
<h1>Page Title</h1>
</header>
<section>
<!-- ... -->
</section>
</article>
</main>
<footer>
<!-- ... -->
</footer>
</body>
</html>
```
And I really like the way it works: the content is styled based on its semantic
markup, and not on a HTML imposed structure.
For example, here is [Bootstrap Modal component]:
```html
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal Title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Modal Body
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
```
Here is the [Modal component from Tailwind Plus]:
```HTML
<div>
<button class="rounded-md bg-gray-950/5 px-2.5 py-1.5 text-sm font-semibold text-gray-900 hover:bg-gray-950/10">Open dialog</button>
<div class="relative z-10" aria-labelledby="dialog-title" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-gray-500/75 transition-opacity" aria-hidden="true"></div>
<div class="fixed inset-0 z-10 w-screen overflow-y-auto">
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<div class="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div class="mx-auto flex size-12 shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:size-10">
<svg class="size-6 text-red-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-base font-semibold text-gray-900" id="dialog-title">Modal Title</h3>
<div class="mt-2">
Modal Body
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<button type="button" class="inline-flex w-full justify-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-red-500 sm:ml-3 sm:w-auto">Save changes</button>
<button type="button" class="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-xs ring-1 ring-gray-300 ring-inset hover:bg-gray-50 sm:mt-0 sm:w-auto">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
```
Compare those with [PicoCSS Modal component]:
```html
<dialog open>
<article>
<header>
<button aria-label="Close" rel="prev"></button>
<p>
<strong>Modal Title</strong>
</p>
</header>
Modal Body
<footer>
<button class="secondary">Close</button>
<button>Save changes</button>
</footer>
</article>
</dialog>
```
It makes a huge difference in simplicity, readability and accessibility (note
that the ARIA attributes are rendered useless because the semantic markup
already carries that information).
[TailwindCSS]: https://tailwindcss.com
[CSS Selectors Level 4]: https://drafts.csswg.org/selectors-4/
[BootstrapCSS]: https://getbootstrap.com
[PicoCSS]: https://picocss.com
[Bootstrap Modal Component]: https://getbootstrap.com/docs/4.3/components/modal/#live-demo
[Modal component from Tailwind Plus]: https://tailwindcss.com/plus/ui-blocks/application-ui/overlays/modal-dialogs
[PicoCSS Modal component]: https://picocss.com/docs/modal
## `@import` to split CSS files
One last thing I liked to use SASS for was the possibility to split CSS files
into smaller ones to make them easier to grasp. For example:
```scss
@use 'reset';
@use 'typography';
@use 'layout';
@use 'content';
```
With the [CSS Cascading and Inheritance Level 5] module, CSS has that natively:
```css
@import url('reset.css');
@import url('typography.css');
@import url('layout.css');
@import url('content.css');
```
From my understanding, the `@import`ed CSS files are downloaded in parallel,
which reduces the penalty of having several files to download.
CSS `@import` rules even have the benefit of being conditional. For example:
```css
@import url("light.css") only screen and (prefers-color-scheme: light);
@import url('dark.css') only screen and (prefers-color-scheme: dark);
```
[CSS Cascading and Inheritance Level 5]: https://drafts.csswg.org/css-cascade-5/
## Things I'm looking forward to
Those are some things I'm looking forward to using. I do not use them yet
because of browser support or because I did not have a use for them yet. But I'm
excited to try them out.
### CSS Mixins
CSS Mixins are also a major feature of SASS, and foster a cleaner and more
reusable CSS code.
CSS will have them with the [CSS Functions and Mixins Module], which is still a
draft where mixins are not specified yet.
In the meantime, here is an example from [SASS Mixin Guide]:
```scss
@mixin rtl($property, $ltr-value, $rtl-value) {
#{$property}: $ltr-value;
[dir=rtl] & {
#{$property}: $rtl-value;
}
}
.sidebar {
@include rtl(float, left, right);
}
```
Though in some cases, it can easily be replaced with CSS variables:
```css
:root {
--sidebar-float: left;
}
[dir=rtl] {
--sidebar-float: right;
}
.sidebar {
float: var(--sidebar-float);
}
```
[SASS Mixin Guide]: https://sass-lang.com/documentation/at-rules/mixin/#arguments
[CSS Functions and Mixins Module]: https://www.w3.org/TR/2025/WD-css-mixins-1-20250515/
### CSS Custom Properties
This one is a nice little feature from the [CSS Properties and Values API Level
1] module which extends CSS variables nicely.
They allow to define the type, initial value and inheritance rule of a custom
variables. For example:
```css {linenos=true}
@property --my-color {
syntax: "<color>";
inherits: false;
initial-value: black;
}
.primary {
--my-color: red;
}
.secondary {
--my-color: 10px;
}
button {
background-color: var(--my-color);
color: white;
}
```
Here, the definition of `--my-color` on line 12 is not valid (it is a length and
not a color). As the property value is not inherited from a parent, the initial
value will be used: a `<button class="secondary">` will have a black background.
However, as the property is defined to be a color, linters like [Stylelint] and
[ESLint] will eventually be able to catch such errors, in addition to catching
typos in values or in the property name.
[CSS Properties and Values API Level 1]: https://drafts.css-houdini.org/css-properties-values-api
[Stylelint]: https://stylelint.io
[ESLint]: https://eslint.org
### CSS Scopes
This one is maybe the one I am expecting the most.
To style a UI component, it is often necessary to target a specific element of
the component, and repeat selectors:
```css
.card { /*...*/ }
.card article { /*...*/ }
.card article header { /*...*/ }
.card article footer { /*...*/ }
.card article footer button { /*...*/ }
```
With nested CSS modules, this can be simplified to:
```css
.card {
/*...*/
article {
/*...*/
header {
/*...*/
}
footer {
/*...*/
button {
/*...*/
}
}
}
}
```
It can however have some edge cases and yield unexpected results (see the
[example on MDN]).
Scopes are a new feature from the [CSS Cascading and Inheritance Level 6]
module. They are a more natural way of defining rules:
```css
@scope (.card){
:scope {
/*...*/
}
article {
/*...*/
header {
/*...*/
}
footer {
/*...*/
button {
/*...*/
}
}
}
}
```
`@scope` power comes from several fact:
* It follows a proximity rules: an element is styled with the nearest scope
rules;
* It adds no specificity to the selector, which means that it can be overridden
more easily;
* it is more expressive.
[CSS Cascading and Inheritance Level 6]: https://drafts.csswg.org/css-cascade-6/
[example on MDN]: https://developer.mozilla.org/en-US/docs/Web/CSS/@scope#how_scope_conflicts_are_resolved

View file

@ -0,0 +1,543 @@
---
# vim: spell spelllang=fr
title: 'Adopter un CSS moderne'
slug: '008-adopter-css-moderne'
date: '2025-07-06T14:29:26+02:00'
draft: false
categories:
- dev
tags:
- CSS
summary:
Exploration de développements récents de CSS dont j'étais passé à côté.
description: |
L'article explore les récentes évolutions du CSS, telles que l'imbrication des
règles, les variables CSS, et l'utilisation de CSS sans classes, qui
permettent une écriture plus propre et plus efficace des feuilles de style. Il
mentionne également des fonctionnalités futures comme les mixins CSS, les
propriétés personnalisées CSS, et les portées CSS, qui promettent d'améliorer
encore davantage la manière de styliser les interfaces utilisateur.
---
Je suis récemment tombé sur une note dans une page de [Plain Vanilla] dans
laquelle j'ai appris que le CSS imbriqué est valide. C'est possible depuis assez
longtemps, mais je ne le savais pas (je suis assez en retard dans mon lecteur
RSS).
Cela m'a permis de rattraper certaines des récentes évolutions du CSS.
[Plain Vanilla]: https://plainvanillaweb.com/pages/styling.html
## CSS imbriqué
L'imbrication des règles CSS est l'une des principales raisons pour lesquelles
j'ai utilisé [SASS] pendant 15 ans. J'ai toujours préféré écrire des règles
imbriquées pour regrouper des unités cohérentes de CSS. Par exemple,
```scss
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
header {
nav {
ul {
list-style: none;
li {
text-align: center;
}
}
}
}
```
a plus de sens pour moi que
```css
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
header nav ul {
list-style: none;
}
header nav ul li {
text-align: center;
}
```
Il y a plusieurs raisons à ça :
* C'est plus facile à lire car les sélecteurs sont plus courts et la hiérarchie
est plus facile à comprendre ;
* Je peux déplacer un groupe de sélecteurs sans risquer d'oublier une
déclaration ;
* Je peux utiliser le repliement de code basé sur l'indentation de mon IDE pour
fermer un groupe et naviguer dans de longs fichiers CSS.
Depuis que le module [CSS Nesting] est disponible de manière générale et est
[supporté par 90% des utilisateurs], il peut être utilisé pour écrire du CSS
imbriqué. Donc maintenant, c'est du CSS valide :
```css
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
header {
nav {
ul {
list-style: none;
li {
text-align: center;
}
}
}
}
```
Le fichier [CSS de ce site] a été réécrit en utilisant le CSS imbriqué.
[SASS]: https://sass-lang.com
[CSS Nesting]: https://drafts.csswg.org/css-nesting/
[supporté par 90% des utilisateurs]: https://caniuse.com/css-nesting
[CSS de ce site]: https://bcarlin.net/static/css/bcarlin.css
## Variables CSS
Pour moi, les variables sont essentielles pour assurer une interface utilisateur
cohérente. Elles permettent de réutiliser des couleurs, des tailles, des
espacements, etc.
C'est aussi une raison pour laquelle j'ai utilisé SASS. Cela m'a permis d'écrire
du CSS avec des variables réutilisables :
```scss
$color-error: red;
$color-success: green;
label {
&.error {
color: $color-error;
}
&.success {
color: $color-success;
}
}
.notification {
&.error {
background-color: $color-error;
}
&.success {
background-color: $color-success;
}
}
```
J'ai manqué la publication du module [CSS Custom Properties for Cascading
Variables Module Level 1] de 2017, qui m'a permis d'écrire la même chose en CSS
pur :
```css
:root {
--color-error: red;
--color-success: green;
}
label {
&.error {
color: var(--color-error);
}
&.success {
color: var(--color-success);
}
}
.notification {
&.error {
background-color: var(--color-error);
}
&.success {
background-color: var(--color-success);
}
}
```
[CSS Custom Properties for Cascading Variables Module Level 1]: https://www.w3.org/TR/css-variables/
## CSS Sans Classes
Peut-être que je vais à contre-courant ici, , compte tenu de la popularité des
frameworks CSS « utilitaires » comme [TailwindCSS].
Ce point n'est pas vraiment une fonctionnalité CSS en soi, mais c'est une façon
d'écrire du CSS, où le HTML sémantiquement correct est automatiquement mis en
forme correctement. Dans une certaine mesure, il est cependant soutenu par
certains [Sélecteurs CSS Niveau 4] qui sont maintenant largement implémentés
dans les navigateurs, tels que `:has`, `:is`, `:where`, `:not`, etc.
J'utilisais habituellement [BootstrapCSS] dans mes projets parce qu'il est
complet et facile à utiliser, mais je n'ai jamais aimé la façon dont il imposait
une structure CSS relativement lourde. Pour ce site, je cherchais quelque chose
de plus léger et je suis tombé sur [PicoCSS] qui a mis en forme 90% de mon site
sans changer quoi que ce soit à mes modèles.
J'avais déjà une structure HTML de base sémantiquement significative :
```html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... -->
</head>
<body>
<header>
<nav>
<ul>
<li><a href="/">Accueil</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
</header>
<main>
<article>
<header>
<h1>Titre de la Page</h1>
</header>
<section>
<!-- ... -->
</section>
</article>
</main>
<footer>
<!-- ... -->
</footer>
</body>
</html>
```
Et j'aime vraiment la façon dont cela fonctionne : le contenu est mis en forme
en fonction de son balisage sémantique, et non en fonction d'une structure HTML
imposée.
Par exemple, voici le [composant Modal de Bootstrap] :
```html
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Titre de la fenêtre</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Fermer">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
Corps de la fenêtre
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-primary">Enregistrer</button>
</div>
</div>
</div>
</div>
```
Voici le [composant Modal de Tailwind Plus] :
```html
<div>
<button class="rounded-md bg-gray-950/5 px-2.5 py-1.5 text-sm font-semibold text-gray-900 hover\:bg-gray-950/10">Ouvrir le dialogue</button>
<div class="relative z-10" aria-labelledby="dialog-title" role="dialog" aria-modal="true">
<div class="fixed inset-0 bg-gray-500/75 transition-opacity" aria-hidden="true"></div>
<div class="fixed inset-0 z-10 w-screen overflow-y-auto">
<div class="flex min-h-full items-end justify-center p-4 text-center sm\:items-center sm\:p-0">
<div class="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm\:my-8 sm\:w-full sm\:max-w-lg">
<div class="bg-white px-4 pt-5 pb-4 sm\:p-6 sm\:pb-4">
<div class="sm\:flex sm\:items-start">
<div class="mx-auto flex size-12 shrink-0 items-center justify-center rounded-full bg-red-100 sm\:mx-0 sm\:size-10">
<svg class="size-6 text-red-600" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
</svg>
</div>
<div class="mt-3 text-center sm\:mt-0 sm\:ml-4 sm\:text-left">
<h3 class="text-base font-semibold text-gray-900" id="dialog-title">Titre de la fenêtre</h3>
<div class="mt-2">
Corps de la fenêtre
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm\:flex sm\:flex-row-reverse sm\:px-6">
<button type="button" class="inline-flex w-full justify-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover\:bg-red-500 sm\:ml-3 sm\:w-auto">Enregistrer</button>
<button type="button" class="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-xs ring-1 ring-gray-300 ring-inset hover\:bg-gray-50 sm\:mt-0 sm\:w-auto">Fermer</button>
</div>
</div>
</div>
</div>
</div>
</div>
```
Comparez-les avec le [composant Modal de PicoCSS] :
```html
<dialog open>
<article>
<header>
<button aria-label="Fermer" rel="prev"></button>
<p>
<strong>Titre de la fenêtre</strong>
</p>
</header>
Corps de la fenêtre
<footer>
<button class="secondary">Fermer</button>
<button>Enregistrer</button>
</footer>
</article>
</dialog>
```
Cela fait une énorme différence en termes de simplicité, de lisibilité et
d'accessibilité (notez que les attributs ARIA sont rendus inutiles car le
balisage sémantique porte déjà cette information).
[TailwindCSS]: https://tailwindcss.com
[Sélecteurs CSS Niveau 4]: https://drafts.csswg.org/selectors-4/
[BootstrapCSS]: https://getbootstrap.com
[PicoCSS]: https://picocss.com
[composant Modal de Bootstrap]: https://getbootstrap.com/docs/4.3/components/modal/#live-demo
[composant Modal de Tailwind Plus]: https://tailwindcss.com/plus/ui-blocks/application-ui/overlays/modal-dialogs
[composant Modal de PicoCSS]: https://picocss.com/docs/modal
## `@import` pour diviser les fichiers CSS
Un dernièr point pour lequel j'aimais utiliser SASS était la possibilité de
diviser les fichiers CSS en fichiers plus petits pour les rendre plus faciles à
comprendre. Par exemple :
```scss
@use 'reset';
@use 'typography';
@use 'layout';
@use 'content';
```
Avec le module [CSS Cascading and Inheritance Level 5], CSS a cela nativement :
```css
@import url('reset.css');
@import url('typography.css');
@import url('layout.css');
@import url('content.css');
```
De ma compréhension, les fichiers CSS `@import`és sont téléchargés en parallèle,
ce qui réduit le coût d'avoir plusieurs fichiers à télécharger. Les règles
CSS `@import` ont même l'avantage d'être conditionnelles. Par exemple :
```css
@import url("light.css") only screen and (prefers-color-scheme: light);
@import url('dark.css') only screen and (prefers-color-scheme: dark);
```
[CSS Cascading and Inheritance Level 5]: https://drafts.csswg.org/css-cascade-5/
## Les évolutions que j'attends avec impatience
Voici quelques spécifications que j'ai hâte d'utiliser. Je ne les utilise pas
encore en raison du support des navigateurs ou parce que je n'en ai pas encore
eu besoin. Mais je suis impatient de les essayer.
### Mixins CSS
Les Mixins CSS sont également une fonctionnalité majeure de SASS, et favorisent
un code CSS plus propre et plus réutilisable.
CSS les aura avec le [Module des fonctions et mixins CSS], qui est encore un
brouillon, et dans lequel les mixins ne sont pas encore spécifiés.
En attendant, voici un exemple du [Guide des Mixins SASS] :
```scss
@mixin rtl($property, $ltr-value, $rtl-value) {
#{$property}: $ltr-value;
[dir=rtl] & {
#{$property}: $rtl-value;
}
}
.sidebar {
@include rtl(float, left, right);
}
```
Bien que dans certains cas, cela puisse être facilement remplacé par des
variables CSS :
```css
:root {
--sidebar-float: left;
}
[dir=rtl] {
--sidebar-float: right;
}
.sidebar {
float: var(--sidebar-float);
}
```
[Guide des Mixins SASS]: https://sass-lang.com/documentation/at-rules/mixin/#arguments
[Module des fonctions et mixins CSS]: https://www.w3.org/TR/2025/WD-css-mixins-1-20250515/
### Propriétés Personnalisées CSS
Celle-ci est une petite fonctionnalité sympa du module [CSS Properties and
Values API Level 1] qui étend les variables CSS.
Elles permettent de définir le type, la valeur initiale et la règle d'héritage
d'une variable personnalisée. Par exemple :
```css {linenos=true}
@property --my-color {
syntax: "<color>";
inherits: false;
initial-value: black;
}
.primary {
--my-color: red;
}
.secondary {
--my-color: 10px;
}
button {
background-color: var(--my-color);
color: white;
}
```
Ici, la définition de `--my-color` à la ligne 12 n'est pas valide (c'est une
longueur et non une couleur). Comme la valeur de la propriété n'est pas héritée
d'un parent, la valeur initiale sera utilisée : un `<button class="secondary">`
aura un fond noir.
Cependant, comme la propriété est définie pour être une couleur, des linters
comme [Stylelint] et [ESLint] pourront attraper de telles erreurs, en plus
d'attraper les fautes de frappe dans les valeurs ou dans le nom de la propriété.
[CSS Properties and Values API Level 1]: https://drafts.css-houdini.org/css-properties-values-api
[Stylelint]: https://stylelint.io
[ESLint]: https://eslint.org
### Scopes CSS
Celle-ci est peut-être celle que j'attends le plus. Pour styliser un composant
d'interface utilisateur, il est souvent nécessaire de cibler un élément
spécifique du composant, et de répéter les sélecteurs :
```css
.card { /*...*/ }
.card article { /*...*/ }
.card article header { /*...*/ }
.card article footer { /*...*/ }
.card article footer button { /*...*/ }
```
Avec les modules CSS imbriqués, cela peut être simplifié en :
```css
.card {
/*...*/
article {
/*...*/
header {
/*...*/
}
footer {
/*...*/
button {
/*...*/
}
}
}
}
```
Cela peut cependant avoir quelques cas particuliers et donner des résultats
inattendus (voir l'[exemple sur MDN]).
Les portées sont une nouvelle fonctionnalité du module [CSS Cascading and
Inheritance Level 6]. Elles sont une manière plus naturelle de définir des
règles :
```css
@scope (.card) {
:scope {
/*...*/
}
article {
/*...*/
header {
/*...*/
}
footer {
/*...*/
button {
/*...*/
}
}
}
}
```
La puissance de @scope vient de plusieurs faits :
* Il suit des règles de proximité : un élément est stylisé avec les règles de
portée les plus proches ;
* Il n'ajoute aucune spécificité au sélecteur, ce qui signifie qu'il peut être
remplacé plus facilement ;
* Il est plus expressif.
[CSS Cascading and Inheritance Level 6]: https://drafts.csswg.org/css-cascade-6/
[exemple sur MDN]: https://developer.mozilla.org/en-US/docs/Web/CSS/@scope#how_scope_conflicts_are_resolved