Licence CC BY-NC-SA

TP : adapter un exemple au format mobile !

Vous savez déjà ce qu’il faut faire pour avoir un site web mobile. Maintenant, rien ne vous arrête si vous voulez adapter tout de suite votre site, mais j’aimerais à présent que vous vous exerciez avant de partir dans le vrai monde cruel. :p

Après ce TP, vous aurez vu en pratique comment on peut obtenir un site fait pour mobile. Au final, vous verrez que ce n’était pas si compliqué ! ;)

Instructions pour réaliser le TP

Si vous avez suivi le tutoriel de M@teo21 sur le html, vous vous rappelez sûrement du TP qui consistait à créer de toutes pièces son site. Et bien maintenant qu’il est "tout beau, tout propre, prêt à envahir le web", il faut penser aux utilisateurs de mobiles !

Les fichiers de départ

Comme vous êtes déjà censés avoir réalisé ce TP, je vous autorise (Que je suis gentil !) à télécharger directement les fichiers finaux :

De plus, vous pourrez peut-être avoir besoin d’une autre image, mais je n’en dis pas plus :

Votre objectif

Et bien, vous le connaissez déjà : faire en sorte qu’une page s’affiche correctement pour un mobile. De multiples difficultés vous attendent, toutes plus retorses les unes que les autres… Amusez-vous bien ! :pirate: (Notez qu’à l’heure où j’écris ces lignes, je n’ai pas encore fait le TP, donc je n’en ai aucune idée. ^^ )

Comment procéder ?

N’oubliez jamais, vous devez toujours procéder avec méthode. Prenez du papier et un crayon, reprenez l’allure du site que vous devez adapter, et posez-vous ces quelques questions (liste non exhaustive !) :

  • Ce bloc-là est trop large, comment je vais faire pour qu’il soit plus petit ?
  • Ici, deux blocs sont côtes à côtes, donc un des deux devra passer sous l’autre. Mais lequel ?
  • Ce "truc" est là uniquement pour faire joli. Est-ce que j’en ai encore besoin pour un mobile ?

99.9 % du temps que vous allez mettre pour réaliser ce TP va être du temps que vous allez passer sur du CSS. En effet, n’oubliez quand même pas la balise <meta name="viewport"/>, ce serait bête. :p Mais vous pouvez bien sûr faire de minimes changements dans le code HTML si c’est plus simple pour vous.

Et enfin, une bonne nouvelle : Le code HTML créé par M@teo21 est vraiment bien structuré, ce sera d’autant plus facile pour vous de l’adapter ! (Tous en chœur : "Merci M@teo21 !") Je peux vous dire que pour mon premier site, qui n’était pas très bien formé, j’ai eu un mal fou à l’adapter pour mobile. C’est dire si la conception HTML de départ est fondamentale !

À vous de jouer !

Il ne vous reste plus qu’à prendre du papier et un crayon, décider ce que vous allez faire (les fameuses questions à se poser !), et ensuite mettre ça en pratique avec du CSS !

Un dernier petit conseil : ne vous affolez surtout pas si quelque chose ne fonctionne pas du tout comme prévu ! Cela peut être une faute de frappe, une propriété donnée à une mauvaise balise, mais tout ça est heureusement facile à corriger. Utilisez les outils pour développeur de votre navigateur pour déterminer ce qui ne va pas, et surtout, prenez votre temps ! Vous n’allez pas forcément réussir du premier coup.

A bientôt pour la correction ! :D

Correction

Je ne vais pas vous donner tout un bloc de code dès le départ. Je vais essayer de vous guider dans cette correction, de sorte que ceux qui ne sont pas arrivés à réaliser ce TP puissent au moins comprendre la démarche à suivre.

Bien entendu, la méthode que je vous présente n’est qu’une solution parmi une infinité ! Si vous avez fait autrement, mais que votre design vous plaît, il n’y a aucune raison de considérer mon code comme meilleur.

Sur ce, place à la correction !

Bien commencer

Sans rien toucher au code de M@teo21, avec Safari Mobile, vous obtenez ce rendu :

Screenshot du site sans rien toucher Figure : Screenshot du site sans rien toucher

Maintenant, on rajoute la balise <meta> pour pouvoir, par la suite, utilisez les media queries :

