Article SEO SEO Technique

Subdomain vs Subfolder

SEO Technique : Sous-domaine vs Sous-dossier (Subdomain vs Subfolder)

Introduction

Dans le paysage complexe du SEO technique, la question de choisir entre un sous-domaine (subdomain) et un sous-dossier (subfolder ou sous-répertoire) se pose fréquemment aux webmasters, développeurs et spécialistes du marketing digital. Ces deux structures jouent un rôle crucial dans l’organisation de votre site web et peuvent influencer la façon dont votre visibilité organique progresse dans le temps.

Contrairement à une idée reçue, il n’existe pas de règle absolue où l’un serait « toujours meilleur » que l’autre. En revanche, le choix a un impact direct sur :

  • la consolidation de l’autorité (backlinks, signaux de confiance, notoriété),
  • la vitesse de progression SEO d’un projet,
  • la complexité technique (hébergement, DNS, certificats SSL, analytics),
  • la gestion des données (Search Console, GA4, outils SEO),
  • la gestion des risques (sanctions, problèmes de qualité, expérimentations).

Cet article propose une analyse approfondie des différences entre sous-domaine et sous-dossier, des bonnes pratiques actuelles, des cas d’usage typiques (dont le SEO international) et des critères concrets pour faire le bon choix dans votre contexte.

Concepts clés : sous-domaine et sous-dossier

Avant d’aborder les implications SEO et techniques, il est essentiel de bien comprendre ce qu’est un sous-domaine et ce qu’est un sous-dossier, ainsi que la manière dont les moteurs de recherche les appréhendent.

Qu’est-ce qu’un sous-domaine (subdomain) ?

Un sous-domaine est une extension du domaine principal qui permet de créer une section distincte, souvent perçue comme un site séparé du point de vue des moteurs de recherche. Il se place avant le domaine racine dans l’URL. Par exemple, si votre domaine principal est example.com, des sous-domaines typiques seraient :

  • blog.example.com pour un blog éditorial,
  • shop.example.com pour une boutique en ligne,
  • support.example.com pour un centre d’aide,
  • fr.example.com ou de.example.com pour des versions internationales.

Les sous-domaines sont fréquemment utilisés lorsque l’on souhaite :

  • séparer des projets très distincts (app, SaaS, communauté, espace client),
  • donner une autonomie technique forte (CMS différent, stack technique séparée, hébergement ou équipe dédiée),
  • cloisonner des zones d’expérimentation ou des services qui n’ont pas le même positionnement que le site principal,
  • gérer des zones géographiques ou des entités légales fortement autonomes.

Dans la pratique, un sous-domaine se gère souvent comme un site presque indépendant : configuration DNS spécifique, certificat SSL dédié, property Search Console séparée, flux de données GA4 distinct, etc.

Qu’est-ce qu’un sous-dossier (subfolder ou sous-répertoire) ?

Un sous-dossier est une section du site située dans le même domaine, représentée sous forme de chemin après le domaine dans l’URL. Par exemple :

  • example.com/blog pour un blog intégré,
  • example.com/shop pour un e-commerce rattaché au site principal,
  • example.com/fr/, example.com/de/ pour des versions linguistiques,
  • example.com/ressources/ pour une bibliothèque de contenus.

Les sous-dossiers sont généralement utilisés pour :

  • organiser le contenu de manière hiérarchique et logique à l’intérieur d’un même site,
  • conserver une expérience utilisateur cohérente autour d’une marque ou d’un thème central,
  • profiter au maximum de la notoriété et des backlinks du domaine principal,
  • simplifier la gestion technique et l’analyse de données.

Principales différences SEO entre sous-domaine et sous-dossier

Sur le plan purement conceptuel, un moteur de recherche moderne est capable de traiter correctement les deux structures. En pratique, la différence majeure porte sur la consolidation des signaux SEO et la façon dont l’autorité se diffuse.

  • Sous-domaines : ils sont généralement traités comme des entités distinctes. L’autorité acquise par le domaine principal ne bénéficie pas automatiquement à un sous-domaine. Chaque sous-domaine doit donc construire sa propre autorité (contenus, liens, historique).
  • Sous-dossiers : ils font pleinement partie du même site. Les backlinks, la notoriété et les signaux de confiance du domaine principal profitent directement aux sous-dossiers. Le flux de liens internes et externes est plus naturellement partagé.

Cette différence de traitement impacte :

  • la vitesse à laquelle une nouvelle section peut se positionner,
  • le volume d’efforts SEO nécessaires pour faire émerger un projet,
  • la lisibilité de la structure pour les moteurs et pour les utilisateurs.

Sous-domaine vs sous-dossier : implications SEO détaillées

Impact sur l’autorité et le PageRank

Dans une structure en sous-dossiers, toute nouvelle page bénéficie plus rapidement de la force des liens et de la notoriété du domaine principal. Cela ne garantit pas un bon classement, mais facilite l’indexation et la capacité à se positionner sur des mots-clés concurrentiels, surtout lorsque le domaine racine est déjà solide.

Dans une structure en sous-domaines, chaque sous-domaine doit accumuler ses propres signaux : liens externes, signaux de marque, engagement utilisateur. Les liens internes entre domaine principal et sous-domaine existent, mais ils agissent davantage comme des backlinks entre sites différents que comme une simple redistribution interne d’autorité. Concrètement, cela peut ralentir la montée en puissance SEO d’un nouveau sous-domaine si aucun effort spécifique n’est consenti.

Indexation et crawl

Les moteurs de recherche gèrent la découverte et l’indexation des sous-domaines et des sous-dossiers, mais le budget de crawl et la priorisation peuvent varier selon la taille du site et sa popularité.

  • Avec des sous-dossiers, le robot voit un seul site structuré ; le crawl peut être plus facilement optimisé via le maillage interne, les sitemaps et les signaux globaux du domaine.
  • Avec plusieurs sous-domaines volumineux, le moteur doit allouer des ressources de crawl à chacun comme à des sites distincts, ce qui peut exiger une gestion plus fine des sitemaps, des fichiers robots.txt et des priorités.

La stratégie de liens internes est plus simple et plus puissante dans une architecture en sous-dossiers :

  • les liens internes restent dans le même site,
  • la répartition du link equity est plus directe,
  • la navigation et les breadcrumbs sont plus cohérents pour l’utilisateur.

Dans une architecture avec de nombreux sous-domaines, le maillage interne entre ces entités ressemble davantage à du netlinking entre sites différents, ce qui nécessite une stratégie plus élaborée pour tirer parti de la popularité globale de la marque.

Gestion des risques SEO

Le choix entre sous-domaine et sous-dossier influence aussi la manière dont les risques sont répartis :

  • En sous-dossier, un problème de qualité massif (contenu faible, spam, erreurs techniques graves) peut plus facilement impacter l’ensemble du domaine, car tout est fortement interconnecté.
  • En sous-domaine, un segment du site peut être isolé : une sanction ou un problème sérieux touche surtout le sous-domaine concerné, ce qui limite parfois les effets sur le domaine principal. En contrepartie, chaque sous-domaine demande une vigilance SEO propre.

Bonnes pratiques SEO : sous-domaine et sous-dossier

Quel que soit votre choix, les fondamentaux du SEO restent incontournables. Cependant, certains points prennent une importance spécifique selon la structure retenue.

Optimiser le contenu

Qu’il soit placé en sous-domaine ou en sous-dossier, le contenu doit :

  • répondre clairement à une intention de recherche précise,
  • cibler des mots-clés pertinents alignés avec vos objectifs business et les besoins de vos utilisateurs,
  • offrir une valeur ajoutée réelle (expertise, profondeur, exemples concrets),
  • être mis à jour régulièrement pour rester pertinent.

Dans une stratégie privilégiant les sous-dossiers, il est particulièrement efficace de créer des hubs thématiques (pages piliers) qui structurent votre contenu et redistribuent l’autorité vers des pages plus ciblées via un maillage interne optimisé.

Améliorer la structure du site

Une structure claire et logique est essentielle pour :

  • faciliter la compréhension de votre site par les moteurs de recherche,
  • offrir une expérience utilisateur intuitive,
  • réduire les problèmes de contenu orphelin ou de duplication.

