Utilisation de la fonction CSS clamp pour le calcul de tailles relatives | CDW

clamp(), la fonction CSS de calcul de valeur fluide

La fonction CSS clamp permet de calculer une valeur dynamique dite fluide, entre deux limites minimale et maximale, en fonction d’une 3e valeur relative choisie. Si au premier abord, la fonction clamp peut paraître assez intuitive, comprendre son fonctionnement en profondeur va nous permettre de l’utiliser dans un contexte ou le fluid design pour la création de sites internet vise à progressivement remplacer en partie nos traditionnels media queries.

Consultez la description de clamp sur le site MDN pour vous familiariser avec sa signature.

Syntaxe de la fonction clamp()

Clamp prend 3 arguments :

  1. La valeur minimale souhaitée
  2. La valeur relative calculée (valeur dynamique dite fluide)
  3. La valeur maximale à ne pas dépasser
font-size: clamp( min, fluidVal, max);

On notera que la valeur dynamique est calculée de façon relative à un élément donné. Ainsi, dans le cas d’un calcule de taille de police de caractères, on souhaitera modifier cette valeur en fonction de la taille de l’écran, soit, la largeur du viewport du navigateur (l’agent utilisateur).

Utilisation de la fonction clamp() pour la taille des polices

La fonction clamp autorise donc le calcule d’une valeur en fonction du viewport ou de la dimension d’un élément de référence. C’est notamment ce que nous faisons habituellement avec nos media queries traditionnelles lorsque nous définissons la taille de nos titres ou de nos paragraphes.

Nous fixons généralement une taille par défaut correspondant aux écrans de petite taille, puis nous redéfinissions ces valeurs en fonction d’un groupe de supports cibles :

@media only screen and (min-width: 768px) and (max-width: 1023px) {
	.my-section-title {
		font-size: 22px;
	}
}

Ici, nous avons définis une taille de police à 22 pixels pour un titre de section sur un iPad en mode portait, ainsi que pour toutes les tablettes allant jusqu’à 1023 pixels de large.  

Mais si les media queries permettent de définir assez finement les tailles de nos blocs de texte du smartphone à l’écran de bureau, elles ne pourront pour autant jamais couvrir l’ensemble des supports et des navigateurs du marché.

Le design « fluide » permet donc de répondre au besoin de couvrir la totalité des lecteurs sans nous soucier du ratio de pixel ou de la dimension de chaque écran du marché.

Calcul dynamique proportionnel à la taille de l’écran

Nous pouvons partir d’un exemple simple pour déterminer un facteur de taille relatif à la fenêtre d’un navigateur.

Si nous définissions la largeur maximale d’un conteneur central à 1200px, nous pouvons imaginer que nous souhaitons afficher le titre principal de notre page web défini à une taille maximale de 28px pour cet affichage.

Sur les smartphones les plus petits, nous souhaitons réduire cette taille à 20px.

Notre objectif sera donc de définir une taille de police pour notre titre, correspondant à 2.333333333333333% d’un viewport à 1200px, limitée à 20px pour la borne inférieure et 28px pour le maximum.

\[t = 28/1200X100 = 2.333333333333333\]

Nous pourrions définir une taille de police uniquement basée sur la taille de l’écran, mais nous ne contrôlerions ainsi ni sa taille minimale ni sa maximale, au risque de voir notre titre s’étendre à plus de 56px pixels sur un écran de 2560px, et réduit à 10 pixels illisibles sur les petits smartphones :

h1.titre-principal {
	font-size : 2.33vw;
} 

Nous pouvons donc utiliser la fonction clamp() suivante pour limiter (pincer) notre titre principal sur une échelle allant de 20 à 28px.

N.B. Nous garantissons une compatibilité avec les anciens navigateurs en définissant d’abord une valeur de repli (fallback) pour la taille notre titre :  

h1.titre-principal {
	font-size : 24px ;
	font-size : clamp(20px, 2.33vw, 28px) ;
}

La taille de notre police va ainsi évoluer de viewport en viewport entre les limites fixées :

ViewportValeur calculéeValeur appliquée
320px7.456px20px
768px17.8944px20px
1024px23.8592px23.8592px
1200px27.96px27.96px
1400px32.62px28px

Mais ce mode de calcul de valeur « fluide » nous pose deux problèmes majeurs :

  1. L’utilisation de valeurs absolues dans la fonction clamp() ne permet pas au résultat de s’adapter au zoom éventuel de l’utilisateur ;
  2. Elle ne permet pas non plus, en l’état, de maîtriser avec précision les points de rupture auxquels seront appliqués les tailles dynamiques, donc de remplacer notre système de media queries traditionnel par un système basé sur clamp().

Nous allons solutionner notre second problème en répondant au besoin du premier, dans le contexte d’un besoin exprimé sur des breakpoints habituellement utilisés avec les media queries.

Prise en compte du zoom utilisateur dans le calcul de valeur relative

Lorsque l’utilisateur modifie le zoom de son navigateur, il redéfinit la taille de police à la racine du document (root). Cette valeur est donc exprimée en rem (pour root em).

Cette valeur, initialement définit à 16px, pourra est décrite par 1rem.

Votre devis en 48 H chrono !

Demandez à être rappelé !

Nous préciserons ensemble votre projet
de vive voix 

Nous avons vu que nous pouvions définir notre taille de police comme fraction (un pourcentage) de la largeur de la fenêtre (ici le viewport x), exprimé en unité viewport-width « vw » :

