E-commerce : optimiser le temps de chargement

Une seconde de chargement en plus = 7% de conversions en moins. Sur un site e-commerce, la performance n'est pas un luxe technique, c'est du chiffre d'affaires. Voici comment optimiser concrètement.

L'impact business de la performance

Les chiffres sont sans appel :

-7%
conversions par seconde
53%
abandon si >3s mobile
+2s
= bounce rate x2
SEO
facteur de ranking Google

Exemple concret

Un site e-commerce à 100 000€/mois qui passe de 4s à 2s de chargement peut espérer +15-20% de conversions, soit 15-20k€/mois supplémentaires. L'optimisation se rentabilise en quelques semaines.

Mesurer avant d'optimiser

Pas d'optimisation à l'aveugle. Mesurez d'abord.

Outils de mesure

  • Google PageSpeed Insights : score et recommandations
  • GTmetrix : waterfall détaillé
  • WebPageTest : tests multi-localisation
  • Chrome DevTools : analyse réseau et performance
  • Core Web Vitals : métriques Google (LCP, FID, CLS)

Métriques clés à suivre

LCP (Largest Contentful Paint) : <2.5s - temps avant affichage du contenu principal
FID (First Input Delay) : <100ms - réactivité aux interactions
CLS (Cumulative Layout Shift) : <0.1 - stabilité visuelle
TTFB (Time To First Byte) : <600ms - temps de réponse serveur

Les images : 60% du problème

Sur un site e-commerce, les images produits représentent souvent 60-80% du poids des pages. C'est là qu'il faut commencer.

Format moderne : WebP et AVIF

                
HTML avec fallback
<!-- Format moderne avec fallback --> <picture> <source srcset="product.avif" type="image/avif"> <source srcset="product.webp" type="image/webp"> <img src="product.jpg" alt="Produit"> </picture>

Gains typiques : WebP = -30% vs JPEG. AVIF = -50% vs JPEG. Sur une fiche produit avec 5 images, ça peut représenter 500KB économisés.

Lazy loading natif

                
Lazy loading
<!-- Ne charge que quand visible --> <img src="product.webp" loading="lazy" decoding="async" alt="Produit" > <!-- SAUF pour les images above-the-fold --> <img src="hero.webp" loading="eager" fetchpriority="high" alt="Hero" >

Images responsives

                
Srcset pour différentes tailles
<img srcset=" product-400.webp 400w, product-800.webp 800w, product-1200.webp 1200w " sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px" src="product-800.webp" alt="Produit" >

Erreur courante : Servir des images 2000px sur mobile. Un smartphone n'a pas besoin de plus de 400-600px de large pour une image produit.

Le cache : ne pas refaire ce qui est déjà fait

Cache navigateur

                
Configuration Nginx
# Assets statiques : cache long location ~* \.(css|js|jpg|jpeg|png|webp|avif|gif|ico|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } # HTML : cache court avec revalidation location ~* \.html$ { expires 1h; add_header Cache-Control "public, must-revalidate"; }

CDN (Content Delivery Network)

Pourquoi un CDN est essentiel

Un CDN distribue vos assets sur des serveurs proches de vos utilisateurs. Un visiteur à Marseille ne charge pas les images depuis un serveur parisien.

Options populaires : Cloudflare (gratuit pour commencer), AWS CloudFront, Fastly, BunnyCDN.

Cache applicatif

                
Cache des requêtes lourdes (Laravel)
// Cache la liste des catégories (change rarement) $categories = Cache::remember('categories', 3600, function() { return Category::with('children')->get(); }); // Cache les produits populaires $popular = Cache::remember('products.popular', 900, function() { return Product::popular()->take(12)->get(); });

JavaScript : le tueur silencieux

Le JavaScript bloque le rendu et consomme du CPU. Sur mobile, c'est souvent le principal facteur de lenteur.

Charger intelligemment

                
Chargement optimisé
<!-- Critique : dans le head avec defer --> <script src="critical.js" defer></script> <!-- Non-critique : chargé après --> <script src="analytics.js" async></script> <!-- Widgets externes : lazy load --> <script> // Charge le chat uniquement après interaction document.addEventListener('scroll', function loadChat() { const script = document.createElement('script'); script.src = 'https://chat-widget.com/embed.js'; document.body.appendChild(script); document.removeEventListener('scroll', loadChat); }, { once: true }); </script>

Les coupables habituels

  • Widgets de chat : souvent 200-500KB de JS
  • Pixels de tracking : Facebook, Google, etc. s'accumulent
  • Sliders/carousels : bibliothèques lourdes pour peu de valeur
  • Polyfills inutiles : support de vieux navigateurs non nécessaire

Code splitting

                
Import dynamique (React/Vue)
// Charge le composant checkout uniquement sur la page panier const Checkout = lazy(() => import('./Checkout')); // Charge la galerie uniquement quand nécessaire const ProductGallery = lazy(() => import('./ProductGallery'));

CSS : render-blocking minimisé

CSS critique inline

                
Head optimisé
<head> <!-- CSS critique inline pour le first paint --> <style> /* Header, hero, navigation - above the fold */ .header { ... } .hero { ... } </style> <!-- CSS complet chargé en async --> <link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> </head>

Purger le CSS inutilisé

Un thème e-commerce charge souvent 200-500KB de CSS dont 70% n'est jamais utilisé. Des outils comme PurgeCSS ou UnCSS suppriment automatiquement le code mort.

Base de données : les requêtes qui tuent

Sur une page catégorie avec 50 produits, une requête N+1 peut générer 150+ requêtes SQL au lieu de 3.

Eager loading obligatoire

                
Requêtes optimisées
// MAUVAIS : N+1 queries $products = Product::all(); foreach ($products as $product) { $product->category->name; // 1 requête par produit! $product->images; // encore 1 requête! } // BON : 3 requêtes total $products = Product::with(['category', 'images', 'brand'])->get();

Index sur les colonnes filtrées

                
Index essentiels e-commerce
-- Recherche par catégorie + tri CREATE INDEX idx_products_category_price ON products(category_id, price); -- Filtres courants CREATE INDEX idx_products_filters ON products(category_id, brand_id, in_stock, price); -- Recherche texte CREATE FULLTEXT INDEX idx_products_search ON products(name, description);

Checklist d'optimisation e-commerce

Images

  • ☐ Format WebP/AVIF avec fallback
  • ☐ Lazy loading sur les images below-the-fold
  • ☐ Images responsives (srcset)
  • ☐ Compression optimisée (qualité 80-85%)
  • ☐ Dimensions correctes (pas de redimensionnement CSS)

Cache & CDN

  • ☐ CDN configuré pour les assets
  • ☐ Headers cache appropriés
  • ☐ Cache applicatif sur les données stables
  • ☐ Page cache pour les pages publiques

Code

  • ☐ JS defer/async approprié
  • ☐ CSS critique inline
  • ☐ Minification JS/CSS
  • ☐ Code splitting
  • ☐ Suppression des scripts inutiles

Backend

  • ☐ Eager loading des relations
  • ☐ Index sur les colonnes filtrées
  • ☐ TTFB < 600ms
  • ☐ Compression Gzip/Brotli

Besoin d'aide sur votre projet ?

Je peux vous accompagner dans le développement ou l'optimisation de votre application.

Me contacter