La Cascade

Un peu de tout sur CSS, HTML, SVG et JS,traduit du web anglophone
Rechercher

Comment fonctionne calc()

par Ire Aderinokun, 12 janvier 2019, css, sass, typographie, article original paru le 31 janvier 2017 dans Bits of Code

La fonction calc( ) de CSS nous permet de calculer des valeurs de propriétés. Ire Aderinokun passe en revue son fonctionnement, son utilité et quelques cas pratiques.


La fonction calc() de CSS nous permet de calculer des valeurs de propriétés. Par exemple, au lieu de déclarer des valeurs fixes pour la largeur d'un élément, nous pouvons utiliser calc() pour spécifier que la largeur sera le résultat de l'addition de deux valeurs numériques (ou plus).

.foo {
    width: calc(100px + 50px);
}

Pourquoi calc( ) ?

Si vous avez déjà utilisé des préprocesseurs comme Sass, l'exemple qui précède vous est sans doute familier ( NdT : sinon, voir le guide de style Sass).

.foo {
    width: 100px + 50px;
}

// Ou en utilisant des variables Sass
$width-one: 100px;
$width-two: 50px;
.bar {
    width: $width-one + $width-two;
}

Toutefois, la fonction calc() est une meilleure solution, pour deux raisons.

D'abord parce qu'elle permet de mélanger des unités différentes. En particulier, nous pouvons utiliser des pourcentages et des unités de viewport avec des unités absolues telles que les pixels. Par exemple nous pouvons créer une expression qui va soutraire une valeur en pixels à une valeur en pourcentage.

.foo {
    width: calc(100% - 50px);
}

Dans cet exemple, l'élément foo aura toujours une largeur de 50px inférieure à 100% de son élément parent.

Ensuite parce qu'avec calc() la valeur calculée est l'expression elle-même et non la valeur résultant de l'expression. Je m'explique : lorsqu'on construit des expressions mathématiques avec les préprocesseurs, la valeur passée au navigateur est la valeur résultant de l'expression :

// Valeur spécifiée en SCSS
.foo {
    width: 100px + 50px;
}

// Le SCSS est compilé en CSS
// La valeur passée au navigateur :
.foo {
    width: 150px;
}

Avec calc() la valeur parsée par le navigateur est l'expression elle-même :

// Valeur spécifiée en CSS
.foo {
    width: calc(100% - 50px);
}

// Valeur calculée dans le navigateur
.foo {
    width: calc(100% - 50px);
}

Du coup les valeurs sont dynamiques et s'adaptent aux changements de viewport. Nous pouvons avoir un élément avec une hauteur de viewport moins une valeur absolue, il s'adaptera aux changements du viewport.

Utiliser calc( )

On peut utiliser la fonction calc() pour additionner, soustraire, multiplier ou diviser des valeurs numériques de propriétés : les data types <length>, <frequency>, <angle>, <time>, <number>, ou <integer>.

Voici quelques exemples :

.foo {
    width: calc(50vmax + 3rem);
    padding: calc(1vw + 1em);
    transform: rotate( calc(1turn + 28deg) );
    background: hsl(100, calc(3 * 20%), 40%);
    font-size: calc(50vw / 3);
}

Imbriquer les calc( )

On peut même imbriquer les fonctions calc(). Les fonctions entre parenthèses seront traitées comme de simples expressions. Si nous prenons par exemple :

.foo {
    width: calc( 100% / calc(100px * 2) );
}

la valeur calculée de cette fonction sera :

.foo {
    width: calc( 100% / (100px * 2) );
}

Compatibilité

La fonction calc() est largement supportée. Pour voir la compatibilité à la date de lecture de cet article, vous pouvez consulter — comme toujours — CanIUse.

Si un navigateur n'est pas compatible, toute l'expression propriété-valeur est ignorée. Par conséquent la solution de rechange (fallback) est simple à mettre en oeuvre, il suffit de fournir une valeur statique qui sera utilisée à la place.

.foo {
    width: 90%; /* Fallback pour les anciens navigateurs */
    width: calc(100% - 50px);
}

Quand utiliser calc( ) ?

On peut utiliser cette fonction dans diverses situations.

Exemple 1 - Centrer des éléments

calc() nous offre une solution de plus au problème classique du centrage horizontal et vertical des éléments à l'intérieur d'un conteneur. Si nous connaissons les dimensions de l'élément enfant, une solution typique est d'utiliser des marges négatives pour déplacer l'élément de la moitié de sa hauteur et de sa largeur :

// Avec un élément .foo ayant pour hauteur et pour largeur 300px
.foo {
    position: absolute
    top: 50%;
    left: 50%;
    marging-top: -150px;
    margin-left: -150px;
}

Avec la fonction calc() nous obtenons le même résultat en n'utilisant que les propriétés top et left.

.foo {
    position: absolute
    top: calc(50% - 150px);
    left: calc(50% - 150px);
}

De telles méthodes sont sans doute moins nécessaires maintenant que nous avons Flexbox, cependant dans des cas où Flexbox ne peut être utilisé, par exemple si l'élément doit avoir une position absolue ou fixe, cette méthode reste utile.

Exemple 2 - Créer une dimension de grille à partir de root

On peut utiliser la fonction calc() pour créer une grille basée sur le viewport avec l'unité rem. Pour cela, on définit dans l'élément racine (root) la font-size comme une fraction de la largeur du viewport.

html {
	font-size: calc(100vw / 30);
}

Maintenant 1 rem correspond à 1/30 de la largeur du viewport. Tous les textes dans notre page seront mis à l'échelle automatiquement en fonction du viewport et la même quantité de texte apparaîtra toujours à l'écran quelle que soit sa taille :

Si nous donnons à d'autres éléments non-textuels des dimensions en unités rem, ìls se comporteront de la même manière.

Exemple 3 - Clarté

Enfin, calc() peut s'avérer utile pour rendre les calculs plus évidents à comprendre. Si vous voulez qu'un groupe d'éléments aient pour dimension 1/6 de la largeur de leur conteneur parent, vous pourriez l'écrire ainsi :

.foo {
	width: 16.666666667%;
}

Mais pour les lecteurs de votre CSS, ce serait bien plus clair ainsi :

.foo {
	width: calc(100% / 6);
}

Ressources complémentaires en français

Autres ressources externes

Articles de Ire Aderinokun traduits dans La Cascade

Voir la page de Ire Aderinokun et la liste de ses articles dans La Cascade.
Article original paru le 31 janvier 2017 dans Bits of Code
Traduit avec l'aimable autorisation de Bits of Code et de Ire Aderinokun.
Copyright Bits of Code © 2017