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

iOS 26.4 a rendu ton input “fantôme” en WebView ? Voilà comment je le démonte

Un input qui “disparaît” après blur dans une WKWebView depuis iOS 26.4, ça sent la régression WebKit. Voici une méthode courte pour repro, isoler et mitiger en prod.

12 min de lecture
56 vues
réactions
Partager :
iOS 26.4 a rendu ton input “fantôme” en WebView ? Voilà comment je le démonte

Si tu es tombé sur le bug iOS 26.4 où un champ texte fonctionne, puis tu fais un blur et sa bordure (voire toute la zone) devient “fantôme” jusqu’à un repaint… tu n’es pas seul. Et non, ce n’est pas forcément ton CSS “bizarre” ou ton framework qui a décidé de saboter ton formulaire. Ça ressemble très fort à une régression de rendu dans WebKit, surtout quand ça arrive dans une app hybride en WKWebView et que le moindre changement visuel (ouvrir un dropdown, forcer un scroll, etc.) “répare” temporairement.

L’objectif ici est simple : te donner une méthode de diagnostic qui évite de patcher à l’aveugle, et des mitigations pragmatiques qui limitent la casse en attendant un fix upstream.

Reconnaître le bug : “l’élément est là, mais WebKit ne le repeint plus”

Le pattern typique, c’est un champ <input> qui s’affiche normalement au focus. Tu tapes. Tu sors du champ. Et là, soit la bordure disparaît, soit l’intérieur du champ semble “effacé”, soit la zone devient non-interactive. Le pire, c’est que le DOM n’a rien bougé. Si tu forces un repaint (un changement d’état, un overlay qui s’ouvre, un scroll minuscule), le champ réapparaît comme si de rien n’était.

Ce détail est important parce qu’il te fait gagner un temps fou. Si ton input disparaît parce qu’il est réellement masqué (style, condition React/Vue, classe ajoutée, etc.), un repaint ne va pas le ressusciter par magie. Là, on est dans un problème de paint/compositing ou de gestion de couches (layers) après un changement d’état comme le blur ou l’ouverture/fermeture du clavier.

Construire un repro minimal (le seul truc qui compte si tu veux avancer)

Je sais, c’est tentant de debug directement dans ton app. Mauvaise idée. Les apps hybrides ont mille couches de complexité (router, overlays, transitions, scroll containers, safe areas, web components, etc.). Le bon move, c’est de créer une page HTML la plus bête possible, puis d’ajouter une seule contrainte à la fois jusqu’à déclencher le bug.

Commence par un fichier unique, sans build, sans framework. Tu testes d’abord dans Safari iOS. Puis dans ta WKWebView. Si tu arrives à le déclencher en Safari, tu as déjà une histoire plus simple à raconter. Si ça n’arrive que dans WKWebView, tu sais que tu vas devoir inclure le contexte “hybride” dans le rapport de bug.

