Bonjour,
Il y a quelques temps j'ai codé des flip cards et les ai intégré à la code base de mon petit CMS. Voici une version de démonstration en statique : https://scriptura.github.io/page/articles.html
Et surtout voici un Code Pen : https://codepen.io/olivier-c/pen/WNWBpMG
Ça fonctionne avec ou sans JavaScript :
- en CSS les flip cards feront le minimum syndical mais sont accessibles au clavier (désactivez JS pour voir),
- avec JS l'expérience est améliorée mais je perds la possibilité d'atteindre le verso des cards avec le clavier.
J'ai tenté tout un tas de trucs plus ou moins complexes... pas très concluants (puisque je suis là !). L'exemple exposé ici est épuré de mes tentatives infructueuses, j'ai rétrogradé à une version moins usine à gaz avant de venir vers vous.
Voilà donc, je suis ouvert à vos suggestions pour rendre accessible ce script au clavier. Merci.
____
Le HTML :
Le CSS :
Le JS :
Modifié par Olivier C (30 Jun 2024 - 23:18)
Il y a quelques temps j'ai codé des flip cards et les ai intégré à la code base de mon petit CMS. Voici une version de démonstration en statique : https://scriptura.github.io/page/articles.html
Et surtout voici un Code Pen : https://codepen.io/olivier-c/pen/WNWBpMG
Ça fonctionne avec ou sans JavaScript :
- en CSS les flip cards feront le minimum syndical mais sont accessibles au clavier (désactivez JS pour voir),
- avec JS l'expérience est améliorée mais je perds la possibilité d'atteindre le verso des cards avec le clavier.
J'ai tenté tout un tas de trucs plus ou moins complexes... pas très concluants (puisque je suis là !). L'exemple exposé ici est épuré de mes tentatives infructueuses, j'ai rétrogradé à une version moins usine à gaz avant de venir vers vous.
Voilà donc, je suis ouvert à vos suggestions pour rendre accessible ce script au clavier. Merci.
____
Le HTML :
<div class="column-fix gap gap-bottom">
<article class="flip card" tabindex="0">
<section>
<h2 class="h2">
<a href="/page/article.html">Integer hendrerit</a>
</h2>
<p>Vivamus sodales eget eros ut euismod...</p>
</section>
<section>
<h2 class="h2">
<a href="/page/article.html">Integer hendrerit</a>
</h2>
<ul>
<li>Auteur : Anonyme</li>
<li>Créé le : 17/05/2024</li>
<li>Modifié le : 26/06/2024</li>
<li>Mots clés : Concombres, Carottes, Choux</li>
</ul>
</section>
</article>
</div>
Le CSS :
.flip {
display: grid;
perspective: 60em;
transform-style: preserve-3d; /* @note Utile pour les éléments enfants */
outline: none;
& > * {
grid-area: 1/-1; /* @note Évite un position absolute, les 2 éléments enfants de .flip s'adaptent donc l'un à l'autre, selon le contenu le plus conséquent des 2. */
backface-visibility: hidden;
transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition-duration: var(--flip-duration, 3s);
transition-property: transform, opacity;
cursor: pointer;
}
& > :last-child {
transform: rotateY(-180deg);
}
&.active {
& > * {
transition-duration: 1s;
}
& > :first-child {
transform: rotateY(180deg);
}
& > :last-child {
transform: rotateY(0deg);
}
}
@media (scripting: none) {
&:focus,
&:active {
& > * {
transition-duration: 1s;
}
& > :first-child {
transform: rotateY(180deg);
}
& > :last-child {
transform: rotateY(0deg);
}
}
}
}
Le JS :
'use strict'
const flipList = document.querySelectorAll('.flip')
let autoFlipTimeout, autoUnflipTimeout
let isAutoFlipping = true // Variable de contrôle
/**
* Script de démonstration permettant à l'utilisateur de comprendre qu'une action
* est possible sur la carte. Retourne automatiquement la première carte après n seconde
* et la remet à son état initial après n seconde.
*/
const autoFlipFirstCard = () => {
if (flipList.length > 0) {
autoFlipTimeout = setTimeout(() => {
flipList[0].classList.add('active')
autoUnflipTimeout = setTimeout(() => {
flipList[0].classList.remove('active')
isAutoFlipping = false // Processus automatique terminé
}, 1500)
}, 1000)
}
}
/**
* Gère l'événement de vue de page en mettant à jour le compteur de vues dans
* le stockage local et en retournant automatiquement la première carte si le
* compteur de vues est inférieur à n.
*
* @note Le compteur de vues est unique pour toutes les pages.
*/
const handlePageView = () => {
const pageViewed = 'demoFlipCard' // @note Un unique compteur pour toutes les pages.
let views = parseInt(localStorage.getItem(pageViewed)) || 0
views++
localStorage.setItem(pageViewed, views)
if (views < 4) {
autoFlipFirstCard()
}
}
handlePageView()
/**
* Ajoute un gestionnaire d'événements à chaque élément avec la classe 'flip'.
* Lorsqu'un élément est cliqué, il vérifie s'il possède déjà la classe 'active'.
* Si c'est le cas, il la supprime, sinon il l'ajoute.
* Si un autre élément a déjà la classe 'active', elle lui est retirée après 3 secondes.
* @param {NodeList} flipList Liste des éléments auxquels ajouter des gestionnaires d'événements.
*/
flipList.forEach(flip => {
flip.addEventListener('click', () => {
// Annuler le processus automatique si l'utilisateur clique sur la première carte flip
if (flip === flipList[0] && isAutoFlipping) {
clearTimeout(autoFlipTimeout)
clearTimeout(autoUnflipTimeout)
isAutoFlipping = false
}
if (flip.classList.contains('active')) {
flip.classList.remove('active')
} else {
document.querySelectorAll('.flip').forEach(element => {
if (element !== flip && element.classList.contains('active')) {
setTimeout(() => {
element.classList.remove('active')
}, 3000)
}
})
flip.classList.add('active')
}
})
// Enlever la classe .active lorsqu'un élément prend le focus
flip.addEventListener('focus', () => {
flip.classList.remove('active')
})
})
Modifié par Olivier C (30 Jun 2024 - 23:18)