Aller au contenu principal
Site en cours de refonte — quelques pages peuvent bouger ou évoluer.
29 mars 2026

Le widget Calendly m’a pété le viewport sur iPhone (et mon CSS n’y pouvait rien)

Tu peux blinder ton CSS : si une iframe embarque un layout plus large, iOS Safari peut quand même te coller un scroll horizontal. Voilà comment limiter la casse sans y passer 3 jours.

10 min de lecture
42 vues
réactions
Partager :
Le widget Calendly m’a pété le viewport sur iPhone (et mon CSS n’y pouvait rien)

Tu intègres Calendly en inline sur une page. Sur desktop, nickel. Sur Android, ça passe. Et sur iPhone Safari… après une réservation, la page de confirmation dans l’iframe pousse la largeur comme si ton site faisait 1200px. Résultat, scroll horizontal, viewport “élargi” qui reste pété même si tu reviens en arrière, et une impression générale de site bricolé.

Le piège, c’est que tu peux sortir l’artillerie CSS côté parent (overflow-x: hidden, max-width: 100vw, contain, clip-path) et avoir quand même le bug. Parce qu’une iframe, surtout cross-origin, ce n’est pas “du HTML dans ton site”. C’est une boîte noire. Et iOS Safari a ses humeurs quand cette boîte noire se met à calculer une largeur interne absurde.

Le symptôme typique : tout va bien, puis la page de confirmation te flingue le layout

Le scénario est toujours le même. Tu affiches l’embed Calendly, l’utilisateur choisit un créneau, remplit le formulaire, valide. Et au moment où Calendly affiche la confirmation (dans la même iframe), boum : un élément interne déborde, Safari recalcule des dimensions, et ton document se retrouve avec une largeur scrollable plus grande que l’écran.

Le truc qui rend fou, c’est l’effet persistant. Tu peux fermer l’overlay, revenir en arrière, changer de section… le viewport reste “large”, comme si Safari avait décidé que ton site méritait un horizontal scroll pour le reste de la session. Dans la vraie vie, ça se traduit par des pages qui semblent “se décaler”, des blocs centrés qui ne le sont plus, et des interactions tactiles moins fiables parce que tu peux scroller latéralement par accident.

Pourquoi ton CSS “parfait” ne sert à rien dans une iframe (surtout cross-origin)

Le point dur, c’est la frontière de sécurité. Une iframe Calendly est cross-origin. Tu ne peux pas aller mettre un overflow-x: hidden sur le body de l’iframe, ni corriger un composant qui a une min-width trop grande, ni forcer un word-break sur une URL de confirmation trop longue. Donc si le contenu interne a un débordement, toi tu ne peux pas “corriger la cause”.

Et même si, sur le papier, “un débordement dans l’iframe” ne devrait pas élargir ton layout à toi, dans la pratique iOS Safari mélange parfois les pinceaux entre le viewport visuel, le layout viewport, et les dimensions des éléments embarqués. C’est exactement le genre de bug où tu peux avoir raison théoriquement… et perdre quand même en prod.

Ajoute à ça le fait que les widgets tiers changent de “page” sans changer d’URL chez toi. Tu ne contrôles pas quand ils reflow, quand ils chargent des polices, quand ils injectent un bloc avec une largeur fixe, ni comment ils gèrent les safe areas iOS. Bref : tu peux soigner ton CSS, mais tu n’as pas la main sur ce qui déclenche l’overflow.

Ce qui déclenche souvent le débordement : du contenu “innocent” mais non responsive

Sur une page de confirmation, tu as souvent des éléments parfaits pour casser le responsive : des IDs de réservation, des liens longs, un bouton avec une chaîne non coupable, un layout en colonnes prévu d’abord pour desktop, ou un conteneur qui a une largeur minimale un peu trop ambitieuse. Sur Chrome ça se voit à peine. Sur iOS Safari, ça peut suffire à faire apparaître un scroll horizontal, puis à “polluer” la largeur scrollable du document.

