Parce que les chiffres ne mentent pas : nous sommes de plus en plus nombreux à avoir un smartphone. (Essayez de prononcer cette phrase d'un ton concerné en public sans rire, ça vous fera l'après-midi)
Webdev tag cpu css design dom html javascript libre mobilité ordinateur projet

Cet article est dans la série consacrée au développement de la bibliothèque cpu-audio.js et documente les affres de sa version 6.

  1. Mettre de l'audio dans le web n'a pas été simple
  2. Reconstruire son lecteur audio pour le web (sur la version 5)
  3. Retravailler un lecteur web audio dans les petites largeurs
  4. Le blues du Web Share (english version)
  5. Deux couleurs bizarres en CSS
  6. Tout-terrain WebVTT pour de l'audio
  7. Dichotomie entre podcast et web sur l'audience

Et cet article est long, car comme le premier, je tiens à documenter ma démarche. Et comme j'aborderais plusieurs thématiques, vous aurez plusieurs épisodes. Vous pouvez tester l'application ici ↓ dans sa version de travail en cours.

Pour lire ce billet, il est conseiller d'aller sur mon site dascritch.net. Si vous lisez ce texte, c'est que probablement vous n'y êtes pas.

Performance de Jean-Yves Jouannais et le Chevalier de Rinchy avec Kinou et DJ No Breakfast lors du festival Printemps de Septembre 2010, tous droits réservés .

Avant d'entrer dans le vif du sujet, je rappelle que je ne suis pas web-designer, mais un développeur d'applications web et que je n'ai qu'un minimum de bagages pour construire un web component faisant office de player audio. Que ce composant a été écrit afin de l'intégrer dans un site d'une émission radio, ceci dans le but de lier et de lire des sonores qui durent en moyenne une bonne heure. La plus longue des émissions de CPU dure 5h30, un exemple NSFW qui montre à l'extrême les contraintes.

J'ai qu'un minimum de culture en design, mais j'ai eu la chance d'avoir fréquenté depuis 2000 des designers web (des vrais) qui étaient exigeants et m'ont beaucoup appris à coups de b la dure.

Petits dans la poche, gros dans les contraintes

L'un des gros gros chantiers évolutifs de CPU-Audio.js pour cette version fut la mise au point d'une interface confortable pour les smartphones.

Par rapport à ceux dits de bureau, on a sur ce type d'ordinateurs deux problématiques supplémentaires :

  1. Un écran nettement plus petit,
  2. un dispositif de pointage bien moins précis.

Voici la comparaison avec mon web component sur mon propre blog dans sa version de Janvier 2019, tel que vu sur un ordinateur de bureau (1920 px de large) avec un pointeur de souris.

la souris a une précision au pixel et son curseur ne cache pas tout l'environnement immédiat

… et le même composant, mais vu sur un smartphone d'une largeur de 320 px (virtuels, résolution typique d'un iPhone 5 en mode portrait, en fait l'écran fait dans les 1080 pixels physiques, mais expliquer les dppx dans la foulée serait trop long).
Le disque rouge est une simulation l'espace d'appui d'un gros doigt normal prompt à la bourde.

environ 50 pixels de diamètre, sans compter l'imprécision dû au virage effectué par votre bus à une certaine vitesse

Il existe un certain nombre de règles de bonnes pratiques pour y palier :

J'étais déjà parti avec un design liquide (ou fluide ou coulant) pour être le plus confortable, dans l'idée que mon composant puisse être intégré quels que soient les choix sur le design du layout des sites. Pour la légèreté, je tente de maintenir le code compilé sous les 50 kB, même s'il a pris 20% de poids en plus entre la v5 et la v6.

Mais il y avait encore quelques manques dans la version 5 pour que mon player audio soit vraiment confortable à utiliser sur smartphones.

Et déjà un premier souci avec les CSS media queries breakpoints

