Interface HTML-CSS

Identification

Infoforall

12 - Création d'une interface


Nous traiterons ici de la façon de placer précisement et définitivement(au pixel près) les éléments de votre page.

interface finale

Jusqu'à présent, nous avons travaillé avec des éléments placés uniquement en fonction de :

  • Leur nature display : block, inline-block ou inline.
  • Leur taille via height et width.
  • Les marges externe et interne : margin et padding.
  • La propriété float éventuelle.

Nous allons voir aujourd'hui comment déplacer les éléments affichés où vous voulez en donnant directement et de façon fixe les coordonnées en x et en y.

Pour rappel, voici les axes de coordonnées utilisés :

les axes x et y

Le point (0,0) est donc en haut à gauche.

L'avantage est que le placement des éléments est assez intuitif :

  • Plus x est grand, plus on est à droite
  • Plus y est grand, plus on est en bas

Le désavantage est qu'on ne gère pas réellement la taille des écrans.

Nous allons ici créer une interface pour un jeu où il faudra détecter les animaux féroces.

1 - Première version sans utiliser position

Nous avons 9 animaux, féroces ou non. Nous voudrions pouvoir les afficher selon un regroupement en 3x3 sans utiliation de tableau.

Commençons par voir ce que cela donne en plaçant simplement les images :

ANIMAUX FEROCES

1 2 3 4 5 6 7 8 9
<img src="agneau.jpg" alt="agneau" width="259" height="194"> <img src="canard.jpg" alt="canard" width="259" height="194"> <img src="chaton.jpg" alt="chaton" width="275" height="183"> <img src="ecureuil.jpg" alt="ecureuil" width="259" height="194"> <img src="koala.jpg" alt="koala" width="276" height="183"> <img src="lapin.jpg" alt="lapin" width="212" height="238"> <img src="suricate.jpg" alt="suricate" width="225" height="225"> <img src="tarentule.jpg" alt="tarentule" width="260" height="194"> <img src="tigre.jpg" alt="tigre" width="260" height="194">
agneau canard chaton ecureuil koala lapin suricate tarentule tigre

On peut voir que les éléments sont tous sauf bien alignés. De plus, si vous modifiez la taille de la fenêtre, vous pourrez constatez que les images changent de place. Pourquoi ?

Display

Il existe trois manières d'afficher une balise :

Avec display: inline, les éléments sont placés les uns à la suite des autres sur la même ligne et on ne peut pas définir de largueur pour les éléments. Il s'agit du réglage par défaut de la balise span, strong, ... Bref, toutes les balises affichant des bouts de texte.

Avec display: block, les éléments sont placés les uns en dessous des autres : on passe à la ligne avant d'afficher le block et on ne place qu'un bloc sur une 'ligne'. C'est par défaut le cas des balises div, h, p ...

Enfin, il existe un cas intermédiaire : display: inline-block. Dans ce cas, on place les éléments les uns derrière les autres mais ils possèdent néanmoins des propriétés height et width. C'est le cas, par défaut, des balises images img.

Comme nous affichions des images, elles se sont donc placées les unes derrière les autres.

Comme nous voudrions des cases 'images' de taille identique, nous allons placer chaque image dans des balises div, elles-mêmes contenues dans une div nommée "conteneur".

Voici le code de notre interface HTML :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>INTERFACE GRAPHIQUE</title> <meta http-equiv="content-Language" content="fr" /> <link rel="stylesheet" href="animaux-feroces.css" /> </head> <body> <header> <h3>ANIMAUX FEROCES</h3> </header> <section> <div id="conteneur"> <div> <img src="agneau.jpg" alt="agneau" width="259" height="194"> </div> <div> <img src="canard.jpg" alt="canard" width="259" height="194"> </div> <div> <img src="chaton.jpg" alt="chaton" width="275" height="183"> </div> <div> <img src="ecureuil.jpg" alt="ecureuil" width="259" height="194"> </div> <div> <img src="koala.jpg" alt="koala" width="276" height="183"> </div> <div> <img src="lapin.jpg" alt="lapin" width="212" height="238"> </div> <div> <img src="suricate.jpg" alt="suricate" width="225" height="225"> </div> <div> <img src="tarentule.jpg" alt="tarentule" width="260" height="194"> </div> <div> <img src="tigre.jpg" alt="tigre" width="260" height="194"> </div> </div> </section> <footer> <p>Ici, c'est le footer.</p> </footer> </body> </html>