Bonnes pratiques recommandées :

  • utiliser des URLs courtes et descriptives, lisibles par les humains,
  • éviter les niveaux de profondeur excessifs dans l’arborescence,
  • maintenir une cohérence sémantique entre l’URL, la balise </code>, la balise <code><h1></code> et le contenu,</li> <li>définir une <strong>navigation claire</strong> (menus, fil d’Ariane, blocs de liens internes contextuels).</li> </ul> <h3 id="creer-et-maintenir-un-maillage-interne-solide">Créer et maintenir un maillage interne solide</h3> <p>Le <strong>maillage interne</strong> est un levier majeur pour renforcer la cohérence et l’autorité de votre site :</p> <ul> <li>il aide les moteurs à comprendre quelles pages sont les plus importantes,</li> <li>il améliore la découverte de nouvelles pages,</li> <li>il redistribue l’autorité au sein du site.</li> </ul> <p>En structure sous-dossier, l’impact du maillage interne est particulièrement fort, car il s’exerce au sein d’un même domaine. En structure multi-sous-domaines, le maillage reste utile, mais il se combine avec une stratégie de liens externes plus soutenue.</p> <h3 id="strategie-de-liens-externes-backlinks">Stratégie de liens externes (backlinks)</h3> <p>Pour les sous-dossiers, il est souvent plus efficace de concentrer les efforts de netlinking vers le domaine principal et ses sections stratégiques, ce qui renforce l’ensemble de l’écosystème de pages.</p> <p>Pour les sous-domaines, il est nécessaire de <strong>développer des backlinks spécifiques</strong> vers chaque sous-domaine qui doit se positionner de manière compétitive. Les liens pointant uniquement vers le domaine principal ne suffisent pas toujours à rendre un sous-domaine performant sur des requêtes concurrentielles.</p> <h3 id="mise-en-place-d-une-strategie-multilingue-et-internationale">Mise en place d’une stratégie multilingue et internationale</h3> <p>Dans le cadre du <strong>SEO international</strong>, deux schémas d’URL sont couramment utilisés :</p> <ul> <li><strong>Sous-dossiers par langue</strong> : <em>example.com/fr/</em>, <em>example.com/de/</em>, <em>example.com/es/</em>. Cette approche permet de <strong>consolider l’autorité</strong> sur un seul domaine, de simplifier la gestion des balises <code>hreflang</code> et d’avoir une vision unifiée des performances internationales.</li> <li><strong>Sous-domaines par pays ou langue</strong> : <em>fr.example.com</em>, <em>de.example.com</em>, <em>es.example.com</em>. Ce choix est pertinent lorsque chaque marché dispose d’une <strong>autonomie forte</strong> (équipe locale, contenus, CMS, offres, contraintes légales) et nécessite une gestion technique indépendante.</li> </ul> <p>Dans la plupart des cas où la marque, l’offre et les équipes restent centralisées, les sous-dossiers sont privilégiés pour accélérer la visibilité globale et réduire la complexité.</p> <h2 id="outils-et-ressources-pour-gerer-sous-domaines-et-sous-dossiers">Outils et ressources pour gérer sous-domaines et sous-dossiers</h2> <p>Une bonne stratégie SEO technique pour sous-domaines et sous-dossiers s’appuie sur des outils permettant de :</p> <ul> <li>surveiller l’indexation et les performances,</li> <li>identifier les erreurs techniques,</li> <li>analyser les backlinks et le maillage,</li> <li>suivre les données par section ou par projet.</li> </ul> <h3 id="outils-essentiels-pour-le-seo-technique">Outils essentiels pour le SEO technique</h3> <ul> <li><strong>Google Search Console</strong> : indispensable pour surveiller l’indexation, les performances de recherche et les éventuelles erreurs. Chaque sous-domaine doit disposer de sa propre propriété si vous en utilisez plusieurs.</li> <li><strong>Google Analytics (GA4)</strong> : permet d’analyser le trafic et le comportement des utilisateurs. En structure multi-sous-domaines, il est souvent nécessaire de configurer des flux ou propriétés adaptés pour disposer d’une vue consolidée ou segmentée par entité.</li> <li><strong>Outils de crawl (type Screaming Frog, Sitebulb, etc.)</strong> : utiles pour auditer vos URLs, vérifier les structures internes, détecter les erreurs 4xx/5xx, problèmes de balisage, contenu dupliqué et anomalies de maillage.</li> <li><strong>Outils d’analyse de liens et de mots-clés</strong> (Ahrefs, Semrush, Moz, etc.) : permettent d’étudier l’autorité de votre domaine, la répartition des backlinks entre sous-domaines et sous-dossiers, ainsi que les opportunités de mots-clés pour vos différentes sections.</li> </ul> <h3 id="gestion-des-donnees-et-analytics">Gestion des données et analytics</h3> <p>La structure choisie a un impact direct sur la <strong>lecture des données</strong> :</p> <ul> <li>Avec des <strong>sous-dossiers</strong>, il est plus simple d’avoir une vision globale de tout le site dans une seule propriété Search Console ou GA4, tout en filtrant par chemin d’URL pour analyser une section précise.</li> <li>Avec plusieurs <strong>sous-domaines</strong>, vous devrez souvent gérer plusieurs propriétés ou flux, puis agréger les données au besoin. Cela ajoute une couche de complexité analytique, mais offre aussi une séparation plus nette par projet ou pays.</li> </ul> <h2 id="cas-d-usage-quand-choisir-un-sous-domaine-ou-un-sous-dossier">Cas d’usage : quand choisir un sous-domaine ou un sous-dossier ?</h2> <h3 id="quand-privilegier-un-sous-dossier">Quand privilégier un sous-dossier ?</h3> <p>Le <strong>sous-dossier</strong> est généralement recommandé dans les situations suivantes :</p> <ul> <li>vous traitez de <strong>thématiques liées à la même marque</strong> ou au même univers (blog, guides, documentation, landing pages, contenus commerciaux),</li> <li>vous souhaitez <strong>maximiser la transmission d’autorité</strong> du domaine principal à vos nouvelles sections,</li> <li>vous visez une <strong>croissance SEO rapide</strong> pour un nouveau type de contenu lié à votre activité,</li> <li>vous voulez <strong>centraliser la gestion</strong> technique, éditoriale et analytique au même endroit.</li> </ul> <p>Exemples typiques de bons candidats au sous-dossier :</p> <ul> <li>un blog étroitement lié à l’activité principale : <em>example.com/blog/</em>,</li> <li>une section ressources ou études de cas : <em>example.com/ressources/</em>,</li> <li>un espace de documentation produit : <em>example.com/docs/</em>,</li> <li>des versions linguistiques quand la marque reste la même et l’offre est très proche : <em>example.com/fr/</em>, <em>example.com/it/</em>.</li> </ul> <h3 id="quand-privilegier-un-sous-domaine">Quand privilégier un sous-domaine ?</h3> <p>Le <strong>sous-domaine</strong> devient pertinent lorsque la séparation doit être nette, qu’il s’agisse :</p> <ul> <li>d’un <strong>projet très distinct</strong> (par exemple, une application SaaS avec interface propre, un forum communautaire ou une plateforme de formation),</li> <li>d’une <strong>indépendance technique</strong> forte (technologie différente, hébergement séparé, équipe produit dédiée),</li> <li>d’une <strong>organisation internationale complexe</strong> où chaque pays dispose de ses propres équipes, contenus, stratégies et contraintes légales,</li> <li>d’un besoin de <strong>limiter les risques</strong> entre entités (tests agressifs, contenus expérimentaux, programmes partenaires, etc.).</li> </ul> <p>Exemples typiques :</p> <ul> <li>une application ou un produit dérivé : <em>app.example.com</em>,</li> <li>un centre d’aide complètement séparé du site marketing : <em>help.example.com</em> ou <em>support.example.com</em>,</li> <li>un pays géré comme une quasi-filiale autonome : <em>fr.example.com</em> avec équipe, budget et stratégie distincts,</li> <li>une plateforme de communauté ou d’échanges : <em>community.example.com</em>.</li> </ul> <h2 id="cout-complexite-et-maintenance">Coût, complexité et maintenance</h2> <h3 id="complexite-technique">Complexité technique</h3> <p>Les <strong>sous-dossiers</strong> sont généralement :</p> <ul> <li>plus simples à mettre en place au niveau technique,</li> <li>plus économiques en temps de gestion (un seul certificat SSL, une seule infrastructure principale),</li> <li>plus faciles à administrer pour les équipes n’ayant pas de fortes compétences système.</li> </ul> <p>Les <strong>sous-domaines</strong> impliquent souvent :</p> <ul> <li>une configuration DNS spécifique pour chaque sous-domaine,</li> <li>des certificats SSL couvrant l’ensemble des sous-domaines (wildcard ou multiples certificats),</li> <li>des déploiements, sauvegardes et mises à jour potentiellement distincts,</li> <li>plusieurs propriétés Search Console et une configuration analytics plus avancée.</li> </ul> <h3 id="cout-organisationnel">Coût organisationnel</h3> <p>Sur le plan humain et organisationnel :</p> <ul> <li>une structure en <strong>sous-dossiers</strong> convient bien à une équipe centralisée, où le SEO, le contenu et la technique sont gérés par un même groupe,</li> <li>une structure en <strong>sous-domaines</strong> est plus adaptée lorsque différentes équipes (par pays, par business unit, par produit) doivent disposer d’une <strong>autonomie forte</strong> tout en restant sous une marque commune.</li> </ul> <h2 id="mythes-et-idees-recues-sur-sous-domaines-et-sous-dossiers">Mythes et idées reçues sur sous-domaines et sous-dossiers</h2> <p>Plusieurs mythes circulent encore autour de ce sujet. Il est important de les clarifier :</p> <ul> <li><strong>Mythe 1 : « Les sous-dossiers rankent toujours mieux que les sous-domaines ».</strong><br>En réalité, il n’existe pas de pourcentage officiel ou de règle absolue. Ce qui change surtout, c’est la facilité avec laquelle l’autorité se consolide et la rapidité de progression SEO. Une architecture bien pensée en sous-domaines peut aussi obtenir d’excellents résultats, mais demandera souvent davantage d’efforts par entité.</li> <li><strong>Mythe 2 : « Google pénalise les sous-domaines ».</strong><br>Les moteurs de recherche ne pénalisent pas intrinsèquement les sous-domaines. Ils les traitent simplement comme des entités distinctes, avec des signaux propres. Si le contenu est de qualité et la stratégie solide, un sous-domaine peut très bien se positionner.</li> <li><strong>Mythe 3 : « Passer en sous-dossier suffit pour améliorer son SEO ».</strong><br>Changer de structure peut aider à mieux consolider les signaux, mais sans contenu de qualité, sans maillage interne optimisé et sans stratégie de liens, le gain sera limité.</li> </ul> <h2 id="comment-choisir-entre-sous-domaine-et-sous-dossier-methode-pratique">Comment choisir entre sous-domaine et sous-dossier : méthode pratique</h2> <p>Pour prendre une décision éclairée, il est utile de se poser quelques questions clés :</p> <ul> <li>Le projet partage-t-il la <strong>même thématique, la même marque et le même public</strong> que le site principal ?</li> <li>Souhaitez-vous <strong>accélérer la visibilité</strong> de cette nouvelle section en capitalisant sur l’autorité existante ?</li> <li>Avez-vous besoin d’une <strong>indépendance technique</strong> marquée (technos différentes, cycles de déploiement séparés) ?</li> <li>Les équipes qui vont gérer ce projet sont-elles <strong>centralisées ou réparties</strong> par pays / entité ?</li> <li>Votre priorité est-elle la <strong>simplicité de gestion</strong> ou la <strong>flexibilité organisationnelle</strong> ?</li> </ul> <p>De manière générale :</p> <ul> <li>si la réponse est « même marque, même sujet, même équipe », le <strong>sous-dossier</strong> est souvent le plus logique,</li> <li>si la réponse est « projet distinct, équipe distincte, contraintes techniques spécifiques », le <strong>sous-domaine</strong> devient une option solide.</li> </ul> <h2 id="exemples-de-structures-optimisees">Exemples de structures optimisées</h2> <h3 id="exemple-1-site-vitrine-blog-ressources">Exemple 1 : site vitrine + blog + ressources</h3> <p>Pour une entreprise B2B qui souhaite générer des leads grâce au contenu, une structure courante serait :</p> <ul> <li><em>example.com/</em> : site institutionnel, pages de services, pages à forte intention commerciale,</li> <li><em>example.com/blog/</em> : articles, dossiers, actualités,</li> <li><em>example.com/ressources/</em> : livres blancs, études de cas, webinaires.</li> </ul> <p>Tout est en sous-dossiers pour profiter au maximum de l’autorité du domaine et simplifier le suivi des performances.</p> <h3 id="exemple-2-saas-avec-app-documentation-et-marketing">Exemple 2 : SaaS avec app, documentation et marketing</h3> <p>Pour un SaaS, on peut voir :</p> <ul> <li><em>example.com/</em> : site marketing, acquisition, SEO,</li> <li><em>app.example.com</em> : interface utilisateur de l’application, authentification, compte client,</li> <li><em>docs.example.com</em> ou <em>example.com/docs/</em> : documentation technique.</li> </ul> <p>Le choix entre sous-domaine ou sous-dossier pour la documentation dépendra de la proximité souhaitée avec le marketing et du besoin ou non d’une autonomie technique.</p> <h3 id="exemple-3-groupe-international">Exemple 3 : groupe international</h3> <p>Un groupe présent dans de nombreux pays peut adopter :</p> <ul> <li>une logique <strong>sous-dossier</strong> si la marque, les offres et les équipes sont très centralisées : <em>example.com/fr/</em>, <em>example.com/de/</em>, etc.,</li> <li>une logique <strong>sous-domaine</strong> si chaque pays fonctionne presque comme une entité indépendante : <em>fr.example.com</em>, <em>it.example.com</em>, avec sites, contenus et campagnes propres.</li> </ul> <h2 id="conclusion-operationnelle">Conclusion opérationnelle</h2> <p>Le choix entre <strong>sous-domaine</strong> et <strong>sous-dossier</strong> est avant tout un choix stratégique et technique, plus qu’un « hack » algorithmique. Les sous-dossiers facilitent la mutualisation de l’autorité et simplifient l’analyse globale, ce qui en fait le choix privilégié pour la majorité des projets qui restent dans le même univers de marque et de thématique.</p> <p>Les sous-domaines, eux, prennent tout leur sens lorsque vous avez besoin d’une <strong>séparation forte</strong> : projet, pays, produit ou organisation. Ils demandent plus d’efforts SEO et une gestion analytics plus sophistiquée, mais offrent une grande flexibilité et un cloisonnement utile dans certains contextes.</p> <p>Pour maximiser vos résultats, commencez par définir clairement vos objectifs business, vos contraintes techniques et vos ressources internes. Ensuite, choisissez la structure qui vous permettra de construire, dans la durée, un écosystème cohérent, performant et facile à maintenir, plutôt que de chercher une solution « magique » fondée sur des raccourcis ou des idées reçues.</p> </div> <!-- CTA Section --> <div class="mt-12 pt-8 border-t border-gray-200"> <div class="bg-gradient-to-r from-purple-600 to-blue-600 rounded-xl p-8 text-center text-white"> <h3 class="text-2xl font-bold mb-4">Besoin d'aide avec votre SEO ?</h3> <p class="mb-6 text-purple-100">Notre équipe d'experts peut vous aider à optimiser votre site e-commerce</p> <div class="flex flex-col sm:flex-row gap-4 justify-center"> <a href="/seo-ecommerce" class="bg-white text-purple-600 px-8 py-3 rounded-lg font-semibold hover:bg-purple-50 transition inline-block"> Découvrir nos services SEO </a> <a href="/#contact" class="bg-purple-800 text-white px-8 py-3 rounded-lg font-semibold hover:bg-purple-900 transition inline-block"> Nous contacter </a> </div> </div> </div> </article> <!-- Section Commentaires --> <div class="mt-12 max-w-4xl mx-auto bg-white rounded-2xl shadow-xl p-8 md:p-12"> <h2 class="text-3xl font-bold text-gray-900 mb-6 flex items-center gap-3"> <i class="fas fa-comments text-purple-600"></i> Commentaires </h2> <!-- Liste des commentaires approuvés --> <div id="comments-list" class="mb-8 space-y-6"> <!-- Les commentaires approuvés seront chargés ici via JavaScript --> </div> <!-- Formulaire de commentaire --> <div class="border-t border-gray-200 pt-8"> <h3 class="text-xl font-semibold text-gray-900 mb-4">Laisser un commentaire</h3> <form id="comment-form" class="space-y-4"> <input type="hidden" id="article-slug" value="subdomain-vs-subfolder"> <div class="grid md:grid-cols-2 gap-4"> <div> <label for="comment-name" class="block text-sm font-medium text-gray-700 mb-2">Nom *</label> <input type="text" id="comment-name" name="name" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent"> </div> <div> <label for="comment-email" class="block text-sm font-medium text-gray-700 mb-2">Email *</label> <input type="email" id="comment-email" name="email" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent"> </div> </div> <div> <label for="comment-message" class="block text-sm font-medium text-gray-700 mb-2">Message *</label> <textarea id="comment-message" name="message" rows="5" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent"></textarea> </div> <div class="text-sm text-gray-600"> <i class="fas fa-info-circle text-purple-600"></i> Votre commentaire sera soumis à modération avant publication. </div> <button type="submit" class="bg-gradient-to-r from-purple-600 to-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-purple-700 hover:to-blue-700 transition inline-flex items-center gap-2"> <i class="fas fa-paper-plane"></i> Publier le commentaire </button> </form> <div id="comment-status" class="mt-4 hidden"></div> </div> </div> <!-- Navigation Articles --> <div class="mt-12 max-w-4xl mx-auto"> <a href="/blog" class="inline-flex items-center gap-2 text-purple-600 hover:text-purple-800 transition font-semibold"> <i class="fas fa-arrow-left"></i> Retour au blog </a> </div> </div> </section> <!-- Script pour les commentaires --> <script> const articleSlug = 'subdomain-vs-subfolder'; // Charger les commentaires approuvés async function loadComments() { try { const response = await fetch(`/gestion-commentaires/get-comments.php?slug=${articleSlug}`); const data = await response.json(); const commentsList = document.getElementById('comments-list'); if (data.success && data.comments.length > 0) { commentsList.innerHTML = data.comments.map(comment => ` <div class="border-l-4 border-purple-600 pl-4 py-2"> <div class="flex items-center gap-2 mb-2"> <strong class="text-gray-900">${comment.name}</strong> <span class="text-sm text-gray-500">•</span> <span class="text-sm text-gray-500">${new Date(comment.date).toLocaleDateString('fr-FR')}</span> </div> <p class="text-gray-700">${comment.message}</p> </div> `).join(''); } else { commentsList.innerHTML = '<p class="text-gray-500 italic">Aucun commentaire pour le moment. Soyez le premier à commenter !</p>'; } } catch (error) { console.error('Erreur lors du chargement des commentaires:', error); } } // Gérer la soumission du formulaire document.getElementById('comment-form').addEventListener('submit', async function(e) { e.preventDefault(); const formData = { slug: articleSlug, name: document.getElementById('comment-name').value, email: document.getElementById('comment-email').value, message: document.getElementById('comment-message').value }; const submitBtn = this.querySelector('button[type="submit"]'); const originalText = submitBtn.innerHTML; submitBtn.disabled = true; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Envoi en cours...'; try { const response = await fetch('/gestion-commentaires/submit-comment.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }); const result = await response.json(); const messageDiv = document.getElementById('comment-status'); if (result.success) { messageDiv.className = 'mt-4 p-4 bg-green-100 border border-green-400 text-green-700 rounded-lg'; messageDiv.textContent = 'Merci ! Votre commentaire a été soumis et sera publié après modération.'; messageDiv.classList.remove('hidden'); this.reset(); } else { messageDiv.className = 'mt-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded-lg'; messageDiv.textContent = result.message || 'Une erreur est survenue. Veuillez réessayer.'; messageDiv.classList.remove('hidden'); } } catch (error) { const messageDiv = document.getElementById('comment-status'); messageDiv.className = 'mt-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded-lg'; messageDiv.textContent = 'Erreur de connexion. Veuillez réessayer plus tard.'; messageDiv.classList.remove('hidden'); } finally { submitBtn.disabled = false; submitBtn.innerHTML = originalText; } }); // Charger les commentaires au chargement de la page loadComments(); </script> <footer class="bg-gray-950 text-gray-400 py-12"> <div class="container mx-auto px-6"> <div class="flex flex-col md:flex-row justify-between items-center"> <div class="mb-6 md:mb-0 flex items-start gap-4"> <img src="/images/logo.png" alt="Logo VRAIVEX" class="h-32 w-32 md:h-40 md:w-40 object-contain"> <div> <a href="#" class="text-2xl font-bold block"> <span class="gradient-text">VRAIVEX</span> </a> <p class="mt-2 text-sm">Automatisation, IA et SEO au service de la performance e-commerce</p> </div> </div> <div class="flex flex-col items-center md:items-end"> <div class="grid grid-cols-2 md:flex md:flex-wrap gap-3 md:space-x-6 mb-4 text-center md:text-right"> <a href="/#about" class="hover:text-white transition text-sm">À propos</a> <a href="/#services" class="hover:text-white transition text-sm">Services</a> <a href="/#prestations" class="hover:text-white transition text-sm">Prestations</a> <a href="/#bestsellers" class="hover:text-white transition text-sm">Best Sellers</a> <a href="/#realisations" class="hover:text-white transition text-sm">Réalisations</a> <a href="/#brands" class="hover:text-white transition text-sm">Nos Sites</a> <a href="/creation-site-ecommerce" class="hover:text-white transition text-sm">Création Sites</a> <a href="/seo-ecommerce" class="hover:text-white transition text-sm">SEO E-commerce</a> <a href="/partenaires" class="hover:text-white transition text-sm">Partenaires</a> <a href="/#contact" class="hover:text-white transition text-sm">Contact</a> </div> <p class="text-sm text-center md:text-right">© 2026 VRAIVEX. Tous droits réservés.</p> </div> </div> </div> </footer> <!-- Back to Top Button --> <button id="backToTop" class="fixed bottom-8 right-8 bg-gradient-to-r from-purple-600 to-blue-600 text-white p-4 rounded-full shadow-lg hover:shadow-xl transform hover:scale-110 transition-all duration-300 z-50 hidden"> <i class="fas fa-arrow-up text-xl"></i> </button> <script> // Header scroll effect window.addEventListener('scroll', function() { const header = document.getElementById('header'); if (window.scrollY > 100) { header.classList.add('header-scrolled'); } else { header.classList.remove('header-scrolled'); } }); // Smooth scrolling for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); document.querySelector(this.getAttribute('href')).scrollIntoView({ behavior: 'smooth' }); }); }); // Mobile menu toggle const mobileMenuButton = document.getElementById('mobileMenuButton'); const mobileMenu = document.getElementById('mobileMenu'); const menuIcon = document.getElementById('menuIcon'); if (mobileMenuButton && mobileMenu) { mobileMenuButton.addEventListener('click', function() { mobileMenu.classList.toggle('hidden'); // Toggle icon between bars and times if (mobileMenu.classList.contains('hidden')) { menuIcon.classList.remove('fa-times'); menuIcon.classList.add('fa-bars'); } else { menuIcon.classList.remove('fa-bars'); menuIcon.classList.add('fa-times'); } }); // Close menu when clicking on a link const mobileLinks = mobileMenu.querySelectorAll('a'); mobileLinks.forEach(link => { link.addEventListener('click', function() { mobileMenu.classList.add('hidden'); menuIcon.classList.remove('fa-times'); menuIcon.classList.add('fa-bars'); }); }); } // Brands Carousel const brandsCarousel = document.getElementById('brandsCarousel'); const brandsContainer = document.getElementById('brandsContainer'); const brandsPrevBtn = document.getElementById('brandsPrevBtn'); const brandsNextBtn = document.getElementById('brandsNextBtn'); const brandsPrevBtnMobile = document.getElementById('brandsPrevBtnMobile'); const brandsNextBtnMobile = document.getElementById('brandsNextBtnMobile'); if (brandsContainer && brandsCarousel) { let currentIndex = 0; const cards = brandsContainer.querySelectorAll('.brand-card'); const gap = 24; const cardsPerView = { mobile: 1, tablet: 2, desktop: 3, large: 4 }; function getCardsPerView() { const w = window.innerWidth; if (w >= 1280) return cardsPerView.large; if (w >= 1024) return cardsPerView.desktop; if (w >= 768) return cardsPerView.tablet; return cardsPerView.mobile; } function getCardWidth() { const cpv = getCardsPerView(); const cw = brandsCarousel.offsetWidth; return (cw - gap * (cpv - 1)) / cpv; } function updateCarousel() { const cpv = getCardsPerView(); const cardW = getCardWidth(); const maxIdx = Math.max(0, cards.length - cpv); currentIndex = Math.min(currentIndex, maxIdx); const offset = currentIndex * (cardW + gap); brandsContainer.style.transform = `translateX(-${offset}px)`; const atStart = currentIndex === 0; const atEnd = currentIndex >= maxIdx; [brandsPrevBtn, brandsPrevBtnMobile].forEach(function(btn) { if (btn) { btn.style.opacity = atStart ? '0.4' : '1'; btn.style.pointerEvents = atStart ? 'none' : 'auto'; } }); [brandsNextBtn, brandsNextBtnMobile].forEach(function(btn) { if (btn) { btn.style.opacity = atEnd ? '0.4' : '1'; btn.style.pointerEvents = atEnd ? 'none' : 'auto'; } }); if (document.getElementById('brandsCounter')) { document.getElementById('brandsCounter').textContent = (currentIndex + 1) + ' / ' + (maxIdx + 1); } } function nextSlide() { const cpv = getCardsPerView(); const maxIdx = Math.max(0, cards.length - cpv); if (currentIndex < maxIdx) { currentIndex++; updateCarousel(); } } function prevSlide() { if (currentIndex > 0) { currentIndex--; updateCarousel(); } } if (brandsNextBtn) brandsNextBtn.addEventListener('click', nextSlide); if (brandsPrevBtn) brandsPrevBtn.addEventListener('click', prevSlide); if (brandsNextBtnMobile) brandsNextBtnMobile.addEventListener('click', nextSlide); if (brandsPrevBtnMobile) brandsPrevBtnMobile.addEventListener('click', prevSlide); function setCardWidths() { const cardW = getCardWidth(); cards.forEach(function(card) { card.style.width = cardW + 'px'; card.style.minWidth = cardW + 'px'; card.style.flexShrink = '0'; }); } let touchStartX = 0; let touchEndX = 0; brandsCarousel.addEventListener('touchstart', function(e) { touchStartX = e.changedTouches[0].screenX; }, { passive: true }); brandsCarousel.addEventListener('touchend', function(e) { touchEndX = e.changedTouches[0].screenX; const diff = touchStartX - touchEndX; if (Math.abs(diff) > 50) { diff > 0 ? nextSlide() : prevSlide(); } }, { passive: true }); setCardWidths(); updateCarousel(); let resizeTimeout; window.addEventListener('resize', function() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function() { setCardWidths(); currentIndex = 0; updateCarousel(); }, 250); }); } </script> <script> // Header scroll effect window.addEventListener('scroll', function() { const header = document.getElementById('header'); if (window.scrollY > 50) { header.classList.add('header-scrolled'); } else { header.classList.remove('header-scrolled'); } }); // Scroll animations const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); } }); }, observerOptions); // Observe all fade-in-up elements document.querySelectorAll('.fade-in-up').forEach(el => { observer.observe(el); }); // Smooth scroll for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); // Counter animation for stats function animateCounter(element, target, duration = 2000) { let start = 0; const increment = target / (duration / 16); const timer = setInterval(() => { start += increment; if (start >= target) { element.textContent = target + (element.textContent.includes('+') ? '+' : '') + (element.textContent.includes('K') ? 'K€' : ''); clearInterval(timer); } else { element.textContent = Math.floor(start) + (element.textContent.includes('+') ? '+' : '') + (element.textContent.includes('K') ? 'K€' : ''); } }, 16); } // Observe stats section const statsObserver = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting && !entry.target.classList.contains('animated')) { entry.target.classList.add('animated'); const statsCards = entry.target.querySelectorAll('.stats-card'); statsCards.forEach((card, index) => { setTimeout(() => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; setTimeout(() => { card.style.transition = 'all 0.6s ease'; card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }, 100); }, index * 100); }); } }); }, { threshold: 0.3 }); const statsSection = document.querySelector('section.bg-gradient-to-r'); if (statsSection) { statsObserver.observe(statsSection); } </script> <script> // Gestion du formulaire de contact const contactForm = document.getElementById('contact-form'); const formMessage = document.getElementById('form-message'); const submitBtn = document.getElementById('submit-btn'); if (contactForm) { contactForm.addEventListener('submit', async function(e) { e.preventDefault(); // Désactiver le bouton pendant l'envoi submitBtn.disabled = true; submitBtn.textContent = 'Envoi en cours...'; // Récupérer les données du formulaire const formData = new FormData(contactForm); try { // Vérifier que les données sont bien dans le FormData const formDataObj = { name: formData.get('name'), email: formData.get('email'), subject: formData.get('subject'), message: formData.get('message') }; console.log('Données du formulaire:', formDataObj); // Vérifier que tous les champs sont remplis if (!formDataObj.name || !formDataObj.email || !formDataObj.subject || !formDataObj.message) { formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; formMessage.textContent = 'Veuillez remplir tous les champs du formulaire.'; submitBtn.disabled = false; submitBtn.textContent = 'Envoyer le message'; return; } // Essayer d'abord avec JSON (plus fiable) // Siça ne fonctionne pas, on essaiera avec FormData let response; try { // Méthode 1 : Envoyer en JSON (plus fiable selon les forums) response = await fetch('gestion-formulaire-contact/send-email-json.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(formDataObj) }); } catch (jsonError) { console.warn('Erreur avec JSON, essai avec FormData:', jsonError); // Méthode 2 : Fallback avec FormData response = await fetch('send-email.php', { method: 'POST', body: formData }); } // Lire le texte de la réponse d'abord pour déboguer const responseText = await response.text(); console.log('Réponse serveur:', responseText.substring(0, 500)); // Vérifier si la réponse est OK if (!response.ok) { // Essayer de parser le JSON d'erreur try { const errorResult = JSON.parse(responseText); // Afficher le message d'erreur du serveur directement à l'utilisateur formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; formMessage.textContent = errorResult.message || `Erreur ${response.status}: ${response.statusText}`; submitBtn.disabled = false; submitBtn.textContent = 'Envoyer le message'; return; // Sortir de la fonction pour ne pas continuer } catch (e) { throw new Error(`Erreur HTTP ${response.status}: ${response.statusText}. Réponse: ${responseText.substring(0, 200)}`); } } // Vérifier si PHP n'est pas exécuté (le serveur renvoie le code PHP brut) if (responseText.trim().startsWith('<?php') || responseText.includes('<?php')) { console.error('ERREUR: PHP n\'est pas exécuté par le serveur. Le code PHP est renvoyé brut.'); console.error('Le serveur web n\'est pas configuré pour exécuter PHP.'); // Utiliser la solution de secours : sauvegarder dans localStorage const messageData = { name: formData.get('name'), email: formData.get('email'), subject: formData.get('subject'), message: formData.get('message'), timestamp: new Date().toISOString() }; // Sauvegarder dans localStorage comme solution de secours const savedMessages = JSON.parse(localStorage.getItem('vraivex_messages') || '[]'); savedMessages.push(messageData); localStorage.setItem('vraivex_messages', JSON.stringify(savedMessages)); // Afficher un message spécial formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-yellow-600 text-white'; formMessage.innerHTML = '⚠️ PHP n\'est pas configuré sur le serveur. Votre message aété sauvegardé localement. <br>Veuillez nous contacter directement à <strong>contact@vraivex.fr</strong> ou consulter les messages sauvegardés dans la console du navigateur.'; // Afficher les messages sauvegardés dans la console console.log('Messages sauvegardés localement:', savedMessages); console.log('Pour consulter les messages, tapez dans la console: JSON.parse(localStorage.getItem("vraivex_messages"))'); return; // Sortir de la fonction } // Essayer de parser le JSON let result; try { result = JSON.parse(responseText); } catch (parseError) { console.error('Erreur de parsing JSON:', parseError); console.error('Réponse reçue:', responseText.substring(0, 500)); throw new Error('Le serveur a renvoyé une réponse invalide. Vérifiez la console pour plus de détails.'); } // Afficher le message de résultat formMessage.classList.remove('hidden'); if (result.success) { formMessage.className = 'mb-6 p-4 rounded-lg bg-green-600 text-white'; formMessage.textContent = 'Message envoyé avec succès ! Nous vous répondrons dans les plus brefs délais.'; contactForm.reset(); } else { formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; let errorMsg = result.message || 'Une erreur est survenue. Veuillez réessayer.'; // Afficher le message de debug en développement (à retirer en production) if (result.debug) { console.error('Erreur détaillée:', result.debug); } formMessage.textContent = errorMsg; } } catch (error) { formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; // Message d'erreur plus détaillé pour le débogage let errorMsg = 'Une erreur est survenue lors de la communication avec le serveur. '; errorMsg += 'Veuillez réessayer plus tard ou nous contacter directement à contact@vraivex.fr'; // En mode développement, afficher plus de détails if (error.message) { console.error('Erreur détaillée:', error); console.error('Message:', error.message); console.error('Stack:', error.stack); } formMessage.textContent = errorMsg; } finally { // Réactiver le bouton submitBtn.disabled = false; submitBtn.textContent = 'Envoyer le message'; // Masquer le message après 5 secondes setTimeout(() => { formMessage.classList.add('hidden'); }, 5000); } }); } // Back to Top Button functionality const backToTopButton = document.getElementById('backToTop'); // Show/hide button based on scroll position window.addEventListener('scroll', () => { if (window.pageYOffset > 300) { backToTopButton.classList.remove('hidden'); } else { backToTopButton.classList.add('hidden'); } }); // Smooth scroll to top when clicked backToTopButton.addEventListener('click', () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }); </script> </body> </html>