CSS Modernes

Les nouveautés qui changent la vie

1998

CSS 2

2007

CSS 2.1

2024

~600 propriétés en CSS

2012

CSS "living standard"

1999

CSS 3 🤯
(1ère propriété)

1996

CSS 1
(50 propriétés)

Google
Chrome 1

Internet
Explorer 6

Microsoft
Edge

Mozilla
Firefox 1

CSS != SCSS

CSS3 CSS2.1 CSS1 CSS Syntax Generated content Tables Paged media Paged Media Visual Effects Cascade Pseudo Classes Box Properties Text Properties Color + Background Font Properties Selectors L3 Grid Layout Media Queries Background + Borders Multi Column Basic UI Style Attributes Color L3 Ruby Flexible Layout Name spaces MathML Speech Syntax L3 Transforms Transitions Selectors Media Types Box Model Selectors L4 Generated Content Masking Web Animations W3C Recommendation Candidate Recommondation Last Call Working Draft Obsolete or inactive CSS3 Taxonomy & Status (September 2017)

source : Wikipedia

fondamentaux

variables

nesting

@supports

display: content

Variables CSS

Leur vrai nom : "Custom Properties"

:root {
  --color-text: hotpink;
  --spacing-md: 12px;
}

/* Button component */
.button {
  color: var(--color-text);
  padding: var(--spacing-md);
}

Ici nous déclarons les variables dans :root
(= tout le document) et les associons à une valeur.

Ces variables sont appliquées sur ce bouton à l'aide de var().

Les "variables" CSS (custom properties) sont des propriétés personnalisables, manipulables et réutilisables.

Variables CSS

Leur vrai nom : "Custom Properties"

UN cas d'usage classique ?

:root {
  --gap: 16px;
}

.card {
  display: grid;
  gap: var(--gap);
}
@media (min-width: 576px) {
  .card {
    --gap: 32px; 
  }
}

modifier des gouttières dynamiquement

Variables CSS

Leur vrai nom : "Custom Properties"

Variables all the things !

:root {
  /* Transitions et animations */
  --transition-duration: 250ms;

  /* Niveaux de z-index */
  --z-under-page-level: -1;
  --z-above-page-level: 1;
  --z-header-level: 1000;
  --z-above-header-level: 2000;
  --z-above-all-level: 3000;

  /* Espacements */
  --spacing-0: 0;
  --spacing-1: 1px;
  --spacing-2: 0.125rem;
  --spacing-4: 0.25rem;
  --spacing-8: 0.5rem;
  --spacing-12: 0.75rem;
  --spacing-16: 1rem;
  --spacing-20: 1.25rem;
  --spacing-24: 1.5rem;
  --spacing-32: 2rem;
  --spacing-40: 2.5rem;
  --spacing-48: 3rem;
  --spacing-64: 4rem;
  --spacing-80: 5rem;

  /* Familles de police */
  --font-base:  system-ui, sans-serif;
  --font-mono:  ui-monospace, monospace;

  /* Graisses de police */
  --font-weight-light: 300;
  --font-weight-regular: 400;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --font-weight-extrabold: 800;
  --font-weight-black: 900;

  /* Tailles de police */
  --text-14: 0.875rem;
  --text-16: 1rem;
  --text-18: 1.125rem;
  --text-20: 1.25rem;
  --text-24: 1.5rem;
  --text-28: 1.75rem;
  --text-32: 2rem;
  --text-36: 2.25rem;
  --text-40: 2.5rem;
  --text-48: 3rem;
  --text-64: 4rem;
  --text-80: 5rem;

  /* Interlignage (line-height) */
  --line-height-20: 1.25rem;
  --line-height-24: 1.5rem;
  --line-height-28: 1.75rem;
  --line-height-32: 2rem;
  --line-height-36: 2.25rem;
  --line-height-40: 2.5rem;
  --line-height-48: 3rem;
  --line-height-56: 3.5rem;
  --line-height-80: 5rem;
  --line-height-100: 6.25rem;

  /* Border radius */
  --radius-none: 0;
  --radius-4: 0.25rem;
  --radius-8: 0.5rem;
  --radius-12: 0.75rem;
  --radius-16: 1rem;
  --radius-24: 1.5rem;
  --radius-full: 9999px;

  /* Couleurs (globales) */
  --color-white: oklch(1 0 0);
  --color-black: oklch(0 0 0);
  --color-gray-50: oklch(0.97 0 0);
  --color-gray-100: oklch(0.922 0 0);
  --color-gray-200: oklch(0.87 0 0);
  --color-gray-300: oklch(0.708 0 0);
  --color-gray-400: oklch(0.556 0 0);
  --color-gray-500: oklch(0.439 0 0);
  --color-gray-600: oklch(0.371 0 0);
  --color-gray-700: oklch(0.269 0 0);
  --color-gray-800: oklch(0.205 0 0);
  --color-gray-900: oklch(0.145 0 0);
  --color-error-100: oklch(0.97 0.1 27.52);
  --color-error-300: oklch(0.7054 0.19 27.52);
  --color-error-500: oklch(0.5054 0.19 27.52);
  --color-error-700: oklch(0.3554 0.19 27.52);
  --color-error-900: oklch(0.2054 0.11 27.52);
  --color-success-100: oklch(0.9446 0.13 150.685);
  --color-success-300: oklch(0.7166 0.13 150.73);
  --color-success-500: oklch(0.5166 0.13 150.73);
  --color-success-700: oklch(0.3666 0.13 150.73);
  --color-success-900: oklch(0.2166 0.13 150.73);
  --color-warning-100: oklch(0.97 0.08 49.95);
  --color-warning-300: oklch(0.8315 0.17 49.95);
  --color-warning-500: oklch(0.6315 0.17 49.95);
  --color-warning-700: oklch(0.4815 0.17 49.95);
  --color-warning-900: oklch(0.3315 0.11 49.95);
  --color-info-100: oklch(0.97 0.09 256.37);
  --color-info-300: oklch(0.7133 0.18 256.37);
  --color-info-500: oklch(0.5133 0.18 256.37);
  --color-info-700: oklch(0.3633 0.18 256.37);
  --color-info-900: oklch(0.2133 0.11 256.37);
}