<meta name="viewport" content="width=device-width, maximum-scale=1"/>

Vous pouvez utiliser l’option initial-scale=1 temporairement, afin d’avoir le bon zoom dès le départ.

Screenshot du site avec la balise meta Figure : Screenshot du site avec la balise meta

Certaines marges ont été rétrécies, et c’est tout ce que l’on peut observer. En fait, comme au chapitre précédent, dans le CSS, une largeur minimale est définie, ce qui empêche le navigateur d’avoir la largeur qu’il souhaite. Pour cela, on va tout simplement enlever la largeur fixe du site ainsi que des marges créées automatiquement par les navigateurs, et définir une largeur maximale et minimale :

body
{
    background: url('images/fond_jaune.png');
    font-family: 'Trebuchet MS', Arial, sans-serif;
    color: #181818;
    margin: 0;
}
#bloc_page
{
    max-width: 900px;
    margin: auto;
    min-width: 320px;
}

Notez que la ligne de départ est celle du fichier que je change en même temps que vous, et pas la ligne du fichier de départ. Cela va surtout changer par la suite.

Screenshot après les modifications Figure : Screenshot après les modifications

On peut remarquer plusieurs choses intéressantes. Tous les éléments qui ont une valeur fixe gardent cette valeur et empêchent de nouveau le navigateur d’avoir la largeur qu’il veut. Ici, on voit que le menu et le texte sont trop larges, et on va donc les réduire avec les media queries. Mais avant ça, on va se débrouiller pour que le "À propos de l’auteur" puisse être à droite de l’écran lorsqu’on redimensionne la fenêtre.

"À propos de l’auteur"

Pourquoi on s’occupe de ce bloc avant les autres ?

Parce que j’ai envie ! :p De toute façon, tout devra être fait, l’ordre n’a absolument pas d’importance dans notre cas.

Pour que cet élément se place à droite sans que l’on ne définisse de largeur fixe, on va appliquer quelques styles comme ceci :

article, aside
{
    /*display: inline-block;
    vertical-align: top;*/
    text-align: justify;
}

article
{
    /*width: 625px;*/
    margin-right: 275px;
}
aside
{
    position: absolute;
    top: 0;
    right: 0;
    /* ... */
}

/* Afin de positionner le <aside> par rapport à la <section> : */
section
{
    position: relative;
}

On obtient sur un écran d’ordinateur un design très proche de celui de départ et sur mobile on voit ceci :

Le bloc "A propos de l'auteur occupe toute la largeur, le paragraphe ne contient qu'un seul mot par ligne Figure : Le bloc "A propos de l’auteur occupe toute la largeur, le paragraphe ne contient qu’un seul mot par ligne

Or, comme vous vous en doutez, ce n’est pas vraiment ce que l’on veut. :p

On va donc positionner le <aside> au bas de la section à partir d’une certaine valeur avec une condition. Pour cela, on va "tatonner" pour savoir jusqu’à quelle valeur on veut encore le aside à droite. Pour ma part, j’ai choisi la valeur 700px :

@media (max-width: 700px){
    aside
    {
        top: 100%;
    }
    
    article
    {
        margin-right: 0;
        margin-bottom: 463px; 
        /* Pour laisser la place au bloc, sinon il se positionne SUR le pied de page
        Sachant que 463px est la hauteur du <aside>.
        Si vous voulez mettre des marges en plus, augmentez cette valeur */
    }
}

Tu as mis top: 100%;. Pourquoi on ne peut pas mettre bottom: 0; tout simplement ?

Ah, bonne question ! En fait, la propriété top positionne le haut de votre élément, tandis que bottom positionne le bas. Ainsi, en écrivant top: 100%;, on place le haut de notre élément à 100% de la hauteur de l’élément de référence (la section), c’est-à-dire en bas de cet élément de référence, mais si on avait mis bottom: 0;, le bas de notre élément serait au bas de la section et les deux éléments se chevaucheraient.

Ainsi, avec une largeur de 680px (j’ai redimensionné ma fenêtre), on obtient ceci :

Le bloc aside est en dessous du paragraphe, mais est aligné à droite et il manque des marges Figure : Le bloc aside est en dessous du paragraphe, mais est aligné à droite et il manque des marges

Afin de centrer notre aside, j’ai effectué ces modifications :