Le plus frustrant, c’est que ce n’est pas forcément un énorme débordement. Parfois c’est quelques pixels. Mais sur mobile, quelques pixels d’overflow, ça se transforme en comportement utilisateur horrible : tu “rates” tes taps, tu scrolls sans vouloir, ton site donne l’impression d’être instable.

Reproduire proprement sur iOS Safari (sinon tu vas patcher au hasard)

Avant de bricoler, il faut réussir à reproduire de manière fiable. Sur iPhone, je teste au minimum en portrait et en paysage, avec un changement d’orientation pendant le flow, et en ouvrant/fermant le clavier (ça change le viewport). Je fais aussi le test “retour arrière” après confirmation, parce que c’est souvent là que Safari garde une largeur scrollable fantôme.

Ne te fais pas avoir par les simulateurs. Le Responsive Design Mode desktop aide, mais il ne reproduit pas exactement les bugs de WebKit iOS. Le mieux reste un vrai appareil. Si tu peux, branche et débug avec Safari (macOS) pour observer le DOM parent, mesurer document.documentElement.scrollWidth et voir si ton html dépasse vraiment l’écran après l’action Calendly. Ça te dira au moins si tu es face à un overflow global ou à un artefact de scroll.

Mitigation côté parent : empêcher l’overflow de “sortir” de la zone Calendly

Tu ne peux pas réparer Calendly depuis ton CSS, mais tu peux réduire l’impact. L’idée, c’est d’isoler l’iframe dans un wrapper qui clippe vraiment, et de forcer l’iframe à se comporter comme un élément fluide. Sur iOS, j’ai eu de meilleurs résultats avec un wrapper dédié (pas juste un div au milieu du layout) et un combo overflow + contrainte de largeur au niveau de l’iframe.

Ça ne “guérit” pas le bug, mais ça évite souvent le cas où l’iframe élargit la page et te laisse un scroll horizontal permanent.

/* Wrapper qui encaisse les débordements du contenu embarqué */
.calendly-embed {
  max-width: 100%;
  overflow: clip; /* mieux que hidden quand c'est supporté */
  position: relative;
  contain: layout paint; /* limite les dégâts dans le reste de la page */
}

/* Iframe qui ne doit JAMAIS décider d'une largeur “à elle” */
.calendly-embed iframe {
  display: block;
  width: 1px;
  min-width: 100%;
  max-width: 100%;
  border: 0;
}

/* Option plus agressive : empêcher tout scroll horizontal global.
   À tester, parce que ça peut masquer un vrai overflow ailleurs. */
html,
body {
  overflow-x: hidden;
}

Deux remarques terrain. D’abord, overflow: clip est intéressant parce qu’il clippe sans créer de scroll container comme peut le faire overflow: hidden dans certaines situations. Ensuite, le hack width: 1px + min-width: 100% a une réputation de “bizarre”, mais il a un mérite : il pousse le navigateur à considérer l’iframe comme un élément qui doit remplir le conteneur, pas comme un truc qui peut s’étendre en largeur parce que son contenu interne a une scrollWidth délirante.

Est-ce que ça marche à 100% sur tous les iPhone, tous les iOS, tous les modes ? Non. Mais c’est un des rares réglages côté parent qui a une chance réelle de limiter les dégâts.

Le contournement le plus robuste sur mobile : sortir de l’inline embed

Si ton business dépend d’une prise de rendez-vous qui doit “juste marcher”, le plus fiable, c’est d’arrêter de croire que l’inline embed sera toujours stable sur iOS. Oui, c’est agréable d’avoir Calendly dans ta page. Mais sur mobile, ça peut devenir un point de fragilité pour ton site entier.

Deux stratégies que j’assume sans honte : ouvrir Calendly dans un nouvel onglet sur iPhone (ou au moins basculer vers une page dédiée sans le reste de ton layout), ou utiliser un mode popup/overlay géré par le script officiel plutôt qu’un iframe inline dans ton flow. L’objectif n’est pas esthétique, il est opérationnel : isoler le widget pour qu’un bug tiers ne casse pas ta navigation, ton header sticky, ton menu, et le reste.

Exploiter les événements Calendly : remplacer leur confirmation par la tienne