Toutes les valeurs de nos CSS se réfèrent à des variables. (Presque) aucune valeur "en dur".

La syntaxe "classique" de CSS engendre fréquemment des répétitions de sélecteurs qui compliquent la maintenabilité du projet dans la durée.

nesting

Imbrication de sélecteurs CSS

.link {
  display: flex;
  flex-wrap: wrap;
}

.link:hover, .link:focus {
  color: hotpink;
}

@media (min-width: 576px) {
  .link {
    flex-direction: column;
  }
}

.link > * {
  margin-left: 1rem;
}

sans nesting

La syntaxe imbriquée (nesting) rassemble les règles CSS dans un seul sélecteur et évite un grand nombre de répétitions inutiles.

.link {
  display: flex;
  flex-wrap: wrap;
}

.link:hover, .link:focus {
  color: hotpink;
}

@media (min-width: 576px) {
  .link {
    flex-direction: column;
  }
}

.link > * {
  margin-left: 1rem;
}

nesting

Imbrication de sélecteurs CSS

sans nesting

.link {
  display: flex;
  flex-wrap: wrap;
  
  &:hover, &:focus {
    color: hotpink;
  }
  
  @media (min-width: 576px) {
    flex-direction: column;
  }
  
  & > * {
    margin-left: 1rem;
  }
}

avec nesting

Attention au nombre d'imbrications !

@supports

Détection du support navigateur

La règle @supports() s'assure du support navigateur pour une propriété donnée et n'applique les styles que si la condition est respectée.

Si backdrop-filter n'est pas reconnu par le navigateur, la couleur de texte reste noire.

.title {
  color: #000; /* je suis noir par défaut */
}
@supports (backdrop-filter: initial) {
  .title {
    backdrop-filter: blur(10px) brightness(60%);
    color: #fff;
  }
}

display: contents

Effacement d'une boîte en CSS

Un élément en display: contents ne génère plus de boîte. Ses enfants héritent directement des propriétés de son parent, un peu comme si on faisait "sauter un étage" en CSS.

.col-6 {
  display: contents;
}

hop, je ne suis plus là !
(uniquement en CSS)

.row {
  display: flex;
}
/* ou bien */
.row {
  display: grid;
}

marche pô