Car effectivement, il est possible de cibler des définitions CSS par des règles media queries qui s'activent en fonction de la largeur de l'écran ou de la finesse de l'afficheur physique (via l'unité de ratio dppx évoquée plus haut entre parenthèses, oui je sais, ça fait lourd à lire tous ces apartés). Pour les définitions en fonction de la largeur d'écran, cela revient à définir un breakpoint, une dimension critique d'une media query ou le chouïa qui fait changer l'aspect, des propriétés peuvent changer plus ou moins radicalement. J'ai choisi cette stratégie car c'est la plus pratique pour une conception en design liquide.

Mais il y a un gros problème dans l'idée de concevoir un web component installable partout : Il n'est pas possible d'appliquer lesdites règles en fonction de l'espace disponible dans un élément parent en pur CSS. C'est faisable mais avec des polyfill en javascript particulièrement lourdingues.

Je m'explique : Si l'écran est d'une largeur d'écran de bureau (vers 2000 et au-delàààààà), mais qu'un intégrateur installe mon composant sur un site, dans une gouttière qui fait 320 pixels de large, l'aspect de mon composant ne sera pas adapté car les boutons seront trop gros, et par exemple pour les titres, ils ne rentreront pas dedans.
Autre exemple : supposons que la mise en forme du site est entre un bloc principal à largeur variable, et une colonne à taille fixe de 200 pixels. Si le lecteur est dans le bloc principal, il serait logique qu'il change de forme pour une largeur inférieure à 320 pixels quand la fenêtre tombe en dessous de 520 pixels…

@media (max-width: 320px) {
dommage, hein ?
}

Tommy Hodgins a fait une proposition auprès du W3C qui me serait super utile et totalement indiquée dans mon cas : Les CSS Element Queries qui proposent de définir en breakpoints la dimension d'un élément englobant.

La proposition CSS Element Queries permettrait de définir des règles appliquées si la largeur de l'écran fait 320 pixels ou moins ou que l'élément #conteneur a une largeur de 320 pixels ou moins :

@media (max-width: 320px) , @element #conteneur and (max-width: 320px) {
J'en rêve, mais j'en rêve ! (c'est déjà dans mon code)
}

Hélas, cette proposition ne semble pas être au programme du CSS working group du W3C et donc pas près d'être implémentée nativement. Et évidemment, tout polyfill est lourd, même avec l'arrivée prochaine de l'API ResizeObserver.
Pourquoi ? Imaginez que vous chargez 4 ou 5 web components dans la même philosophie de conception, qui chacune lance son polyfill… Ouais, évitez le CSS-in-JS dans ce cas-là : vous risquez de ne plus rien contrôler correctement.

Autre frustration : il n'est pas possible d'utiliser des variables CSS pour définir des breakpoints, des changements de résolutions significatifs. Dans mon projet, le style est défini est dans une CSS locale, tandis que les variables reparamétrables par l'utilisateur sont dans une CSS globale, normalement, toutes les variables qui intéressent les graphistes sont dans la CSS globale… sauf ce qui défini les breakpoints !
C'est pour ça qu'ils sont codés en dur à 640 px, 480 px et 320 px.

Pourquoi une telle frustration ? En fait, ce manque est intentionnel : les variables sont justement variables selon les usages et leur définition, pouvant vite devenir un casse-tête pour les navigateurs web à recalculer dans un media query.

Et on pourrait aussi avoir des… maladresses genre :

--largeur : 1000px;
@media (max-width: var(--largeur)) {
    --largeur : 500px;
}

Do not want comme on dit dans le secteur.

Il tourne actuellement au W3C une autre proposition, définir des constantes CSS d'environnement définissant des informations pour l'ensemble du document. Ces constantes peuvent être définies par le système hôte, le navigateur web ou dans la CSS (et on imagine, idéalement sur le sélecteur :root).
À leur appel en lecture, ces constantes peuvent prendre un paramètre optionnel qui sert de fallback. L'invariance de la valeur représentée en quelqu'endroit du DOM le rend alors utilisable pour définir un breakpoint.

Là aussi l'idée est géniale, et le dossier semble un poil plus avancé, l'implémentation native étant satisfaisante pour être jugée comme générale l'année prochaine. On a la lecture, pas encore la déclaration

:root {
    --largeur : 1000px;
}

@media (max-width: env(--largeur, 320px)) {
    ooooh ouuuuiiiii
}

breakpoint sur un élément, comme on peut, comme un porc

Dans l'immédiat, je suis arrivé à le faire sur le mini-site de présentation du projet grâce à une astuce limite du crade à faire dégainer l'Inspecteur Dirty Hacky

Pièce à conviction n°1, faites entrer l'accusé

J'ai utilisé des <iframe>. Et pourquoi est-ce crade ?

  • Il faut créer une ressource indépendant pour chaque instance appelée, ici 3 documents html de plus ;
  • Évidemment, il faut recharger le script cpu-audio.js, donc le charger et l'instancier 4 fois pour cette page ;
  • Idem pour la feuille de style ;
  • On instancie 3 objets DOM de page en plus, bouffant de la RAM ;
  • C'est impossible de faire un design liquide propre dedans sans pleurer sur certains cas ;
  • Et on perd des fonctionnalités comme :

Je ne l'ai utilisé que pour faire la démo des largeurs. Ne faites jamais ça chez vous, les enfants !

Le problème de la navigation fine sur une largeur fine

Revenons sur les problèmes fonctionnels de mon web component sur les ordinateurs de poche.

Le manque qui me semblait le plus gênant était de revenir en arrière d'une phrase dans un sonore d'une heure. Le lecteur peut interpréter certaines touches comme et , mais aucun smartphone n'a de clavier avec des touches fléchées depuis la mort du dernier Blackberry à touches physiques. Reste le positionnement au doigt levé posé, et donc la navigation dite fine s'y révèle imprécise.
Améliorer ma time-line était indispensable.

Une time-line c'est ÇA :

N'oublions pas que mon web component est prévu pour être utilisé dans une page web, et qu'il a été conçu en design liquide, donc si on passe son smartphone de l'orientation portrait à paysage et que sa dimension n'est pas fixée, le visiteur gagne autant de largeur, donc de précision pour naviguer dans la time-line. Mais la prise en main me semblait toujours insuffisante.

Dans pratiquement tous les lecteurs audios, la time-line est à la fois un indicateur et un élément de contrôle auquel on s'attend pour tout média audio ou vidéo d'une certaine durée. Elle indique à la fois la position en cours de lecture, la partie préchargée immédiatement lisible sans avoir à attendre, et permet à l'auditeur de sauter à une position. Plus cette time-line est large, plus le positionnement au pointeur par l'utilisateur est précis. Plus le sonore est long, moins ce positionnement est précis.
Je ne saurais dater son apparition, mais il me semble qu'elle est apparue avec le premier Quicktime (1991) en tant qu'adaptation de la time-line des éditeurs de sons qui présentaient la forme d'onde du sonore en cours d'édition, et ceci depuis les années 1970s.

Avant de me remettre au redesign à la refactorisation de mon lecteur, et vu que moi-même je ne suis pas parfait, j'ai regardé ailleurs et essayé des applications natives sur smartphones. En me concentrant sur son comportement lors du passage d'une disposition portrait à paysage. Certains choix y sont surprenants, et pas uniquement sur les durées affichées (passée, restante ou totale).

Quatre exemples de time-line en natif


L'application Youtube l'agrandi aussi en passant en mode paysage. En mode portrait, elle utilise le maximum de largeur d'écran.

Mais pourquoi ai-je pris une vidéo d'Eugène Lawn ?


HenryMP, héritier d'un excellent player audio (Appollo sur Cyanogen OS), se montre encore moins aisé : si on décide de basculer l'écran du mode portrait au paysage.... la time-line n'est pas plus grande pour autant. Frustrant.