<!doctype html>
<html lang="fr">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Repro iOS 26.4 input blur repaint</title>
  <style>
    body { font: 16px -apple-system, system-ui, sans-serif; padding: 24px; }
    .card {
      padding: 16px;
      border-radius: 14px;
      background: #fff;
      box-shadow: 0 12px 30px rgba(0,0,0,.12);
      /* Ajoute UNE contrainte à la fois :
         transform, overflow, contain, filter/backdrop-filter, position: sticky/fixed, etc. */
      transform: translateZ(0);
    }
    label { display:block; margin-bottom: 8px; color: #222; }
    input {
      width: 100%;
      padding: 12px 12px;
      border: 2px solid #222;
      border-radius: 12px;
      background: #fff;
      outline: none;
      -webkit-appearance: none;
    }
    input:focus { border-color: #0a66ff; }
  </style>
</head>
<body>
  <div class="card">
    <label for="email">Email</label>
    <input id="email" type="email" placeholder="test@exemple.fr" />
  </div>
</body>
</html>

Ensuite tu joues au Lego. Tu enlèves transform. Tu le remplaces par overflow: hidden. Tu ajoutes position: fixed sur un parent. Tu mets le champ dans un conteneur scrollable. Tu testes avec un header sticky. Tu testes avec un modal. Tu touches une seule chose à la fois, sinon tu ne sauras jamais ce qui déclenche.

Isoler : layout, focus, ou rendu (et comment le prouver vite)

Quand l’input “disparaît”, je veux répondre à une question bête : est-ce qu’il a encore une taille et une position cohérentes, ou est-ce que c’est juste son rendu qui part en vrille ?

Le test le plus rapide côté Web Inspector (Safari sur Mac + device iOS branché, ou inspection de la WKWebView si tu as l’app) : tu sélectionnes l’input et tu regardes son box model. Si les dimensions sont normales, si l’élément est bien dans le flux, et que seul l’affichage déconne, tu es en terrain “paint/compositing”. Et là, ton CSS peut être parfaitement valide, tu subis quand même.

Deuxième test simple : au moment où ça bug, tu modifies en live un style insignifiant, genre background-color ou border-color. Si le champ réapparaît instantanément, tu viens de confirmer que c’est un problème de rafraîchissement graphique, pas un problème de logique applicative.

Troisième test : tu désactives temporairement des familles de propriétés connues pour créer des couches et des effets de composition. Dans le monde iOS, les suspects reviennent toujours : transform sur un parent, filter/backdrop-filter, overflow + border-radius, position: sticky/fixed imbriqués, contain, et tout ce qui ressemble à “je force l’accélération GPU”. Ce n’est pas que ces propriétés sont “mauvaises”. C’est juste que c’est souvent là que les bugs de layers se cachent.

Ce que je vérifie avant d’accuser WebKit (parce que parfois c’est nous)

Avant de partir sur “c’est un bug Safari”, je veux éliminer les régressions applicatives et les conditions qui n’existent que sur certains devices.

D’abord, je compare iOS 26.3 vs iOS 26.4, sur le même modèle si possible. Si ça n’existe qu’en 26.4, c’est un signal fort. Ensuite je compare Safari vs WKWebView. Si Safari ne bug pas mais WKWebView oui, je regarde les différences de config (scroll, opacité, background, viewport, gestion du clavier) et surtout les composants “applis” autour (barres natives, insets, conteneurs scroll custom).

Je teste aussi les réglages d’accessibilité qui changent la donne sur les champs : taille de texte (Larger Text), Display Zoom, Bold Text. Ça peut faire bouger le layout et déclencher une autre branche de rendu. Je teste enfin avec et sans zoom utilisateur (pinch). WebKit 26.4 mentionne des corrections autour de zoom côté CSS et des valeurs remontées en JS. Ce n’est pas forcément ton bug, mais c’est typiquement le genre de zone où une régression peut apparaître.

Dernier point très concret : si tu utilises des animations/transition sur des parents au focus (modals, bottom sheets, “scroll to input”, etc.), coupe-les. Beaucoup de bugs iOS “fantômes” arrivent quand le clavier, le scroll et une transition CSS se superposent. Et comme c’est non-déterministe, tu peux y passer deux jours à te mentir.

Mitigations pragmatiques en prod : forcer un repaint sans tout casser

Quand tu n’as pas le luxe d’attendre un correctif WebKit, tu veux une mitigation qui change le moins possible ton UI. L’idée n’est pas “de réparer WebKit”, juste de provoquer un rafraîchissement au bon moment, typiquement sur blur ou après fermeture du clavier.

Le contournement le plus neutre que j’ai utilisé dans ce genre de cas : toggler un style qui force un reflow/repaint, puis remettre. Ce n’est pas beau, mais c’est local, facile à retirer plus tard, et ça peut sauver un tunnel de conversion.

function nudgeRepaint(el) {
  // 1) Force un reflow (lecture)
  void el.offsetHeight;

  // 2) Toggle un style qui touche au compositing, puis restore
  const prev = el.style.webkitTransform;
  el.style.webkitTransform = 'translateZ(0)';
  requestAnimationFrame(() => {
    el.style.webkitTransform = prev;
  });
}

const input = document.querySelector('#email');
input?.addEventListener('blur', () => {
  // Petit délai pour laisser iOS finir sa tambouille (clavier/scroll)
  setTimeout(() => nudgeRepaint(input), 0);
});

Dans certains layouts, toggler opacity ou display sur un wrapper marche mieux que sur l’input lui-même. Oui, c’est sale. Oui, ça peut provoquer un mini-clignotement si tu le fais n’importe comment. C’est pour ça que je préfère d’abord des nudges discrets et limités au blur.

Et si tu vois que le bug est lié à une combinaison CSS précise (par exemple un parent transformé + overflow), la meilleure mitigation, c’est souvent d’arrêter d’empiler des “optimisations” CSS là-dessus. Typiquement, j’évite de mettre transform sur un conteneur qui contient des champs de formulaire critiques. Si j’ai besoin d’un effet, je le mets sur un sibling décoratif, ou je restructure le DOM. C’est moins sexy que de patcher, mais ça tient dans le temps.

Les combinaisons CSS qui déclenchent souvent ce genre de glitch sur iOS

Je ne vais pas te vendre une règle universelle, parce que WebKit a ses propres demons et ça change selon les versions. Mais dans la vraie vie, les “inputs fantômes” que j’ai vus sur iOS avaient presque toujours un point commun : un parent qui crée une nouvelle couche graphique et un contexte de clipping, et au milieu un champ qui change d’état (focus/blur) pendant que le viewport bouge à cause du clavier.

Si tu veux aller vite, cible d’abord les éléments autour du champ, pas le champ. Les filtres et flous (surtout backdrop-filter) sont des tueurs silencieux sur mobile. Pareil pour les conteneurs avec overflow: hidden + border-radius utilisés pour “arrondir” une card entière. Ça marche, jusqu’au jour où un input dedans décide de ne plus se repeindre correctement.

Le piège classique côté UI moderne, c’est le wrapper qui a transform pour animer une card ou un sheet. C’est souvent là que tu gagnes un bug. Si tu tiens absolument à animer, essaye une approche où le champ n’est pas dans la sous-arborescence transformée, ou où l’animation s’arrête réellement avant interaction (pas juste visuellement).

Safari 26.4 / WebKit 26.4 : pourquoi cette release peut “expliquer” une régression

Dans les notes WebKit Safari 26.4, on voit à la fois de nouvelles features CSS et un gros paquet de corrections. Ce genre de release, c’est exactement le moment où une régression de rendu peut apparaître, surtout autour du layout/zoom/focus. Ils mentionnent notamment des fixes liés à zoom (layout et valeurs exposées en JS) et des corrections de compatibilité CSS qui touchent directement les <input>. Ça ne prouve rien à lui seul, mais ça donne une piste crédible quand ton bug “arrive” pile après l’update.

En pratique, ce qui t’aide, c’est d’ancrer ton diagnostic sur des faits reproductibles, pas sur une intuition. Un repro minimal qui casse en 26.4 et pas en 26.3, c’est déjà 80% du travail.

Rédiger un bug report WebKit utile (et éviter le “cannot reproduce”)

Si tu veux que ça bouge côté WebKit, ton rapport doit être en béton. Pas long. Béton. Le ticket parfait, c’est celui où quelqu’un peut cliquer, reproduire en 15 secondes, et voir exactement le comportement attendu vs observé.

Concrètement, je donne toujours la version iOS exacte, le device, si c’est Safari ou WKWebView, et surtout un lien vers une page de repro hébergée (ou un zip HTML). J’ajoute une vidéo de l’écran, parce que les bugs de rendu sans vidéo finissent souvent en ping-pong stérile. Et je décris le déclencheur comme une recette de cuisine : “tap input, type, tap outside, observe la bordure disparaître, ensuite ouvre le select et observe que ça revient”. Ce niveau de précision évite beaucoup de “chez moi ça marche”.

Si le bug n’existe que dans une WKWebView, c’est pareil, mais il faut le dire clairement et préciser la config si tu la contrôles. À défaut, tu documentes au moins le contexte hybride (navigation interne, conteneur scroll, présence d’un header natif). Le but, c’est de permettre à quelqu’un de reconstruire un environnement proche sans lire ton code source.

Mon avis (assez tranché) : patcher oui, mais seulement après avoir isolé

Sur mobile, tu peux “fix” ce genre de bug en rajoutant des hacks au hasard. Et parfois tu tombes juste. Le problème, c’est qu’un hack de repaint non maîtrisé peut t’en créer un autre, plus discret, plus cher, et tu ne feras le lien que trois semaines plus tard. Donc je patch, oui. Mais je patch après avoir construit un repro minimal et identifié le déclencheur le plus probable.

Si ton produit dépend d’un formulaire, traite ça comme un incident UX. Monitoring, tests manuels sur devices, et une mitigation qui se retire facilement. Une fois que WebKit corrige, tu veux pouvoir supprimer ton bricolage en une PR, pas devoir réapprendre pourquoi tu avais mis translateZ(0) sur un input “pour une raison obscure”.

Conclusion : vise le repro minimal, pas l’héroïsme

Le bug “input fantôme” sur iOS 26.4 est typiquement le genre de truc qui te fait douter de toi, alors que tu es surtout en train de subir une régression de rendu. Le bon réflexe, c’est de réduire, isoler, comparer Safari vs WKWebView, et mettre une mitigation proprement encapsulée.

Et si tu arrives à faire un repro minimal public, tu rends service à tout le monde, toi compris. Le jour où tu retombes dessus, tu n’y repasses pas deux jours. Tu sais exactement où appuyer.

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 !