Informatique
Responsive design

Table des matières + X

Introduction

La possibilité d'enfin utiliser CSS à son plein potentiel (mise en forme de texte mais aussi et surtout positionnement) a conduit à un principe de design permettant de s'adapter à tous les écrans : l'elastic design. Cet article de A list apart de 2004 décrit bien le principe : Elastic Design · An A List Apart Article.

Avec la généralisation des smartphone et tablettes, la donne a brutalement changé, la diversité d'équipements pouvant utiliser les sites et applications devenant immense !

Grace aux Media Queries en CSS, un nouveau principe est apparu, dérivé de l'elastic design : le responsive design. L'idée est alors, suivant la dimension de l'écran, d'adapter le positionnement et même carrément l'affichage des éléments.

Un autre système de conception est apparu en 2011, proposé par Luke Wroblewski dans son livre "Mobile First". Comme son nom l'indique, l'idée est de concevoir d'abord à destination des mobiles, puis d'enrichir successivement. Les avantages de la méthode sont bien décrits dans la conclusion de l'ouvrage :

Starting with this personal and portable device in mind first allows us to:

Mais évidemment, aucune méthode n'est idéale : comme on l'image bien, la situation de base est que les utilisateurs auront des besoins et usages différents suivant le matériel qu'ils utilisent... en plus des "simples" contraintes techniques !
Je vous recommande la lecture de ce billet chez Alsacreations qui décrit bien les différentes solutions (site dédié, application, site commun) : C'est quoi le Responsive Web Design ?.

Sur la GepapiR, il n'y a que quelques pages de contenu, aussi la réponse s'est plutôt orientée vers une adaptation aux différentes résolutions ! Cet article décrit ce qui a été mis en place.


Balise meta viewport

Par défaut les navigateurs sur mobile vont initialiser un zoom afin d'afficher la page dans son entier, au plus près de ce que l'on aurait sur un écran plus grand. L'utilisateur est alors obligé d'utiliser massivement le zoom manuel...

Une balise meta viewport permet d'éviter ce comportement !.
Voir le document de recommandation du W3C : Mobile Web Application Best Practices - Use Meta Viewport Element To Identify Desired Screen Size
Ou cet article sur le très bon quirksmode.org : Meta viewport.

Sur la GepapiR j'utilise :

<meta name="viewport" content="width=device-width, initial-scale=1.0">

Unités CSS relatives

Les dimensions en CSS peuvent s'exprimer en différentes unités : voir la liste dans la recommandation !

Afin de s'adapter au paramétrage des navigateurs, les dimensions de texte et marges sont définies avec l'unité em. Cependant, utiliser cette unité poserait problème pour les marges horizontales : en effet celles-ci sont plus liées à la dimension du viewport (la zone qu'affiche le navigateur) que aux paramètres de police ! Aussi, ces marges là sont définies sur la GepapiR en utilisant l'unité %, et s'adaptent donc en fonction de la largeur disponible.
Exemples d'adaptation des marges horizontales dans les captures ci-dessous :

1024px
800px
360px

Un très bon article à lire sur les unités CSS et leurs effets : Font sizing with rem - Snook.ca.
Sur la GepapiR, je n'utilise pas l'unité rem car la structure des pages est simple et fait que les problèmes d'imbrication décrits dans l'article sont absents.


Menu de navigation

Trois différentes largeurs d'écran sont gérées pour le menu de navigation, via des media queries, comme montré ci-dessous. Pour chacun d'elle on adapte la position et la taille du texte autour des icones. La longueur variable du border-radius est gérée par une dimension en unité "%".

Par défaut
Si la largeur <= 760px

@media screen and (max-width: 760px)
{
	nav a:before
	{
	content: none;
	}

	nav a>span.menu_icon
	{
	display: block;
	margin: auto;
	}
}
Si la largeur <= 420px

@media screen and (max-width: 420px)
{
	nav ul
	{
	font-size: 0.7em;
	}
}

A noter : on utilise max-width (largeur du viewport) plutôt que max-device-width (largeur physique de l'écran) à dessein : ces modifications sont aussi intéressantes si l'on redimensionne la fenêtre d'un navigateur sur grand écran !
A ce sujet lire : Faut arrêter avec les Media Queries ! – HTeuMeuLeu


Séparateurs

On va simplement afficher une partie des séparateurs si le viewport est moins large que l'image :


@media screen and (max-width: 645px)
{
	hr.sep
	{
	width: 98%;
	}
}

Images larges

Plusieurs images sont assez larges et dépassent du viewport sur des écrans à taille réduite !

Une solution serait d'utiliser l'attribut HTML 5 srcset, mais le support est assez faible à ce jour (août 2014 : juste Chrome 34+ et Safari 8+ - lien CanIUse) et ça nécessiterai de créer de nouvelles images... Un avantage pour renvoyer des images plus légères, mais les images concernées sont peu nombreuses, relativement peu lourdes et bien cachées.

L'idée a donc été d'appliquer un width en % sur media query. Mais comme chaque image a une taille différente, la mise en place est compliquée : écriture d'un code quasi identique mais variant sur les dimensions de chaque image, et éparpillement entre la balise IMG et le code CSS qu'il faut penser à écrire et à éventuellement mettre à jour.

Pour y remédier j'ai écris un simple JavaScript chargé au démarrage, et qui va modifier des images marquées dans la page :

Les images à modifier sont identifiées par un attribut data-responsive-img.
Les attributs data-* sont un ajout de HTML 5. Pour en savoir plus :

Le script est lancé en onDomReady, en utilisant la librairie de tubalmartin.
Le code :


function writeCSSRespImg()
{
	var elements = document.getElementsByTagName("img"),
		image,
		width,
		height,
		cssClassName,
		cssClasses,
		cssCode,
		style,
		maxWidth;
	for (i = 0; i <= elements.length - 1; i++) {
		image = elements[i];
		if (image.hasAttribute("data-responsive-img")) {
			// Récup width / height
			width = parseInt(image.getAttribute("width"));
			height = parseInt(image.getAttribute("height"));

			// Ajoute classe
			cssClassName = "responsive-img-" + i;
			cssClasses = image.className;
			if (cssClasses != "") {
				cssClasses += " ";
			} else {
				cssClasses = "";
			}
			cssClasses += cssClassName;
			image.className = cssClasses;

			// Ecriture du CSS
			cssCode = "";
			style = document.createElement("style");
			maxWidth = width + 5;
			cssCode = "\nimg." + cssClassName + "\n\
{\n\
width: " + width + "px;\n\
height: " + height + "px;\n\
}\n\
@media screen and (max-device-width: " + maxWidth + "px)\n\
{\n\
	img." + cssClassName + "\n\
	{\n\
	width: 98%;\n\
	height: auto;\n\
	}\n\
}\n";
			style.appendChild(document.createTextNode(cssCode));
			document.head.appendChild(style);

			// Suppression des attributs du tag img
			image.removeAttribute("width");
			image.removeAttribute("height");
		}
	}
}



onDomReady(writeCSSRespImg);

Création le 13/08/2014
Dernière mise à jour le 14/09/2014

Un oubli, une erreur, une suggestion ? N'hésitez pas à me contacter sur pgoiffon -at- free.fr