On obtient alors ceci, ce qui n'est pas beaucoup mieux pour l'instant : comme ce sont des divs, ce n'est pas en ligne mais avec une image par ligne...

ANIMAUX FEROCES v2

agneau
canard
chaton
ecureuil
koala
lapin
suricate
tarentule
tigre

02° Lancer en local la solution que vous venez de télécharger. Vous devriez avoir quelque chose qui ressemble à la présentation ci-dessous.

Si ca ne fonctionne pas, tenter de voir d'où viens le problème et si vous ne voyez vraiment pas, penser à me joindre de façon à pouvoir avancer.

ANIMAUX FEROCES v3

agneau
canard
chaton
ecureuil
koala
lapin
suricate
tarentule
tigre

03° Ouvrir le fichier css dans Atom ou Notepad++. Vous pourrez constater que nous y avons inséré quelques règles.

Explications sur le CSS avant de commencer réellement l'activité :

On commence par modifier les marges de la balise qui va contenir l'ensemble.

  • On modifie le style de la div d'id valant "conteneur" de façon à mettre à zéro sa bordure externe (margin) et interne (padding).
  • On rajoute une bordure noire d'un pixel de façon à la visualiser.
1 2 3 4 5 6
/* Cette première définition permet d'avoir des blocs qui se collent, sans marge et autres */ #conteneur { margin:0px; padding: 0px; border: 1px solid #660000; }

Nous avons ensuite modifier la façon dont les balises div contenant les photos vont s'afficher :

  • On commence par demander à changer l'affichage : on désire que ces div deviennent des inline-block.
  • On impose une marge externe (margin: 0px) et interne (padding: 0px) de 0 pixel de façon à ne gérer la largeur réelle qu'avec width.
  • On impose alors à la div d'avoir une largeur et une hauteur de 300 pixels. On entoure avec une bordure pour voir clairement la limite de la div.
1 2 3 4 5 6 7 8
#conteneur div { display: inline-block; margin: 0px; padding: 0px; width: 300px; height: 300px; border: 1px solid #777777; }

Erreur typique : une fois sur deux lorsqu'on m'appele sur ce type d'activité, c'est que l'affichage ne gère pas bien les largeurs. D'où vient souvent problème ? Du fait que vous laissez un espace entre les valeurs et le px qui indique l'unité. Ainsi 300 px ne sera pas compris correctement, là où une indication 300px fonctionne. Attention aux espaces donc.

Reste la gestion CSS des images. On les transforme en balise block (elles sont initialement en inline-block) et on supprime les marges internes et externes.

1 2 3 4 5
#conteneur div img { display: block; margin: 0px; padding: 0px; }

Comme vous pouvez le voir, c'est mieux mais nous n'avons pas 3x3 images par lignes.

04° Observez bien le résultat. Est-il normal de voir des blancs entre les bordures des différentes div contenant les images ?

...CORRECTION...

Et la réponse est NON.

C'est un problème du placement des inline-block : l'interpréteur va lire n'importe quel caractère d'espacement (même un passage à la ligne !) comme une demande d'espacement. Si on regarde le code HTML, on voit bien qu'on passe à la ligne entre chaque div contenant une image.

Du coup, ça laisse un espace d'environ 4 ou 5 pixels selon les navigateurs.

Comment se débarasser de ces espaces ?

La première solution est barbare : il suffit de supprimer les passages à la ligne !

