CSS : les parties inévitablement mauvaises
(matklad.github.io)- Pour styliser une page web, un petit sous-ensemble maîtrisable suffit pour un blog simple ou une interface graphique, mais des pièges comme les valeurs par défaut du navigateur et la mise en page peuvent entraîner plusieurs jours de débogage
- En utilisant d’abord des balises HTML5 sémantiques et en réduisant les wrappers, il devient plus facile de faire en sorte que le CSS fonctionne avec le balisage existant
- Il n’existe pas d’algorithme universel unique pour la mise en page en CSS, et il faut comprendre quels types d’agencement chaque système autorise
box-sizing,margin,font-size,line-height,word-breakse comportent différemment de l’intuition, si bien qu’un petit changement peut provoquer des problèmes globaux de disposition ou de lisibilité- Pour une page simple, un CSS reset, du CSS sans classes, flexbox et des règles responsive non excessives peuvent constituer un bon point de départ
Portée de l’apprentissage de CSS et point de vue de base
- CSS, HTML et les Web API sont extrêmement vastes et demandent une vraie expertise, mais pour des tâches comme un blog technique ou une GUI simple, un sous-ensemble raisonnable du web moderne suffit
- Je n’ai pas vu de ressource qui n’enseigne que le sous-ensemble nécessaire aux tâches simples, mais on peut s’en faire une idée en suivant MDN
- Le problème, ce sont les pièges imprévus qui cassent la page et dont la cause peut demander plusieurs jours à trouver
- Le style de ce site tient dans environ 200 lignes de CSS lisible
Les bons côtés : HTML sémantique et CSS sans classes
-
Balises sémantiques HTML5
- Cela vaut la peine de parcourir la référence des éléments de MDN, et le nombre d’éléments HTML n’est pas si élevé
- Des balises comme
main,article,nav,kbdpeuvent faciliter la structuration d’une page ulpeut servir à toutes sortes de listes, par exemple pour les sections d’un site dansheader > navdetailspeut servir pour une table des matières, et on peut consulter le code source de MDNdletdtpeuvent être utilisés pour des listes par paires
-
Réduire les wrappers
- En regardant le code source de vrais sites web, on voit souvent de nombreuses couches de wrappers, ce qui peut donner l’impression que les problèmes de layout se résolvent avec des wrappers
- Sans trancher sur les pratiques CSS de production, il a semblé plus facile à comprendre de se limiter à des balises sémantiques porteuses de sens, puis de chercher le CSS adapté à ce balisage
-
CSS sans classes
- On ne peut pas réinitialiser complètement le style à un état neutre de type « rien du tout » : du texte blanc ou transparent reste encore un style
- Après une réinitialisation, on peut styliser directement les éléments HTML courants
- En utilisant des balises
main,header,footer,nav, on peut définir le layout global de la page sans multiplier les sélecteurs CSS - Cette approche amène le CSS à faire des hypothèses sur la structure HTML, mais si c’est votre HTML et votre CSS, vous pouvez les changer si le résultat ne vous convient pas
Les mauvais côtés : layout, valeurs par défaut du navigateur, sélecteurs
-
Layout
- Les problèmes de layout ne sont pas propres au web ; ils sont difficiles dans de nombreux frameworks GUI
- Il existe plusieurs façons de disposer une image raster de taille fixe et un paragraphe de texte qui l’explique dans un rectangle d’écran
- Une GUI générale est une hiérarchie de boîtes avec beaucoup de « degrés de liberté de layout »
- Le layout de chaque boîte influe sur celui de toutes les autres, et en général toutes les boîtes doivent s’emboîter exactement sans espace ni chevauchement
- Il n’existe pas d’algorithme de layout universel unique : selon le système, on utilise des heuristiques différentes, de RectCut aux constraint solvers, en passant par des approches intermédiaires
- Mieux vaut se demander non pas « comment produire tel layout dans ce système », mais « quels layouts ce système autorise »
-
Valeurs par défaut du navigateur et CSS reset
- Même un HTML sémantique sans CSS reçoit dans le navigateur des styles par défaut : couleurs, polices, tailles, gros titres, liens soulignés, etc.
- Ces styles par défaut sont utiles, mais ils varient selon les navigateurs ; si l’on dépend de valeurs par défaut qu’on n’a pas écrites, on peut obtenir des résultats différents ailleurs
- La solution habituelle consiste à utiliser un CSS reset ou une normalisation, c’est-à-dire à écraser les valeurs par défaut avec des règles explicites au début du CSS
- Le problème n’est pas que les valeurs par défaut soient mauvaises en soi, mais qu’elles ne soient pas cohérentes entre elles
- Pour savoir quelles règles écraser en pratique, mieux vaut comparer plusieurs CSS reset existants
-
Faut-il styliser une page web ?
- La plateforme web porte à la fois une vision du média visuel souple et adaptatif, et une vision centrée sur la diffusion de contenu, où l’utilisateur devrait pouvoir personnaliser la présentation
- Par défaut, une page sans style est peu agréable à utiliser et peu esthétique
- Un monde où une page sans CSS resterait naturellement facile à lire serait préférable, mais dans l’environnement actuel, appliquer du style au contenu reste utile
- Il est bon de permettre aux utilisateurs avancés d’apporter leur propre CSS
- Le balisage HTML doit rester raisonnable, il ne faut pas le suradapter au CSS, et la page doit fonctionner en reader mode
-
Sélecteurs CSS
- Le CSS de base fonctionne comme une forme d’héritage puissante, et chaque élément visuel d’une page est influencé par plusieurs règles
- On peut toujours « patcher » un élément existant en ajoutant du CSS à la fin du fichier
- Les sélecteurs CSS sont vus comme une abstraction ajoutée sur le mauvais axe, d’où une approche possible fondée sur le CSS sans classes et les styles inline
- Des outils comme Tailwind réduisent l’inconfort de l’écriture inline, et les moteurs de templates qui prennent en charge JSX ou la composition limitent la répétition HTML
- Avec CSS nesting, on peut réduire les sélecteurs qui s’étendent trop loin et styliser à l’échelle d’un composant
Modèle de boîte et disposition : box-sizing, margin, flux par défaut, flexbox
-
box-sizing- Une interface est un ensemble récursif de rectangles, et le layout consiste à décider où chacun de ces rectangles se place
- Dans le comportement par défaut du HTML,
widthetheightd’un élément n’incluent ni la bordure ni le padding, ce qui n’est pas intuitif - Si l’on augmente le padding à un seul endroit, tout le layout qui semblait parfait au départ peut se décaler de manière inattendue
* { box-sizing: border-box; }mérite de figurer en première ligne d’un CSS reset, car cela rend l’ajout d’une bordure local
-
Fusion des marges
- Si l’on veut un espacement de
8pxautour d’un élément, utiliser du padding peut faire passer l’espace entre deux éléments adjacents à16px marginfonctionne en combinant les marges voisines non pas par addition mais parmax- La fusion des marges est très utile, mais elle peut produire des comportements surprenants
- On peut voir cela comme une marge d’enfant qui déborde hors de son parent, même si l’intuition sur
marginn’est pas entièrement solide - L’article de Julia Evans Moving away from Tailwind, and learning to structure my CSS présente en général une approche de type owl selector où le parent contrôle la marge entre les enfants plutôt que d’attribuer une marge à chaque élément lui-même
- Ajouter une marge à tous les enfants d’une
sectionsauf le premier est compris comme une façon de réduire les problèmes liés aux marges - Il est frustrant que ce genre de connaissance soit difficile à acquérir sans devenir développeur web professionnel ou sans rétroconcevoir d’autres frameworks CSS
- Si l’on veut un espacement de
-
Layout en flux par défaut
- L’algorithme de layout par défaut est lié aux origines de HTML comme langage de document, et semble adapté à la production de documents papier centrés sur le texte et les images
- Pour le texte courant, le flux par défaut se comporte en pratique de façon assez proche de ce que l’on souhaite
- Pour contrôler directement la répartition spatiale des éléments d’une page, il faut une approche différente du flux par défaut
-
flexbox
- flexbox permet de disposer une série d’éléments verticalement ou horizontalement et de les adapter à l’espace disponible
- Autrefois, même un agencement du type « ça à gauche, ça à droite » demandait une connaissance approfondie de CSS ou un framework CSS opaque
- flexbox reste assez complexe, au point qu’il faut souvent revenir à MDN, mais on finit généralement par obtenir ce qu’on veut
-
Design responsive
- Le CSS moderne permet d’interroger la taille de l’écran et d’implémenter une logique conditionnelle selon les contraintes du user agent
- HTML est intrinsèquement responsive : contrairement à PostScript ou PDF, les paragraphes se redistribuent automatiquement quand la taille de la fenêtre change
- Il vaut mieux éviter les règles responsive explicites et laisser le layout se comporter raisonnablement de lui-même
- Ce blog s’affiche correctement sur mobile, tablette et desktop sans requêtes
@mediaexplicites - Il suffit souvent d’imposer un
max-widthà la colonne principale du texte
Taille et texte : pixels, police, hauteur de ligne, retours à la ligne
-
Pixels
1pxfait ce qu’on attend, mais ne signifie pas forcément un pixel physique de l’écran- Le
1pxde CSS est une unité d’angle visuel, conçue pour paraître perceptivement similaire sur n’importe quel écran - Selon la taille de l’écran, sa densité de pixels et la distance d’observation habituelle, cela se convertit en un nombre différent de pixels physiques
- On peut donc exprimer toutes les tailles en pixels sans avoir à réfléchir séparément à la densité de pixels des différents écrans
- Même les unités « réelles » de CSS, comme les centimètres et les pouces, sont définies à partir du pixel et fonctionnent donc elles aussi comme des angles
-
font-size- Dans
font-size: 16px,16pxn’est pas la taille d’un glyphe précis, mais celle d’une boîte virtuelle autour du glyphe - Cette boîte n’épouse pas exactement le glyphe, et la taille réelle du glyphe dépend de la police
font-size-adjustpeut rendrefont-sizeplus cohérent d’une police à l’autre- Aujourd’hui,
font-size-adjustreste une fonctionnalité très de niche ; personnellement, on aimerait mettrefont-size-adjust: ex-height 0.53;à côté debox-sizing, mais peu de pages le font - La valeur par défaut de
font-sizeest relativement cohérente entre navigateurs, et16pxdomine largement - Selon la police,
16pxpeut paraître petit, et certaines polices par défaut le sont particulièrement - Chez Apple,
font-family: serifparaît bien plus petit quesans-serif, au point qu’à16px, la lecture devient presque inconfortable - Définir
font-sizeen CSS désactive le mécanisme par défaut du navigateur pour ajuster la taille de la police - Il ne faut pas supposer que le texte sera lisible par défaut ; il faut vérifier avec d’autres réglages
- Si l’on réduit les degrés de liberté avec
font-size-adjustet qu’on fixe le sens defont-size, alors si le résultat est correct avec la taille de police par défaut16px, c’est terminé - Sinon, il faut définir
font-sizeà une valeur plus élevée, puis vérifier ensuite si la lecture reste facile aussi en reader mode
- Dans
-
line-height- Contrairement à ce que son nom suggère,
line-heightne définit pas la hauteur d’une ligne line-heightcorrespond à la hauteur d’un groupe de glyphes défini avec une même police- Quand tout le texte utilise la même police, la hauteur de ligne et celle du groupe de glyphes coïncident
- Si certains mots passent en police
monospace, le résultat peut ne pas correspondre à l’attente font-size-adjustcorrige la taille des glyphes dans la boîte, mais pas leur position relative- Quand des groupes de texte de polices différentes sont alignés verticalement sur une même baseline, leurs
line-heightetline-boxse décalent les uns par rapport aux autres - La hauteur totale de la ligne peut alors se construire comme une union et devenir plus grande que prévu
- Cet effet est détaillé dans Deep dive CSS: font metrics, line-height and vertical-align
- Contrairement à ce que son nom suggère,
-
Rythme vertical
- Le rythme vertical consiste à faire en sorte que, même avec des titres ou des images, les lignes entre paragraphes tombent aux mêmes positions relatives
- Cela se décrit comme l’alignement d’une page web sur une réglure invisible en arrière-plan
- Dans une mise en page à une seule colonne, cela est jugé peu utile
- Dans une mise en page à deux colonnes, on peut vouloir aligner les lignes des deux côtés
- Dans une seule colonne, déployer des efforts complexes pour cela n’a guère de sens
-
word-break- L’avantage du layout en flux est son comportement dynamique : quand la fenêtre se rétrécit, le texte se répartit proprement sur plusieurs lignes
- Les lignes ne peuvent être coupées qu’aux espaces ou aux points d’insertion de césure
- De longues séquences comme du
code inlineou des URL peuvent ne pas se couper - Ce problème provoque des débordements horizontaux sur mobile, qu’on ne remarque souvent qu’après publication
- Il n’existe pas d’astuce unique pour le corriger, mais Against Horizontal Scroll propose quelques conseils
Conclusion pratique
- Pour créer un blog simple, il faudrait une ressource qui explique brièvement mais suffisamment les parties nécessaires de HTML et CSS
- Le texte se termine par une demande : un petit livre d’une centaine de pages qui explique HTML et CSS juste assez pour construire un blog simple sans se faire piéger par des problèmes comme la fusion des marges
1 commentaires
Avis sur Lobste.rs
C’est un détail, mais la définition du responsive design est bien de « garantir l’utilisabilité et la satisfaction en permettant un bon rendu sur une variété d’appareils et de tailles de fenêtre/d’écran »
Les media queries ou les container queries ne sont que des outils parmi d’autres pour y parvenir, et le responsive design relève davantage d’un état d’esprit que de l’idée « mettons des media queries partout »
Donc ce qui semble vraiment « mauvais », ce n’est pas le responsive design en lui-même, mais plutôt les media queries ou l’abus de points de rupture
La partie sur les « Browser defaults » prête pas mal à confusion. Les feuilles de style de reset et les feuilles de style de normalisation ont des objectifs et des comportements très différents, et l’article les mélange
Un reset ne sert pas tant à supprimer les différences entre navigateurs qu’à effacer les différences par défaut entre éléments, comme le
padding-inline-startdeolou l’apparence native debutton, afin de permettre de construire les styles depuis une page blanche plutôt qu’au-dessus de la feuille de style de l’agent utilisateurLa normalisation, elle, cherche à coopérer avec la feuille de style de l’agent utilisateur, avec un mélange de corrections des écarts entre navigateurs et de changements vers des valeurs par défaut jugées « plus raisonnables »
Aujourd’hui, les valeurs par défaut des navigateurs diffèrent rarement de façon significative, donc les auteurs de contenu web ordinaires peuvent presque les ignorer. Il reste quelques exceptions comme Chromium has the wrong
tableborder-color, WebKit fixed theirs 1½ years ago, certaines différences de marge/taille sur des éléments de formulaire,appearance, ou encore le stylage de::markerpour<summary>dans WebKitJe suis aussi opposé à
box-sizing: border-box.border-boxest centré sur la mise en page, alors quecontent-boxest centré sur le contenu ; à mon avis, il vaut mieux laisser le parent gérer la mise en page et concevoir à partir du contenu. Dès qu’on manipule des proportions,content-boxdevient nécessaire, et le seul cas oùborder-boxest réellement utile, c’est à peu près pour faire remplir le viewport aubodyJe suis aussi sceptique sur
font-size-adjust. On remplace un problème bien connu par un problème moins validé, qui peut être un peu meilleur pour certaines personnes et un peu pire pour d’autres. Le problème de fond ne peut pas vraiment être résolu, et cela impose des hypothèses infondées sur les proportions et les métriques de police des utilisateursLa formulation sur
line-heightet le fait de « régler avec la même police » n’est pas non plus très rigoureuse. En pratique, la taille de police, les changements de langue,font-family: monospace,vertical-align,<sup>,<sub>et les métriques de police s’entremêlent, donc il est difficile de ramener ça simplement à une question de même policeLa fusion des marges est plus complexe que ne le laisse entendre l’article, mais elle est aussi assez pratique. Si on utilise
flexougridpour du contenu général, on se retrouve souvent à devoir retoucher sans cessegapou les marges, ce qui rend l’ensemble fragile. Avecdisplay: flow-root, on peut empêcher la fusion des marges des enfants avec celles du parentJe ne suis pas d’accord avec la vision d’ensemble sur le responsive design, mais l’idée de réduire les media queries inutiles et d’éviter de se battre contre le navigateur est la bonne. Si on peut exprimer les changements de mise en page à partir du contenu, c’est généralement préférable
Ces derniers temps, j’utilise beaucoup l’interpolation linéaire avec
clampà l’aide d’unités de viewport :margin-inline: --vw-lerp(1rem at 20rem, 2.5rem at 60rem);, développé enmargin-inline: clamp(1rem,1rem + ((2.5 - 1)/(60 - 20)*(100vw - 20rem)),2.5rem);Je l’ai implémenté l’an dernier implemented this as a LightningCSS visitor, et cela donne 1rem quand le viewport fait 20rem ou moins, puis une augmentation fluide jusqu’à 2.5rem à 60rem avant de s’arrêter, ce qui évite les points de rupture tout en s’adaptant à la taille de police de l’utilisateur, avec un rendu très agréable
font-size-adjustfonctionne comme ça. Le nom prête à confusion, mais je comprendsfont-sizecomme la taille de la boîte em, etfont-size-adjustcomme la modification de la taille des glyphes à l’intérieur de cette boîte emDonc
emetremrestent identiques, tandis quechchange. Maischdépend déjà de la police, donc c’est logique qu’il changeJ’aimerais bien voir un article sur
font-size-adjust. Je ne suis pas expert, donc mon niveau de confiance reste faible, mais jusqu’ici cela me semble être une amélioration énorme pourtant très peu connue. On ne peut pas aligner automatiquement n’importe quelles deux polices dans tous les contextes, mais rien qu’en égalisant la taille duxplutôt que celle de la boîte em, j’ai l’impression qu’on couvre 90 % des polices/contextesL’intention de l’article est bonne, et le point de vue de gens qui ne vivent pas entièrement dans HTML/CSS est important, mais une grande partie de ces « mauvaises choses » peut être bénéfique selon le contexte
Les sélecteurs CSS sont faciles à abuser, mais ils ne sont pas mauvais par nature. Au lieu de conclure en termes de A ou B, on peut définir des règles/sélecteurs généraux puis ajouter au besoin des classes d’exception ou des classes utilitaires
L’article lui-même contient un bon exemple de sélecteur :
Les media queries aussi peuvent devenir inutiles si cela peut être résolu avec les container queries
La surface de CSS peut sembler énorme, et vu son usage massif et tout ce qu’il permet de faire, les désaccords d’opinion sont fréquents. Mais il faut aussi voir à quel point CSS a progressé et tout ce qu’on peut accomplir avec relativement peu de code une fois les concepts assimilés
Si vous voulez aller plus loin, https://every-layout.dev/ m’a beaucoup aidé à comprendre comment différents éléments s’articulent en CSS
J’ai commencé à comprendre les layouts web quand j’ai réalisé qu’un bon site web est fondamentalement conçu verticalement. Les éléments devraient s’empiler naturellement de haut en bas, et il suffit de concevoir d’abord pour l’écran mobile, puis de déployer plus largement sur grand écran en bonus
J’ai du mal à être d’accord avec cette affirmation. L’imbrication CSS n’est qu’un sucre syntaxique, et elle n’aide pas vraiment à éviter le problème des sélecteurs trop spécifiques.
Il y a 15 ans déjà, on utilisait beaucoup l’imbrication de sélecteurs avec Sass, et on en est arrivés un par un à la conclusion qu’on s’était nous-mêmes piégés en liant trop étroitement les sélecteurs CSS à la structure HTML.
Le piège de l’imbrication ne se voit pas bien au début d’un projet. Dans la phase greenfield, où l’on crée surtout de nouvelles fonctionnalités, écrire le CSS ainsi paraît très séduisant.
Quelques mois plus tard, quand on commence une grosse refonte de layout et du design, les éléments wrapper changent de place dans le HTML, et adapter le CSS à cela donne l’impression de résoudre un Rubik’s Cube sous LSD.
À mon avis, le sommet en matière de gestion de la spécificité des sélecteurs, c’était de garder l’essentiel au niveau de sélecteurs simples, c’est-à-dire une seule classe, et de n’utiliser qu’un petit nombre de sélecteurs composés et de sélecteurs combinés comme
a:hover. C’est la lignée BEM, OOCSS, etc., avant que l’attention ne se déplace brutalement vers des outils centrés sur JS.Article intéressant, mais on dirait que l’auteur utilise les sélecteurs imbriqués à un endroit où cela n’apporte aucun effet.
&était une erreur, et utilisent donc toujours&. Je trouve cette position assez raisonnable.Personnellement, je suis encore partagé. Au début, je pensais aussi que c’était une erreur, mais dans les situations où il suffit d’englober un tas de styles dans
header { … }pour en restreindre la portée, c’est assez pratique. J’aimerais aussi qu’on puisse y mettre des at-rules non fondées sur des sélecteurs, comme@keyframes.Honnêtement, c’est un très mauvais conseil. J’aime les articles de Maklad, mais ici, cela ressemble clairement à quelque chose écrit par quelqu’un qui n’a jamais utilisé CSS en contexte professionnel.
Presque tout relève de mauvaises pratiques d’amateur que l’on évite quand on écrit du CSS de manière professionnelle.
À force de styliser cela sans classes, on finit aussi par styliser
<main>ou<nav>sans sélecteurs de classe.En revanche, en environnement professionnel, on consacre très peu de temps à concevoir la boîte de contenu. On la crée une fois au début du projet, puis on se contente ensuite de corriger lentement de petits bugs.
L’essentiel du temps est consacré à la création de composants custom ou réutilisables. Les composants réutilisables sont plus difficiles et l’on finit pratiquement par créer un clone de Bootstrap spécifique au site.
Les composants custom sont plus simples, mais le code se multiplie, et il faut des stratégies pour éviter les interférences involontaires avec d’autres composants, comme BEM, OOCSS ou des classes utilitaires à la Tailwind.
En conclusion, chaque technique correspond à une échelle différente. Si les façons professionnelles d’écrire du CSS vous semblent inutiles, c’est probablement parce que vous résolvez un problème d’une autre échelle.
Cela dit, je suis d’accord avec
Bad: Wrappers. J’ai déjà vu des experts CSS écrire tout un site dans un ou deux fichiers, et j’ai aussi vu des gens qui utilisaient énormément de CSS.La seconde voie conduit facilement, au final, à des approches erronées comme BEM, mises en place pour gérer une grande quantité de CSS.
Il semble y avoir des conseils contradictoires dans l’article.
Good: Classless CSSetBad: CSS selectorsapparaissent ensemble, alors que pour utiliser du CSS sans classes, il faut au contraire davantage s’appuyer sur les sélecteurs CSS.Référence : https://www.keithcirkel.co.uk/css-classes-considered-harmful/
Ce vertical rhythm, « comme s’il y avait un cahier Seyès invisible derrière la page web », est tout à fait possible avec des valeurs en EM.
Si l’on mélange différentes polices, cela peut légèrement vaciller à cause des différences de métriques, mais même dans ce cas, on peut utiliser
align-items: baselinede flex.