@media (max-width: 700px){
    aside
    {
        top:100%;
        left: 50%; /* On place la gauche de notre élément au mileu de la <section> */
        margin-left: -127.5px; /* Et on décale notre élément de la moitié de sa largeur vers la gauche */
    }
    
    article
    {
        margin-right: 0;
        margin-bottom: 470px;
        padding-bottom: 10px;
    }
}

Le bloc est maintenant centré et il y a des marges suffisantes Figure : Le bloc est maintenant centré et il y a des marges suffisantes

Il ne reste plus qu’à changer la flèche, et je vous l’ai retournée pour que vous n’ayez pas à le faire vous-même, rappelez-vous !

Le menu

On s’attaque maintenant au menu qui a une largeur fixe. On enlève donc la largeur fixe :

/* De plus, j'ai rajouté ceci : */
header
{
    position: relative; /* Même chose que tout à l'heure : 
    on veut positionner le <nav> par rapport au <header> */
}
nav
{
    /*display: inline-block;
    width: 740px;*/
    text-align: right;
    position: absolute;
    bottom: 0;
    right: 0;
}

En redimensionnant la fenêtre, on se rend compte qu’à partir d’environ 600 pixels, le menu est trop large pour tenir sur la même ligne que le titre principal.

Le menu étant aligné à droite, de taille fixe et horizontal, si on réduit trop la fenêtre, il chevauche le titre Figure : Le menu étant aligné à droite, de taille fixe et horizontal, si on réduit trop la fenêtre, il chevauche le titre

Comme il est en position absolue, il est sorti du flux, c’est-à-dire que l’élément n’est plus affiché à la suite des autres (Regardez le site sans le CSS : les éléments sont les uns en dessous des autres). Comme il n’a plus assez de place, il se mélange au titre principal. On va donc le remettre dans le flux :

@media (max-width: 600px){
    nav li
    {
        display: block;
        padding-bottom: 5px;
    }
    	
    nav
	{
        text-align: left;
        position: static; /* La valeur par défaut */
        padding-bottom: 5px;
    }
    
    nav ul 
	{
        margin-top: 0;
        padding-left: 10px;
    }
}

Le menu se place sous le titre et est une liste verticale Figure : Le menu se place sous le titre et est une liste verticale

La bannière

La bannière est assez difficile à adapter à un design extensible. Comme je vous l’ai expliqué au chapitre précédent, on a un problème avec la largeur : On veut une largeur de 100%, mais on veut également des marges intérieures. On va donc rajouter une balise, et vu qu’on a du texte à l’intérieur, on modifie la page comme ceci :

<div id="banniere_image">
    <div id="banniere_description">
        <p>
            Retour sur mes vacances aux États-Unis...
            <a href="#" class="bouton_rouge">Voir l'article <img src="images/flecheblanchedroite.png" alt="" /></a>
        </p>
    </div>
</div>

Etat des lieux concernant le texte et le bouton Figure : Etat des lieux concernant le texte et le bouton

Le texte est un peu trop collé au bas de la bannière, je vous propose d’appliquer ces styles pour améliorer le rendu :

#banniere_description
{
    position: absolute;
    bottom: 0;
    border-radius: 0px 0px 5px 5px;
    width: 100%;
    height: 40px; /* Une hauteur qui me paraît plus qu'acceptable */
    /*padding-top: 15px;
    padding-left: 4px;*/
    background-color: rgb(24,24,24); /* Pour les anciens navigateurs */
    background-color: rgba(24,24,24,0.8);
    color: white;
    font-size: 0.8em;
    
}

#banniere_description>p
{
    padding-left:4px;
}

Le texte continue sous le bouton Figure : Le texte continue sous le bouton

C’est un grand moment ! Maintenant, on a réussi à faire que tous les éléments aient au maximum une largeur de 320px.

Au lieu de positionner le bouton rouge à droite du paragraphe et de lui donner une marge négative, on va utiliser une méthode un peu différente. On commence par sortir le lien du paragraphe que l’on vient de créer.

<div id="banniere_image">
    <div id="banniere_description">
        <p>
            Retour sur mes vacances aux États-Unis...
        </p>
        <a href="#" class="bouton_rouge">Voir l'article <img src="images/flecheblanchedroite.png" alt="" /></a>
    </div>
