Le Hollandais Volant

Fix CSS et JS pour iOS et Safari

Safari sur iOS (et sur Mac) n’utilisent pas Blink, mais Webkit. Apple est parti de son côté avec Webkit et du coup fait un peu n’importe quoi. Ayant désormais un iPhone, je me retrouve à corriger mes sites et outils pour iOS.

Voici quelques trucs et astuces. Cet article sera emmené à être étendu avec le temps.

Zoom lors du tap sur un champ texte

Safari nous zoom la page quand on tape sur un champ texte. Ça part d’une bonne intention, mais premièrement ça déforme la page, et ensuite, quand on sort du champ texte, ça ne dézoome pas. C’est stupide.

La solution qui marche, sans toutefois interdire le zoom à l’utilisateur (ça c’est très important), c’est mettre ce HTML dans votre <head> :

<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=yes"/>

La magie vient du « maximum-scale ». Notez bien qu’il s’agit de l’échelle automatique. Le user-scalable="yes" assure que le zoom à deux doigts reste possible. Si vous mettez « user-scalable="no" », je n’aurais que deux mots : au bûcher !!

Le :hover sur iOS

Sur Vivaldi comme Firefox mobile (android), le :hover est activé lors du tap. Sur iOS il n’en est rien (enfin pas toujours). Ça se résout en ajoutant l’attribut « onclick » sur l’élément. Juste l’attribut, pas de valeur. iOS considère en effet que si l’on click, le hover s’active. Ici on clique, ça n’a pas d’effet directement, mais ça déclenche tout de même le hover.

Alternativement, et en mieux, on peut mettre dans son JS :

document.addEventListener("click", function() { });

Ce qui rend la correction plus rapide que d’ajouter onclick="" partout dans la page.

Certains parlent de mettre un « cursor: pointer » en CSS. Ça aurait été tout à fait pertinent que iOS active le :hover sur un élément dont le curseur est un pointeur (la petite main qui clique), mais malheureusement cette solution ne semble pas fonctionner.

Pour le parsage des dates en JS

La plupart des navigateurs, en JS, quand on leur donne un texte représentatif d’une date, essayent de parser ça comme ils peuvent. C’est censé marcher même quand on leur donne une date en langage naturel, comme « vendredi 4 mars 2022 », qu’ils traduiront en le bon objet de date.

Perso j’utilisais une chaîne de date-heure égale à « 2022-03-04 18:30:59 ». Firefox et Chrome n’ont pas de problèmes pour parser ça. Safari exige qu’on mette un « T » entre la date et l’heure : « 2022-03-04T18:30:59 », sinon il renvoie une erreur.

Safari a raison : le T pour « time » provient de l’ISO 8601 étendue et il faudrait l’inclure tout le temps.
Ceci est donc un rappel que ce n’est pas parce que ça marche sans le T que c’est une bonne pratique.

Placeholder sur [type=date]

Si vous avez un input de type date sans placeholder, alors Firefox et Chrome (blink) mettront une date vide : « jj / mm / aaaa ».

Safari (sur Mac) mettra la date du jour… mais en placeholder, donnant l’illusion que la date est remplie, alors que ce n’est pas le cas. Vérifiez bien que ça soit effectivement le cas dans vos app.

Étrangement, sur iOS, je n’ai pas ce souci, mais il est bien réel sur certaines versions de Safari sur Mac que j’ai pu voir (pas pu regarder plus en détail, désolé).

Les événements load, beforeunload, unload

Ces événements sont dépréciés sur iOS, et ne sont pas forcément fiables ailleurs. En effet, le comportement des utilisateurs sur mobile est de changer d’appli ou d’onglet sans fermer la page, donc sans « unload ». Le problème se pose aussi sur Android, même sur iOS, ces fonctions ne semblent plus fonctionner du tout, ce qui pose effectivement problème dans le cas où l’on ferme l’onglet en cours.

À la place, il est préférable d’utiliser l’événement « visibilitychange » (qui se lance quand on change d’application ou d’onglet) et « pagehide », qui est lancée à la fois quand on change la visibilité de l’onglet et juste avant qu’on le ferme. Dans les faits, pensez à utiliser les deux car le premier agit sur mobile et le second sur desktop. De plus, un bug sur Webkit fait que le « pageHide » n’est pas déclenché quand on change de page lors qu’on clique sur un lien dans celui-ci.

Plus d’information ici (avec un tableau de compatibilité). Et voyez sur les événements supportés par iOS.

Enfin, il en va de même pour l’événement « load », qu’il faudrait remplacer par « pageshow ».