\[t = v/100.x+r\]

La fonction clamp() présente en plus l’avantage d’accepter en arguments des opérations de calcul sur des opérandes d’unités différentes – un peu à la manière de la fonction CSS calc() :

.selecteur {
	width : calc( 100vw – 2em ) ;
}

Nous allons utiliser ce comportement pour baser cette fraction du viewport sur la taille relative fixée sur l’agent utilisateur (fixée en préférences ou par l’utilisateur lui-même).

Nous ajoutons donc à la fraction (v) du viewport (x), pour lequel nous souhaitons définir une valeur préférée, la taille relative du zoom du navigateur :

.mon-titre {
	font-size : clamp( minRem, v/100 . x + r, maxRem )
}

Toute la problématique réside donc dans la définition de la bonne fraction de viewport ainsi que de la bonne taille relative en rem, pour obtenir un calcul utilisable pour nos intégrations web.

Adaptation aux exigences de breakpoints

L’utilisation des media queries nous permettait de répondre à des exigences de design définis sur les points de rupture correspondant initialement aux grandes familles de supports (smartphones, tablettes, écrans de bureau, etc.).

Le calcul de la taille (t) de notre police peut donc s’écrire via cette simple fonction mathématique :

Nous pouvons donc nous projeter dans une situation dans laquelle notre taille de police minimale de 15px (t1) ne changerait qu’à partir de 600px (x1) pour parvenir à une taille de 18px (t2) dès que le viewport atteint 1200px (x2).

Cette projection nous donne ainsi 2 fonctions similaires :

Viewport 1 = 600px;
Taille = 15px;

\[t1 = v/100.x1+r\]

Viewport 2 = 1280px
Taille 2 = 18px

\[t2 = v/100.x2+r\]

Notre taille de police étant égale une fraction vw du viewport courant x + la taille relative de la police assignée à root r, notre objectif sera de pouvoir renseigner les valeurs vw et r de notre fonction clamp(), sur la base des valeurs de t et x, afin qu’elle retourne le résultat attendu aux deux points de rupture fixés (les breakpoints) :

\[t = clamp( minRem, vw . x + r, maxRem )\]

Ces deux constantes (t et x) étant connues pour chacune de nos fonctions, nous pouvons successivement redéfinir au sein de la première fonction, les 2 valeurs v et r, relativement à l’un et à l’autre, afin de les appliquer dans la seconde, et nous retrouver avec un calcul de valeurs v et r uniquement basé sur les constantes disponibles.

Nous commençons par définir une fonction de calcul de v à l’aide d’une valeur fonctionnelle de r :

\[t1 = v/100.x1 + r\] \[r = t1 – v/100.x1\]

Nous intégrons la valeur fonctionnelle de r dans notre 2e fonction

\[t2 = v/100.x2+r\] \[t2 = v/100.x2 + t1 – v/100.x1\] \[t2 = v/100.(x2-x1) + t1\] \[v/100 = (t2-t1) / (x2-x1)\]

Nous définissons maintenant une fonction de calcul de r à l’aide d’une valeur fonctionnelle de v :

\[t1 = v/100.x1+r\] \[v/100 = t1-r / x1\]

Nous intégrons la valeur fonctionnelle de v dans notre 2e fonction

\[t2 = v/100.x2 + r\] \[t2 = (t1-r/x1).x2 + r\] \[t2x1 = x2t1-rx2 + rx1\] \[t2x1 = x2t1-rx2 + rx1\] \[t2x1 = x2t1-r(x1 – x2)\] \[(t2x1 – x2t1) / (x1 – x2) = r\]

Nous nous retrouvons donc avec 2 fonctions nous permettant e calculer les paramètres v (pourcentage de viewport) et r (taille relative du navigateur en rem) à passer à clamp() afin que sont résultat corresponde aux valeurs t1 et t2, attendues sur les 2 viewports x1 et x2 :

\[v = 100(t2 -t1) / (x2 – x1)\] \[r = (t2x1 – t1x2) / (x1 – x2)\]

Nous pouvons maintenant revenir à contraintes de taille et de breakpoints pour notre design fluide :

\[v = 100(18 – 15) / (1280 – 600) = .441176470588235vw\] \[r = ( (600 X 18) – (15 X 600) ) / (600 – 1280) = 12.352941176470588px\]

Intégration de la feuille de style

Une pratique commune visant à simplifier la lisibilité de l’intégration de valeurs relatives rem, est de ramener la valeur par défaut à celle de 10px.

Ceci nous permettra de nous contenter de diviser par 10 nos valeurs en pixels pour les passer en unités relatives :

html {
	font-size: 62.5%;
}
.container p {
	font-size: clamp( 1.5rem, .441176470588235vw + 1.235294rem, 1.8rem );
}

Et voilà !

Désormais, et quelle que soit la taille du conteneur central, nos paragraphes présenteront une taille de police de 15px sur les viewports inférieurs ou égaux à 600px, une taille de police fluide allant de 15 à 18px pour les fenêtres de 600px à 1280px, et resteront à cette valeur pour les écrans de dimension supérieure.

Le recours à la fonction CSS clamp sera de plus en plus souvent répandue à mesure que se développeront les design, dits fluides. Si quelques CMS (tels que WordPress) commencent à généraliser son usage, seules la compréhension de son fonctionnement interne et quelques manipulations mathématiques permettront au développeur ou à l’intégrateur de maîtriser son rendu CSS dans les limites d’un design contraint.

Amusez-vous bien 😉  

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *