CSS

La fonction calc() en CSS

Article par (Intégrateur du Dimanche, Strasbourg)
Créé le , mis à jour le (89525 lectures)
Tags : opérations, unités, calculs, calc

calc() est une fonction CSS3 offrant la possibilité de réaliser des opérations mathématiques en CSS (addition, soustraction, division et multiplication).

Compatibilité

La compatibilité de cette fonction est encore un peu limitée aux navigateurs récents. Les gros écueils étant les versions Internet Explorer antérieures à IE9, et les anciens Android (avant 4.4).

Navigateurs Versions Détails
Internet Explorer Internet Explorer 9+  
Firefox Firefox 4+
Firefox Mobile
préfixe -moz- jusqu'à Firefox 15
Chrome Chrome 19+
Chrome Mobile
préfixe -webkit- jusqu'à Chrome 25
Opera Opera 15+
Opera Mobile 21+
 
Safari

Safari 6+
Safari Mobile 6+

préfixe -webkit- jusqu'à Safari 6.1
Android Browser Android Browser 4.4+  

Et ma calculatrice ? Mon Préprocesseur ?

Le navigateur peint la page, connaît l'interaction entre les éléments, calcule et interprête toutes les valeurs au sein de leur contexte, qu'il s'agisse de pixels, de pourcentages, de em, rem, pt, etc. Concrètement, seul un navigateur est capable de savoir ce que donne l'expression "100px + 2em". Aucune machine à calculer ni aucun préprocesseur ne peut exécuter ce calcul en amont avant que la page ne soit lue par le navigateur, car ils ne connaissent pas le contexte de rendu.

Bref, avec calc(), on laisse faire le navigateur faire son boulot, et c'est tant mieux.

Petit exemple pratique

Prenons une boîte à qui l'on a eu le malheur d'appliquer un width: 100% :

div {
    width: 100%;
    padding: 10px;
}

Bien sûr, la boîte déborde à présent de son parent puisque sa taille réelle n'est pas de 100%, mais de 100% + 20px (la valeur du padding s'ajoute).

Fort heureusement, box-sizing est là pour nous sauver, mais sachez qu'il est également possible de procéder différemment, grâce à l'emploi de calc() :

div {
    width: calc(100% - 20px);
    padding: 10px;
}

Note : attention, l'espace est nécessaire autour du signe d'opération, sans quoi calc() n'aura pas d'effet.

Autres exemples

calc() permet bien évidemment de réaliser des opérations simples et des mélanges d'unités, mais d'autres calculs plus complexes sont envisageables également : ainsi il est par exemple possible d'imbriquer des fonctions calc() au sein des fonctions calc(), et même d'utiliser la fonction attr() pour récupérer la valeur d'un attribut HTML et s'en servir dans des calculs.

Calculs simples

Opérations simples concernant les longueurs et tailles :

.content {
  width: calc(100% / 3); 
}

Voir le résultat :

See the Pen calc(100% / 3) by Alsacreations (@alsacreations) on CodePen.

Ou encore :

.content {
  border-width: calc(10px - 1em); 
}

Positionnements

Toutes les opérations destinées à définir une position ou un décalage :

.content {
  background-position: calc(100% - 50px) calc(100% - 20px);
}

Ou encore :

.content {
  position: relative;
  top: calc(100px - 5rem);
}

Constructions de grilles et gouttières

Calculs savant pour établir les largeurs de colonnes en tenant compte des gouttières. Ici 5 colonnes espacées d'une gouttière de 1em :

.truc > div {
  width: calc((100% / 5) - (1em - 1em / 5));
  float: left;
}

Voir cet exemple en ligne

grille calc()

Associé à un préprocesseur (ici LESS) :

.grid (@number) {
    float: left;
    width: calc((100% - (@gutter*(@number - 1))) / @number);
}

Voir cet exemple en ligne

Combinaisons avec d'autres propriétés

Centrer verticalement une image :

img {
  top: calc(50% - attr(height) / 2);
}

À l'heure actuelle, cette combinaison n'est reconnue par aucun navigateur.

Combinaisons avec des variables CSS

Pour récupérer et exploiter la variable --small-value :

img {
  top: calc(var(--small-value) / 2);
}

À l'heure actuelle, cette combinaison n'est reconnue que par Firefox 30+.

Corrections de bugs de navigateurs

calc() permet également de pallier les déficiences navigateurs :

html {
  font-size: 62.5%;
  /* équivalent 10 pixels, sauf sous IE à partir de la version 9 (qui pense que la taille est de 9.93px) */
  font-size: calc(1em * 0.625);
  /* L'astuce pour corriger le calcul sous IE 9 à 11 */
}

Plus d'informations à propos de ce bug, sur le forum de Microsoft.

(merci @victorbritopro)

Application en responsive

Intégré à certains éléments ou attributs HTML :

sizes="(min-width: 36em) calc(.333 * (100vw - 12em)), 100vw"

Source et explications au sein d'un article sur SmashingMagazine. (et en version française sur La Cascade).

wolf

Comme ces divers exemples le montrent aisément, les possibilités d'usage de calc() sont extrêmement vastes. Dès lors que des nombres sont impliqués : les longueurs, les fréquences, les angles, les durées, les nombres et les entiers. En d'autres termes, vous pouvez l'utiliser partout sauf dans les chaines de caractères.

Alternatives ?

Pour les anciennes versions de navigateurs qui ne reconnaissent pas calc(), son support peut être détecté via Modernizr en JavaScript.

Voici l'extrait de code en question :

var el = document.createElement("div");
var isCalcSupported;

el.style.cssText = "width: calc(2em);"; //adapter pour inclure les préfixes nécessaires
isCalcSupported = !!el.style.length;

(merci @jacqueminv)

Grâce à cette détection, une alternative peut éventuellement être mise en place.

Cet article est inspiré d'un extrait du livre de Hugo Giraudel à paraître prochainement

Commentaires

thej8 a dit le

Très bon article, merci pour ces explications claires.

Par contre n'y a t'il pas une erreur dans le code js donné à la fin (variable non définit : el.style.length à remplacer par el.style.cssText ?).
Je me trompe surement mais en l'état je ne comprends pas le fonctionnement du code.

eXystenZ a dit le

Non, la fonction sert à détecter si l'utilisation de calc() fonctionne. Si ce n'est pas le cas, la troisième ligne ne sera pas prise en compte et la longueur de l'élément (el.style.length) sera égale à 0 et ce qui affectera la valeur "false" à isCalcSupported.

eviouchka a dit le

excellent article ( et très attendu ) ;) merci Raphaël
et merci @Victor BRITO pour les solutions de fallback !
Quelle belle propriété ce calc() !

thej8 a dit le

@eXystenZ merci pour tes explication et oui en y mettant 3 neurones sur le dossier le code devient tout de suite plus compréhensible.

amarine a dit le

Est il possible via cette méthode de l'adapter en grid css

Romulus a dit le

Merci pour cet article très intéressant mais maintenant, je vais devoir repasser sur le code CSS de tous mes projets... ;)

Toledano a dit le

Peut-on m'expliquer (néophyte), car je ne comprend rien du tout...
.truc est normalement une classe mais avant on a le code suivant:
.truc(@num: @number)
{
& > * {width: calc(~"(100% -" @gutter ~"* (" @num ~"- 1)) / " @num);}
& > :nth-child(@{num}n+1){clear: left; margin-left: 0}
}
.truc(@num: @number) sert à quoi?
& > * ... width:calc(... Est-ce que cela veut dire "Calcule la largeur (de quoi? class truc ?) sur la base des variables "gutter" et "num". Pourquoi & > * devant ???
Idem pour la deuxième ligne qui semble indiquer que le dernier? doit être "rétablit" ???

Est-ce quelqu'un pourrait m'expliquer tout ça en langage clair... Pour un "Papy".

Merci

Toledano a dit le

Si > est le sélecteur du Parent
& nested parent
* Tous

Si * alors > et & ne sont pas nécessaires ?
Où je n'ai encore rien compris...