</div>

Pour que le texte aille à la ligne avant d’arriver sous le bouton rouge, j’ai ajouté une marge interne :

#banniere_description>p
{
    padding-left: 4px;
    padding-right: 120px;
}

Le texte revient à la ligne avant le bouton Figure : Le texte revient à la ligne avant le bouton

La hauteur de notre #banniere_description est fixe, et le texte est trop collé au bas. J’ai donc remplacé la hauteur de 40 pixels par : min-height: 40px;.

Le bouton n'est maintenant plus aligné, il était positionné de manière fixe Figure : Le bouton n’est maintenant plus aligné, il était positionné de manière fixe

Il ne reste plus qu’à placer le bouton à mi-hauteur :

.bouton_rouge
{
    display: inline-block;
    height: 25px;
    position: absolute;
    right: 5px;
    top: 50%;
    margin-top: -12.5px;
    background: url('images/fond_degraderouge.png') repeat-x;
    border: 1px solid #760001;
    border-radius: 5px;
    font-size: 1.2em;
    text-align: center;
    padding: 3px 8px 0px 8px;
    color: white;
    text-decoration: none;
}

Et voilà la bannière présentable avec n'importe quelle dimension ! Figure : Et voilà la bannière présentable avec n’importe quelle dimension !

Le pied de page

On approche de la fin ! Il ne reste plus que le pied de page à faire. Voici à quoi il ressemble sans que l’on ne fasse rien :

Les trois catégories sont places en colonnes Figure : Les trois catégories sont places en colonnes

Je verrai bien mettre ces trois catégories, "Tweet", "Photos" et "Amis" les unes en dessous des autres. Pour cela, rien de plus simple ! La largeur est définie en pourcentage dans le code original (autour de 30% pour chacun des trois éléments). On va donc écrire :

@media (max-width: 480px){

    #tweet, #mes_photos, #mes_amis
    {
        width: 100%;
    }

}

Et on obtient ceci :

Les trois catégories sont bien placées les unes en dessous des autres Figure : Les trois catégories sont bien placées les unes en dessous des autres

Finalement, ce n’était pas très compliqué ! Je vous laisse vous occuper des marges et centrer par exemple les photos tout seuls, comme des grands ! :p

Le code final

Les modifications sur le fichier HTML étant très minimes, je vais vous donner uniquement le code du fichier CSS :

/* Définition des polices personnalisées */

@font-face
{
    font-family: 'BallparkWeiner';
    src: url('polices/ballpark.eot');
    src: url('polices/ballpark.eot?#iefix') format('embedded-opentype'),
         url('polices/ballpark.woff') format('woff'),
         url('polices/ballpark.ttf') format('truetype'),
         url('polices/ballpark.svg#BallparkWeiner') format('svg');
    font-weight: normal;
    font-style: normal;
}

@font-face
{
    font-family: 'Dayrom';
    src: url('polices/dayrom.eot');
    src: url('polices/dayrom.eot?#iefix') format('embedded-opentype'),
         url('polices/dayrom.woff') format('woff'),
         url('polices/dayrom.ttf') format('truetype'),
         url('polices/dayrom.svg#Dayrom') format('svg');
    font-weight: normal;
    font-style: normal;
}

/* Eléments principaux de la page */

body
{
    background: url('images/fond_jaune.png');
    font-family: 'Trebuchet MS', Arial, sans-serif;
    color: #181818;
	margin: 0;
}

#bloc_page
{
    max-width: 900px;
    margin: auto;
    min-width: 320px;
}

section h1, footer h1, nav a
{
    font-family: Dayrom, serif;
    font-weight: normal;
    text-transform: uppercase;
}

/* Header */

header
{
    background: url('images/separateur.png') repeat-x bottom;
	position: relative;
}

#titre_principal
{
    display: inline-block;
}

header h1
{
    font-family: 'BallparkWeiner', serif;
    font-size: 2.5em;
    font-weight: normal;
}

#logo, header h1
{
    display: inline-block;
    margin-bottom: 0px;
}

header h2
{
    font-family: Dayrom, serif;
    font-size: 1.1em;
    margin-top: 0px;
    font-weight: normal;
}

/* Navigation */

