Blog des Gens Compliqués

Animations CSS3 & Centrer une image

11/09/2017 21:45:24+02:00|Par DkVZ
Informatique & Web
14 minutes de lecture (facile)

Table des matières

Centrer un élément sur une page web. Initialement on se dit que ça devrait être simple. Détrompez-vous jeune idéaliste, rien n'est simple en web "design".

Il existe plusieurs méthodes mais aucune n'est particulièrement intuitive.

En essayant de centrer des bidules sur des machines je me suis retrouvé à créer cette contribution magistrale au patrimoine de l'humanité:

CLICK MOI

ATTENTION  - Ne fonctionne pas sous Internet Explorer 6 (lel)

Aussi sur Github.

ZE CENTRAGE

Oui, je suis au courant qu'il s'agit d'une liste non-exhaustive de moyens d'arriver au même résultat. Inutile de le répéter sans cesse dans les commentaires. Je n'étais pas prêt pour être célèbre si jeune.

CSS et arrière plan

S'il s'agit de centrer une image, une des solutions les plus simples consiste à utiliser les styles background-*.

Exemple:

body {
	background-color: #285d7c;
	background-image: url('click_here_5.gif');
	background-repeat: no-repeat;
	background-attachment: fixed;
	background-position: center
}

En plus du centrage j'aurais souhaité que la taille de l'image s'ajuste plus ou moins automatiquement (si possible sans Javascript) avec la taille de la fenêtre.

C'est possible avec background-size, qui je pense appartient au HTML5.

Si on ajoute background-size: cover; à notre CSS on obtient ce type de résultat qui est de toute beauté:

background-size: cover
C'est sobre

Cette option étire l'image. Pour garder l'aspect, mais laisser éventuellement apparaître la couleur d'arrière plan, on peut utiliser background-size: contain pour obtenir ce type de résultat de non-moins relative toute beauté:

background-size: contain
C'est sobre aussi

Il est également possible d'empiler des images avec ce type de styles:

html {
  background: url(greatimage.jpg), url(wonderfulimage.jpg);
  background-size: 300px 100px, cover;
  /* La première image fait 300x100, la second couvre toute la zone */
}

Il me semble avoir lu que background-size demande au moins Internet Explorer 9, donc ça va pas fonctionner chez tout le monde.

Pour éviter que l'image ne couvre la totalité de l'espace vertical ou horizontal (selon laquelle de ces mesures est la plus longue) il est possible d'utiliser un pourcentage, par exemple:

body {
	background-color: #285d7c;
	background-image: url('click_here_5.gif');
	background-repeat: no-repeat;
	background-attachment: fixed;
	background-position: center;
  background-size: 50%;
}

Pour plus d'informations sur tout ça: Article developer.mozilla.org sur background-size.

Positionnement absolu

C'est un peu fumant et pas très logique, mais si et seulement si:

  1. On a un conteneur / élément dont la hauteur est clairement définie.
  2. Ouais en fait c'est la seule condition.

Je suppose que vous savez qu'il est possible de centrer un élément horizontalement en plaçant ses marges gauches et droites sur "auto"? Il s'agit de combiner ça et un positionnement absolu de 0 partout. C'est un peu bizarre, je vous l'accorde. On en arrive à ceci:

<!DOCTYPE html>
<html>
<head>
  <title>Test page from hell</title>
  <style>
    .centerEl {
      height: 100px;
      text-align: center;
      position: fixed;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="centerEl">
    Oh hai
  </div>
</body>
</html>

Les inconvénients de cette méthode étant qu'il faut spécifier la hauteur (pas un problème pour une image) et que ça ressemble à un hack vu de loin. Et de près. En même temps c'est du web design il faut pas trop en demander.

A noter qu'il est possible d'utiliser position: absolute; plutôt que fixed et que c'est d'ailleurs ce qui est souvent présenté dans les exemples (après tout j'ai écrit positionnement absolu comme titre de cette section). Le résultat est le même. "Fixed" permet d'avoir un élément qui reste exactement à l'endroit absolu spécifié, même si on fait défiler la page. Sauf qu'on va pas faire défiler la page puisqu'on utilise une taille de viewport (DIT AUSSI PORT DE VUE) maximale.

Méthode années 80

Si on accepte de sortir <TABLE> de son cercueil et que l'on est personnellement peu affecté par tout ce qui est comportement déshonorable, la fin justifie les moyens etc., il y a cette méthode:

<table style="width: 100%; height: 100%">
    <tr>
       <td style="text-align: center; vertical-align: middle;">
            Oh hai
       </td>
    </tr>
  </table>

Ce truc ne fonctionne pas du tout en HTML5. C'est-à-dire que si vous aviez écrit <!DOCTYPE html> au dessus de votre document HTML ou si votre serveur web l'ajoute pour une raison ou une autre, ce ne sera pas centré.

Repost gratuit plus ou moins hors contexte de mon site oueb antique

A vrai dire j'ignorais que HTML5 avait un comportement discriminatoire extrémiste mais c'est bien le cas. Apparemment ce serait dû à l'alignement vertical qui ne serait plus supporté dans un tableau. Vous vous souvenez de l'attribut valign de <td>? C'était mon truc préféré de la vie dans les années 2000.

A propos si vous voulez faire encore plus sale je vous propose ceci:

<TABLE style="height: 100%" width="100%" align="center">
  <TR>
     <TD valign="center">
          <CENTER>JE NIK TA MER HTML5</CENTER>
     </TD>
  </TR>
</TABLE>

Là on est dans le pur iconoclasme, le terrorisme réactionnaire, le retour à la préhistoire, la nécromancie d'Internet Explorer 6, porter ses chaussettes à l'envers par provocation etc.

Le tag <CENTER> n'ayant plus été vu depuis des siècles. Je comprends pas pourtant, il est clair ce tag. Il CENTRE DES TRUCS. Moi je l'aimais bien. Pourquoi il faut toujours changer ce qui fonctionne? Pourquoi on ne peut pas s'en tenir à nos bonnes valeurs traditionnelles qui ont offert toute sa richesse à notre culture catholique coloniale? Sérieusement si Dieu a dit qu'il fallait se circoncire pour aller au Paradis je vois pas pourquoi il faudrait revenir là dessus, juste par précaution il faudrait continuer à mutiler les enfants, que l'anesthésie fonctionne ou pas, et même si c'est vraiment étrange que le Seigneur détester à ce point là les prépuces. C'est mieux qu'une éternité en enfer je vous rappelle hein. Vous voulez prendre le risque? Tous ces trucs soit disants progressistes avec leurs conteneurs fluides qui changent d'orientation sexuelle à chaque version de Chrome, Dieu a créé les hommes et les femmes (enfin techniquement Adam a créé la femme) et c'est tout. Il n'a jamais imaginé que quelqu'un allait empiler des div pour en faire des abominations et autres FLEX-trucs. Il n'y a plus aucune loi, tout est permis, tout le monde s'empile avec tout le monde, on peut même écrire ses propres tags maintenant et les poster sur Tumblr. Où est le progrès là dedans hein? Tout ce que je vois c'est la lente agonie de nos origines, notre culture, les MARQUEE, gifs animés et TABLE qui sont à l'origine de notre belle culture web. Ils sont progressivement et insidieusement remplacés par des relations impures. On essaye de vous faire croire que ce tableau dans un div aligné au centre est mieux que de simplement ajouter align="center" dans le tag table, mais à la génération d'après BOOM BADABANG votre tableau est devenu un div écrit en minuscule et peu importe votre résistance individuelle, les div se reproduisent beaucoup plus vite que les table parce qu'ils ont que ça à faire, ils s'en foutent de notre culture. Pourquoi personne ne réagit???? Boutez-moi tous ces div et flextrucs et CSS de mes deux dehors et dressez-moi un mur à base de <hr width="100%" /> qui les empêcheront de revenir.

Réveillez-vous!

Ceci était une parodie je ne suis pas vraiment nationaliste conservateur qui croit au génocide des blancs. Je crois au génocide de table par contre.

Update: Méthode display: table

Je me suis rendu compte récemment qu'il existe une alternative CSS à la méthode <TABLE>, en lisant cet article.

Plus ou moins au moment où c'est devenu très mal vu d'utiliser le tag table si on veut faire partie de la bande des gens COOL, l'attribut display applicable en feuille de style reçoit le type table. Il devient possible de créer quelque chose qui se comporte comme un tableau en CSS.

Ceci veut également dire que le vertical-align (en CSS) est accepté dans ces cellules de tableau crées par CSS, même en HTML5. Par conséquent, on peut aligner du contenu (peu importe la hauteur du contenu) de cette manière:

<!DOCTYPE html>
<html>
<head>
<style>
html, body {
  display: table;
  height: 100%;
  width: 100%;
}
.cell {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
}
</style>
</head>
<body>
  <div class="cell">
    <p>Paragraph</p>
  </div>
</body>
</html>

Il n'est bien entendu pas obligatoire d'absolument assigner display: table à body, tout ça peut être dans un autre bloc. Par contre, body soit obligatoirement avoir une hauteur de 100% fixée par CSS.

Voir cet exemple (oui c'est un screenshot de Codepen):

Ce code peut être écrit plus ou moins sans honte

Flex truc bidule sa race

Faut que je vous dise un truc, je capte RIEN à Flex. Cette page aligne le div au centre mais je comprends pas du tout pourquoi:

<!DOCTYPE html>
<html>
<head>
  <title>Test page from hell</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    .aligner {
      display: flex;
      align-items: center;
      height: 100vh;
      justify-content: center;
    }
  </style>
</head>
<body>
  <div class="aligner">
    <div>Oh Hai</div>
  </div>
</body>
</html>

OK, analysons ce bidule étape par étape... Déjà ça ne fonctionne pas si on a pas margin et padding à 0 pour le conteneur. Ensuite, il faut utiliser display: flex qui utilise les infos align-items et justify-content.

Sauf que ça ne fonctionne pas. J'ai essayé de mettre height: 100% mais il faut absolument 100vh, qui est un truc de CSS3 pour utiliser des tailles relatives à celle du VIEWPORT (le port de vue).

Essayons un plan B histoire de se limiter à align-items et justify-content, dans un conteneur de taille 100%.

<!DOCTYPE html>
<html>
<head>
  <title>Test page from hell</title>
  <style>
    html,body {
      margin: 0;
      padding: 0;
      height: 100%;
      width: 100%;
    }
    .aligner {
      display: flex;
      height: 100%;
      align-items: center;
      justify-content: center;
    }
  </style>
</head>
<body>
  <div class="aligner">
    <div>Oh Hai</div>
  </div>
</body>
</html>

Ici on a pu utiliser height: 100% mais c'est uniquement parce que j'ai spécifié que html devait avoir taille 100% aussi. Si vous laissez juste body, ça ne fonctionne pas, si vous laissez juste html, ça ne fonctionne pas non plus. Classique.

Bon j'ai toujours rien capté.

Mais VEZDe, tu sais même pas ce que ça fait display:flex, tu penses pas que ce serait un meilleur point de départ?

OK, OK, c'est bon... Je dois avouer qu'en théorie la méthode flex est intéressante, non pas parce qu'elle ne fonctionne pas sous Internet Explorer 10, mais parce qu'on peut ajouter plusieurs éléments qui seront centrés et vont se suivre, selon l'alignement "flex" que l'on peut choisir (verticalement et horizontalement en gros).

L'élément de style justify-content décide d'où le flux de composants est aligné. Du coup center permet de l'aligner horizontalement. On pourrait alternativement définir des margin-left: auto; margin-right: auto; pour arriver vaguement au même résultat. Ouais comptez pas sur moi pour tester.

En fait margin utilisé sur un élément qui est dans un conteneur display:flex a un comportement particulier et permet d'absorber tout l'espace disponible. Par conséquent, ceci centre également l'élément:

<!DOCTYPE html>
<html>
<head>
  <title>Test page from hell</title>
  <style>
    html, body {
      height: 100%;
      padding: 0;
      margin: 0;
    }
    .parent {
      display: flex;
      height: 100%;
    }
    .child {
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="parent">
    <div class="child">Oh Hai</div>
  </div>
</body>
</html>

Est-ce que c'est plus simple? Beurps. Au moins ça fonctionne. Sauf sous Internet Explorer 10 quoi.

Le plan "transform"

C'est la solution que j'ai finalement utilisée et qui s'apparente très fort à celle du positionnement absolu évoquée plus haut sauf que la gymnastique appliquée ici a un sens pour moi. Ce qui à vrai dire est extrêmement auto-étonnant.

Bon alors c'est quoi transform déjà? C'est un truc assez cool qui permet d'appliquer une opération 2D de type rotation, déplacement ainsi que d'autres trucs louches sur un élément.

Contrairement à flex ça fonctionne sous Internet Explorer 10 (youpie) et même 9 avec le préfixe "ms-" en plus.

Certains vont peut-être me corriger pour flex en disant que display: box ou display: flexbox ou encore fessebox etc. Fonctionnent sous IE10. HE BEN M'EN FOUT moi je veux que display: flex y fonctionne OKAY??

Examinez donc ceci:

#centerImg {
  margin: 0;
  padding: 0;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transform: -webkit-translate(-50%, -50%);
  transform: -moz-translate(-50%, -50%);
  transform: -ms-translate(-50%, -50%);
}

On part de 50% de la gauche et 50% du haut du conteneur, ce qui met notre image (ou autre conteneur de taille bien définie) là:

Cette image est extrêmement utile

Pour être centré il faudrait pouvoir reculer horizontalement de la moitié de la largeur de l'image, et verticalement de la moitié de la hauteur de l'image. D'où:

transform: translate(-50%, -50%);

Les autres transform avec -webkit etc. Etant présents pour que ça fonctionne éventuellement sur certains browser moisis mais pas trop.

Animations CSS3

Loin de moi l'idée de dispenser un cours complet sur le sujet, mais j'ai trouvé intéressant, au départ, la possibilité de créer un arrière plan qui change de couleur cycliquement et progressivement. Un peu plus tôt j'avais déjà fait l'agréable découverte de linear-gradient qui permet... D'utiliser des dégradés comme arrière-plans. Si ç'avait existé dans les années 2000 j'aurais utilisé ça sur TOUS mes projets HTML. J'étais obligé de créer une image de hauteur définie et 1 pixel de large dans laquelle bourrer un dégradé dans Gimp, enregistrer l'image et l'utiliser comme arrière-plan à répétition horizontale.

Keyframes

Premièrement, il s'agit de "déclarer" l'animation. Il y a deux principales méthodes:

Les pourcentages

On déclare, dans l'ordre, des pourcentages suivis du style à appliquer pour chaque keyframe. Le moteur de rendu est supposé passer graduellement d'une étape à l'autre. Ce plan consomme beaucoup de CPU sur des machines un peu faiblardes.

@keyframes bg-color {
  0%  {background-color: #fc102f}
  16% {background-color: #ec72f8}
  33% {background-color: #88f98b}
  49% {background-color: #f8ef8a}
  65% {background-color: #7648ff}
  82% {background-color: #1d6d94}
  100% {background-color: #3d31ff}
}

Avant et après

C'est exactement comme utiliser 0% et 100%, je ne comprends pas pourquoi ce moyen de déclarer les keyframes existe... Mais soit, voici un exemple pour passer de transparence 100% à 0%.

@keyframes transpa {
  from  {opacity: 0}
  to {opacity: 1}
}

J'aurais pu reprendre l'exemple d'avant et utiliser deux couleurs d'arrière plan mais cet article est déjà assez chiant comme ça, alors je varie.

Appliquer l'animation

Déclarer l'animation est la première partie. Elle porte le nom qui suit @keyframes, donc ici bg-color. Je souhaite appliquer l'animation à <body>, dont voici le CSS:

body {
  /* Le reste des styles de body */
  animation-name: bg-color;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

Il est possible de tout bourrer sur une seule ligne dans un mono-style animation. Evidemment c'est beaucoup moins clair dans ce cas là... Déjà que c'est moyen clair là.

  • animation-name : C'est le nom qui suit le @keyframe déclaré précédemment et que l'on souhaite appliquer. En fait ça ne doit pas nécessairement être déclaré avant de l'utiliser, peu importe l'ordre.
  • animation-duration : Vous comprenez l'anglais quand même un peu?
  • animation-timing-function : Permet de donner un genre de fonction temporelle à l'évolution de l'animation. Un genre de fonction temporelle? Par exemple linear est le comportement classique, on passe le même temps sur chaque étape déclarée dans keyframes. En pratique si votre ordi est tout pourri et lag comme l'enfer et que la durée d'animation est faible vous ne verrez aucune différence avec les différentes FONCTIONS TEMPORELLES.
  • animation-iteration-count : Déclarer sur infinite si vous voulez un loop.
  • animation-direction : Si vous voulez que votre animation se déroule à l'envers de ce qui est déclaré dans le @keyframe correspondant, il s'agit d'utiliser reverse. Pourquoi ne pas avoir écrit l'animation à l'envers dans ce cas? Judicieuse question M. Fion. On peut également alterner, comme dans l'exemple, ou utiliser reverse-alternate qui est comme alternate mais à l'envers. Pourquoi ne pas avoir écrit l'animation à l'envers plutôt? SJMDKJMLQSJ
    • Oui je sais qu'on peut recycler la même animation et changer l'ordre avec ces styles

Ces glorieuses animations peuvent rapidement ruiner la batterie d'un mobile pas très costaud, ou de mon ordi portable qui n'est que très moyennement impressionnant de performances.

Totally worth it

Compatibilité KIPUE

Comme d'hab avec ces technologies hyper avant-garde il existe des versions précédentes précédées de l'idiome qui correspond au browser. Par ex. moz-animation-name ou webkit-animation-name. Si vous rêviez de devoir maintenir trois styles différents pour faire la même chose et avoir trois fois plus de boulot par modification faites vous plaiz. De toutes façons je suis sûr que vous passez 80% de votre temps à regarder la progress bar de npm install.

Comment tu fais vibrer tes images?

J'ai utilisé ça:

@keyframes vibrateW {
    0% {left: 50%}
    25% {left: 49%}
    50% {left: 50%}
    75% {left: 51%}
    100% {left: 50%}
  }

Alors, tu regrettes d'avoir demandé hein?

Commentaires

Il faut JavaScript activé pour écrire des commentaires ici

#1

DkVZ
09/01/2019 10:32:19+01:00
C'est mignon comme je captais rien aux CSS à l'époque, malgré les avoir utilisés pour... Genre toujours. Ouais en fait c'est pas mignon du tout. Le truc c'est qu'aujourd'hui le moyen le plus simple de centrer un élement (qui a une hauteur, qui peut être 100% ou 100vh) c'est d'utiliser flex. Et j'en parle pas notamment parce que je pensais que c'était trop un truc du futur mais flex est très bien supporté.

Ajouter un commentaire

Votre commentaire a été ajouté
(enfin, je pense)