Un peu moins violente mais un peu bidouillage : on place des commentaires vides entre les balises : ainsi le navigateur n'y voit pas de passages à la ligne puisqu'il n'analyse pas les commentaires.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>8-INTERFACE GRAPHIQUE</title> <meta http-equiv="content-Language" content="fr" /> <link rel="stylesheet" href="animaux-feroces.css" /> </head> <body> <header> <h3>ANIMAUX FEROCES</h3> </header> <section> <div id ="conteneur"> <div><img src="agneau.jpg" alt="agneau" width="259" height="194"></div><!-- --><div><img src="canard.jpg" alt="canard" width="259" height="194"></div><!-- --><div><img src="chaton.jpg" alt="chaton" width="255" height="183"></div><!-- --><div><img src="ecureuil.jpg" alt="ecureuil" width="259" height="194"></div><!-- --><div><img src="koala.jpg" alt="koala" width="276" height="183"></div><!-- --><div><img src="lapin.jpg" alt="lapin" width="212" height="238"></div><!-- --><div><img src="suricate.jpg" alt="suricate" width="225" height="225"></div><!-- --><div><img src="tarentule.jpg" alt="tarentule" width="260" height="194"></div><!-- --><div><img src="tigre.jpg" alt="tigre" width="260" height="194"></div> </div> </section> <footer> <p>Ici, c'est le footer.</p> </footer> <script src="animaux-feroces.js"></script> </body> </html>

Les autres sont plus élégantes. Allez voir si vous voulez vraiment savoir comment supprimer proprement les espaces génants.

Pour information, la solution à ce problème m'est venu du site https://www.alsacreations.com. Merci à eux.

Par contre, comme les espacements entre les div me conviennent en réalité, je vais garder le code sans les commentaires. Mais bon, si vous cherchez un jour une solution à ce problème, pensez à aller voir l'article d'Alsacreation.

06° Rajouter dans votre code HTML quelques balises br (entre les balises div) pour passer à la ligne de façon à avoir 3 images par lignes.

Relancez pour visualiser le résultat.

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>8-INTERFACE GRAPHIQUE</title> <meta http-equiv="content-Language" content="fr" /> <link rel="stylesheet" href="animaux-feroces.css" /> </head> <body> <header> <h3>ANIMAUX FEROCES</h3> </header> <section> <div id ="conteneur"> <div><img src="agneau.jpg" alt="agneau" width="259" height="194"></div> <div><img src="canard.jpg" alt="canard" width="259" height="194"></div> <div><img src="chaton.jpg" alt="chaton" width="255" height="183"></div> <br> <div><img src="ecureuil.jpg" alt="ecureuil" width="259" height="194"></div> <div><img src="koala.jpg" alt="koala" width="276" height="183"></div> <div><img src="lapin.jpg" alt="lapin" width="212" height="238"></div> <br> <div><img src="suricate.jpg" alt="suricate" width="225" height="225"></div> <div><img src="tarentule.jpg" alt="tarentule" width="260" height="194"></div> <div><img src="tigre.jpg" alt="tigre" width="260" height="194"></div> </div> </section> <footer> <p>Ici, c'est le footer.</p> </footer> <script src="animaux-feroces.js"></script> </body> </html>

Normalement, c'est mieux mais l'image n'est toujours pas centrée dans la div. Comment faire ?

Pour centrer horizontalement, c'est simple, il suffit d'utiliser une marge extérieure automatique : on passe donc de margin: 0px à margin: auto.

06° Modifier le CSS des images de façon à les centrer horizontalement.

...CORRECTION...

1 2 3 4 5
#conteneur div img { display: block; margin: auto; padding: 0px; }

ANIMAUX FEROCES v4

agneau
canard
chaton

ecureuil
koala
lapin

tarentule
tigre

C'est bien beau, mais ca reste encore mal centré verticalement !

Nous allons donc forcer le début de l'image à descendre de la moitié de l'espace disponible dans la div. Comment ? Avec l'instruction suivante : margin-top: 50%;. J'ai choisi les unités en pourcentage. Cela veut dire qu'on descend l'image de 50% de la hauteur de la div qui contient l'image.

1 2 3 4 5 6
#conteneur div img { display: block; margin: auto; padding: 0px; margin-top: 50%; }

07° Modifier le code CSS des images pour décaler l'image de 50% de la taille de la div.

Vous devriez obtenir ceci 

ANIMAUX FEROCES v5

agneau
canard
chaton

ecureuil
koala
lapin

suricate
tarentule
tigre

Bon, toujours pas top car l'img sort de la place disponible. Mais on a bien le début de l'image à 50% de la hauteur de la div.

Il nous reste à remonter les images. De combien ? Et bien, nous aimerions que la moitié de la div corresponde à la moitié de l'image. Il faudrait donc remonter l'image de 50% de sa propre hauteur. Ca tombe bien, il existe une propriété qui permet de faire cela : transform: translateY(-50%).

08° Modifiez une dernière fois le CSS de façon à obtenir l'affichage ci-dessous.

1 2 3 4 5 6 7
#conteneur div img { display: block; margin: auto; padding: 0px; margin-top: 50%; transform: translateY(-50%); }

ANIMAUX FEROCES v6

agneau
canard
chaton

ecureuil
koala
lapin

suricate
tarentule
tigre
Bilan sur les unités

On notera qu'avec transform: translateY(-50%);, si vous notez 50% cela veut dire 50% de la hauteur de l'image elle-même.

Par contre, avec margin-top: 50%, si vous notez 50%, cela veut dire 50% de la hauteur de la div qui contient votre image.

Vous auriez pu également noter margin-top: 50px : on décale alors de 50 pixels.

Ou encore : margin-top: 50vh où vh veut dire vertical height. On décale alors de 50% de la hauteur de l'écran.

Cette dernière unité peut être très utile si vous voulez adapter votre interface à la place disponible.

Pour la largeur, il y a vw pour viewport's width : elle correspond à 1% de la largeur disponible sur l'écran. 25vw veut donc dire de prendre 25% de la largeur disponible à l'écran.

09° Réduire la taille de l'écran. Est-ce que cela fonctionne encore ?

Pour imposer la taille du conteneur et éviter le retour à la ligne, il suffit de le signaler via le CSS :.

1 2 3 4 5 6
#conteneur { margin:0px; padding: 0px; border: 1px solid #660000; width: 1200px; }

10° Tester. Cette fois, on gardera normalement la bonne disposition même si l'écran devient trop petit.

ANIMAUX FEROCES v7

agneau
canard
chaton

ecureuil
koala
lapin

suricate
tarentule
tigre

Ce n'est pas si difficile à comprendre une fois qu'on a compris l'intérêt de chaque ligne de code mais il faut avouer qu'il faut penser à beaucoup de choses.

Nous allons voir maintenant des méthodes de placement plus directes.

2 - Avec position: relative

Nous allons voir maintenant une méthode plus directe et précise pour positonner les éléments dans un élément conteneur.

Imaginons que nous voulions obtenir ceci : un affichage de 800 pixels sur 650 pixels (un carreau correspondant à 50 pixels).

interface voulue

Ainsi le carré bleu commence en (x=50;y=50).

Le carré orange commence en (x=300;y=50)...

Avec la gestion habituelle, il est possible de les placer exactement à ses endroits mais cela va demander un certain temps de réflexion (gestion des marges ...).

Nous allons voir comment faire cela plus rapidement avec position: relative;.

Le relative veut dire qu'on va pouvoir modifier la position de l'élément relativement à la position 'normale' qu'aurait eu l'élément.

Voici la partie HTML :

1 2 3 4 5 6 7 8 9 10 11
<div id="web080_test7"> <div id="bleu"></div> <div id="orange"></div> <div id="vert"></div> <div id="rouge"></div> <div id="jaune"></div> <div id="noir"></div> <div id="violet"></div> <div id="cyan"></div> <div id="gris"></div> </div>

Regardons ce que donne le positionnement 'normal' dans une div de 800px sur 650px :

Et voici un début de code CSS :

On commence avec la div-conteneur :

1 2 3 4 5 6 7
#web080_test7 { margin: 0px; padding: 0px; border: 1px solid #660000; width: 800px; height: 650px; }

Je définis une balise div-conteneur en lui donnant la bonne largeur (800px) et hauteur (650px).

On passe maintenant au CSS commun des div de couleurs contenues dans la div-conteneur. Nous créons des carrés de 150px de côté :

1 2 3 4 5 6 7 8
#web080_test7 div { display: inline-block; margin: 0px; padding: 0px; width: 150px; height: 150px; border: 1px solid #777777; }

Nous pouvons maintenant décrire le CSS de chaque div de couleur, une à une :

1 2 3 4 5 6
#bleu { background-color: blue; position: relative; top: 50px; left: 50px; }

On précise en ligne 3 que cette balise aura un positionnement relatif par rapport à sa position normale.

On donne ensuite en pixels le décalage à effectuer à la boite à l'aide de top et left.

Nous aurions également pu donner d'autres points de coordonnées : right pour le bord droit et bottom pour le bord bas. Attention néanmoins : si vous imposez left et right, vous ne pouvez pas en même temps imposer width puisqu'on trouve la largeur en fonction de la position du bord gauche et du bord droit !

Nous aurions également pu donner des valeurs négatives.

Voici quelques exemples pour les autres balises div colorées.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#orange {background-color: orange;} #vert { background-color: green; position: relative; top: 50px; left: 50px; } #rouge { background-color: red; position: relative; top: 0px; left: -50px; } #jaune {background-color: yellow;} #violet {background-color: purple;} #noir {background-color: black;} #cyan {background-color: cyan;} #gris {background-color: grey;}

Voici le résultat pour l'instant :

Voici une image qui vous permettra de comprendre pourquoi les balises sont positionnées ainsi : on y trace un point corresopndant la position 'normale" du coin supérieure gauche et le trajet jusqu'à la position actuelle.

interface voulue

Comme on le voit, positionner un ou deux éléments de cette façon est possible mais le faire pour la totalité est plutôt délicat. En effet, nous devons d'abord avoir une idée précise de la position de l'élément AVANT modification pour ensuite modifier sa position... Ce n'est pas très intuitif puisqu'il n'existe par d'origine commune de coordonnées.

C'est normal, nous aurions dû utiliser une autre valeur pour cette propriété : position: absolute.

10° Positionner néanmoins les trois premiers carrés correctement avec position: relative par rapport à l'interface voulue.

Pour rappel :

interface voulue

3 - Avec position: absolute

Cette fois, nous allons pouvoir placer les éléments par rapport à une orgine de coordonnées commune à toutes nos balises.

Une subtilité néanmoins : si la div-conteneur ne possède pas elle-même de propriété position, l'élément possèdant une propriété position: absolute va se positionner par rapport à l'origine de la page elle-même ! Le point (0,0) serait alors le coin supérieur gauche de la page elle-même. Il faut faire extrêmement attention à cette subtilité.

Regardons un code HTML et CSS utilisant ce principe :

1 2 3 4 5 6 7 8 9 10 11
<div id="web080_test8"> <div id="bleu"></div> <div id="orange"></div> <div id="vert"></div> <div id="rouge"></div> <div id="jaune"></div> <div id="noir"></div> <div id="violet"></div> <div id="cyan"></div> <div id="gris"></div> </div>

Et pour le CSS :

1 2 3 4 5 6 7 8
#web080_test8{ margin: 0px; padding: 0px; border: 1px solid #660000; width: 800px; height: 650px; position: relative; }

11° Cette div possède-t-elle une propriété position ? Dans la mesure où on ne donne pas d'information supplémentaire, comment va-t-elle être positionnée ?

...CORRECTION...

Oui, le css indique ceci : position: relative

Dans la mesure où on ne donne aucune indication de décalage ensuite, cela veut dire qu'on reste à la position 'normale'.

Cette ligne ne sert donc qu'à fournir une origine des positions pour les div dans cette div-conteneur : on prendra le (0,0) de ce conteneur et pas le (0,0) de la page elle-même.

On retrouve ensuite les données communes des div-carrés colorés :

1 2 3 4 5 6 7 8
#web080_test8 div { display: inline-block; margin: 0px; padding: 0px; width: 150px; height: 150px; border: 1px solid #777777; }