.row {
  display: flex;
}
/* ou bien */
.row {
  display: grid;
}
<div class="row">
  <div class="col-6">
    <div>1</div>
    <div>2</div>
    <div>3</div>
  </div>
</div>

Je veux appliquer Flexbox ou Grid sur "row" et avoir une action sur les div 1, 2 et 3...
(toute ressemblance avec Bootstrap n'est pas fortuite)

responsive webdesign

media query range

clamp()

grid layout

container query

Media queries range

La nouvelle syntaxe intuitive

La syntaxe moderne (range) des Media Queries est bien plus intuitive que la syntaxe historique

.card {
  display: flex;
  flex-direction: column;
  
  @media (width >= 576px) {
    flex-direction: row;
  }
}

et en plus on peut l'imbriquer (nesting) !

@media (width >= 576px) {
  ...
}
@media (width <= 768px) {
  ...
}
@media (320px <= width <= 768px) {
  ...
}

#new

@media (min-width: 576px) {
  ...
}
@media (max-width: 768px) {
  ...
}
@media (min-width: 320px) and (max-width: 768px) {
  ...
}

#old

clamp()

Valeur fluide entre une borne inférieure et supérieure

clamp() accepte 3 valeurs : une valeur minimale, la valeur souhaitée et une valeur maximale.

version Media Queries

h1 {
  font-size: 2rem;
  
  @media (width >= 480px) {
    font-size: 3rem;
  }
  
  @media (width >= 768px) {
    font-size: 4rem;
  }
  
  @media (width >= 1280px) {
    font-size: 5rem;
  }
}
:root {
  --spacing-m: 1rem;
  
  @media (width >= 480px) {
    --spacing-m: 1.5rem;
  }

  @media (width >= 768px) {
    --spacing-m: 2rem;
  }

  @media (width >= 1280px) {
    --spacing-m: 3rem;
  }
}
h1 {
  font-size: clamp(2rem, 0.8261rem + 5.2174vw, 5rem);
}
:root {
  --spacing-m: clamp(1rem, 0.2174rem + 3.4783vw, 3rem);
}

version clamp

Grid Layout

Le positionnement moderne en CSS

.container {
  display: grid;
  gap: 10px;
  
  @media (width > 576px) {
    grid-template-columns: 200px 1fr;
    
    & header,
    & footer {
      grid-column: span 2; 
    }
  }
}

affichage sur écran réduit :
une seule colonne

affichage sur écran plus large : deux colonnes

Grid Layout est le modèle de positionnement responsive en CSS par excellence. Tout est y réalisable : placement, fluidité, alignements, etc.

<div class="container">
  <header>header</header>
  <nav>nav</nav>
  <article>article</article>
  <footer>footer</footer>
</div>

Grid Layout

Le positionnement moderne en CSS

Centrer verticalement et horizontalement avec Grid Layout ? 

Trop facile !

propriété raccourcie de justify-content et align-content

.container {
  display: grid;
  place-content: center;
}
<div class="container">
  <h1 class="title"></h1>
</div>

Container Queries

Styles conditionnés par la taille d'un conteneur

Les Container Queries permettent d'interroger la taille d'un conteneur ancêtre et d'adapter conditionnellement des styles CSS sur un élement descendant.

.card-container {
  container-type: inline-size;
}

@container (inline-size >= 400px) {
  .card {
    /* styles à appliquer */
  }
}

Je fais une requête sur la largeur (inline-size)
de .card-container

Si la condition de largeur est remplie, alors j'applique plein de jolis styles CSS

<div class="card-container">
  <article class="card">
    <img>
    <h2></h2>
    <p></p>
    <button></button>
  </article>
</div>

interactivité

scroll-snap

scroll-snap

Technique de scroll avec des points d'accroche

Scroll-snap crée des positions d'accroche lors du défilement,  permettant de garantir la position sur laquelle on arrive après avoir fait défiler du contenu.

.card-group {
  overflow-x: auto; 
  scroll-snap-type: x mandatory;
}
.card {
  scroll-snap-align: center;
}

adhérence des enfants sur l'axe x

alignement de chaque card sur la "grille"
(ici, elle sera centrée)

Exercices !

Responsive

Disclaimer : ces exercices contiennent peut-être des consignes non vues en formation

(en clair, faut vous débrouiller un peu)

badge

scroll