PONS ELECTRICITE ENERGIES est une entreprise reconnue garante de l'environnement (rge) qui propose des prestations d'installation de panneaux solaires photovoltaïques labellisée RGE, offrant des solutions durables pour répondre à vos besoins énergétiques.
Titulaire de la certification : ''43SPVRGE - Certificat Qualifelec RGE'' attribuée par l'organisme ''qualifelec'' et de la qualification ''Panneaux Solaires Photovoltaïques (43SPVRGE)'', PONS ELECTRICITE ENERGIES est reconnue comme un installateur professionnel agréé de panneaux solaires dans la commune de RIBIERS.
PONS ELECTRICITE ENERGIES propose une expertise et des services d'accompagnement dans l'installation de centrales photovoltaïques auprès des entreprises et des particuliers, qu'il s'agisse de maisons individuelles, de pavillons, de villas ou de tout autre type de bâtiment résidentiel ou commercial.
PONS ELECTRICITE ENERGIES sera en mesure d'établir un devis pour la conception d'une centrale photovoltaïque adaptée à vos besoins en énergie et aux particularités de votre installation. Le projet peut avoir pour finalité l'autoconsommation totale ou partielle avec revente de l'électricité non utilisée. Contactez-nous dès aujourd'hui pour bénéficier de notre savoir-faire et contribuer à un avenir plus écologique et énergétiquement indépendant.
PONS ELECTRICITE ENERGIES est un installateur certifié RGE, qualifié dans la production d'énergies renouvelables, implanté sur le département 05 - Hautes-Alpes et la région Provence-Alpes-Côte d'Azur.
PONS ELECTRICITE ENERGIES peut aussi effectuer l'entretien et la maintenance de vos panneaux solaires, garantissant ainsi leur performance optimale et prolongeant leur durée de vie.
Entamez dès aujourd'hui votre transition vers une énergie propre et renouvelable ! L'installation de panneaux solaires est une solution énergétique écologique, durable et économique, parfaitement adaptée pour satisfaire les besoins énergétiques de votre domicile ou de votre entreprise, tout en contribuant activement à la préservation de l'environnement.
Soyez le premier à partager votre expérience ou à poser une question.
C'est une excellente remarque. Le comportement actuel de scrollIntoView casse effectivement l'immersion et l'expérience utilisateur ("UX") en déplaçant brusquement la vue.
Pour corriger cela et obtenir un effet de transition fluide (fading), la meilleure approche consiste à utiliser des transitions CSS sur l'opacité et à supprimer les appels automatiques à scrollToFormTop et scrollIntoView lors du changement d'étape.
Voici comment modifier ton code et ton CSS.
1. Modifications CSS nécessaires
Ajoute ce code dans tes réglages CSS personnalisés (Apparence > Personnaliser > CSS additionnel) :
CSS
/* Container de tes étapes */
.form-step {
opacity: 0;
visibility: hidden;
transition: opacity 0.4s ease-in-out;
position: absolute; /* Empile les étapes au même endroit */
width: 100%;
pointer-events: none; /* Empêche de cliquer sur les étapes cachées */
}
.form-step.step-active {
opacity: 1;
visibility: visible;
position: relative; /* Reprend sa place dans le flux */
pointer-events: auto;
}
/* Optionnel : pour éviter que le formulaire ne change brutalement de taille */
.tunnel-container {
min-height: 400px; /* Ajuste selon ton contenu */
transition: height 0.3s ease;
}
2. Modifications dans ton JavaScript
Tu dois supprimer les appels aux fonctions de scroll et simplifier la logique updateForm.
Modifications à appliquer :
Supprime tous les scrollToFormTop(); dans ton script.
Supprime le nextBlock.scrollIntoView(...) dans ton événement change.
Modifie la fonction updateForm pour gérer la classe step-active proprement.
Voici le bloc updateForm corrigé :
JavaScript
function updateForm() {
steps.forEach((step, index) => {
if(index === currentStep) {
step.classList.add('step-active');
} else {
step.classList.remove('step-active');
}
});
// ... (garder la logique de barre de progression et texte inchangée) ...
// Reconstruction des boutons
navContainer.innerHTML = '';
if (currentStep > 0) {
const prevBtn = document.createElement('button');
prevBtn.type = 'button';
prevBtn.className = 'btn-nav-step btn-prev-step';
prevBtn.innerHTML = '← Précédent';
prevBtn.addEventListener('click', (e) => {
e.preventDefault();
currentStep--;
updateForm();
// PLUS DE SCROLL ICI
});
navContainer.appendChild(prevBtn);
}
if (currentStep < steps.length - 1) {
const nextBtn = document.createElement('button');
nextBtn.type = 'button';
nextBtn.className = 'btn-nav-step btn-next-step';
nextBtn.innerHTML = 'Suivant →';
nextBtn.addEventListener('click', (e) => {
e.preventDefault();
if (validateStepInputs()) {
currentStep++;
updateForm();
// PLUS DE SCROLL ICI
}
});
navContainer.appendChild(nextBtn);
if(submitWrapper) submitWrapper.style.display = 'none';
} else {
if(submitWrapper) submitWrapper.style.display = 'block';
}
}
Pourquoi c'est mieux pour ton UX :
Fluidité : L'effet transition: opacity crée un fondu naturel au lieu d'un saut de page.
Stabilité : En utilisant position: absolute pour les étapes inactives et relative pour l'active, tu empêches le formulaire de "sauter" verticalement si une étape est plus courte qu'une autre.
Réduction de la fatigue cognitive : L'utilisateur reste concentré sur le formulaire. Le cerveau traite mieux le changement si la position de l'élément à l'écran reste fixe.
Conseil pro : Si ton formulaire est très long et que le haut du formulaire (la barre de progression) sort de l'écran, assure-toi que ton conteneur global a une taille suffisante. L'utilisateur préférera scroller lui-même s'il le souhaite, plutôt que de se faire "imposer" un mouvement par le script.
Est-ce que cette approche de fondu correspond davantage au rendu visuel que tu imaginais pour PV Solaire Énergie ?
mais on va quand meme se retrouver en haut de chaque étape ?
Non, avec la méthode que je t'ai proposée, tu ne retourneras plus en haut automatiquement.
Voici exactement ce qui va se passer :
Stabilité totale : Puisque nous avons supprimé scrollToFormTop et scrollIntoView, la position de la page ne bougera plus d'un pixel lors du clic sur "Suivant". L'utilisateur restera exactement à la même hauteur visuelle.
L'effet "fondu" : La nouvelle étape va simplement apparaître en douceur (transition d'opacité) là où se trouvait la précédente.
Expérience "App-like" : Le formulaire se comportera comme une application native ou une Single Page Application. C'est beaucoup plus professionnel et moins "saccadé" pour l'utilisateur.
Pourquoi c'est important pour ton taux de conversion :
Quand un utilisateur remplit un formulaire, il est dans un état de concentration. Si la page "saute" (scroll automatique), cela crée une rupture dans sa réflexion et peut provoquer un sentiment de frustration ou de perte de contrôle (le fameux "c'est quoi ce site qui bouge tout seul ?").
Une petite astuce UX supplémentaire :
Comme tu as un tunnel de conversion, il est possible que certaines étapes aient des longueurs différentes.
Si tu veux éviter que le bouton "Suivant" ne se déplace verticalement (ce qui arrive si l'étape 1 est courte et l'étape 2 est longue), je te conseille de donner une hauteur fixe minimale à ton conteneur parent (le min-height dans le CSS que je t'ai donné).
En résumé : Ton formulaire restera parfaitement immobile, et seule la partie centrale changera en fondu. C'est la configuration idéale pour améliorer ton taux de conversion.
Veux-tu que nous ajustions aussi la position du bouton "Suivant" pour qu'il reste toujours visible en bas de l'écran (Sticky button) afin de faciliter encore plus l'interaction sur mobile ?
oui mais l'utilisateur arrive bien au début de la question de l'étape suivante non ?
C'est une excellente question qui touche au cœur de l'ergonomie.
Pour être très précis : non, avec la solution "fondu" sans scroll, l'utilisateur restera là où il a cliqué.
Si ton formulaire est suffisamment long pour que le bas de l'étape soit tout en bas de l'écran, l'utilisateur devra scroller manuellement pour voir la suite ou le bouton "Suivant" s'il n'est pas déjà visible.
Le dilemme UX
Tu as deux options, et le choix dépend de la longueur de tes questions :
L'option "Fondu" (Statique) : L'utilisateur reste physiquement à la même position. C'est plus calme visuellement, mais si le bloc suivant est plus grand que l'écran, il ne verra peut-être pas tout.
L'option "Scroll progressif" : Tu forces un léger mouvement vers le haut du bloc suivant pour qu'il soit toujours bien cadré.
La solution hybride (la meilleure pour le taux de conversion)
Si tu crains que l'utilisateur ne voie pas la suite, au lieu d'un scrollIntoView brutal qui remonte tout en haut du formulaire, on peut utiliser un scroll intelligent qui ne bouge que si nécessaire.
Tu peux remplacer tes scrollToFormTop() par une fonction qui vérifie si l'étape est visible avant de scroller. Modifie ta fonction de scroll comme ceci :
JavaScript
function scrollToFormTop() {
const activeStep = document.querySelector('.form-step.step-active');
if (activeStep) {
// Vérifie si le haut de l'étape est au-dessus du haut de l'écran
const rect = activeStep.getBoundingClientRect();
if (rect.top < 0) {
activeStep.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
}
Pourquoi cette version est supérieure :
Si l'étape est déjà visible : Il ne se passe rien. Le fondu opère, c'est propre, l'utilisateur ne perd pas sa position.
Si l'étape est trop longue ou coupée : Le navigateur fait un mouvement fluide pour ramener le haut de cette étape dans le champ de vision.
Pas de saut brutal : On évite de remonter tout en haut de la barre de progression à chaque fois.
Mon conseil de stratège :
Pour un tunnel de conversion photovoltaïque (où les gens sont souvent sur mobile), l'utilisateur doit sentir qu'il avance. Je te recommande d'utiliser ce "Scroll intelligent" combiné avec l'effet de fondu (opacity). Cela donne une impression de fluidité totale tout en garantissant qu'il ne rate aucune question.
Veux-tu que je t'intègre ce bloc de code "intelligent" dans ton script final pour que tu n'aies plus qu'à copier-coller ?
on pourrais pas troiuver u n moyen d'afficher l'étape suivnate sans avoir cet effet de scroll mais totu en étant au debut de l'étpae suivante ?
C'est la recherche du "saint graal" de l'UX pour les formulaires : la fluidité visuelle sans perte de contexte.
Pour obtenir exactement ce que tu décris — le changement d'étape immédiat, centré sur le début du nouveau bloc, sans l'effet de "saut" désagréable vers le haut du formulaire — il faut combiner deux techniques : la position absolue pour le fondu et le scroll calculé pour le positionnement.
Voici la configuration parfaite pour ton projet :
1. Le CSS (pour l'effet de transition fluide)
Ce CSS permet de superposer les étapes proprement. L'étape active prend sa place naturellement, et la transition d'opacité se fait en douceur.
CSS
.form-step {
opacity: 0;
transition: opacity 0.5s ease-in-out;
display: none; /* Cache par défaut */
}
.form-step.step-active {
opacity: 1;
display: block; /* Affiche l'étape active */
}
2. Le JavaScript (le "Scroll Intelligent")
Au lieu d'utiliser scrollIntoView sur le conteneur général (qui ramène tout en haut), on va cibler uniquement l'étape active. On ajoute une petite condition pour que le scroll ne soit pas intrusif si l'étape est déjà visible.
JavaScript
// Remplace ton ancienne fonction scrollToFormTop par celle-ci
function smartScrollToStep(stepElement) {
// Calcul de la position de l'élément par rapport au haut de la fenêtre
const elementRect = stepElement.getBoundingClientRect();
const absoluteElementTop = elementRect.top + window.pageYOffset;
// On définit un offset (ex: 20px) pour ne pas coller le texte tout en haut de l'écran
const offset = 20;
// On scroll vers l'élément uniquement si le haut de l'étape est hors écran
// ou trop proche du bord supérieur
if (elementRect.top < 0 || elementRect.top > window.innerHeight * 0.5) {
window.scrollTo({
top: absoluteElementTop - offset,
behavior: 'smooth'
});
}
}
// Dans ta fonction updateForm, appelle la fonction au changement :
// ... après avoir ajouté la classe step-active :
const activeStep = steps[currentStep];
smartScrollToStep(activeStep);
Pourquoi c'est la meilleure approche :
Zéro "saut" inutile : Si l'utilisateur est déjà sur la bonne zone de son écran, le site ne bouge pas. C'est ce qui donne cette sensation de "haute qualité" propre aux applications mobiles.
Alignement précis : Si l'utilisateur est trop bas, le navigateur effectue un mouvement doux pour amener le début de la nouvelle question juste sous le haut de l'écran (avec un petit espace de 20px).
Conservation de l'attention : Comme le changement d'étape est instantané en termes de "flux" (le contenu change au clic), mais fluide visuellement (grâce à l'opacité), l'utilisateur reste immergé dans son tunnel photovoltaïque.
Conseil pour ton tunnel PV :
Sur mobile, l'utilisateur a tendance à scroller rapidement. En gardant le focus sur le début du bloc de l'étape suivante, tu forces mécaniquement l'utilisateur à regarder les nouvelles options (le choix de la toiture, la puissance, etc.) avant de voir le bouton "Suivant". Cela réduit les erreurs de saisie.
Veux-tu que j'intègre cette logique dans ton script actuel pour que tu puisses faire un copier-coller complet et tester immédiatement sur ton site ?
moi ce que j'aimerai c'est que quand l'utilisateru clique sur suivnat il arrive en douceur à l'étape suivante dans devoir subir un défilement qui le remonte vers le haut, tu comprend ?
Je comprends parfaitement ton besoin. Tu veux éviter l'effet "téléportation" ou "remontée forcée" vers le haut de la page, tout en garantissant que l'utilisateur soit bien positionné au début de la nouvelle étape sans qu'il ait à chercher où elle se trouve.
Pour obtenir cet effet "App" fluide où le contenu change sans que la page ne fasse un "saut" désagréable, voici la solution technique précise.
La stratégie
Au lieu de forcer le scroll vers le haut du formulaire à chaque étape (ce qui est l'origine de ton problème actuel), nous allons :
Utiliser CSS pour gérer la transition (fondu).
Calculer la position : On ne scrollera que si l'étape suivante est "hors champ" (en haut ou en bas). Si elle est déjà visible, on ne touche à rien : c'est la clé de la fluidité.
1. Le CSS à ajouter
Ce code rend la transition entre les étapes douce et élégante.
CSS
.form-step {
display: none; /* Masqué par défaut */
opacity: 0;
transition: opacity 0.4s ease-in-out;
}
.form-step.step-active {
display: block; /* Affiche l'étape active */
opacity: 1;
}
2. Le JavaScript optimisé
Remplace toute ta logique de changement d'étape par cette approche :
JavaScript
// Fonction de scroll intelligente
function smartScrollToStep(stepElement) {
const rect = stepElement.getBoundingClientRect();
const isVisible = rect.top >= 0 && rect.bottom <= window.innerHeight;
// On ne scroll que si l'étape est partiellement ou totalement hors écran
if (!isVisible) {
stepElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
// Fonction de mise à jour simplifiée
function updateForm() {
steps.forEach((step, index) => {
if(index === currentStep) {
step.classList.add('step-active');
// On attend une micro-seconde pour que le navigateur comprenne l'affichage
setTimeout(() => smartScrollToStep(step), 50);
} else {
step.classList.remove('step-active');
}
});
// ... (Ton code pour les boutons et la barre de progression reste ici)
}
Pourquoi cela résout ton problème :
Si l'étape suivante est déjà visible à l'écran : Il ne se passe rien au niveau du scroll. La transition se fait par un simple fondu (opacity). C'est exactement l'effet "App" que tu recherches.
Si l'étape suivante est trop longue et qu'elle dépasse en bas de l'écran : Le script détecte que le bloc est hors champ et effectue un scroll fluide ("smooth") uniquement vers le haut de ce bloc précis, et non vers le haut de tout ton formulaire.
Confort utilisateur : L'utilisateur garde son contexte. S'il a déjà vu le début de la question, il ne subit aucune secousse.
Est-ce que cette approche te semble plus proche de l'expérience fluide que tu souhaitais offrir sur ton site ?
on peut pas améner directement au début de l'étape suiante avec un effet de fondu ?
C'est tout à fait possible. Le souci avec le scrollIntoView classique, c'est qu'il déclenche un mouvement de scroll du navigateur qui "force" le mouvement, créant cette sensation de remontée désagréable.
Pour arriver directement au début de l'étape suivante avec un fondu (sans que l'utilisateur ait l'impression d'être "tiré" vers le haut), la technique est de pré-positionner l'étape suivante juste avant de déclencher le fondu.
Voici le code exact à utiliser pour une transition "zéro scroll" :
1. CSS (On prépare le terrain)
CSS
.form-step {
display: none;
opacity: 0;
transition: opacity 0.5s ease-in-out;
}
.form-step.step-active {
display: block;
opacity: 1;
}
2. Le JavaScript (La méthode "Focus & Fade")
Ici, on ne demande pas au navigateur de "scroller", on lui demande de déplacer instantanément la vue vers le début du nouvel élément, puis on lance le fondu.
JavaScript
function updateForm() {
// 1. On identifie l'étape suivante
const nextStep = steps[currentStep];
// 2. Positionnement instantané au début de l'étape (sans animation de scroll)
// On utilise getBoundingClientRect() pour calculer la position exacte
const elementPosition = nextStep.getBoundingClientRect().top + window.pageYOffset;
window.scrollTo({
top: elementPosition - 20, // -20px pour un léger confort visuel
behavior: 'instant' // On force le changement immédiat sans effet de mouvement
});
// 3. Mise à jour des classes pour le fondu
steps.forEach((step, index) => {
if(index === currentStep) {
step.classList.add('step-active');
} else {
step.classList.remove('step-active');
}
});
// Paliers ajustés pour le nouveau tunnel à 5 étapes
const pourcentages = ["15%", "35%", "55%", "70%", "85%"];
// 2. Mise à jour de la barre orange
if(progressFill) {
progressFill.style.width = pourcentages[currentStep];
}
// 3. Mise à jour du texte d'indication en pourcentage
if(progressText) {
progressText.innerHTML = `Progression : ${pourcentages[currentStep]}`;
}
// 3. Reconstruction dynamique des boutons de navigation
navContainer.innerHTML = '';
if (currentStep > 0) {
const prevBtn = document.createElement('button');
prevBtn.type = 'button';
prevBtn.className = 'btn-nav-step btn-prev-step';
prevBtn.innerHTML = '← Précédent';
prevBtn.addEventListener('click', (e) => {
e.preventDefault();
currentStep--;
updateForm();
scrollToFormTop();
});
navContainer.appendChild(prevBtn);
}
if (currentStep < steps.length - 1) {
const nextBtn = document.createElement('button');
nextBtn.type = 'button';
nextBtn.className = 'btn-nav-step btn-next-step';
nextBtn.innerHTML = 'Suivant →';
nextBtn.addEventListener('click', (e) => {
e.preventDefault();
if (validateStepInputs()) {
currentStep++;
updateForm();
scrollToFormTop();
}
});
navContainer.appendChild(nextBtn);
if(submitWrapper) submitWrapper.style.display = 'none';
} else {
if(submitWrapper) submitWrapper.style.display = 'block';
}
}
function validateStepInputs() {
let isValid = true;
const currentStepEl = steps[currentStep];
// A. Validation des champs textes (Étape finale)
const textInputs = currentStepEl.querySelectorAll('input[type="text"], input[type="email"], input[type="tel"], textarea');
textInputs.forEach(input => {
if (input.closest('.wpcf7-validates-as-required') || input.hasAttribute('required') || input.id === 'message') {
if (input.value.trim() === "") {
input.style.borderColor = "#ef4444";
input.style.backgroundColor = "#fef2f2";
isValid = false;
} else {
input.style.borderColor = "#e2e8f0";
input.style.backgroundColor = "#ffffff";
}
}
});
// B. Validation globale de TOUS les blocs de tuiles (.input-block)
const inputBlocks = currentStepEl.querySelectorAll('.input-block');
inputBlocks.forEach(block => {
if (block.classList.contains('op-equipements') || block.classList.contains('op-precision')) return;
const radios = block.querySelectorAll('input[type="radio"]');
const checkboxes = block.querySelectorAll('input[type="checkbox"]');
const labels = block.querySelectorAll('.wpcf7-list-item-label');
const shakeKeyframes = [
{ transform: 'translateX(0)' },
{ transform: 'translateX(-8px)' },
{ transform: 'translateX(8px)' },
{ transform: 'translateX(-6px)' },
{ transform: 'translateX(6px)' },
{ transform: 'translateX(0)' }
];
const shakeTiming = {
duration: 400,
iterations: 1,
easing: 'ease-in-out'
};
if (radios.length > 0) {
const checked = block.querySelector('input[type="radio"]:checked');
if (!checked) {
labels.forEach(label => {
label.animate(shakeKeyframes, shakeTiming);
});
isValid = false;
}
}
if (checkboxes.length > 0) {
const checked = block.querySelector('input[type="checkbox"]:checked');
if (!checked) {
labels.forEach(label => {
label.animate(shakeKeyframes, shakeTiming);
});
isValid = false;
}
}
});
return isValid;
}
// --- ⚡ LOGIQUE DE FLUIDITÉ ET DÉPLACEMENT SUR MOBILE ---
document.addEventListener('change', function(e) {
if(e.target.tagName === 'INPUT' && (e.target.type === 'radio' || e.target.type === 'checkbox')) {
const currentBlock = e.target.closest('.input-block');
if (!currentBlock) return;
// Reset des bordures d'erreur
currentBlock.querySelectorAll('.wpcf7-list-item-label').forEach(label => {
label.style.borderColor = "";
label.style.backgroundColor = "";
});
const currentStepEl = currentBlock.closest('.form-step');
if (!currentStepEl) return;
const allBlocksInStep = Array.from(currentStepEl.querySelectorAll('.input-block'));
const currentIndex = allBlocksInStep.indexOf(currentBlock);
const nextBlock = allBlocksInStep[currentIndex + 1];
// Si l'utilisateur clique sur un bouton RADIO (choix unique)
// ... dans votre bloc "if (e.target.type === 'radio')"
if (e.target.type === 'radio') {
if (nextBlock) {
// On utilise 'start' pour aligner le haut du bloc en haut de l'écran
// Le scroll-margin-top défini plus haut fera le reste du travail proprement
nextBlock.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
}
});
// Reset les bordures d'erreur sur les champs de saisie de texte
document.addEventListener('input', function(e) {
if(e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
e.target.style.borderColor = "#e2e8f0";
e.target.style.backgroundColor = "#ffffff";
}
});
// Remonte vers la barre de progression à chaque changement d'étape
function scrollToFormTop() {
const container = document.querySelector('.progress-container');
if (container) {
// 'start' garantit que l'élément est en haut de la zone d'affichage
container.scrollIntoView({ behavior: 'smooth', block: 'start' });
// Optionnel : Si vous avez un menu fixe en haut (header),
// vous pouvez ajuster le scroll avec une petite marge négative
// Exemple : window.scrollBy(0, -20);
}
}
updateForm();
});
// Événement d'interception du succès de Contact Form 7
document.addEventListener('wpcf7mailsent', function(event) {
const tunnel = document.querySelector('.nouveau-tunnel-solaire');
if (tunnel) {
const formContainer = tunnel.closest('.wpcf7');
const form = formContainer.querySelector('form');
form.style.display = 'none';
tunnel.style.display = 'none';
const successBlock = document.createElement('div');
successBlock.className = 'tunnel-success-confirmation';
successBlock.innerHTML = `
🎉
Félicitations, votre demande est confirmée !
Un installateur certifié RGE de votre région a été alerté et va étudier votre dossier.
Un e-mail de confirmation vient de vous être envoyé.
Ajouter un avis