nav
{
    /*display: inline-block;
    width: 740px;*/
    text-align: right;
    position: absolute;
    bottom: 0;
    right: 0;
}

nav ul
{
    list-style-type: none;
}

nav li
{
    display: inline-block;
    margin-right: 15px;
}

nav a
{
    font-size: 1.3em;
    color: #181818;
    padding-bottom: 3px;
    text-decoration: none;
}

nav a:hover
{
    color: #760001;
    border-bottom: 3px solid #760001;
}

/* Bannière */

#banniere_image
{
    margin-top: 15px;
    height: 200px;
    border-radius: 5px;
    background: url('images/sanfrancisco.jpg') no-repeat;
    position: relative;
    box-shadow: 0px 4px 4px #1c1a19;
    margin-bottom: 25px;
}

#banniere_description
{
    position: absolute;
    bottom: 0;
    border-radius: 0px 0px 5px 5px;
    width: 100%;
    min-height: 40px; /* Une hauteur qui me paraît plus qu'acceptable */
    /*padding-top: 15px;
    padding-left: 4px;*/
    background-color: rgb(24,24,24); /* Pour les anciens navigateurs */
    background-color: rgba(24,24,24,0.8);
    color: white;
    font-size: 0.8em;
    
}

#banniere_description>p
{
    padding-left:4px;
    padding-right: 120px;
}

.bouton_rouge
{
    display: inline-block;
    height: 25px;
    position: absolute;
    right: 5px;
    top: 50%;
    margin-top: -12.5px;
    background: url('images/fond_degraderouge.png') repeat-x;
    border: 1px solid #760001;
    border-radius: 5px;
    font-size: 1.2em;
    text-align: center;
    padding: 3px 8px 0px 8px;
    color: white;
    text-decoration: none;
}

.bouton_rouge img
{
    border: 0;
}

/* Corps */

article, aside
{
    /*display: inline-block;
    vertical-align: top;*/
    text-align: justify;
}

article
{
    /*width: 625px;*/
    margin-right: 275px;
}

.ico_categorie
{
    vertical-align: middle;
    margin-right: 8px;
}

article p
{
    font-size: 0.8em;
}

section
{
    position: relative;
}

aside
{
    position: absolute;
	top: 0;
	right: 0;
    width: 235px;
    background-color: #706b64;
    box-shadow: 0px 2px 5px #1c1a19;
    border-radius: 5px;
    padding: 10px;
    color: white;
    font-size: 0.9em;
}

#fleche_bulle
{
    position: absolute;
    top: 100px;
    left: -12px;
}

#photo_zozor
{
    text-align: center;
}

#photo_zozor img
{
    border: 1px solid #181818;
}

aside img
{
    margin-right: 5px;
}

/* Footer */

footer
{
    background:  url('images/ico_top.png') no-repeat top center, url('images/separateur.png') repeat-x top, url('images/ombre.png') repeat-x top;
    padding-top: 25px;
}

footer p, footer ul
{
    font-size: 0.8em;
}

footer h1
{
    font-size: 1.1em;
}

#tweet, #mes_photos, #mes_amis
{
    display: inline-block;
    vertical-align: top;
}

#tweet
{
    width: 28%;
}

#mes_photos
{
    width: 35%;
}

#mes_amis
{
    width: 31%;
}

#mes_photos img
{
    border: 1px solid #181818;
    margin-right: 2px;
}

#mes_amis ul
{
    display: inline-block;
    vertical-align: top;
    margin-top: 0;
    width: 48%;
    list-style-image: url('images/ico_liensexterne.png');
    padding-left: 2px;
}

#mes_amis a
{
    text-decoration: none;
    color: #760001;
}


/* Correctifs pour les vieilles versions d'Internet Explorer */

/* Pour activer un positionnement type inline-block sur les vieilles versions d'IE */

.old_ie #titre_principal, .old_ie #logo, .old_ie header h1, .old_ie nav, .old_ie nav li, .old_ie .bouton_rouge, .old_ie article, .old_ie aside, .old_ie #tweet, .old_ie #mes_photos, .old_ie #mes_amis, .old_ie #mes_amis ul
{
    display: inline;
    zoom: 1;
}

/* Quelques ajustements pour les vieilles versions d'IE */

.old_ie section h1, .ie8 section h1
{
    font-size: 1.1em;
}

.old_ie footer div, .ie8 footer div
{
    margin-top: 30px;
    background: url('images/separateur.png') repeat-x top;
}




/* MEDIA QUERIES */

@media (max-width: 700px){
    aside
    {
        top: 100%;
        left: 50%; /* On place la gauche de notre élément au mileu de la <section> */
        margin-left: -127.5px; /* Et on décale notre élément de la moitié de sa largeur vers la gauche */
    }
    
    article
    {
        margin-right: 0;
        margin-bottom: 470px;
        padding-bottom: 10px;
    }
}

@media (max-width: 600px){
    nav li
    {
        display: block;
        padding-bottom: 5px;
    }
    	
    nav
	{
        text-align: left;
        position: static; /* La valeur par défaut */
        padding-bottom: 5px;
    }
    
    nav ul 
	{
        margin-top: 0;
        padding-left: 10px;
    }
}

@media (max-width: 480px){

    #tweet, #mes_photos, #mes_amis
    {
        width: 100%;
    }

}

Et c’est terminé ! Ce n’était pas si long finalement ! ;)

Aller plus loin

Vous aurez remarqué que le design que je vous propose peut encore être amélioré (comme tout, me direz-vous !). De plus, les modifications apportées ont raboté quelques marges, et même si ce n’est pas fondamental, certains d’entre vous peuvent trouver cela gênant. À vous de les rajouter ! Je vous montre une impression écran de ce que j’ai fait, au cas où vous n’auriez pas d’idée :

Ma version finale de ce site Figure : Ma version finale de ce site

Pour un site, habituellement, vous pourrez créer une version tablette : une version mobile en un peu plus grand, pensée pour du tactile. Ici, ce n’est pas vraiment la peine, mais vous pouvez par exemple mettre le <aside> plus large que haut en fonction de la largeur.

Vous pouvez aussi faire une version "grand écran", avec une largeur de plus de 1200px de large par exemple. Au lieu de mettre simplement des marges vides sur le côté, mettez-y votre menu en position: fixed;, pour simplifier encore plus l’utilisation de votre site !

Ainsi, votre code CSS pourrait ressembler à ceci :

/* Votre code générique (couleurs, polices, survol...) et la mise en page pour ordinateur */
...

/* Mise en page pour mobile */
@media (max-width: 480px) { ... }

/* Mise en page pour tablettes */
@media (max-width: 767px) { ... }

/* Mise en page pour les grands écrans */
@media (min-width: 1200px) { ... }

Les valeurs qui sont ici peuvent bien entendu être modifiées selon vos envies, mais ce sont les valeurs standards que je vous ai montrées plus tôt.

Encore une idée : vous pouvez également laisser l’en-tête du site en haut de l’écran si vous estimez que cela ne va pas gêner le visiteur. Pour cela, vous utiliserez la propriété position: fixed; de nouveau avec une condition sur la hauteur de l’écran cette fois-ci. N’oubliez pas de mettre une marge pour que votre bannière ne se retrouve pas sous votre en-tête !

Une autre approche

Des lecteurs du tutoriel m’ont signalé qu’une autre approche pour créer un site pour mobile était possible, et peut-être même mieux : le mobile-first.

Cette technique consiste à créer le site d’abord pour mobiles, avec de "gros boutons", et seulement après à utiliser les media queries pour avoir un site correct depuis un ordinateur. Ici, comme je vous proposais d’adapter le TP de M@teo21, ce n’était pas applicable mais songez-y lorsque vous débutez un design !

Néanmoins, les anciennes versions d’IE (encore lui !) ne supportant pas les media queries, il faudra utiliser les commentaires conditionnels, sinon la version mobile s’affichera pour votre visiteur.

Vous vous demandez sûrement pourquoi s’embêter à faire tout ça ? Et bien tout simplement pour accélérer (un peu) le chargement de vos pages, ce qui est fondamental pour les mobiles. N’hésitez donc pas à réduire vos images pour les mobiles et à minimiser toutes les ressources externes à partir du moment où vous créez un site pour mobile.

Merci à Satovo et soyel pour leurs commentaires !


J’espère que vous avez apprécié ce TP. :)

Passons à la suite : accéder à la version pour ordinateur depuis un mobile !