J'imagine que la logique y est plus d'écouter des singles d'environ 4 minutes et de mieux voir la pochette de l'album, pas forcément de naviguer dans un DJ-set de 2 heures ou dans une conférence au Collège de France

Note : Cette application n'est plus maintenue depuis 4 ans, elle est présentée ici pour l'exemple.

Podcast Addict, qui est une excellente application orientée podcast (merci Capitaine Évidence), a quelques manques dans sa prise en main pour naviguer. En gros, si l'émission n'est pas chapitrée ou n'a pas de liens explicatifs dans son texte descriptif, on pointe sur la time-line puis on utilise des boutons pour se positionner plus finement.

Dans la vue présentation d'un épisode, basculer en mode paysage étend la time-line. Sauf que, petite inconsistance : sur la vue propre à un sonore, en mode paysage, la time-line est… plus courte. Oups.

Je termine ce tour avec une application très particulière, celle de Les Croissants, qui propose une matinale par modules, composée en fonction de vos centres d'intérêts.
(Manque de bol : La société Les Croissants a fermé la veille de la publication programmée de cet article. Pas d'bol.)

En haut, vous avez une vue sur l'ensemble de l'émission dans une time-line globale, et au milieu, chaque chapitre a sa propre barre de défilement, mais à la verticale, sur la gauche.

On a certes une redite de la time-line entre la vue totale (horizontale) et celle par chapitre, mais ce qui est nettement plus notable et bizarre est que la progression des time-lines des chapitres n'est pas constante, puisque la hauteur de cet élément est fixe, mais que la durée peut varier (entre 3mn et 7mn). Mais ces bizarreries sont plus une signature et non gênantes à l'usage.

On a vu quelques outils de consultation destinés au public, j'aimerais vous présenter un outil professionnel de lecture de média :

Le jog shuttle du Beta SP

Le magnétoscope Beta SP de Sony est avec sa cassette Betacam un engin de chantier de l'audiovisuel des années 1980s-2000s. Costaud, robuste, très cher et indispensable pour toute production de qualité. La première fois que j'ai pu en utiliser un, j'ai immédiatement adoré l'usage du bouton jog shuttle ! Oui, même en pleine frustrajoie.

Vous ne pouvez pas louper le jog shuttle : c'est ce gros bouton rond noir proéminent idéalement placé sous votre main droite sur le panneau inférieur.
Photo non créditée sur Pinterest

Dans le mode shuttle en pause ou pendant la lecture, vous pivotez le bouton rotatif, la bande défile alors vers l'avant ou l'arrière plus ou moins rapidement, entre le ralenti et l'accélération ×8 en fonction de l'angle de rotation. Relâchez, le bouton rotatif revient en position neutre.
Mais si vous cliquez sur le bouton, le ressort est désactivé, et le mode de fonctionnement passe en jog, où vous faites défiler les images en tournant le bouton. Comme si vous bougiez manuellement la bobine de la bande sur un bon vieux reel-to-reel ReVox, ou que vous caliez un disque vinyle (étant à Radio <FMR>, j'ai voulu être DJ). Ce qui permet un calage à l'image près, indispensable pour le monteur vidéo.

On a donc un outil de calage qui passe d'un clic d'un positionnement grossier au calage à l'image élémentaire. La prise en main est incroyablement intuitive une fois qu'elle vous a été montrée.

À 1m42s, une petite démo avec un lecteur XDCam portable, mais il s'agit d'un bouton combo (voir le paragraphe suivant). Pour 60€, je vous aurais intégré cette vidéo éclairante avec un vrai BetaSP. Et y'a celle-là montrant un autre point de vue.

À noter que certains magnétoscopes très haut de gamme des années 1990s avaient un combo bouton central shuttle rotatif et pourtour jog à ressort. Peut-être fut-il utile pour monter les Sept Premiers Bitomans.

Depuis, la génération Betacam est passée.
Au prix de la bande, les BetaSP sont devenus des pièces de musée, et on monte au clavier et au trackpad. Mais le jog shuttle est resté dans cette micro-culture industrielle pour ceux qui ont connu avant l'informatisation totale du banc de montage. Pas mal de monteurs vidéos, qui ont un jog shuttle wheel sur leur poste de montage. Les control knob prévus pour Windows 10 tels le Surface Dial s'en approchent mais n'ont pas le retour haptique avec ressort, si intuitif.

Et dans les logiciels ?
Il me semble qu'une version (bêta ?) de QuickTime Pro avait tenté à la fin des années 1990s d'ajouter dans un panneau de son interface une molette de défilement… qui ressemblait trop furieusement au jog-dial, une molette crantée cliquable que Sony incrustait absolument partout. Et quand je dis partout, ce jog-dial  a été la signature des produits Sony de la fin des années 1990s : sur les baladeurs Mini-Discs (utile pour titrer un MD, mais dont l'usage bourrait de saletés l'intérieur de mon MZ-R35), le téléphone Z5 (celui de l'An 2000) ou encore les PDA Clié. Il me semble que les designers de Sony se soient retenus pour les télés et playstations.
Apple a retiré l'interface avant un procès prévisible, ou peut-être en souvenir de l'échec de la molette de volume du Quicktime 4 ?

Mais je m'égare dans mes rushes.
Alors l'idée d'un jog shuttle dial est super, mais non-intuitive pour le visiteur lambda d'un site à qui il faudrait lui expliquer le manuel, or, rappelons la règle d'or du design réussi :

S'il faut expliquer le fonctionnement d'une interface grand public
    ⇒ c'est que ton design est loupé
    ⇒ F.B.I. Fausse Bonne Idée.

Accessoirement, elle est aussi un poil lourd à écrire from scratch. Pas infaisable, juste lourd. Et prendrait de la place sur l'écran.

Maintenant qu'on a fait ce petit tour de l'État de l'Art pour se mettre en appétit, passons à l'action !

Supprimer les bords ronds

Un truc totalement idiot où j'ai pêché par coquetterie : j'ai mis des bords ronds au début et à la fin de la time-line. En fait, cela rend moins facile de viser le début d'un sonore (oui, les recherches avancées ont prouvé que statistiquement, nous cherchons plus souvent à revenir au début qu'à aller dans les 5 dernières secondes d'une émission d'une heure). Donc tant pis pour les bords ronds, on revient au bon vieux rectangle.

Je vais prendre exemple sur mon propre blog, avec une de mes émissions actuelles qui ne dure qu'une heure : Sur 320 pixels de large, le web component fait 291 pixels de large à cause de la mise en page.

La time-line fait 195 pixels de large, les bords ronds en bouffent 2×4 pixels.

Je me suis appliqué la Règle des Cinq Pourquois pour chercher la vraie raison de ma décision graphique. Alors, euuuuuh… les bords ronds sont moins agressifs, parce qu'il y a trop de rectangles, Steve Jobs a inventé les rectangles arrondis… Au final, j'avais mis ces bords ronds sans aucune raison valable.

Bon ben, on vire !

À 18 secondes par pixels pour un sonore d'une heure, cela faisait 2'27" rabotées par pure coquetterie, et non pas par design.

Parce que, oui, il faut se rappeler que le design n'est pas qu'une question de couleurs et de formes mais surtout de praticité pour tous. Faire du décor ne suffit pas et n'est pas du design.

Agrandir la time-line

Passer de la souris à la précision d'un pixel sur un écran de 52 cm de large (1920 px soit 96 dpi) à un écran tactile de 8 cm de large (1080 px soit 400 dpi, plus qu'un album de bd !) avec la précision d'un gros pouce… inutile de dire que sur smartphones, une telle précision peut entrainer autant de dégâts collatéraux qu'une guerre chirurgicale. Et cette imprécision devient de plus en plus problématique quand on a mis en ligne un podcast qui dure une heure (voire 5h30), rendant encore plus problématique un bête besoin comme celui de revenir d'une minute en arrière dans une interview.

Il était évident que garder la time-line contrainte entre les deux boutons ▸︎play/⏸︎pause et action n'était pas une super idée graphique : Je perdais environ 2×48 px en largeur disponible, ce qui n'est pas négligeable quand on a moins de 320 px de large.

Pour reprendre l'exemple de mon blog, la time-line fait 195 pixels de large soit 18 secondes par pixel pour un sonore d'une heure

Il m'a fallu jouer une fugue en CSS mineure pour que cette barre bascule en-dessous de ces boutons pour gagner en largeur. Comme je voulais aussi garder l'indication des longueurs de chapitres (les lignes noires discontinues), je considère qu'elles deviennent transparentes aux actions pointeurs en dessous d'une certaine largeur d'écran, pour éviter un appui malheureux dessus.
Oui, si c'est conditionné avec un breakpoint, c'est que j'ai utilisé une propriété CSS qui influe les interactions du curseur avec des éléments. Cette propriété qui tient de la magie vaudou mérite votre attention : pointer-events : none;

Retravaillée la time-line fait toute la largeur du web component, 291 pixels de large soit 12,4 secondes par pixel pour un sonore d'une heure.
Vous noterez aussi que les deux boutons ont perdu un poil de hauteur et que la place laissée au timecode dans la liste des chapitres est devenue élastique ce qui permet de gagner des lignes dès la première entrée.

Comme l'utilité d'une telle finesse est moins pressante sur de plus grandes largeurs, qui correspondent en général à des ordinateurs avec des dispositifs de pointages plus précis (le doigt occupant une fraction moins importante de l'écran, ou ayant un stylet voire la souris), la disposition entre les deux boutons revient au-delà d'une certaine largeur.

Deviner où l'on vise d'un coup d'œil

On le voit sur la capture au-dessus, j'ai fait apparaitre sous la time-line une indication pointilliste des chapitres. Elle existait depuis un an, mais uniquement dans les grandes largeurs. Celle-ci est désormais aussi visible sur les petites largeurs, mais il n'est pas dit que tous les utilisateurs de mon script vont penser à renseigner un manifeste de chapitrage au format WebVTT. On en reparlera dans un chapitre à part, j'ai beaucoup à dire sur le sujet ; si cela vous intéresse, vous pouvez déjà vous amuser avec mon éditeur en ligne.

Pour aider visuellement à sa navigation, j'ai ajouté une fonctionnalité qui permet d'afficher l'enveloppe du son. Il s'agit d'une option, disponible via l'attribut waveform="".

Pour des raisons évidentes de performances, l'image de l'enveloppe en question est pré-générée au moment de la compression du sonore en PÀD (prêt à diffuser). Afin de tester la fonction et de donner un exemple fonctionnel dans ma doc, j'ai profité d'une fonction méconnue de l'utilitaire en ligne de commande sox, véritable couteau suisse pour travailler du son avec le minimum de dépendances. Un script qu'on trouve souvent dans des chaines de publication audio industrialisées sur des serveurs de rendus.
Anecdote : j'ai utilisé cet outil en 2004 pour faire des messages de répondeurs personnalisé par prénoms et pour biper des ringback tones. Un script de 20 lignes permettait à des ingés son de gagner des journées de travail en supprimant des silences superflus, concaténant des sons et normalisant le rendu.
L'option pour générer ce graphique est spectrogram. Par rapport à la traditionnelle vue de la courbe, elle permet de mieux distinguer les voix et les musiques sur une très petite hauteur, ici 8 pixels de haut. C'est pas toujours vrai et c'est surtout un choix personnel, il est susceptible d'évoluer plus tard.

Comparaison entre une vue d'une forme d'onde (en haut, niveau sonore en ordonnée) et un spectrogramme (en bas, fréquence en ordonnée) de l'émission 🍺 Bière

Naviguer plus finement

Reprenons les problématiques de la navigation sur smartphone : L'écran est tout petit, et notre doigt est démesurément gros pour essayer de se placer précisément. Et donc nous avons toujours le problème de la navigation fine, quand on veut revenir de quelques secondes en arrière.

J'étais parti sur l'idée qu'un appui long sur ma time-line est une tentative pour se placer finement. Ben oui, ça m'arrivait plusieurs fois d'appuyer à un endroit du player, puis de bouger délicatement mon doigt en le faisant pivoter, tout en approchant de près mon smartphone et en tirant la langue afin de contrebalancer le manque de précision… ce qui me rendait totalement idiot dans le bus.

AHEM !
Une requête pour afficher la navigation alternative, nous disions.

L'idée étant évidemment de suivre l'analogie UX de la blague de l'interface : s'il faut l'expliquer à l'utilisateur, c'est que ton interface n'est pas bonne.

j'ai mis des boutons, juste pour voir si la requête en question marchait. Mais j'avais pas forcément idée de le garder. J'avais même réfléchi à zoomer la time-line avec des mouvements genre pinch-in/pinch-out (pincer/étendre), mais je me suis rendu compte que ce n'était ni intuitif, ni pratique, voire complètement frustrant sur iOS : le pinch-out à une certaine ampleur peut vous sortir du navigateur web pour aller vers un sélecteur d'applications (Un parti-pris d'Apple très con et totalement frustrant quand votre appli utilise le pinch, justement).
Et comme mon web component a aussi pour objectif d'être repris, hors de question de risquer une contradiction parce que le site hôte a déjà son usage du pinch-in/pinch-out.

Donc finalement, supposer qu'un appui long sur la time-line est une demande explicite de l'utilisateur vers plus de précision, me semble pas trop erroné.

Mettre des boutons ◂◂◂ ◂◂ ▸︎▸︎ ▸︎▸︎▸︎ semblait pas trop pourri.

J'ai dit semblait, une fois de plus, je dis pas avoir raison.

La mauvaise surprise du temps

J'ai tenté de mettre une entrée de temps, utilisant un champ <input type="time">, yep, icelui : . Après tout, les smartphones ont en général un excellent sélecteur de date et d'heure.

Le sélecteur d'heure d'Android, extrait de l'excellent article sur <input type="time"> de Mozilla Developer Network.
Une chouette analogie aux vieilles horloges à aiguilles, compréhensible parce que des équipes de Google (comme Microsoft, Apple et Mozilla) ont investi des milliers d'heures sur ce problème à votre place.

Sauf qu'il y avait un os ! J'ai pris un sélecteur d'heure, faute d'avoir un sélecteur en HTML5 pour exprimer une durée. Ce qui veut dire que… l'heure peut afficher au format 12 heures avec une locale américaine ! Et impossible de le localiser de force avec un attribut comme lang="fr".

Tiens, si je règle un champ time à 0h1mn23s, dans Firefox avec l'interface paramétrée en Français, vous aurez :

00:01:23 bon là, vous m'comprenez si vous me lisez en Français

Et avec l'interface paramétrée en Anglais Américain (en-US), qui est l'interface par défaut pour beaucoup de monde :

12:01:23 AM Tempora mori, tempora mundis recorda comme dirait le roi de Loth,
ça veut pas du tout dire la même chose, et surtout pas une durée

En fait, il n'y a pas de règle uniforme du comportement basculant entre les affichages en 12 h ou 24 h  : certains navigateurs se basent sur la langue de leur interface, d'autres celles du système d'exploitation (heureusement, le DOM expose au javascript une représentation unique au format 24 heures, idem pour l'envoi d'un formulaire à un serveur, sinon je serais devenu fou).

J'avais le même souci dans mon éditeur de chapitrage puisqu'il utilisait le même type de champ. Pour le résoudre, il suffirait d'écrire un polyfill d'affichage agissant sur un champ <input type="time"> caché… ouaip, ça craint.
Ben j'ai écrit une mécanique différente.

En résumé, pour un champ natif de durée, il manque :

  • soit un type de champ <input> pour gérer la durée, une décision à prendre au niveau du W3C ;
  • soit le respect de la propriété lang="" dans les contrôles, ce qui peut être implémenté par les navigateurs mais peut poser des soucis d'UX ;
  • soit la possibilité de styliser un champ <input type="time"> dans sa présentation et son interface pour basculer entre les modes 12 et 24 heures, une décision qui peut être testée par les navigateurs par une propriété CSS préfixée expérimentale avant standardisation.

Néanmoins, je n'étais pas satisfait de cette navigation alternative.

L'enfer des petits détails

La barre de navigation alternative apparaît quand on clique plus de 400 ms : au-delà, Chrome sur Android et surtout l'affreux iOS considèrent que l'utilisateur veut une autre fonction, genre sélectionner du texte. Alors qu'on a déjà désactivé la sélection de texte. Le pire étant iOS qui va lancer un sélecteur d'application qui n'a rien à voir.
À noter que pour les ordinateurs de bureau, il est possible de l'afficher en faisant un clic droit à la souris sur la time-line (la fonction normale est disponible en combinaison avec ⇧Shift).

Voilà où en était mon brouillon, que j'ai finalement gardé. Ici en faisant abstraction du champ input type="time" pour ne pas plus vous distraire avec…

Pour être le plus standard possible, j'ai créé des boutons ◂◂ et ▸︎▸︎, calqués sur les appuis de touches et tels qu'interprétés dans mon web component (faisant des sauts de 5 secondes, durée paramétrable) , ainsi que sur la touche . Puis j'ai ajouté ◂◂◂ et ▸︎▸︎▸︎, qui font comme ◂◂ et ▸︎▸︎, mais répétés 4 fois.

J'ai tenté ce sélecteur, mais design liquide oblige, j'étais obligé de cacher certains boutons qui me semblaient moins utiles, d'un usage moins fréquent. notamment ◂◂, un choix décidé grâce à une technique scientifique de pifométrie, ce qui une fois de plus, vaut ce qu'il vaut et que je n'ai pas forcément eu raison.

Dans la plus petite largeur recommandée (320 px de large, soit un iPhone 5 en portrait), on a l'essentiel utilisable

Mais ces boutons étaient câblés sur l'événement click (clic de souris). Vous cliquez, l'avance se fera. Une fois. Ça serait cool de rajouter la répétition, non ? Tant que vous ne relâchez pas, l'action continue au même rythme.

Donc au final, j'ai dû écrire un gestionnaire d'appui-long/répétition pour 4 boutons, avec un mode de fonctionnement proche d'un clavier de bureau : Une première attente (400 ms) avant de commencer à répéter, puis répéter l'action sur des intervalles nettement plus courts (100 ms). Des durées paramétrables par le site, car je déteste les constantes magiques au milieu du code, et pour qu'un webmaster qui n'aime pas les réglages puisse faire mumuse avec, comme ça, il se sentira plus fort.
Ouarf.

Peut-être pouvait-on faire une accélération de l'avancée en fonction du temps qu'on appuie sur le bouton, mais je ne suis pas sûr qu'un tel système à accélération progressive soit pratique.

Bref…

In fine, j'ai travaillé les fonctionnalités sur mon lecteur audio pour qu'il soit aussi pratique à utiliser sur un ordinateur de bureau que sur smartphone.

Je ne garantis rien. Maintenant reste le plus difficile : en faire autant sur la navigation fine pour l'accessibilité.


En plus de la navigation fine, il faudrait aussi parler du chapitrage audio, mais le sujet est très vaste, il interviendra après qu'on ait parlé de Web Share...