Regardons maintenant les div colorées : les carrés bleu, vert et rouge sont déclarées en position absolue : les indications données sur le coin supérieur gauche va donc correspondre à leurs coordonnées finales dans la div-conteneur, le parent. Cette fois, il ne s'agit plus d'un décalage par rapport à leur position 'normale', mais d'un décalage par rapport à l'origine (0,0) de la div-conteneur.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
#bleu { background-color: blue; position: absolute; top: 50px; left: 50px; } #orange {background-color: orange;} #vert { background-color: green; position: absolute; top: 100px; left: 50px; } #rouge { background-color: red; position: absolute; top: 150px; left: 50px; } #jaune {background-color: yellow;} #violet {background-color: purple;} #noir {background-color: black;} #cyan {background-color: cyan;} #gris {background-color: grey;}

Le résultat en image :

13° Vérifier que les coordonnées des trois div bleu, vert et rouge soient bien cohérentes avec le code. Modifier quelques coordonnées pour bien comprendre le principe.

...CORRECTION...

Certaines div ont la propriété suivante : position: absolute

Cela veut dire qu'elles seront positionnées par rapport à l'origine choisie : le (0,0) d'un conteneur.

Ici, puisque la div-conteneur possède une valeur position: relative, c'est la position (0,0) de la div-conteneur qui sera choisie comme origine.

Ainsi, tous les décalages left de 50 px placent les div à la même position horizontale.

14° Modifier le CSS en supprimant la référence position: relative de la div-conteneur. Que constatez-vous ?

...CORRECTION...

Si la div-conteneur ne possède pas de propriété position du tout, le navigateur remonte le long des div-conteneurs. Comme il ne trouve aucune propriété position, il choisit comme référence le (0,0) de la page elle-même !

Ainsi, la nouvelle référence est simplement le point en haut à gauche de votre page.

15° Question notée : modifiez maintenant le CSS pour obtenir l'interface voulue depuis le début, à savoir :

4 - Les autres valeurs possibles de position

Nous allons voir rapidement deux autres valeurs possibles.

static et fixed

Premièrement, position: static veut dire que la div ne possède pas en réalité de valeur de position : elle est gérée automatiquement par le navigateur. Pourquoi l'utiliser au lieu de ne rien préciser ? Il est possible que le CSS impose une valeur à position à un ensemble de div via une classe et que vous vouliez uniquement placer certaines d'entre elles de façon "automatique". Attention, une valeur de ce type sur une balise conteneur veut dire qu'elle ne possède pas de propriété position.

Deuxième nouvelle valeur : position: fixed. Cette fois, vous fixez la balise sur l'écran et elle apparaitra toujours au même endroit même en bougeant la molette de la souris et en faisant dérouler la page. C'est pratique pour les menus de sélection ou autre.

Voilà pour le positionnement précis de vos éléments sur vos interfaces graphiques.

Il y a encore deux petites choses que vous pouvez trouvez facilement sur internet, sur W3School par exemple. Aucune explication ici car cela ne concerne pas directement les interfaces.

  • position: sticky qui permet de gérer normalement une balise (en mode relative) mais qui permet de ne pas la faire disparaitre lorsqu'on va trop bas lors du déroulement de la page : on passe alors en fixed et la balise restera par exemple en haut de page même si vous continuez à faire dérouler la page.
  • On peut gérer quelle div passe devant l'autre en cas de chevauchement avec la propriété CSS z-index (par exemple z-index:-1) où on donne la valeur de la 'couche' sur laquelle on désire placer la div. On peut ainsi préciser qui passe au dessus de quoi.

Vous avez maintenant toutes les cartes en main pour réaliser les pages que vous désirez. Il ne reste plus qu'à aller voir la partie Javascript pour rendre vos pages réactives.

Remarque : il existe également la propriété flex.

L'intéret du flex est que l'affichage va pouvoir être modifié facilement et automatiquement en fonction de la taille de l'écran.

Le premier désavantage est que le placement n'est pas fixe. Or, parfois, on veut que les éléments soient placés à un endroit précis et pas ailleurs. Pour un jeu par exemple.

Le deuxième désavantage est que l'utilisation de flex n'est pas forcément facile à comprendre.

Par contre, si votre but est d'obtenir un placement dynamique, il va falloir aller voir l'activité sur FLEX un jour.

Activité publiée le 29 09 2019
Dernière modification : 29 09 2019
Auteur : ows. h.