Une justification s'impose

Fonction récursive et justification en JavaScript

Présentation

Aujourd’hui à l’agence VOUS, j’ai dû faire l’intégration d’une maquette web de la page d’attente du site pour un architecte, bodarchitecture.com. Rien de sorcier tu vas me dire… Ben non effectivement, mais le texte central, qui reprend les coordonnées de Mr Bodart, devait être parfaitement justifié, comme sur la maquette. Mais le truc c’est qu’on n’avait pas envie d’utiliser une grosse image pour que les coordonnées puissent être copiées et collées facilement.

Bon je ne vais pas t’expliquer les contraintes et les problèmes de la justification dans le web. Pour faire court, c’est super limité, je vais juste te donner une solution qui marche.

HTML

Au niveau de la structure HTML, je fais quelque chose de super simple, je définis un wrapper et dedans je place une image (le logo du client) et les trois paragraphes qui vont représenter les trois lignes de texte.
La première ligne n’a pas besoin d’être justifiée, j’ai ajouté une classe « person » et dedans deux span, l’un en float left et l’autre en float right, et également une classe « client » sur sur le nom et le prénom du client pour pouvoir ajouter un fond blanc.
Pour les deux dernières lignes, j’ai ajouté la classe « justifiy » pour le texte qui devra être justifié.

<div id="wrapper">
	<img src="img/logo-archi.png" alt="logo" />		
	<p class="person"><span class="client">BODART MICHAEL</span><span class="job">ARCHITECTE</span></p>
	<p class="adress justify">340, avenue de Longwy BT2</p> 
	<p class="adress justify">6700 ARLON <span class="separator">&nbsp;</span> Tél. 063 600 803</p>
</div>

Un peu de css

Pour construire ma feuille de style, j’ai utilisé du less.
Pour générer les séparateurs blancs entre les trois paragraphes, j’ai ajouté un border bottom sur le wrapper, et pour les autres j’ai à chaque fois ajouté un border top sur les paragraphes (en ciblant les classes).
Pour la première ligne, la classe client est float left et job est en float right, donc pas besoin de justification pour cette partie.
Pour la dernière ligne de texte j’ai ajouté également un span qui me sert de séparateur.

#wrapper{
	padding-top: 7.5rem;
	max-width: 14.275rem;
	width:100%;
	margin: 0 auto;
	border-bottom: 1px solid white;
	img{
		width: 100%;
		padding-bottom: 1.36rem;
	}
	p.person, p.adress{
		border-top: 1px solid white;
		line-height: 1.625rem;
		background: black;
		color: white;
		font-size:0.8125rem;
		&:after{
			content: " ";
			clear: both;
			display: block;
		}
		.client, .job{
			background: black;
			color: white;
			line-height: auto;
			float: left;
		}
		.job{
			float:right;
		}
		.client{
			background: white;
			color: black;
			padding: 0 0.4rem;
		}
		.separator{
			width: 1px;
			line-height: 1.625rem;
			background: white;
			display: inline-block;
		}
	}
}

JS et justification

Donc là, l’idée c’est de justifier le texte à l’aide de JavaScript en ajoutant dynamiquement du word-spacing. Et si je devais expliquer grossièrement comment ça marche et ben c’est ultra simple, je regarde quel est la hauteur d’un paragraphe, mettons 20 pixels. Je lance un script qui va ajouter un peu de word-spacing, les mots vont se décaler entre eux. Si jamais j’en ajoute trop, alors mon texte va passer sur deux lignes et la hauteur ne sera plus égale à 20 pixels, donc l’astuce c’est de créer une fonction récursive qui ajoute du word-spacing tant que la hauteur ne dépasse pas la hauteur d’origine.

Dans mon code j’ai ajouté deux variables, max_height qui correspond en fait à la hauteur maximale d’un paragraphe et step qui est la valeur d’ajout du word-spacing. Plus cette dernière est petite et plus le positionnement sera précis.

Pour chaque paragraphe ayant la class « justify » je lance la fonction adapte_spacing() qui prend en paramètre le paragraphe courant et l’espace à ajouter entre les mots. Ensuite la fonction ajoute du word-spacing suivant la valeur de spacing (par défaut 0.1), et juste après, je fais un petit test pour savoir si la hauteur a changé. Si oui, alors je relance la fonction en augmentant la valeur de spacing (je l’incrémente chaque fois avec step) et si jamais elle n’a pas changé, ben la ça veut dire que le word-spacing est trop grand, donc je l’ajuste en soustrayant la valeur de spacing (valeur de step) et j’obtiens pile poil la bonne valeur pour que le texte ne déborde pas.

En dessous, j’ai lancé un petit timer pour attendre le chargement de typo (oui je sais, c’est indigne de moi) et qui rebalance le calcul, car des typo différentes ne prennent pas la même place sur une ligne et donc ça pose problème. Idéalement, il faudrait détecter le chargement de typo avant de lancer la fonction.

jQuery(function($){
	var max_height  = $("p.justify:eq(0)").outerHeight();;
	var step	= 0.1;
	
	function adapte_spacing(p, spacing){
		p.css("word-spacing",spacing+"rem");
		if( parseInt(p.outerHeight()) > parseInt(max_height) || spacing > 2){
			p.css("word-spacing", (spacing-step) +"rem");
			return false;
		}else{
			adapte_spacing(p, spacing + step);
		}
	}
	
	$("p.justify").each(function(k,v){
		adapte_spacing($(v),step);
	});
	
	setTimeout(function(){
		$("p.justify").each(function(k,v){
			adapte_spacing($(v),step);
		});
	}, 1000);
});

05/09/2016

Yann Vangampelaere - nouslesdevs -

Sinon jete un coup d’oeil aux autres catégories

Ma boîte aux lettres

Tu veux me demander quelque chose ?