Aller au contenu

CSS⚓︎

Scroller en douceur⚓︎

🐣 2022-08

smooth.css
1
2
3
4
5
/* Applying it to the html element will provide smooth scrolling to anchors
https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior */
html {
  scroll-behavior: smooth;
}

Prendre en compte les préférences utilisateur·ice pour lancer une animation⚓︎

🐣 2022-08

motion.css
/* Remove animations for folks who set their OS to reduce motion.
 1. Immediately jump any animation to the end point
 2. Remove transitions & fixed background attachment
 See: https://github.com/mozdevs/cssremedy/issues/11
*/
@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    animation-delay: -1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    background-attachment: initial !important;
    scroll-behavior: auto !important;
    transition-delay: 0s !important;
    transition-duration: 0s !important;
  }
}

Une autre option est de le faire directement en ne chargeant la CSS dédiée aux animations que si la préférence utilisateur·ice la rend acceptable :

motion-link.html
1
2
3
4
5
6
7
/* Another approach (no-motion-first approach)
   See: https://tatianamac.com/posts/prefers-reduced-motion/ */
<link
  rel="stylesheet"
  href="animations.css"
  media="(prefers-reduced-motion: no-preference)"
/>

Voir aussi ce qu’il est possible de faire en HTML et en JS.

Avoir un bon ratio pour les vidéos⚓︎

🐣 2022-08

Une façon documentée par ici pour afficher des incrustations vidéos dans un format convenable :

video-ratio.css
1
2
3
4
.video {
  aspect-ratio: 16 / 9;
  width: 100%;
}

Un reset minimaliste⚓︎

🐣 2022-08

Un reset très bien documentée par ici qui est relativement court :

reset.css
*, *::before, *::after {
  box-sizing: border-box;
}
* {
  margin: 0;
}
html, body {
  height: 100%;
}
body {
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}
input, button, textarea, select {
  font: inherit;
}
p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

J’ajoute souvent aussi ces quelques règles que j’estime être importantes pour avoir des styles par défaut cohérents :

reset-extras.css
summary {
  cursor: pointer;
}
[hidden] {
  display: none !important;
}
[disabled] {
  pointer-events:none;
  opacity: 0.3;
}

Il y a d’autres projets comme minireset.css qui existent.

Masquer du contenu⚓︎

🐣 2022-08

Il y a plusieurs façons de le faire mais je trouve que la meilleure explication vient de Kitty Giraudel à travers deux articles de 2020.

screen-readers-only.css
.sr-only {
  border: 0 !important;
  clip: rect(1px, 1px, 1px, 1px) !important;
  -webkit-clip-path: inset(50%) !important;
  clip-path: inset(50%) !important;
  height: 1px !important;
  overflow: hidden !important;
  margin: -1px !important;
  padding: 0 !important;
  position: absolute !important;
  width: 1px !important;
  white-space: nowrap !important;
}
.sr-only.sr-only--focusable:focus,
.sr-only.sr-only--focusable:active {
  clip: auto !important;
  -webkit-clip-path: auto !important;
  clip-path: auto !important;
  height: auto !important;
  overflow: visible !important;
  width: auto !important;
  white-space: normal !important;
}

C’est ensuite utilisable ainsi, par exemple pour un lien d’accès direct au contenu où l’on a besoin de conserver le focus :

<a href="#main" class="sr-only sr-only--focusable">Skip to content</a>

Changement de graisse⚓︎

🐣 2022-08

Lorsqu’on clic sur un élément pour le rendre gras (ou l’inverse), ça modifie l’espace réservé par le navigateur pour ce(s) terme(s). Parfois, cela peut engendrer des effets disgracieux (hover sur un lien, item actif d’un onglet, etc).

Une solution trouvée par ici est de charger le contenu en gras dans un ::before

reserve-bold-space.css
1
2
3
4
5
6
7
.reserve-bold-space::before {
  content: attr(data-text);
  font-weight: bold;
  display: block;
  block-size: 0;
  visibility: hidden;
}

On peut ensuite l’appeler ainsi dans le HTML :

1
2
3
<div class="reserve-bold-space" data-text="The tab label">
    The tab label
</div>

Notez bien qu’il faut que le contenu du data-text soit le même que le contenu affiché !

Augmenter la spécificité d’une classe⚓︎

🐣 2022-08

Si vous n’avez accès qu’à une classe et qu’il vous faut la spécificité d’un id par exemple, il est possible d’utiliser :not() avec un id ce qui va artificiellement passer ce sélecteur à une spécificité d’id même si celui-ci n’existe pas ! Merci Robert Koritnik.

bump-specificity.css
1
2
3
.app:not(#nonexisting) {
  /* whatever. */
}

Pour tester les spécificités en CSS : Specificity Calculator

🧑‍🔬 Cas d’usages de is() et has()⚓︎

🐣 2022-08

Support navigateur

Attention, si is() n’est pas trop mal supporté, has() n’est pas implémenté par de nombreux navigateurs à ce jour (22 août 2022). Je consigne les cas d’usage ici pour l’avenir mais ça n’est pas envisageable en production pour l’instant.

Il est possible de tester son existence avec @supports + selector() :

@supports (selector(:has(works))) {
  /* safe to use :has() */
}

Plein d’exemples qui viennent du blog de webkit.

Lorsque tu veux que les éléments qui suivent un titre soient proches de ce titre :

has-titles.css
1
2
3
:is(h1, h2, h3, h4, h5, h6):has(+ :is(p, figcaption, pre, dl, ul, ol)) {
  margin-bottom: 0;
}

Lorsque tu veux que ton formulaire t’indique un peu mieux où est l’erreur :

has-errors.css
1
2
3
fieldset:has(input:invalid) label {
  color: red;
}

Ici, j’applique un style au label mais ça pourrait être plus large bien entendu, ça ouvre de très nombreuses possibilités !

Lorsque tu veux changer des variables CSS en fonction d’un choix utilisateur·ice (par exemple un sélecteur de thème) :

has-choice.css
1
2
3
4
5
6
body:has(option[value='pony']:checked) {
  --font-family: cursive;
  --text-color: #b10267;
  --body-background: #ee458e;
  --main-background: #f4b6d2;
}

Ça ne fait qu’effleurer les possibilités mais ça promet .

Un article par Bramus Van Damme à ce sujet ainsi qu’un article sur le blog de Chrome qui donnent d’autres exemples.

Trouver les déclarations CSS non utilisées⚓︎

🐣 2022-10

Un petit script à copier-coller dans sa console pour afficher toutes les déclarations CSS qui ne sont pas utilisées dans la page en cours (inspiré de cet article, ce site est une mine).

unused-css.js
;(function () {
  let rulesCounter = 0
  Array.from(document.styleSheets).forEach((stylesheet) => {
    const rules = Array.from(stylesheet.cssRules || [])
    const sheethref = stylesheet.href || 'inline'
    rules.forEach((rule) => {
      if (
        !document.querySelectorAll(rule.selectorText).length &&
        rule.selectorText !== undefined
      ) {
        console.log(`${sheethref}: "${rule.selectorText}" not found.`)
        rulesCounter += 1
      }
    })
  })
  console.log(`${rulesCounter} CSS rules unused on that page.`)
})()

Info

Les CSS sont généralement utilisées pour plusieurs pages à la fois donc ça peut ne pas être très pertinent mais ça donne quand même une aperçu de ce qui pourrait être optimisé pour l’affichage de cette seule page !

Scroll et sticky header⚓︎

🐣 2022-11

La propriété scroll-margin-top permet de gérer la distance depuis le haut de la page et l’endroit jusqu’où scrolle la page lorsqu’il y a une ancre ciblée. C’est particulièrement intéressant dans un contexte de header sticky :

scroll-sticky-header.css
.topnav {
  top: 0;
  position: sticky;
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.topnav div {
  font-size: 1.2rem;
}

[id] {
  scroll-margin-top: calc(1.2rem + 2rem); /* (1)! */
}
  1. La taille du texte plus les deux paddings.

Une arborescence à base de ul et de details⚓︎

🐣 2022-11

Un article détaillé de Kate Rose Morley pour recréer une arborescence en CSS en combinant des ul/li et des details/summary, particulièrement malin !

tree-ul-details.css
.tree {
  --spacing: 1.5rem;
  --radius: 10px;
}

.tree li {
  display: block;
  position: relative;
  padding-left: calc(2 * var(--spacing) - var(--radius) - 2px);
}

.tree ul {
  margin-left: calc(var(--radius) - var(--spacing));
  padding-left: 0;
}

.tree ul li {
  border-left: 2px solid #ddd;
}

.tree ul li:last-child {
  border-color: transparent;
}

.tree ul li::before {
  content: '';
  display: block;
  position: absolute;
  top: calc(var(--spacing) / -2);
  left: -2px;
  width: calc(var(--spacing) + 2px);
  height: calc(var(--spacing) + 1px);
  border: solid #ddd;
  border-width: 0 0 2px 2px;
}

.tree summary {
  display: block;
  cursor: pointer;
}

.tree summary::marker,
.tree summary::-webkit-details-marker {
  display: none;
}

.tree summary:focus {
  outline: none;
}

.tree summary:focus-visible {
  outline: 1px dotted #000;
}

.tree li::after,
.tree summary::before {
  content: '';
  display: block;
  position: absolute;
  top: calc(var(--spacing) / 2 - var(--radius));
  left: calc(var(--spacing) - var(--radius) - 1px);
  width: calc(2 * var(--radius));
  height: calc(2 * var(--radius));
  border-radius: 50%;
  background: #ddd;
}

.tree summary::before {
  content: '+';
  z-index: 1;
  background: #696;
  color: #fff;
  line-height: calc(2 * var(--radius) - 2px);
  text-align: center;
}

.tree details[open] > summary::before {
  content: '−';
}

Par ici un exemple complet assez brut car c’est toujours chouette de jouer avec en direct :

Ouvrir dans un nouvel onglet

Exemples de CSS minimalistes / sans classe⚓︎

🐣 2022-10

Pour jouer⚓︎

🐣 2022-10


Dernière mise à jour: 2022-11-30