Inleiding

Een dynamische fotogalerij bouwen met filter- en sorteermogelijkheden verandert een statische beeldcollectie in een boeiende, gebruiksvriendelijke ervaring. Bezoekers kunnen snel beelden vinden die overeenkomen met hun interesses. Bijvoorbeeld filteren op natuur, stad of mensen en herschikken van resultaten op naam, datum of waardering zonder pagina herladen. Dit artikel biedt een uitgebreide, productiegerichte benadering om een dergelijke galerie te creëren met behulp van gewone JavaScript, HTML en CSS. Je leert hoe je je markering kunt structureren, efficiënt filteren en sorteren, prestaties kunt verbeteren met luie laden en de beste praktijken op de toegankelijkheid volgt. De uiteindelijke galerie zal responsief, onderhoudsbaar en gemakkelijk uit te voeren zijn.

De HTML-structuur instellen

Een goed gestructureerde HTML-fundatie maakt filteren en sorteren eenvoudig. Elk image-element moet aangepaste attributen bevatten die de categorie, naam, datum of andere eigenschap beschrijven die u wilt filteren of sorteren.

Basisopmaak voor filters en sorteerknoppen

Maak een container aan voor filterknoppen en een andere voor het sorteren van controles. Gebruik elementen met en ] attributen:

<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>

Inclusief en verbetert de toegankelijkheid voor gebruikers van schermlezers. De knop wordt gemarkeerd met een klasse om de begintoestand aan te geven; je stijlt dit met CSS.

Afbeeldingsgalerij Container

Plaats in een elke foto in zijn eigen wikkelelement. Gebruik , , , en ] attributen voor het filteren en sorteren. Bijvoorbeeld:

<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>

De attribuut stelt het laden van off-screen beelden uit, waardoor de eerste pagina laadprestaties verbetert. Elke fotowikkel kan ook een bijschrift of overlay bevatten voor aanvullende informatie.

Gegevensattributen effectief gebruiken

Gegevensattributen (bijv. ], ] zijn niet beperkt tot tekenreeksen. Voor het numeriek sorteren, slaan nummers op als tekenreeksen; JavaScript zal ze ontleden indien nodig. Voor meerdere categorieën kunt u een spatie-afzonderlijke lijst zoals opslaan en splitsen tijdens het filteren. Deze techniek laat beelden onder meerdere filters verschijnen, een functie die we later zullen implementeren. Zie voor een uitgebreide referentie over gegevensattributen de MDN documentatie op de dataset API.

De galerie styling met CSS

Een schone, responsieve lay-out stelt het podium voor de interactieve functies. Gebruik CSS Grid of Flexbox voor het raster van foto's, en style de knoppen om actieve filters en sorteerstatus aan te geven.

Opmaak van het fotoraster

.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);
}

Dit raster zorgt ervoor dat de beelden zich aanpassen aan de schermgrootte. Het zweefeffect voegt een subtiele zoominteractie toe, waardoor de galerie zich meer gepolijst voelt.

Actieve staat voor knoppen

#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;
}

De toepassing van de klasse op de huidige filter/sort-knop geeft visuele feedback. JavaScript zal het toevoegen en verwijderen van deze klasse beheren.

Responsieve overwegingen

Zorg ervoor dat de galerie werkt op touch-apparaten. Verhoog de knop touch doel maten tot ten minste 44px door 44px (WCAG 2.1 aanbeveling). Gebruik media queries indien nodig om over te schakelen van een multi-kolom raster naar een enkele kolom op zeer kleine schermen.

Uitvoering van JavaScript Filtering

Nu brengen we de gallerie tot leven. Het kernidee: luister naar klikken op filterknoppen, laat dan foto-elementen zien of verbergt op basis van hun attribuut.

DOM-elementen selecteren en initialiseren

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

Het opslaan .2]] als een array geeft ons gemakkelijk toegang tot array methoden zoals .2]] en .6.2]]. We houden ook de huidige filter en sorteren orde, zodat we opnieuw kunnen sorteren na een filterverandering.

Logica filteren

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);
}

Deze functie ondersteunt meerdere categorieën: als , dan kiest u of ..nou" of ..landscape zal de foto tonen. Opmerking: geeft de waarde van (als een tekenreeks). Met wordt de multi-categorie case behandeld.

EventLuisteraars aan filterknoppen koppelen

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);
 });
});

Het verwijderen van de klasse van alle knoppen en het toevoegen aan de geklikte zorgt voor visuele consistentie. De functie wordt aangeroepen met de geselecteerde filterwaarde.

Uitvoering JavaScript Sorteren

Sorteren reorganiseert de zichtbare foto's in de DOM op basis van een gekozen attribuut (bijv. naam, datum, beoordeling).

Sorteerfunctie

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));
}

Sorteren werkt alleen op zichtbare foto's, wat betekent dat na een filterverandering u de volgorde volgens het actieve type herstelt. Voor strings gebruiken we ] voor de juiste alfabetische volgorde. Data worden vergeleken met Datum objecten, en de ratings zijn gesorteerd in aflopende volgorde (meest populair eerst).

Eventluisteraars voor sorteerknoppen

sortButtons.forEach(button => {
 button.addEventListener('click', () => {
 const sortBy = button.dataset.sort;
 sortButtons.forEach(btn => btn.classList.remove('active'));
 button.classList.add('active');
 sortPhotos(sortBy);
 });
});

Als er op een sorteerknop wordt geklikt, werken we de actieve klasse bij en bellen we met de gewenste sorteersleutel. Omdat al aanroept ] blijft de galerie consistent.

Initiële instelling

// 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');

Oproepen zorgt er bij het begin voor dat de gallerij gevuld is met alle afbeeldingen en gesorteerd wordt op het standaardtype (naam).

Geavanceerd filteren en zoeken

Een eenvoudig categoriefilter is nuttig, maar u kunt meerdere filters combineren of een tekstzoekinvoer toevoegen. De volgende verbeteringen bouwen op de kernlogica.

Meerdere categoriefilters (controlevakken)

In plaats van exclusieve knoppen, gebruik checkboxen zodat gebruikers kunnen kiezen uit meerdere categorieën:

<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>

Pas vervolgens de filterlogica aan om een reeks actieve categorieën te bouwen:

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);
}

Als er geen selectievakjes zijn aangevinkt, kunt u ervoor kiezen om alle afbeeldingen te tonen (zoals in de bovenstaande code) of geen enkele te tonen.

Tekstinvoer

Voeg een invoerveld toe dat titels zoekt of het -attribuut:

<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);
});

Combineer zoeken met filterknoppen om de resultaten verder te kunnen vernauwen. Merk op dat u de huidige filterstatus moet opslaan om deze te respecteren tijdens het zoeken.

Prestaties en toegankelijkheid

Een dynamische galerij moet snel en bruikbaar zijn voor iedereen, inclusief mensen die behulpzame technologieën gebruiken.

Lui laden van afbeeldingen

We hebben al gebruikt die het laden uitstelt totdat de afbeelding in de buurt van de viewport is. Voor oudere browsers kunt u een JavaScript lui-loaden terugval uitvoeren met behulp van de Intersectie-waarnemer API. Dit zorgt ervoor dat zelfs als native lui laden niet wordt ondersteund, off-screen-afbeeldingen niet worden geladen, waardoor de bandbreedte wordt verminderd en de waargenomen prestaties worden verbeterd.

Zoekinvoer wordt afgewezen

Als u de zoekluisteraar aan koppelt, brandt hij op elke toetsaanslag. Voor grote galeries, overweeg dan om de handler (bijvoorbeeld 200m vertraging) te ontbinden om buitensporige DOM manipulaties te voorkomen. Een eenvoudig debounce hulpprogramma:

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 adding aria-pressed attributes 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>

Na elke filter/sortering actie, de tekst van dat element bijwerken, bijvoorbeeld, . .Toon 8 natuurfoto's gesorteerd op naam. Dit helpt gebruikers die vertrouwen op schermlezers begrijpen wat veranderd.

CSS voor verborgen inhoud

In plaats van alleen te gebruiken, overwegen we om een CSS-klasse te gebruiken zoals die het element verbergt en verwijdert uit de toegankelijkheidsboom:

.hidden {
 display: none !important;
 visibility: hidden;
}

Gebruik verwijdert elementen uit de toegankelijkheidsboom, wat passend is. Zorg er alleen voor dat je niet alleen vertrouwt op zonder omdat dat het element de ruimte in beslag neemt.

Conclusie

Door schone semantische HTML, responsieve CSS en goed gestructureerde JavaScript te combineren, kunt u een dynamische fotogalerij bouwen die snel, toegankelijk en aangenaam te gebruiken is. De technieken die zijn behandeld met filtering per categorie (inclusief meerdere categorieën), sorteren op verschillende attributen, toevoegen van tekst zoeken, en het optimaliseren van prestaties te bieden een solide basis die kan worden uitgebreid met functies zoals paginatie, oneindige scroll, of integratie met een backend API.

Voor verdere lezing, de MDN documentatie op Array.prototype.sort() legt het sorteeralgoritme uit, en de web.dev responsieve ontwerphandleiding] biedt extra layout tips. Experimenteren met verschillende gegevens attributen, animaties en aangepaste styling om de galerij aan te passen aan uw projectbehoeften. Het resultaat is een krachtige, interactieve component die gebruikers in controle van hun browse-ervaring brengt.