Optimiser l'UX d'une boutique PrestaShop : menu, scroll infini et navigation
Guide complet pour améliorer l'expérience utilisateur PrestaShop : menu déroulant avec compteur produits, scroll infini maîtrisé, navigation sticky et bonnes pratiques UX.
En bref : Guide complet pour optimiser l'UX d'une boutique PrestaShop : menu déroulant avec compteur de produits (requête SQL optimisée), scroll infini maîtrisé via bouton de chargement, header sticky en CSS moderne, et checklist UX complète avant mise en production.
Introduction
L'expérience utilisateur d'une boutique en ligne conditionne directement le taux de conversion. Un menu peu ergonomique, un scroll infini qui masque le footer, un favicon oublié… ces détails apparemment mineurs font fuir les visiteurs sans qu'ils sachent toujours pourquoi.
Dans cet article, je passe en revue les optimisations UX les plus fréquentes sur une boutique PrestaShop, avec le code correspondant et les bonnes pratiques à appliquer dès la mise en ligne.
Menu déroulant avec compteur de produits par catégorie
Afficher le nombre de produits dans chaque catégorie du menu est un excellent levier UX : le visiteur sait immédiatement où se concentre l'offre, ce qui réduit les clics inutiles et améliore la navigation.
Approche sur PrestaShop 1.6
Sur PrestaShop 1.6, on pouvait créer une méthode statique dans un module personnalisé de thème :
// modules/montheme/montheme.php
public static function countProductInCat($id_category)
{
$category = new Category((int) $id_category, (int) Context::getContext()->language->id);
return $category->getProducts(
(int) Context::getContext()->language->id,
1,
1,
null,
null,
true // count_only = true
);
}
Puis dans le template Smarty du header :
<ul class="sub-menu">
{foreach from=$menu item=item}
<li class="menu-item">
<a href="{$link->getCategoryLink($item.id_category)}">
{$item.name} ({MonTheme::countProductInCat($item.id_category)})
</a>
</li>
{/foreach}
</ul>
Attention aux performances : cette méthode exécute une requête SQL par catégorie à chaque chargement de page. Sur un catalogue conséquent, cela peut dégrader sérieusement les temps de réponse.
Approche optimisée pour PrestaShop 8.x
Sur PrestaShop 8.x, privilégiez une requête SQL unique avec cache :
use PrestaShop\PrestaShop\Adapter\Entity\Category;
public static function getCategoryProductCounts(int $id_lang): array
{
$cacheKey = 'category_product_counts_' . $id_lang;
if (!Cache::isStored($cacheKey)) {
$sql = 'SELECT cp.id_category, COUNT(DISTINCT cp.id_product) AS total
FROM ' . _DB_PREFIX_ . 'category_product cp
INNER JOIN ' . _DB_PREFIX_ . 'product_shop ps
ON cp.id_product = ps.id_product
AND ps.id_shop = ' . (int) Context::getContext()->shop->id . '
AND ps.active = 1
GROUP BY cp.id_category';
$results = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
$counts = [];
foreach ($results as $row) {
$counts[(int) $row['id_category']] = (int) $row['total'];
}
Cache::store($cacheKey, $counts);
}
return Cache::retrieve($cacheKey);
}
Cette approche réduit les appels SQL de N requêtes (une par catégorie) à une seule requête globale, mise en cache pour le reste de la requête HTTP.
Maîtriser le scroll infini sans sacrifier le footer
Le scroll infini est séduisant pour les catalogues visuels (mode, déco, textile), mais il pose un problème majeur : le footer devient inaccessible. Or le footer contient les mentions légales, les liens de réassurance, les coordonnées — autant d'éléments obligatoires et rassurants pour l'acheteur.
La solution : scroll infini déclenché par bouton
Plutôt qu'un chargement automatique permanent, implémentez un bouton « Charger plus de produits » :
// assets/js/infinite-scroll.js
document.addEventListener('DOMContentLoaded', function () {
const loadMoreBtn = document.getElementById('load-more-products');
let currentPage = 1;
if (!loadMoreBtn) return;
loadMoreBtn.addEventListener('click', function () {
currentPage++;
const url = `${window.location.pathname}?page=${currentPage}`;
fetch(url, {
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(response => response.text())
.then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const newProducts = doc.querySelectorAll('.product-miniature');
if (newProducts.length === 0) {
loadMoreBtn.style.display = 'none';
return;
}
const container = document.getElementById('product-list');
newProducts.forEach(product => container.appendChild(product));
})
.catch(error => console.error('Erreur chargement produits:', error));
});
});
Cette approche préserve l'accès au footer tout en gardant l'aspect dynamique du chargement progressif.
Ajouter des ancres de navigation rapide
Complétez avec des boutons de navigation vers le haut et le bas de page :
/* assets/css/navigation-helpers.css */
.scroll-nav-btn {
position: fixed;
right: 20px;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: var(--primary-color, #4F46E5);
color: #fff;
border: none;
cursor: pointer;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.8;
transition: opacity 0.3s ease;
}
.scroll-nav-btn:hover {
opacity: 1;
}
.scroll-to-top { bottom: 70px; }
.scroll-to-bottom { bottom: 20px; }
Point important : assurez-vous que les boutons de navigation sont visuellement distincts et utilisent des icônes explicites (flèches). Un carré coloré sans icône ne sera pas compris par les visiteurs.
Menu sticky : garder la navigation accessible
Un header fixe qui suit le défilement améliore considérablement la navigation, surtout sur les pages longues (catalogues, fiches produits détaillées).
Implémentation CSS moderne
/* assets/css/sticky-header.css */
.main-header {
position: sticky;
top: 0;
z-index: 1030;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
transition: box-shadow 0.3s ease;
}
Préférez position: sticky à position: fixed (ou à la classe Bootstrap navbar-fixed-top de l'époque 1.6). Le sticky conserve le flux naturel du document et ne nécessite pas de padding compensatoire sur le body.
Menu déroulant : slideToggle plutôt que slideDown
Un menu qui ne peut que s'ouvrir sans se refermer est une source de frustration. L'erreur classique est d'utiliser slideDown() au clic sans gérer la fermeture.
Le problème
// ❌ Le menu s'ouvre mais ne se referme jamais au clic
$('.dropdown').click(function (event) {
event.stopPropagation();
$('.sub-menu').slideDown();
});
La solution
// ✅ Le menu bascule entre ouvert et fermé
$('#dropdownMenu').click(function (e) {
e.preventDefault();
$(this).find('.sub-menu').slideToggle('fast');
$(this).toggleClass('is-open');
});
// Fermer le menu au clic en dehors
$(document).on('click', function (e) {
if (!$(e.target).closest('#dropdownMenu').length) {
$('.sub-menu').slideUp('fast');
$('#dropdownMenu').removeClass('is-open');
}
});
Bonne pratique : utilisez un id plutôt qu'une class pour cibler un menu unique, et ajoutez une classe d'état (is-open) pour pouvoir styler le menu selon son état (rotation de la flèche, changement de couleur).
Approche moderne sans jQuery (PrestaShop 8.x)
PrestaShop 8.x s'éloigne progressivement de jQuery. Voici l'équivalent en JavaScript natif :
const dropdown = document.getElementById('dropdownMenu');
const submenu = dropdown?.querySelector('.sub-menu');
if (dropdown && submenu) {
dropdown.addEventListener('click', function (e) {
e.preventDefault();
submenu.classList.toggle('is-visible');
dropdown.classList.toggle('is-open');
});
document.addEventListener('click', function (e) {
if (!dropdown.contains(e.target)) {
submenu.classList.remove('is-visible');
dropdown.classList.remove('is-open');
}
});
}
.sub-menu {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.sub-menu.is-visible {
max-height: 500px;
}
Checklist UX avant mise en production
Avant de livrer une boutique PrestaShop, vérifiez systématiquement ces points :
Éléments obligatoires
- **Favicon personnalisé** : le favicon PrestaShop par défaut trahit un site non finalisé. Générez toutes les tailles nécessaires (16x16, 32x32, 180x180 pour Apple Touch) et placez-les dans `img/favicon/`.
- **Mentions légales** : obligatoires en France (CGV, CGU, politique de confidentialité). Leur absence expose à des sanctions.
- **Liens sociaux fonctionnels** : vérifiez que chaque lien pointe vers la bonne page et s'ouvre dans un nouvel onglet (`target="_blank"` avec `rel="noopener noreferrer"`).
Éléments de réassurance
- **Délais de livraison clairs** : « Livraison en 48h » est plus vendeur que « Expédition sous 48h ». Le client veut savoir quand il recevra son colis, pas quand il partira de l'entrepôt.
- **Hiérarchie visuelle du panier** : le bouton panier doit être plus visible que les icônes sociales. L'objectif principal reste l'achat.
- **Séparateurs non ambigus** : évitez le tiret `-` comme séparateur dans les informations de prix ou de livraison. Il peut être confondu avec un signe négatif. Utilisez plutôt `|` ou `·`.
Éléments de confort
- **Produits mis en valeur** : sur fond blanc uniforme, les fiches produits se fondent dans le décor. Ajoutez des bordures subtiles, des ombres légères ou un fond légèrement contrasté pour les zones produits.
- **Navigation retour visible** : un bouton back-to-top est indispensable dès que la page dépasse deux écrans de hauteur.
Conclusion
L'optimisation UX d'une boutique PrestaShop ne se résume pas à choisir un beau thème. Ce sont les détails d'interaction — un menu qui se replie, un footer accessible, une hiérarchie visuelle cohérente — qui font la différence entre un site amateur et une boutique professionnelle qui convertit. Prenez le temps d'auditer chaque page avec un regard critique avant la mise en production, et n'hésitez pas à solliciter des retours extérieurs : ce que vous trouvez évident ne l'est jamais pour vos visiteurs.
Questions fréquentes
Tout ce que vous devez savoir sur ce sujet.
Un projet PrestaShop ?
Discutons-en directement.
193 projets livrés
Lire sur le blog

Alexandre Carette
Expert PrestaShop & Architecture E-commerce
Développeur PrestaShop depuis 2014, 193 projets livrés. Je conçois des architectures headless Nuxt + PrestaShop et des outils d'automatisation IA pour les e-commerçants.