Introduction
Chaque fois que je démarre un nouveau projet, la première chose à faire est de poncer certaines des aspérités du langage CSS. Je le fais avec un ensemble fonctionnel de styles de ligne de base personnalisés.
Pendant longtemps, j’ai utilisé le fameux CSS Reset d’Eric Meyer. C’est un morceau solide de CSS, mais c’est un peu long dans la dent à ce stade ; il n’a pas été mis à jour depuis plus d’une décennie, et beaucoup a changé depuis !
Récemment, j’ai utilisé ma propre réinitialisation CSS personnalisée. Il comprend toutes les petites astuces que j’ai découvertes pour améliorer à la fois l’expérience utilisateur et l’expérience de création CSS.
Comme les autres réinitialisations CSS, il n’a pas d’avis en matière de conception/cosmétique. Vous pouvez utiliser cette réinitialisation pour n’importe quel projet, quelle que soit l’esthétique que vous recherchez.
Dans ce didacticiel, nous allons faire le tour de ma réinitialisation CSS personnalisée. Nous allons creuser dans chaque règle, et vous apprendrez ce qu’elle fait et pourquoi vous voudrez peut-être l’utiliser !
Sans plus tarder, voilà:
It’s relatively short, but there’s a lot of stuff packed into this small stylesheet. Let’s get into it!
Pop quiz! Measuring by the visible pink border, how wide is the .box
element in the following scenario, assuming no other CSS has been applied?
Our .box
element has width: 100%
. Because its parent is 200px wide, that 100% will resolve to 200px.
But where does it apply that 200px width? By default, it will apply that size to the content box.
If you’re not familiar, the “content box” is the rectangle in the box model that actually holds the content, inside the border and the padding:
The width: 100%
declaration will set the .box
‘s content-box to 200px. The padding will add an extra 40px (20px on each side). The border adds a final 4px (2px on each side). When we do the math, the visible pink rectangle will be 244px wide.
When we try and cram a 244px box into a 200px-wide parent, it overflows:
Code Playground
Résultat
Actualiser le volet des résultats
Bizarre ce comportement, non ? Heureusement, nous pouvons le changer, en fixant la règle suivante :
With this rule applied, percentages will resolve based on the border-box. In the example above, our pink box would be 200px, and the inner content-box would shrink down to 156px (200px – 40px – 4px).
This is a must-have rule, in my opinion. It makes CSS significantly nicer to work with.
We apply it to all elements and pseudo-elements using the wildcard selector (*
). Contrary to popular belief, this is not bad for performance.
Browsers make common-sense assumptions around margin. For example, an h1
will include more margin by default than a paragraph.
These assumptions are reasonable within the context of a word-processing document, but they might not be accurate for a modern web application.
Margin is a tricky devil, and more often than not, I find myself wishing elements didn’t have any by default. So I’ve decided to remove it all. 🔥
If/when I do want to add some margin to specific tags, I can do so in my custom project styles. The wildcard selector (*
) has extremely low specificity, so it’ll be easy to override this rule.
Have you ever tried to use a percentage-based height in CSS, only to discover that it seems to have no effect?
Here’s an example:
Code Playground
Résultat
Actualiser le volet des résultats
Le main
l’élément a height: 100%
mais l’élément ne grandit pas du tout !
Cela ne fonctionne pas car dans la mise en page Flow (le mode de mise en page principal en CSS), height
et width
fonctionnent selon des principes fondamentalement différents. La largeur d’un élément est calculée en fonction de son parent, mais la hauteur d’un élément est calculé en fonction de son enfants.
C’est un sujet compliqué, et c’est bien au-delà de la portée de cet article. Je prévois d’écrire un article de blog à ce sujet, mais en attendant, vous pouvez tout apprendre à ce sujet dans mon cours CSS, CSS pour les développeurs JavaScript.
En guise de démonstration rapide, nous voyons ici que notre main
element peut croître lorsque nous appliquons cette règle :
Aire de jeux codée
Résultat
Actualiser le volet des résultats
Si vous utilisez un framework JS comme React, vous pouvez également ajouter un troisième sélecteur à cette règle : l’élément de niveau racine utilisé par le framework.
Par exemple, dans mes projets Next.js, je mets à jour la règle comme suit :
line-height
controls the vertical spacing between each line of text in a paragraph. The default value varies between browsers, but it tends to be around 1.2.
This unitless number is a ratio based on the font size. It functions just like the em
unit. With a line-height
of 1.2, each line will be 20% larger than the element’s font size.
Here’s the problem: for those who are dyslexic, these lines are packed too closely together, making it harder to read. The WCAG criteria states that line-height should be at least 1.5.
Now, this number does tend to produce quite-large lines on headings and other elements with large type:
Code Playground
Résultat
Actualiser le volet des résultats
Vous souhaiterez peut-être remplacer cette valeur sur les en-têtes. Je crois comprendre que les critères WCAG sont destinés au “corps” du texte, pas aux en-têtes.
Alright, so this one is a bit controversial.
On MacOS computers, the browser will use “subpixel antialiasing” by default. This is a technique that aims to make text easier to read, by leveraging the R/G/B lights within each pixel.
In the past, this was seen as an accessibility win, because it improved text contrast. You may have read a popular blog post, Stop “Fixing” Font Smoothing, that advocates against switching to “antialiased”.
Here’s the problem: that article was written in 2012, before the era of high-DPI “retina” displays. Today’s pixels are much smaller, invisible to the naked eye.
The physical arrangement of pixel LEDs has changed as well. If you look at a modern monitor under a microscope, you won’t see an orderly grid of R/G/B lines anymore.
In MacOS Mojave, released in 2018, Apple disabled subpixel antialiasing across the operating system. I’m guessing they realized that it was doing more harm than good on modern hardware.
Confusingly, MacOS browsers like Chrome and Safari still use subpixel antialiasing by default. We need to explicitly turn it off, by setting -webkit-font-smoothing
to antialiased
.
Here’s the difference:
Antialiasing
Subpixel Antialiasing
MacOS est le seul système d’exploitation à utiliser l’anticrénelage des sous-pixels, et cette règle n’a donc aucun effet sur Windows, Linux ou les appareils mobiles. Si vous êtes sur un ordinateur MacOS, vous pouvez expérimenter un rendu en direct :
Aire de jeux codée
Résultat
Actualiser le volet des résultats
So here’s a weird thing: images are considered “inline” elements. This implies that they should be used in the middle of paragraphs, like <em>
or <strong>
.
This doesn’t jive with how I use images most of the time. Typically, I treat images the same way I treat paragraphs or headers or sidebars; they’re layout elements.
If we try to use an inline element in our layout, though, weird things happen. If you’ve ever had a mysterious 4px gap that wasn’t margin or padding or border, it was probably the “inline magic space” that browsers add with line-height
.
By setting display: block
on all images by default, we sidestep a whole category of funky issues.
I also set max-width: 100%
. This is done to keep large images from overflowing, if they’re placed in a container that isn’t wide enough to contain them.
Most block-level elements will automatically grow/shrink to fit their parent, but media elements like <img>
are special: they’re known as replaced elements, and they don’t follow the same rules.
If an image has a “native” size of 800×600, the <img>
element will also be 800px wide, even if we plop it into a 500px-wide parent.
This rule will prevent that image from growing beyond its container, which feels like much more sensible default behavior to me.
Here’s another weird thing: by default, buttons and inputs don’t inherit typographical styles from their parents. Instead, they have their own weird styles.
For example, <textarea>
will use the system-default monospace font. Text inputs will use the system-default sans-serif font. And both will choose a microscopically-small font size (13.333px in Chrome).
As you might imagine, it’s very hard to read 13px text on a mobile device. When we focus an input with a small font size, the browser will automatically zoom in, so that the text is easier to read.
Unfortunately, this is not a good experience:
If we want to avoid this auto-zoom behavior, the inputs need to have a font-size of at least 1rem / 16px. Here’s one way to address the issue:
This fixes the auto-zoom issue, but it’s a band-aid. Let’s address the root cause instead: form inputs shouldn’t have their own typographical styles!
font
is a rarely-used shorthand that sets a bunch of font-related properties, like font-size
, font-weight
, and font-family
. By setting it to inherit
, we instruct these elements to match the typography in their surrounding environment.
As long as we don’t choose an obnoxiously small font size for our body text, this solves all of our issues at once. 🎉
In CSS, text will automatically line-wrap if there isn’t enough space to fit all of the characters on a single line.
By default, the algorithm will look for “soft wrap” opportunities; these are the characters that the algorithm can split on. In English, the only soft wrap opportunities are whitespace and hyphens, but this varies from language to language.
If a line doesn’t have any soft wrap opportunities, and it doesn’t fit, it will cause the text to overflow:
Code Playground
Résultat
Actualiser le volet des résultats
Cela peut causer des problèmes de mise en page ennuyeux. Ici, il ajoute une barre de défilement horizontale. Dans d’autres situations, le texte peut chevaucher d’autres éléments ou se glisser derrière une image/vidéo.
Le overflow-wrap
La propriété nous permet de modifier l’algorithme de retour à la ligne et de lui donner la permission d’utiliser des retours à la ligne durs lorsqu’aucune opportunité de retour à la ligne n’est trouvée :
Aire de jeux codée
Résultat
Actualiser le volet des résultats
Aucune des deux solutions n’est parfaite, mais au moins l’emballage rigide ne gâchera pas la mise en page !
Merci à Sophie Alpert pour proposer une règle similaire! Elle suggère de l’appliquer à tous éléments, ce qui est probablement une bonne idée, mais pas quelque chose que j’ai personnellement testé.
Vous pouvez également essayer d’ajouter le hyphens
propriété:
hyphens: auto
utilise des traits d’union (dans les langues qui les prennent en charge) pour indiquer les retours à la ligne. Cela rend également les enveloppements durs beaucoup plus courants.
Cela peut être utile si vous avez des colonnes de texte très étroites, mais cela peut aussi être un peu distrayant. J’ai choisi de ne pas l’inclure dans la réinitialisation, mais cela vaut la peine d’expérimenter !
Lien vers cette rubrique
9. Contexte d’empilement racine
Ce dernier est facultatif. Il n’est généralement nécessaire que si vous utilisez un framework JS comme React.
Comme nous l’avons vu dans “What The Heck, z-index ??”, le isolation
propriété nous permet de créer un nouveau contexte d’empilement sans avoir besoin de définir un z-index
.
Ceci est bénéfique car cela nous permet de garantir que certains éléments hautement prioritaires (modaux, listes déroulantes, info-bulles) apparaîtront toujours au-dessus des autres éléments de notre application. Pas de bogues de contexte d’empilement bizarres, pas de course aux armements z-index.
Vous devez ajuster le sélecteur pour qu’il corresponde à votre cadre. Nous voulons sélectionner l’élément de niveau supérieur dans lequel votre application est rendue. Par exemple, create-react-app utilise un <div id="root">
donc le bon sélecteur est #root
.
Voici à nouveau la réinitialisation CSS, dans un format condensé compatible avec la copie :
N’hésitez pas à copier/coller ceci dans vos propres projets ! Il est publié sans aucune restriction, dans le domaine public (mais si vous vouliez garder le lien vers ce billet de blog, j’apprécierais !).
J’ai choisi de ne pas publier cette réinitialisation CSS en tant que package NPM car j’ai l’impression que vous devriez posséder votre réinitialisation. Intégrez cela dans votre projet et modifiez-le au fil du temps au fur et à mesure que vous apprenez de nouvelles choses ou découvrez de nouvelles astuces. Vous pouvez toujours créer votre propre package NPM pour faciliter la réutilisation dans vos projets, si vous le souhaitez. Gardez simplement à l’esprit : vous possédez ce code, et il devrait grandir avec vous.
Merci à Andy Bell d’avoir partagé son Modern CSS Reset. Cela m’a aidé à affiner une partie de ma réflexion et a inspiré cet article de blog !
Ma réinitialisation CSS est assez courte (seulement 11 déclarations !), et pourtant j’ai réussi à passer un article de blog entier à en parler. Et honnêtement, il y a tellement plus Je veux dire! Nous n’avons fait qu’effleurer la surface dans un tas d’endroits.
CSS est un langage trompeusement complexe. Sauf si vous ouvrez le capot et apprenez ce qui est vraiment passe là-dessous, la langue se sentira toujours un peu imprévisible et incohérente. Lorsque votre modèle mental est incomplet, vous êtes obligé de rencontrer des problèmes.
Si vous prenez un peu de temps pour apprendre comment la langue vraiment fonctionne, cependant, tout devient tellement plus intuitif et prévisible. J’adore écrire du CSS ces jours-ci !
Depuis un an et demi, je me concentre sur l’aide aux développeurs JS pour changer leur relation avec CSS. J’ai récemment lancé un cours en ligne complet et interactif appelé CSS pour les développeurs JavaScript.
Si vous souhaitez faire partie de ces personnes qui ont aimé/compris le CSS, j’ai créé ce cours spécialement pour vous ! Vous pouvez tout savoir sur la page d’accueil du cours :
https://css-for-js.dev
Dernière mise à jour
29 novembre 2022