Un truc qui aide vraiment, c’est de ne pas laisser l’iframe aller jusqu’à une “confirmation page” qui change le layout interne. Si tu peux capter l’événement de rendez-vous programmé, tu peux faire simple : tu retires l’embed, tu affiches ta propre confirmation (dans ton DOM), et tu laisses Calendly vivre sa vie ailleurs.

Calendly envoie des messages (postMessage) quand des événements se produisent. Ce n’est pas parfait, mais c’est un levier concret pour éviter le moment exact où l’iframe passe sur une vue qui déborde.

window.addEventListener('message', (e) => {
  // Calendly poste des événements du type "calendly.event_scheduled".
  const data = e.data;
  if (!data || typeof data !== 'object') return;

  if (data.event === 'calendly.event_scheduled') {
    // Mitigation simple : on retire l'embed pour éviter une confirmation interne buggée,
    // et on affiche une confirmation maîtrisée côté site.
    const embed = document.querySelector('.calendly-embed');
    if (embed) embed.innerHTML = '<p>Merci, votre rendez-vous est confirmé. Vous allez recevoir un email.</p>';

    // Bonus : on “reset” un scroll horizontal résiduel.
    window.scrollTo({ left: 0, top: window.scrollY, behavior: 'instant' });
    document.documentElement.scrollLeft = 0;
  }
});

Évidemment, ce code ne remplace pas un vrai correctif côté Calendly. Mais en prod, ce genre de contournement est parfois la différence entre “on perd des conversions iPhone pendant 2 semaines” et “on passe au travers”.

Les erreurs fréquentes : le “fix” qui masque le problème et crée des effets de bord

Le réflexe overflow-x: hidden sur body peut marcher, mais il a un défaut : il peut aussi cacher un overflow réel de ton propre site. Et quand tu touches au scroll global, tu peux casser des trucs subtils, notamment des comportements de focus, des carrousels, ou certains layouts qui s’appuient sur un scroll container précis.

Autre piège : essayer de “gérer la taille” de l’iframe comme si tu pouvais la mesurer. Sur du cross-origin, tu ne peux pas lire le scrollHeight interne. Donc les hacks JS qui marchent sur une iframe same-origin ne marcheront pas ici. Si tu veux une hauteur dynamique fiable, il faut soit que Calendly la gère via leur script, soit accepter une hauteur fixe raisonnable, soit faire une page dédiée.

Documenter et monitorer un bug tiers sans s’y noyer

Le vrai risque, ce n’est pas le bug en lui-même. C’est le temps que tu peux perdre à “prouver” que ça ne vient pas de toi. Mon approche : je garde une page de repro minimale (une page HTML avec uniquement l’embed), je note précisément le device/iOS, et je capture une vidéo courte où on voit le scroll horizontal apparaître après confirmation. Avec ça, tu peux ouvrir un ticket, communiquer au client, et surtout justifier un contournement temporaire sans débat interminable.

Et si c’est une page critique, je teste systématiquement iOS Safari en QA avant release, même quand “on n’a touché qu’au CSS”. Les embeds tiers transforment le front en système distribué. Il faut jouer en conséquence.

Conclusion : une iframe, ce n’est pas un composant, c’est un fournisseur de surprises

Quand un widget tiers te casse le viewport sur iPhone, ce n’est pas forcément “ton CSS qui est mauvais”. Souvent, ton CSS n’a juste pas de prise. Le bon move, c’est de limiter le rayon d’explosion avec un wrapper sérieux, d’éviter les vues internes les plus risquées (confirmation dans l’iframe), et d’assumer un fallback mobile plus robuste, même si c’est moins “embed natif”.

Si tu veux aller plus loin, le vrai sujet derrière Calendly, c’est la stratégie générale d’intégration des widgets SaaS : où tu les mets, comment tu les isoles, et à quel moment tu décides que l’expérience mobile vaut mieux qu’un embed parfait sur desktop.

Sources

Cet article vous a plu ?

Commentaires

Laisser un commentaire

Entre 10 et 2000 caractères

Les commentaires sont modérés avant publication.

Aucun commentaire pour le moment.

Soyez le premier à donner votre avis !