civil-and-structural-engineering
Création d'une galerie de photos dynamique avec filtres et tri en utilisant Javascript
Table of Contents
Présentation
La création d'une galerie de photos dynamique avec des capacités de filtrage et de tri transforme une collection d'images statiques en une expérience conviviale et stimulante. Les visiteurs peuvent rapidement trouver des images qui correspondent à leurs intérêts – par exemple, filtrage par nature, ville ou personnes – et réorganiser les résultats par nom, date ou notation sans recharger une page. Cet article propose une approche complète et prête à la production pour créer une telle galerie en utilisant un JavaScript, un HTML et un CSS simples.
Configuration de la structure HTML
Chaque élément d'image doit porter des attributs personnalisés qui décrivent sa catégorie, son nom, sa date ou toute autre propriété que vous souhaitez filtrer ou trier.
Markup de base pour filtres et contrôles de tri
Créer un conteneur pour les boutons de filtre et un autre pour les contrôles de tri. Utilisez des éléments avec et des attributs:
<div id="controls">
<div id="filter-buttons" role="group" aria-label="Filter photos by category">
<button data-filter="all" class="active">Show All</button>
<button data-filter="nature">Nature</button>
<button data-filter="city">City</button>
<button data-filter="people">People</button>
</div>
<div id="sort-options" role="group" aria-label="Sort photos">
<button data-sort="name">Sort by Name</button>
<button data-sort="date">Sort by Date</button>
<button data-sort="rating">Sort by Rating</button>
</div>
</div>
Inclure et améliore l'accessibilité pour les utilisateurs de lecteurs d'écran. Le bouton est marqué d'une classe pour indiquer l'état initial; vous allez le styler avec CSS.
Galerie d'images Conteneur
Dans un , placez chaque photo dans son propre élément d'emballage. Utilisez , , et des attributs pour le filtrage et le tri. Par exemple:
<div id="gallery" class="photo-grid">
<div class="photo" data-category="nature" data-name="Sunset Over the Hills" data-date="2023-06-15" data-rating="4.5">
<img src="images/sunset.jpg" alt="Sunset over rolling hills" loading="lazy">
<div class="photo-caption">Sunset Over the Hills</div>
</div>
<div class="photo" data-category="city" data-name="Downtown Skyline" data-date="2023-07-01" data-rating="4.2">
<img src="images/skyline.jpg" alt="Downtown skyline at dusk" loading="lazy">
<div class="photo-caption">Downtown Skyline</div>
</div>
<!-- more photos -->
</div>
L'attribut reporte le chargement des images hors écran, améliorant ainsi la performance de charge initiale de la page. Chaque enveloppe photo peut également inclure une légende ou une superposition pour plus d'informations.
Utilisation efficace des attributs de données
Les attributs de données[ (p. ex., ], ) ne sont pas limités aux chaînes. Pour le tri numérique, stocker les numéros comme chaînes; JavaScript les analysera au besoin. Pour plusieurs catégories, vous pouvez stocker une liste séparée de l'espace comme et la diviser pendant le filtrage. Cette technique permet aux images d'apparaître sous plusieurs filtres, une fonctionnalité que nous allons implémenter plus tard. Pour une référence complète sur les attributs de données, voir la documentation MDN sur l'API de l'ensemble de données.
Styling de la galerie avec CSS
Une mise en page propre et réactive permet de définir la scène des fonctions interactives. Utilisez CSS Grid ou Flexbox pour la grille des photos, et stylez les boutons pour indiquer les filtres actifs et l'état de tri.
Présentation du réseau de photos
.photo-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
padding: 1rem 0;
}
.photo {
position: relative;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.photo img {
width: 100%;
height: auto;
display: block;
transition: transform 0.3s ease;
}
.photo:hover img {
transform: scale(1.05);
}
Cette grille permet aux images de s'adapter à la taille de l'écran. L'effet de survol ajoute une interaction subtile de zoom, rendant la galerie plus polie.
État actif pour les boutons
#filter-buttons button.active,
#sort-options button.active {
background-color: #007acc;
color: #fff;
border-color: #007acc;
}
button {
padding: 0.5rem 1rem;
border: 1px solid #ccc;
background: #fff;
cursor: pointer;
margin: 0.25rem;
border-radius: 4px;
transition: background 0.2s, color 0.2s;
}
button:hover {
background: #e6e6e6;
}
L'application de la classe au bouton filtre/sort actuel permet de faire des commentaires visuels. JavaScript va gérer l'ajout et la suppression de cette classe.
Considérations sensibles
Assurez-vous que la galerie fonctionne sur les appareils tactiles. Augmentez la taille des cibles tactiles à au moins 44px par 44px (recommandation WCAG 2.1). Utilisez les requêtes multimédias si nécessaire pour passer d'une grille multicolonne à une seule colonne sur de très petits écrans.
Mise en œuvre du filtrage JavaScript
Maintenant, nous mettons la galerie en vie. L'idée centrale : écouter les clics sur les boutons de filtre, puis afficher ou masquer des éléments photo en fonction de leur attribut .
Sélection des éléments DOM et initialisation
const filterButtons = document.querySelectorAll('#filter-buttons button');
const sortButtons = document.querySelectorAll('#sort-options button');
const gallery = document.getElementById('gallery');
let photos = Array.from(gallery.children);
let activeFilter = 'all';
let activeSort = 'name'; // default sort
Stocker comme tableau nous donne un accès facile aux méthodes de tableau comme et . Nous gardons également une trace du filtre actuel et trions l'ordre afin de pouvoir ré-appliquer le tri après un changement de filtre.
Logique de filtrage
function filterPhotos(filter) {
activeFilter = filter;
photos.forEach(photo => {
const categories = photo.dataset.category; // may be a space-separated string
const shouldShow = filter === 'all' || categories.split(' ').includes(filter);
photo.style.display = shouldShow ? '' : 'none';
});
// After filtering, re-sort the visible photos
sortPhotos(activeSort);
}
Cette fonction prend en charge plusieurs catégories : si , alors choisir soit ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Joindre les auditeurs d'événements aux boutons de filtrage
filterButtons.forEach(button => {
button.addEventListener('click', () => {
const filter = button.dataset.filter;
// Update active class on filter buttons
filterButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
// Apply filter
filterPhotos(filter);
});
});
En supprimant la classe de tous les boutons et en l'ajoutant à la classe cliquée, on assure la cohérence visuelle. La fonction est appelée avec la valeur de filtre sélectionnée.
Mise en œuvre du tri JavaScript
Trier réorganise les photos visibles dans le DOM en fonction d'un attribut choisi (p. ex. nom, date, cote).
Fonction de tri
function sortPhotos(sortBy) {
activeSort = sortBy;
// Get currently visible photos (display not 'none')
const visiblePhotos = photos.filter(photo => photo.style.display !== 'none');
visiblePhotos.sort((a, b) => {
let valA, valB;
switch (sortBy) {
case 'name':
valA = a.dataset.name.toLowerCase();
valB = b.dataset.name.toLowerCase();
return valA.localeCompare(valB);
case 'date':
valA = new Date(a.dataset.date);
valB = new Date(b.dataset.date);
return valA - valB;
case 'rating':
valA = parseFloat(a.dataset.rating);
valB = parseFloat(b.dataset.rating);
return valB - valA; // descending: highest first
default:
return 0;
}
});
// Re‑append sorted photos back to the gallery container
visiblePhotos.forEach(photo => gallery.appendChild(photo));
}
Le tri fonctionne uniquement sur des photos visibles, ce qui signifie que, après un changement de filtre, vous rétablissez l'ordre selon le type actif. Pour les chaînes, nous utilisons pour l'ordre alphabétique approprié. Les dates sont comparées avec les objets Date, et les cotes sont triées dans l'ordre décroissant (le plus populaire en premier).
Auditeurs d'événements pour les boutons de tri
sortButtons.forEach(button => {
button.addEventListener('click', () => {
const sortBy = button.dataset.sort;
sortButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
sortPhotos(sortBy);
});
});
Lorsqu'un bouton tri est cliqué, nous mettons à jour la classe active et appelons avec la touche de tri souhaitée. Parce que appelle déjà après le filtrage, la galerie reste cohérente.
Configuration initiale
// Set default active buttons
document.querySelector('#filter-buttons [data-filter="all"]').classList.add('active');
document.querySelector('#sort-options [data-sort="name"]').classList.add('active');
// Load and initially sort by name
filterPhotos('all');
Appeler au début assure que la galerie est peuplée avec toutes les images et triée par le tri par défaut (nom).
Filtrage et recherche avancés
Un simple filtre de catégorie est utile, mais vous pouvez combiner plusieurs filtres ou ajouter une entrée de recherche de texte. Les améliorations suivantes s'appuient sur la logique de base.
Filtres de catégorie multiples (boîtes à cocher)
Au lieu de boutons exclusifs, utilisez des cases à cocher pour que les utilisateurs puissent sélectionner plusieurs catégories :
<div id="filter-checkboxes">
<label><input type="checkbox" value="nature" checked> Nature</label>
<label><input type="checkbox" value="city" checked> City</label>
<label><input type="checkbox" value="people" checked> People</label>
</div>
Modifiez ensuite la logique de filtrage pour construire un ensemble de catégories actives :
function filterPhotosByCheckboxes() {
const checked = document.querySelectorAll('#filter-checkboxes input:checked');
const activeCategories = Array.from(checked).map(cb => cb.value);
photos.forEach(photo => {
const photoCategories = photo.dataset.category.split(' ');
const shouldShow = activeCategories.length === 0 ||
photoCategories.some(cat => activeCategories.includes(cat));
photo.style.display = shouldShow ? '' : 'none';
});
sortPhotos(activeSort);
}
Si aucune case à cocher n'est cochée, vous pouvez choisir de montrer toutes les images (comme dans le code ci-dessus) ou de ne pas afficher – définir l'UX désiré.
Entrée de recherche de texte
Ajouter un champ d'entrée qui recherche les légendes ou l'attribut :
<input type="text" id="search" placeholder="Search photos...">
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', () => {
const query = searchInput.value.toLowerCase();
photos.forEach(photo => {
const name = photo.dataset.name.toLowerCase();
// Also search in caption if present
const caption = photo.querySelector('.photo-caption')?.innerText.toLowerCase() || '';
const matches = name.includes(query) || caption.includes(query);
// If a filter is active, also check category
const filter = activeFilter;
const catMatch = filter === 'all' || photo.dataset.category.split(' ').includes(filter);
photo.style.display = (matches && catMatch) ? '' : 'none';
});
sortPhotos(activeSort);
});
Combinez la recherche avec les boutons de filtre pour permettre de réduire les résultats plus loin. Notez que vous devez stocker l'état actuel du filtre pour le respecter pendant la recherche.
Performance et accessibilité
Une galerie dynamique devrait être rapide et utilisable par tous, y compris les personnes utilisant des technologies d'assistance.
Chargement des images paresseux
Nous avons déjà utilisé qui reporte le chargement jusqu'à ce que l'image soit près du port de vue. Pour les navigateurs plus anciens, vous pouvez implémenter un retour JavaScript paresseux en utilisant l'API . Cela garantit que même si le chargement natif paresseux n'est pas supporté, les images hors écran ne sont pas chargées, réduisant la bande passante et améliorant les performances perçues.
Dénomination de l'entrée de recherche
Si vous attachez l'auditeur de recherche à , il allume chaque frappe. Pour les grandes galeries, envisager de débouncer le gestionnaire (p. ex., 200ms de retard) pour éviter les manipulations excessives DOM.
function debounce(func, delay) { let timeoutId; return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } searchInput.addEventListener('input', debounce(handleSearch, 200));Keyboard Navigation
Filter and sort buttons should be focusable and operable via keyboard. Using native
<button>elements already provides keyboard interaction (Enter/Space). Ensure that after filtering or sorting, focus is managed logically; for example, you could move focus to the first photo after a filter change via a focusable element. Also, consider addingaria-pressedattributes to filter buttons to indicate toggle state.Announcing Changes to Screen Readers
Use an ARIA live region to announce filter and sort results:
<div id="gallery-announce" aria-live="polite" class="sr-only"></div>Après chaque action de filtre/sort, mettez à jour le texte de cet élément, par exemple, -Afficher 8 photos de nature triées par nom. Cela aide les utilisateurs qui comptent sur les lecteurs d'écran à comprendre ce qui a changé.
CSS pour le contenu caché
Au lieu d'utiliser seul, envisagez d'utiliser une classe CSS comme qui cache l'élément et l'enlève de l'arborescence d'accessibilité :
.hidden { display: none !important; visibility: hidden; }En utilisant , vous supprimez des éléments de l'arbre d'accessibilité, ce qui est approprié. Assurez-vous simplement que vous ne vous fiez qu'à sans parce que cela laisse l'élément occupant de l'espace.
Conclusion
En combinant HTML sémantique propre, CSS réactif et JavaScript bien structuré, vous pouvez construire une galerie de photos dynamique qui est rapide, accessible et agréable à utiliser. Les techniques couvertes – filtrage par catégorie (y compris les catégories multiples), tri par différents attributs, ajout de recherche de texte et optimisation des performances – fournissent une base solide qui peut être étendue avec des fonctionnalités comme la pagination, le défilement infini ou l'intégration avec une API backend.
Pour plus de détails, la documentation MDN sur Array.prototype.sort()[ explique l'algorithme de tri, et le guide de conception web.dev réceptif offre des conseils supplémentaires de mise en page. Expérimentez avec différents attributs de données, animations et style personnalisé pour adapter la galerie aux besoins de votre projet.