Wprowadzenie

Building a dynamic photo gallery with filtering andsorting capabilities transformas a static image a stattion into an engaging, user-friendly experience. Visitors can quickly find images that match their interests - for example, filtering by nature, city, or conclusive - and reorder result by name, date, or rating with a page reload. This articles provides a conclutris a conclussive, production-ready approposition to such a gay using aid aid, aid, avalin, and.

Setting Up then HTML Structure

A well-structured HTML foundation makes filtering andd sorting prospectforward. Each image element should carry conserm indi.1; indiv1; FLT: 0 indiv3; indivationes that descripby its category, name, date, or any indivatir contribute you intend to filter or sort by.

Base Markup for Filtry i Sorting Controls

Stwórz container for filter buttons and anotherr for sorting controls. Usie english 1; english 1; fLT: 1 english 3; english 3; elements witch english 1; english 1; english 1; english 3; english 3; english 3; english 3; english 3; english:

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

Including Xi1; Xi1; FLT: 5 XI3; XI3; XI1; FLT: 6 XI3; XI3; improwizuje accessibility for screen reacer users. The XI1; XI1; FLT: 7 XI3; XI3; button is marked with a class Xi1; XI1; FLT: 8 XI3; XI3; tO indicate thee inigal state; you 'll style e this with CSS.

Inside a dem1; dem1; FLT: 9; dem3; dem3;, place each photo in its own wrapper element. Usie dem1; mand1; FLT: 10; mand3; mand3;, mande 1; mande; mandżawce: 11; mandżawce; mandżawce: 12; mandżawce; mandżawce: 13; mandżawce: 3; mandżawce: mand. mandsorting. For example:

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

Thee Booking 1; Xion1; FLT: 15 XI3; Xion3; actribute defers loading of off-screen images, improwing g initional page load performance. Each photo wrapper can also include a caption our overlay for additional information.

Using Data Attributes Effectively

B-1; FLT: 0-3; FLT: 0-3; Data-3; FLT: 1-3; FLT: 1-3; FLT: 1-3; FLT: 16-3; FLT: 16-3; FLT: 17-3; FLT: 17-3; FLT: 1R-3; FLT: 1S-3;) Are not limited to-strings. For-nutrical sorting, story-a-strings; FLT: JavaScript will parse them as needed. For multiple-contriories, you can store a space-separate lix like ampe 1r-1; FLT: 18-3d; And-3d-split duriing-ing.

A clean, responsive layout sets the stage for the interacte factories. Usie CSS Grid or Flexbox for thee grid of photos, and style thee buttons to indicate active filters andd sorting state.

Layout Grid Photo

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

This grid ensures images adampt to screen size. The hover effect adds a subtle zoom interactive on, making the gallery feel more polished.

Przyciski Active State for

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

Thompying the hee head1; Xion1; FLT: 21 Xion3; Xion3; class to the current filter / sort button provides visaal feedback. JavaScript will manage adding and removing this class.

Odpowiedzi

Ensure thee gallery works on touch devices. Increase button touch target sizes to at leaset 44px by 44px (WCAG 2.1 recommendation). Usie media queries if necessary ty to switch from a multi-column grid to a single column on very small screens.

Wdrażanie JavaScript Filtering

Nie mamy czasu na to, by się z nimi skontaktować.

Selecting DOM Elements andInitializazing

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

Storing Xi1; Xi1; FLT: 24 XI3; Xi3; as an array gives us easys accords to o array methods like Xi1; Xi1; FLT: 25 XI3; XI3; AND XI1; XI1; FLT: 26 XI3; XI3;. We also keep track of the streat filter andd sort order so we we can re-appey sorting after a filter change.

Filtering Logic

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

This function supports multiple private: if vir1; Ig1; FLT: 28 contribution 3; Ig3;, then choosing either supports; nature contribution quentiles; or quantiquentiquentes; landscape contribute quentios; will show the photo. Iglo1; FLT: 0 contribute 3; Igloo61; Igloo63; Igloo61; Igloo61; Igloo61; Igloo6x3e; Igloo6e-category case: 30; Igloo63; Igloo6g). Using; Ig. 1; Igloo61; Igloo633ehd; Igloo6e multi-case.

Attaching Event Listeners to Filtr Przyciski

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

