Niveau : Expert

Slideshow en CSS3

Tutoriel par (WebDesigner grapilleur de Kiwiz, Strasbourg)
Créé le , mis à jour le (111843 lectures)
Tags : css, target, css3, transitions, images-clefs, keyframes, slideshow

Sommaire


Un slideshow avec contrôle au clic (:target)

Agir sur un élément enfant d'un élément ciblé

Dans la logique des sélecteurs CSS, il est possible d'agir sur les styles d'un élément enfant de l'élément ciblé. Nous allons naturellement utiliser la pseudo-classe :target tout en reprenant l'exemple précédent de la FAQ.

<a href="#faire-lien">Comment faire un lien</a>

<div id="faire-lien" class="blocReponse"> 
   <p class="question">Comment faire un lien ?</p> 
   <p class="reponse">La réponse à la question...</p> 
</div>

En ciblant notre bloc réponse on peut très bien imaginer styler la réponse en plus du bloc complet :

.blocReponse:target {
   background: #AAA;
   border: 1px solid #000;
}

.blocReponse:target .reponse {
   font-style: italic;
   color: #FFF;
}

Voir l'exemple

Nous allons simplement utiliser cette base pour notre slideshow.

Déplacer une division imbriquée dans une autre

Il va s'agir de faire bouger une liste contenant nos éléments à visualiser dans une division conteneur aux dimensions restreintes et au débordement caché. Mettons notre code HTML en place :

<div id="slideshow">
	<ul id="sContent"><!--
		--><li><img src="images/bleu.png" alt="Image bleue" /></li><!--
		--><li><img src="images/vert.png" alt="Image verte" /></li>
	</ul>
</div>
<a href="#sContent">Prev</a> - <a href="#slideshow">Next</a>

L'utilisation d'un commentaire HTML entre les éléments de liste me permet de supprimer l'espace d'environ 4px entre ces éléments en display: inline;.

Je prévois ici un lien Prev et Next pour déclencher les target, mais vous allez vite comprendre que ce code n'est pas optimisé.

Voici le style CSS correspondant :

#slideshow {
	position: relative;    /* le parent positionné */
	width: 150px;          /* limite en largeur (1 élément du slideshow) */
	height: 150px;         /* limite en hauteur */
	overflow: hidden;      /* on cache ce qui déborde */
}
#sContent {
	position: absolute;   /* on sort l'élément du flux */
	top: 0;               /* on le positionne précisément dans... */
	left: 0;              /* l'angle haut gauche de son parent positionné */
	margin: 0;            
	padding: 0;
        width: 300px;          /* ou 200% (car deux éléments) */
	/* CSS3 Transition */
	transition: left 1s;
}
#sContent li {
	display: inline;      /* on aligne les éléments du slideshow */
}
#slideshow:target #sContent {
        /* en ciblant #slideshow on décale #sContent */
	left: -150px;         /* ou - 100% */
}

Voir l'exemple

Comme vous pouvez le constater, cela fonctionne, mais reste assez limité. En effet on ne cible que deux éléments différents, donc on ne peut avoir que deux éléments à visualiser dans notre slideshow. Ce n'est pas très utile en l'état, il nous faudrait alors pour l'améliorer quelque peu :

  • Pouvoir gérer plus de deux éléments à visualiser
  • Afficher uniquement deux liens Prev et Next, et seulement lorsque l'on peut en avoir besoin

Pour cela nous allons ajouter un peu plus de balisage, c'est l'un des bémols de cette méthode.

Un slideshow ++

Nous allons reprendre notre code HTML précédent pour y apporter les modifications suivantes :

  • Une division contenant la liste #sContent par élément de liste
  • Une paire de liens Prev/Next par élément, sauf pour la première et la dernière image
  • Faire en sorte que ces liens soient les frères de la liste #sContent

Voilà ce que ça donne une fois le code modifié :

<div id="slideshow"> 
    <div id="s1">
        <div id="s2">
            <div id="s3">
                <a class="next next1" href="#s2">Next</a> <!-- Pour la 1ère étape -->
                <a class="prev prev2" href="#s1">Prev</a> - <a class="next next2" href="#s3">Next</a> <!-- Pour la 2ème étape -->
                <a class="prev prev3" href="#s2">Prev</a> <!-- Pour la 3ème étape -->
                <ul id="sContent"> 
                    <li><img src="images/bleu.png" alt="Texture bleue" /></li><!-- 
                    --><li><img src="images/vert.png" alt="Texture verte" /></li><!--
                    --><li><img src="images/brun.png" alt="Texture brune" /></li>
                </ul>
            </div>
        </div>
    </div>
</div>

Dans cet exemple le nombre de divisions imbriquées a été exagéré pour simplifier la lecture du futur code CSS. En effet j'aurais pu me contenter d'une seule division en plus pour ces trois éléments de slideshow, j'aurais ainsi ciblé #slideshow, #s1 et #sContent avec mes liens Prev et Next, mais le code CSS aurait été moins lisible.

Mettons en style tout cela afin de comprendre le principe général :

#slideshow {
	position: relative;    /*le parent positionné*/
	width: 150px;          /*limite en largeur (1 élément du slideshow)*/
	height: 150px;         /*limite en hauteur*/
	margin: 30px;
	overflow: hidden;      /*on cache ce qui déborde*/
}
#sContent {
	position: absolute;   /*on sort l'élément du flux*/
	top: 0;               /*on le positionne précisément dans ...*/
	left: 0;              /*l'angle haut gauche de son parent positionné*/
	width: 450px;         /*ou 300% car 3 éléments*/
	margin: 0;            
	padding: 0;
	z-index: 10;
	
	/*CSS3 transition*/
        -webkit-transition: all 1s;
	-moz-transition: all 1s;
	-o-transition: all 1s;
	transition: all 1s;
}
#sContent li {
	display: inline;      /*on aligne les éléments du slideshow*/
}

#slideshow .next, #slideshow .prev {
	position: absolute;
	top: 65px;
	z-index: 20;
}
#slideshow .prev { left: 0; }
#slideshow .next { right: 0; }

/* initialisation */
#slideshow .next, #slideshow .prev { display: none; }
#slideshow .next1 { display: block; }

/* Vers 1ère étape */
#s1:target #sContent { left: 0px; }
#s1:target .next, #s1:target .prev { display: none; }
#s1:target .next1 { display: block; }

/* Vers 2ème étape */
#s2:target #sContent { left: -150px; } /*ou -100%*/
#s2:target .next, #s2:target .prev { display: none; }
#s2:target .next2, #s2:target .prev2 { display: block; }

/* Vers 3ème étape */
#s3:target #sContent { left: -300px; } /*ou -200%*/
#s3:target .next, #s3:target .prev { display: none; }
#s3:target .prev3 { display: block; }

Voir l'exemple

Tout réside dans les petits "blocs-étape". Pour chaque étape nous avons dans l'ordre :

  • la position du bloc #sContent
  • tous les liens à faire disparaître
  • afficher uniquement les liens qui permettent le passage aux autres étapes

    Pour le reste, l'animation est prévue par la propriété transition sur #sContent.

    Voilà mon idée pour combiner :target et transition pour monter un slideshow assez facilement. Bien sûr le code HTML est redondant, et bien sûr la mise à jour d'un tel système est loin d'être aisée (pas autant qu'en JavaScript), mais c'est quand même intéressant d'y parvenir avec CSS !

    Voici une page sur laquelle j'ai procédé à mes premiers tests : Slideshow et Webdesign en CSS3