21-05-2015 13:56:00
Article original par Louistiti

Dans cette vidéo je vous propose de découvrir comment créer un élément particulier en CSS. Ici il ne s'agira pas de créer une interface complexe mais une petite carte qui vous permettra de présenter vos dernier articles par exemple.

Le design

Le design que l'on utilisera aujourd'hui a été crée par Justin kwak que je tiens à remercier pour avoir autorisé l'utilisation de son design dans ce tutoriel.

Le code HTML

Nous allons donc commencer par la partie HTML en créant la syntaxe la plus sémantique possible. Il ne s'agira pas ici de créer des classes génériques mais plutôt d'avoir une syntaxe sémantique qui représente la stucture de notre document. Exit donc les classes du style align-right text-red.

<article class="card">
  <header class="card__thumb">
    <a href="#">
      <img src="http://lorempicsum.com/futurama/370/235/2">
    </a>
  </header>
  <div class="card__date">
    <span class="card__date__day">12</span>
    <span class="card__date__month">Mai</span>
  </div>
  <div class="card__body">
    <div class="card__category"><a href="#">Photos</a></div>
    <h2 class="card__title"><a href="#">Bender Should Not Be Allowed on TV</a></h2>
    <div class="card__subtitle">A Head in the Polls</div>
    <p class="card__description">
      With a warning label this big, you know they gotta be fun! This is the worst part. The calm before the battle. No! The cat shelter's on to me. Yes, I saw. You were doing well, until everyone died. Daylight and everything.
    </p>
  </div>
  <footer class="card__footer">
    <span class="icon icon--time"></span>6 min
    <span class="icon icon--comment"></span><a href="#">39 comments</a>
  </footer>
</article>

Pour le nommage des classes j'ai chosi d'utiliser la méthode BEM. N'hésitez pas à adapter les noms des classes avec vos conventions.

Le CSS

Pour la partie CSS nous allons utiliser un préprocesseur pour ne pas avoir à créer les règles avec les différents préfixes (si vous vous sentez un peu perdu vous pouvez suivre cette vidéo).

Avant même de commencer, si ce n'est pas déjà fait, on met en place un box-sizing border-box pour tous nos éléments pour se faciliter le travail :

* { box-sizing: border-box;  }

On va commencer par positionner la carte au milieu de l'écran pour la présentation. Et on en profiter pour réécrire le style de tous les liens pour ne pas être géné par la suite.

.card{
  position: absolute;
  overflow: hidden;
  top: 50%;
  left: 50%;
  width: 370px;
  transform: translateX(-50%) translateY(-50%);
  background-color: #fff;
  box-shadow: 0px 0px 20px rgba(0,0,0, 0.1);
  transition: box-shadow $duration;
}

.card a{
  color:inherit;
  text-decoration: none;
}

.card:hover{
  box-shadow: 0px 0px 50px rgba(0,0,0,0.3);
}

On va ensuite positionner la date en haut à droite de notre élément à l'aide d'un position absolute.

.card__date{
  position: absolute;
  top: 20px;
  right: 20px;

  width: 45px;
  height: 45px;
  padding-top: 10px;

  color: #FFF;
  text-align: center;
  line-height: 13px;
  font-weight: bold;

  background-color: $color;
  border-radius: 50%;

  &__day{
    display: block;
    font-size: 14px;
  }

  &__month{
    display: block;
    font-size: 10px;
    text-transform: uppercase;
  }
}

Pour la miniature qui sert de visuel on animera la hauteur de l'élément et on appliquera une transformation CSS scale()afin de retranscrire l'effet de zoom sur l'image.

.card__thumb{
  height: 235px;
  overflow: hidden;
  background-color: #000;
  transition: height $duration;

  img{
    display: block;
    opacity: 1;
    transition: opacity $duration, transform $duration;
    transform: scale(1);
  }

  .card:hover & img{
    opacity: 0.6;
    transform: scale(1.2);
  }
  .card:hover &{
    height: 235px - 145px;
  }
}

Ce changement de taille entraine une déformation de l'élément. On va contrebalancer ce changement de hauteur en modifiant aussi la taille de la class .card__body.

.card__body{
  position: relative;
  padding: 20px;
  height: 185px;
  transition: height $duration;

  .card:hover &{ height: 185px + 145px; }
}

Les autres blocs sont plutôt classique si ce n'est la partie description qui doit s'afficher de manière spécifique. On utilisera pour cela une position absolute et une translation en Y pour donner un effet de léger déplacement, en décalage avec le reste de l'animation.

.card__description{
  position: absolute;
  left: 20px;
  right: 20px;
  bottom: 65px;

  margin: 0;
  padding: 0;

  color: #666C74;
  font-size: 14px;
  line-height: 27px;

  opacity: 0;
  transition: opacity $duration - 0.1s, transform $duration - 0.1s;
  transition-delay: 0s;
  transform: translateY(25px);

  .card:hover &{
    opacity: 1;
    transition-delay: 0.1s;
    transform: translateY(0);
  }
}

Enfin le footer, quant à lui sera collé au bas de la carte

.card__footer{
  position: absolute;
  bottom: 20px;
  left: 20px;
  right: 20px;

  font-size: 11px;
  color: #A3A9AB;

  .icon--comment{
    margin-left: 12px;
  }
}

Le flou de mouvement

Si on regarde l'animation originale on remarque un effet de flou de mouvement sur le titre et le sous-titre. Il n'est malheureusement pas possible d'obtenir un véritable flou en CSS (le filtre blur() ne faisant qu'un flou gaussien et non directionnel). Ceci étant dit on va pouvoir imiter cet effet en utilisant un text-shadow et en l'animant


.card__title{
  margin: 0;
  padding: 0 0 10px 0;

  font-size: 22px;
  color: #000;
  font-weight: bold;

  .card:hover &{
    animation: titleBlur $duration;
  }
}

.card__subtitle{
  margin: 0;
  padding: 0 0 10px 0;

  font-size: 19px;
  color: $color;

  .card:hover &{
    animation: subtitleBlur $duration;
  }
}

@keyframes titleBlur {
  0%{
    opacity:0.6;
    text-shadow: 0px 5px 5px rgba(0,0,0,0.6);
  }
  100%{
    opacity:1;
    text-shadow: 0px 5px 5px rgba(0,0,0,0);
  }
}

@keyframes subtitleBlur {
  0%{
    opacity:0.6;
    text-shadow: 0px 5px 5px rgba($color,0.6);
  }
  100%{
    opacity:1;
    text-shadow: 0px 5px 5px rgba($color,0);
  }
}