Html5
Css3
Sidebar
Filtre
Catalogue
Checkbox
Range
Responsive
Navigation
Snippet
Barre latérale de filtres en HTML5 et CSS3 pur avec cases à cocher, curseurs de prix, sections dépliantes et bouton reset pour catalogue.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="copyright" content="AngularForAll" />
<meta name="author" content="AngularForAll" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="public, max-age=604800" />
<title>Snippets Sidebarfilter HTML CSS 2026 05011610 | AngularForAll</title>
<style>
:root {
--primary: #6366f1;
--primary-light: #e0e7ff;
--bg: #f8fafc;
--sidebar-bg: #ffffff;
--text: #1e293b;
--text-light: #64748b;
--border: #e2e8f0;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
}
/* Layout principal */
.app-container {
display: flex;
min-height: 100vh;
position: relative;
}
/* Overlay mobile */
.sidebar-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 998;
opacity: 0;
visibility: hidden;
transition: var(--transition);
}
.sidebar-overlay.active {
opacity: 1;
visibility: visible;
}
/* Sidebar */
.sidebar {
width: 320px;
background: var(--sidebar-bg);
border-right: 1px solid var(--border);
height: 100vh;
position: sticky;
top: 0;
overflow-y: auto;
transition: var(--transition);
z-index: 999;
flex-shrink: 0;
}
.sidebar::-webkit-scrollbar {
width: 6px;
}
.sidebar::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 3px;
}
.sidebar-header {
padding: 1.5rem;
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
position: sticky;
top: 0;
background: var(--sidebar-bg);
z-index: 2;
}
.sidebar-header h2 {
font-size: 1.25rem;
font-weight: 700;
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn-clear {
background: none;
border: none;
color: var(--primary);
cursor: pointer;
font-size: 0.875rem;
font-weight: 500;
padding: 0.25rem 0.75rem;
border-radius: 0.5rem;
transition: var(--transition);
}
.btn-clear:hover {
background: var(--primary-light);
}
.btn-close-sidebar {
display: none;
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--text);
padding: 0.25rem;
}
/* Filtres actifs */
.active-filters {
padding: 1rem 1.5rem;
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
border-bottom: 1px solid var(--border);
}
.filter-tag {
display: inline-flex;
align-items: center;
gap: 0.25rem;
background: var(--primary-light);
color: var(--primary);
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 500;
}
.filter-tag .remove-tag {
cursor: pointer;
margin-left: 0.25rem;
opacity: 0.7;
transition: var(--transition);
}
.filter-tag .remove-tag:hover {
opacity: 1;
}
/* Sections de filtres */
.filter-sections {
padding: 0.5rem 0;
}
.filter-section {
border-bottom: 1px solid var(--border);
}
.filter-section-header {
padding: 1rem 1.5rem;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
user-select: none;
transition: var(--transition);
}
.filter-section-header:hover {
background: var(--bg);
}
.filter-section-header h3 {
font-size: 0.938rem;
font-weight: 600;
}
.filter-section-header .arrow {
transition: transform 0.3s;
font-size: 0.75rem;
color: var(--text-light);
}
.filter-section-header.open .arrow {
transform: rotate(180deg);
}
.filter-section-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.filter-section-content.open {
max-height: 500px;
}
.filter-section-body {
padding: 0 1.5rem 1rem;
}
/* Catégories */
.category-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.category-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
border-radius: 0.5rem;
cursor: pointer;
transition: var(--transition);
font-size: 0.875rem;
}
.category-item:hover {
background: var(--bg);
}
.category-item.active {
background: var(--primary-light);
color: var(--primary);
font-weight: 500;
}
.category-count {
margin-left: auto;
color: var(--text-light);
font-size: 0.75rem;
}
/* Fourchette de prix */
.price-inputs {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
.price-input {
flex: 1;
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 0.5rem;
font-size: 0.875rem;
transition: var(--transition);
}
.price-input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px var(--primary-light);
}
.price-separator {
color: var(--text-light);
}
.btn-apply-price {
width: 100%;
padding: 0.5rem;
background: var(--primary);
color: white;
border: none;
border-radius: 0.5rem;
cursor: pointer;
font-weight: 500;
transition: var(--transition);
}
.btn-apply-price:hover {
opacity: 0.9;
}
/* Notes */
.rating-option {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0;
cursor: pointer;
transition: var(--transition);
}
.rating-option:hover {
color: var(--primary);
}
.stars {
color: #f59e0b;
font-size: 0.875rem;
}
.rating-option input[type="checkbox"] {
margin-right: 0.5rem;
accent-color: var(--primary);
}
/* Couleurs */
.colors-grid {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.color-option {
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
border: 2px solid transparent;
transition: var(--transition);
position: relative;
}
.color-option:hover {
transform: scale(1.1);
}
.color-option.active {
border-color: var(--primary);
box-shadow: 0 0 0 2px white, 0 0 0 4px var(--primary);
}
.color-option[data-color="noir"] { background: #1a1a1a; }
.color-option[data-color="blanc"] { background: #f5f5f5; border: 2px solid #ddd; }
.color-option[data-color="rouge"] { background: #dc2626; }
.color-option[data-color="bleu"] { background: #2563eb; }
.color-option[data-color="vert"] { background: #16a34a; }
.color-option[data-color="jaune"] { background: #f59e0b; }
.color-option[data-color="violet"] { background: #7c3aed; }
/* Tailles */
.sizes-grid {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.size-option {
min-width: 48px;
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 0.5rem;
text-align: center;
cursor: pointer;
font-size: 0.875rem;
transition: var(--transition);
background: white;
}
.size-option:hover {
border-color: var(--primary);
}
.size-option.active {
background: var(--primary);
color: white;
border-color: var(--primary);
}
.size-option.disabled {
opacity: 0.4;
cursor: not-allowed;
text-decoration: line-through;
}
/* Marques */
.brand-search {
width: 100%;
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 0.5rem;
margin-bottom: 0.5rem;
font-size: 0.875rem;
transition: var(--transition);
}
.brand-search:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px var(--primary-light);
}
.brand-list {
display: flex;
flex-direction: column;
gap: 0.25rem;
max-height: 200px;
overflow-y: auto;
}
.brand-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
cursor: pointer;
border-radius: 0.5rem;
transition: var(--transition);
}
.brand-item:hover {
background: var(--bg);
}
.brand-item input[type="checkbox"] {
accent-color: var(--primary);
}
/* Contenu principal */
.main-content {
flex: 1;
padding: 2rem;
}
.main-content h1 {
font-size: 2rem;
margin-bottom: 1rem;
}
.btn-toggle-sidebar {
display: none;
padding: 0.75rem 1.5rem;
background: var(--primary);
color: white;
border: none;
border-radius: 0.5rem;
cursor: pointer;
font-weight: 500;
margin-bottom: 1rem;
transition: var(--transition);
}
.btn-toggle-sidebar:hover {
opacity: 0.9;
}
/* Compteur résultats */
.results-count {
color: var(--text-light);
margin-bottom: 1rem;
}
.loading-indicator {
display: none;
text-align: center;
padding: 2rem;
}
.loading-indicator.active {
display: block;
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid var(--border);
border-top-color: var(--primary);
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin: 0 auto;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Responsive */
@media (max-width: 768px) {
.sidebar {
position: fixed;
left: -320px;
top: 0;
height: 100vh;
z-index: 999;
}
.sidebar.open {
left: 0;
box-shadow: 4px 0 20px rgba(0,0,0,0.3);
}
.btn-toggle-sidebar {
display: block;
}
.btn-close-sidebar {
display: block;
}
}
</style>
</head>
<body>
<div class="app-container">
<!-- Overlay -->
<div class="sidebar-overlay" id="sidebarOverlay"></div>
<!-- Sidebar -->
<aside class="sidebar" id="sidebar">
<div class="sidebar-header">
<h2>
<span>🔍</span> Filtres
</h2>
<div style="display: flex; align-items: center; gap: 0.5rem;">
<button class="btn-clear" onclick="clearAllFilters()">
Tout effacer
</button>
<button class="btn-close-sidebar" onclick="closeSidebar()">
✕
</button>
</div>
</div>
<!-- Filtres actifs -->
<div class="active-filters" id="activeFilters"></div>
<!-- Sections de filtres -->
<div class="filter-sections">
<!-- Catégories -->
<div class="filter-section">
<div class="filter-section-header open" onclick="toggleSection(this)">
<h3>📁 Catégories</h3>
<span class="arrow">▼</span>
</div>
<div class="filter-section-content open">
<div class="filter-section-body">
<ul class="category-list" id="categoryList">
<li class="category-item active" data-category="all" onclick="filterCategory('all', this)">
Tout <span class="category-count">120</span>
</li>
<li class="category-item" data-category="electronics" onclick="filterCategory('electronics', this)">
Électronique <span class="category-count">34</span>
</li>
<li class="category-item" data-category="clothing" onclick="filterCategory('clothing', this)">
Vêtements <span class="category-count">28</span>
</li>
<li class="category-item" data-category="home" onclick="filterCategory('home', this)">
Maison <span class="category-count">22</span>
</li>
<li class="category-item" data-category="sports" onclick="filterCategory('sports', this)">
Sports <span class="category-count">18</span>
</li>
<li class="category-item" data-category="beauty" onclick="filterCategory('beauty', this)">
Beauté <span class="category-count">18</span>
</li>
</ul>
</div>
</div>
</div>
<!-- Prix -->
<div class="filter-section">
<div class="filter-section-header open" onclick="toggleSection(this)">
<h3>💰 Prix</h3>
<span class="arrow">▼</span>
</div>
<div class="filter-section-content open">
<div class="filter-section-body">
<div class="price-inputs">
<input type="number" class="price-input" placeholder="Min" id="priceMin" value="0">
<span class="price-separator">—</span>
<input type="number" class="price-input" placeholder="Max" id="priceMax" value="1000">
</div>
<button class="btn-apply-price" onclick="applyPriceFilter()">
Appliquer
</button>
</div>
</div>
</div>
<!-- Notes -->
<div class="filter-section">
<div class="filter-section-header" onclick="toggleSection(this)">
<h3>⭐ Notes</h3>
<span class="arrow">▼</span>
</div>
<div class="filter-section-content">
<div class="filter-section-body">
<label class="rating-option">
<input type="checkbox" value="4" onchange="applyRatingFilter()">
<span class="stars">★★★★☆</span>
<span>& plus</span>
</label>
<label class="rating-option">
<input type="checkbox" value="3" onchange="applyRatingFilter()">
<span class="stars">★★★☆☆</span>
<span>& plus</span>
</label>
<label class="rating-option">
<input type="checkbox" value="2" onchange="applyRatingFilter()">
<span class="stars">★★☆☆☆</span>
<span>& plus</span>
</label>
</div>
</div>
</div>
<!-- Couleurs -->
<div class="filter-section">
<div class="filter-section-header" onclick="toggleSection(this)">
<h3>🎨 Couleurs</h3>
<span class="arrow">▼</span>
</div>
<div class="filter-section-content">
<div class="filter-section-body">
<div class="colors-grid" id="colorsGrid">
<div class="color-option" data-color="noir" onclick="toggleColor(this)" title="Noir"></div>
<div class="color-option" data-color="blanc" onclick="toggleColor(this)" title="Blanc"></div>
<div class="color-option" data-color="rouge" onclick="toggleColor(this)" title="Rouge"></div>
<div class="color-option" data-color="bleu" onclick="toggleColor(this)" title="Bleu"></div>
<div class="color-option" data-color="vert" onclick="toggleColor(this)" title="Vert"></div>
<div class="color-option" data-color="jaune" onclick="toggleColor(this)" title="Jaune"></div>
<div class="color-option" data-color="violet" onclick="toggleColor(this)" title="Violet"></div>
</div>
</div>
</div>
</div>
<!-- Tailles -->
<div class="filter-section">
<div class="filter-section-header" onclick="toggleSection(this)">
<h3>📏 Tailles</h3>
<span class="arrow">▼</span>
</div>
<div class="filter-section-content">
<div class="filter-section-body">
<div class="sizes-grid" id="sizesGrid">
<div class="size-option" data-size="XS" onclick="toggleSize(this)">XS</div>
<div class="size-option" data-size="S" onclick="toggleSize(this)">S</div>
<div class="size-option active" data-size="M" onclick="toggleSize(this)">M</div>
<div class="size-option" data-size="L" onclick="toggleSize(this)">L</div>
<div class="size-option" data-size="XL" onclick="toggleSize(this)">XL</div>
<div class="size-option disabled" data-size="XXL">XXL</div>
</div>
</div>
</div>
</div>
<!-- Marques -->
<div class="filter-section">
<div class="filter-section-header" onclick="toggleSection(this)">
<h3>🏷️ Marques</h3>
<span class="arrow">▼</span>
</div>
<div class="filter-section-content">
<div class="filter-section-body">
<input type="text" class="brand-search" placeholder="Rechercher une marque..." oninput="searchBrands(this.value)">
<div class="brand-list" id="brandList">
<label class="brand-item">
<input type="checkbox" value="apple" onchange="applyBrandFilter()"> Apple
</label>
<label class="brand-item">
<input type="checkbox" value="samsung" onchange="applyBrandFilter()"> Samsung
</label>
<label class="brand-item">
<input type="checkbox" value="nike" onchange="applyBrandFilter()"> Nike
</label>
<label class="brand-item">
<input type="checkbox" value="adidas" onchange="applyBrandFilter()"> Adidas
</label>
<label class="brand-item">
<input type="checkbox" value="sony" onchange="applyBrandFilter()"> Sony
</label>
<label class="brand-item">
<input type="checkbox" value="lg" onchange="applyBrandFilter()"> LG
</label>
</div>
</div>
</div>
</div>
</div>
</aside>
<!-- Contenu principal -->
<main class="main-content">
<button class="btn-toggle-sidebar" onclick="openSidebar()">
☰ Filtres
</button>
<h1>Produits</h1>
<p class="results-count" id="resultsCount">120 résultats trouvés</p>
<div class="loading-indicator" id="loadingIndicator">
<div class="spinner"></div>
<p>Chargement...</p>
</div>
<div id="productsGrid">
<p style="color: var(--text-light);">
← Utilisez les filtres dans la barre latérale pour affiner les résultats.
Sur mobile, cliquez sur le bouton "Filtres".
</p>
</div>
</main>
</div>
<script>
// État des filtres
const filterState = {
category: 'all',
priceMin: 0,
priceMax: 1000,
ratings: [],
colors: [],
sizes: ['M'],
brands: []
};
// Gestion des sections accordéon
function toggleSection(header) {
const content = header.nextElementSibling;
const isOpen = content.classList.contains('open');
header.classList.toggle('open');
content.classList.toggle('open');
}
// Gestion sidebar mobile
function openSidebar() {
document.getElementById('sidebar').classList.add('open');
document.getElementById('sidebarOverlay').classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeSidebar() {
document.getElementById('sidebar').classList.remove('open');
document.getElementById('sidebarOverlay').classList.remove('active');
document.body.style.overflow = '';
}
document.getElementById('sidebarOverlay').addEventListener('click', closeSidebar);
// Fermer avec Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeSidebar();
});
// Filtre catégorie
function filterCategory(category, element) {
filterState.category = category;
document.querySelectorAll('.category-item').forEach(item => {
item.classList.remove('active');
});
element.classList.add('active');
updateActiveFilters();
applyAllFilters();
}
// Filtre prix
function applyPriceFilter() {
filterState.priceMin = parseFloat(document.getElementById('priceMin').value) || 0;
filterState.priceMax = parseFloat(document.getElementById('priceMax').value) || 1000;
updateActiveFilters();
applyAllFilters();
}
// Filtre notes
function applyRatingFilter() {
filterState.ratings = Array.from(document.querySelectorAll('.rating-option input:checked'))
.map(input => parseInt(input.value));
updateActiveFilters();
applyAllFilters();
}
// Filtre couleurs
function toggleColor(element) {
const color = element.dataset.color;
element.classList.toggle('active');
if (element.classList.contains('active')) {
filterState.colors.push(color);
} else {
filterState.colors = filterState.colors.filter(c => c !== color);
}
updateActiveFilters();
applyAllFilters();
}
// Filtre tailles
function toggleSize(element) {
if (element.classList.contains('disabled')) return;
const size = element.dataset.size;
element.classList.toggle('active');
if (element.classList.contains('active')) {
filterState.sizes.push(size);
} else {
filterState.sizes = filterState.sizes.filter(s => s !== size);
}
updateActiveFilters();
applyAllFilters();
}
// Filtre marques
function applyBrandFilter() {
filterState.brands = Array.from(document.querySelectorAll('.brand-item input:checked'))
.map(input => input.value);
updateActiveFilters();
applyAllFilters();
}
function searchBrands(query) {
const brands = document.querySelectorAll('.brand-item');
brands.forEach(brand => {
const text = brand.textContent.toLowerCase();
brand.style.display = text.includes(query.toLowerCase()) ? 'flex' : 'none';
});
}
// Mise à jour des tags de filtres actifs
function updateActiveFilters() {
const container = document.getElementById('activeFilters');
let tags = [];
if (filterState.category !== 'all') {
tags.push({
label: `Catégorie: ${filterState.category}`,
clear: () => {
filterState.category = 'all';
document.querySelectorAll('.category-item').forEach(item => {
item.classList.remove('active');
if (item.dataset.category === 'all') item.classList.add('active');
});
updateActiveFilters();
applyAllFilters();
}
});
}
if (filterState.priceMin > 0 || filterState.priceMax < 1000) {
tags.push({
label: `Prix: ${filterState.priceMin}€ - ${filterState.priceMax}€`,
clear: () => {
filterState.priceMin = 0;
filterState.priceMax = 1000;
document.getElementById('priceMin').value = 0;
document.getElementById('priceMax').value = 1000;
updateActiveFilters();
applyAllFilters();
}
});
}
filterState.ratings.forEach(rating => {
tags.push({
label: `${'★'.repeat(rating)}${'☆'.repeat(5-rating)} & plus`,
clear: () => {
filterState.ratings = filterState.ratings.filter(r => r !== rating);
document.querySelectorAll('.rating-option input').forEach(input => {
if (parseInt(input.value) === rating) input.checked = false;
});
updateActiveFilters();
applyAllFilters();
}
});
});
filterState.colors.forEach(color => {
tags.push({
label: `Couleur: ${color}`,
clear: () => {
filterState.colors = filterState.colors.filter(c => c !== color);
document.querySelector(`.color-option[data-color="${color}"]`)?.classList.remove('active');
updateActiveFilters();
applyAllFilters();
}
});
});
filterState.sizes.forEach(size => {
tags.push({
label: `Taille: ${size}`,
clear: () => {
filterState.sizes = filterState.sizes.filter(s => s !== size);
document.querySelector(`.size-option[data-size="${size}"]`)?.classList.remove('active');
updateActiveFilters();
applyAllFilters();
}
});
});
filterState.brands.forEach(brand => {
tags.push({
label: `Marque: ${brand}`,
clear: () => {
filterState.brands = filterState.brands.filter(b => b !== brand);
document.querySelector(`.brand-item input[value="${brand}"]`).checked = false;
updateActiveFilters();
applyAllFilters();
}
});
});
container.innerHTML = tags.map(tag => `
<span class="filter-tag">
${tag.label}
<span class="remove-tag" onclick="arguments[0].stopPropagation();">×</span>
</span>
`).join('');
// Attacher les événements de suppression
container.querySelectorAll('.remove-tag').forEach((btn, index) => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
tags[index].clear();
});
});
}
// Tout effacer
function clearAllFilters() {
filterState.category = 'all';
filterState.priceMin = 0;
filterState.priceMax = 1000;
filterState.ratings = [];
filterState.colors = [];
filterState.sizes = [];
filterState.brands = [];
document.querySelectorAll('.category-item').forEach(item => {
item.classList.remove('active');
if (item.dataset.category === 'all') item.classList.add('active');
});
document.getElementById('priceMin').value = 0;
document.getElementById('priceMax').value = 1000;
document.querySelectorAll('.rating-option input').forEach(input => {
input.checked = false;
});
document.querySelectorAll('.color-option').forEach(option => {
option.classList.remove('active');
});
document.querySelectorAll('.size-option').forEach(option => {
option.classList.remove('active');
});
document.querySelectorAll('.brand-item input').forEach(input => {
input.checked = false;
});
updateActiveFilters();
applyAllFilters();
}
// Application des filtres (simulation)
function applyAllFilters() {
const loading = document.getElementById('loadingIndicator');
loading.classList.add('active');
// Simuler un chargement
setTimeout(() => {
loading.classList.remove('active');
console.log('Filtres appliqués:', filterState);
// Mise à jour du compteur (simulation)
const randomCount = Math.floor(Math.random() * 50) + 10;
document.getElementById('resultsCount').textContent =
`${randomCount} résultats trouvés`;
}, 500);
}
// Initialisation
updateActiveFilters();
</script>
</body>
</html>
Télécharger le fichier source