Removing thee hee behin1; Xi1; FLT: 33 Xi3; Xi3; class frem all buttons andadding it to the clicked one ensures visaal considency. The Xion1; Xion1; FLT: 34 Xion3; Xion3; cffiction is called with thee selected filter value.

Wdrażanie JavaScript Sorting

Sorting reorganizates the visible photos in the DOM based on a chosen accesse (np., name, date, rating).

Function Sortinga

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

Sorting works only on visible photos, which means after a filter change you recore the order according to the activite sort. For strings, we use indict 1; indi1; FLT: 36 contribution 3; indisation 3; for proper alphanical ordering. Dates are compared as Date objects, and ratings are sorted in descourding order (most popular first).

Event Listeners for Sort Buttons

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

When a sort button is clicked, we update thee activete class andcall indis1; indis1; FLT: 38 contribution 3; indis3; wigh the desired sort key. Becausie indis1; indis1; FLT: 39 contributes 3; endis3; already calls indis1; endis3; fLT: 40 contribution 3; after filtering, the gallery consistent.

Inicjal Setup

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

Calling Beyon1; Calling; Velon1; FLT: 42 Beyon3; Velon3; at start ensures the gallery is populated with all images and sorted bye the default sort (name).

Advanced Filtering andSearch

A simple category filter is useful, but you may want to combinate multiple filters or add a text search input. The following enhancements build on the core logic.

Filtry wielofunkcyjne (Checkboxes)

Instad of exclusivy buttons, use checkboxes so users can select multiple conclusories:

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

Then modify the filtering logic to build a set of active activies:

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

If no checkboxes are checked, you might choose te show all images (as in the code above) or show none - definite the desired UX.

Text Search Input

Add an input field that searches captions or the indic1; Addic1; FLT: 45 indic3; Addic3; Assione:

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

Combinate search ch witch filter buttons to allow narrowing results further. Note that you need to story thee current filter state te te to respect it during search.

Wykonanie i Accessibility

Dynamic galleria powinna być faset i usable by everyone, including gine using assistive technologies.

Leniwy Loading Images

We already used the viewport. For older browsers, you can implement a JavaScript lazy-loading fallback using thee measures 1; FLT: 0 measure 3; FLT: 0 measurant; Intersection Observer API 1; FLT: 1 measurant 3; FLT: 1 measurant; FLT; FLT: 1 measurant; FL3; FLS ensures that evene native lazy loading is not supported, off-shien izes are noe t loaded, reducing width and improwinved perceance.

Debouncing Search Input

If you attach the searchener to index1; inde1; FLT: 49 contain3; index3;, it fires on every keystroke. For large galleries, consider debouncing the handler (e.g., 200ms delay) to avoid excessive DOM manipulations. A simpliche debounce utility:

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>

After each filter / sort action, update thee text of that element, np., quenquentquit; Showing 8 nature photos sorted by by name. quentquenties; Thies helps users who rely on screen readers understand what changed.

CSS for Hidden Content

Instead of using present 1; informó1; FLT: 51 presenta3; informe3; alone, consider using a CSS class like presental; informe1; FLT: 52 presentable 3; informerate; that hidges the element and removes it frem the e accessibility tree:

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

Using presentat 1; Xi1; FLT: 54 presenta3; Xi3; does remove elements frem the accessibility tree, which ch is approvate. Just ensure you don 't rely solely on 1.55 extended 3; FLT: 55 extentail 3; VI1; FLT: 56 context 3; XI3; because that leafes the element overbying space.

Konkluzja

By combinang clean semantic HTML, responsive CSS, and well-structured JavaScript, you can build a dynamic photo gallery that is fass, accessible, and pleasant to use. The techniques covered - filtering by category (including multiple contributionies), sorting by various accordises, adding text search, and optimizing performance - provide a solid foundation that can best expended with viceures like pagination, infinite scroll, or intrition viton wita backend.

For further reading, the eng1; Xi1; FLT: 0 + 3; Xi3; MDN documentation on Array.prototype. Sort () Xi1; FLT: 1 + 3; FLT: 1 + 3; FLT: + 3; FLT: + 3; FLT: + 1 + FLT: + 1 + FLT; FLT: + 3 + FLT: + 3 + FLV + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +