Personal tools
Integrazione degli Icon Font in Plone, in modo accessibile

Se dico 🐢 ♥ 🐍 capite tutti?

Feb 25, 2014

Integrazione degli Icon Font in Plone, in modo accessibile

Che sia una moda o una vera rivoluzione, l'uso degli icon font si sta diffondendo moltissimo, ma qualcuno ci mette in guardia sulla loro effettiva accessibilità

Sempre più i siti Web moderni abbandonano l'uso indiscriminato di icone per sostituirle con la tecnica degli icon font.

Toolbar di comandi su GitHubGuardiamo ad esempio la barra dei comandi di GitHub (un sito sempre aggiornato per quanto riguarda le tecniche di front-end). Credete ci sia anche solo un'immagine qui?

Da profano, posso spiegarvi la tecnica in due parole: sfruttare CSS (e la direttiva font-face) per mostrare un carattere Unicode all'interno del testo.

Dato che si parla di Unicode, ci sono centinaia di simboli che possono sembrare icone, eppure dopo tutto stiamo pur sempre parlando di caratteri! ☼ ✰ ⌂ ♥

Bello, eh?

La mia (inizialmente poca) attenzione sull'argomento parte col rilascio del prodotto di integrazione tra Plone e FontAwesome.
Il prodotto di per sé non fa molto, se non registrare in Plone i CSS di FontAwesome all'interno di Plone, e nulla più.
Sta poi allo sviluppatore/grafico utilizzare o meno queste nuove regole nei propri template, mentre non c'è nessun supporto all'abilitazione di questi nuovi stili all'interno di TinyMCE.

E' l'accessibilità?

Qualche tempo fa mi sono imbattuto nell'articolo Bulletproof Accessible Icon Fonts in cui si parla dei problemi di accessibilità che questa tecnica può introdurre (e qui la mia attenzione si è fatta più viva!).

Il problema è fondamentalmente legato a come gli screen reader interpretano questi caratteri. Vediamo un esempio:

<p>E' nata una <span class="icon-star">stella</span></p>

Il carattere "stella" (&#xf061;) potrebbe semplicemente venire letto come "Black Star" ed essere quindi completamente incomprensibile e al di fuori di ogni contesto.

Se questo utilizzo ha una funzione puramente decorativa, lo screen reader dovrebbe passare oltre. Purtroppo pare che il supporto alla regola CSS "speak: none" sia ancora molto limitato.

Ci sono alternative?

L'articolo descrive come strada meglio percorribile l'uso di ARIA, nello specifico l'applicazione di aria-hidden. Lo scopo dell'attributo è marcare in modo esplicito l'elemento come "nascosto" e la tecnologia assistiva (se supporta ARIA, cosa a dire il vero non scontata) lo ignorerà.

<p>E' nata una <span aria-hidden="true" class="icon-star">stella</span></p>

E ora torniamo a Plone!

Dopo aver letto l'interessante articolo mi sono chiesto come poter rendere accessibile il prodotto collective.fontawesome con la tecnica qui sopra descritta.
Pare che le cose da fare non siano poche, quindi prendete il codice che seguirà come un "proof-of-concept" piuttosto che qualcosa di definitivo!

Aggiunta di stili a TinyMCE

Innanzitutto, come detto poco fa, collective.fontawesome si limita all'aggiunta dei CSS in Plone, ma non c'è nessun aiuto per l'utente che utilizza l'editor TinyMCE di Plone per poter usare questi nuovi stili.

La soluzione in questo caso è semplice: aggiungere alcune nuove opzioni nella configurazione degli stili del sito:

Configurazione di TinyMCE per Font AwesomePreview di TinyMCE con Font Awesome

Fatto questo, gli utenti potranno selezionare del testo dell'editor ed assegnargli lo stile voluto.

Stili FontAwesome applicati

Intercettare e correggere l'uso di icone

Per sistemare l'accessibilità del testo andrebbe quindi applicato l'attributo ARIA a questi elementi. L'idea è quella di intercettare le modifiche fatte al testo (evento onChange di TinyMCE), ma purtroppo in Plone tutto questo non è molto semplice.

L'inizializzazione dell'editor (fatta dal Products.TinyMCE) non permette facilmente di aggiungere dei callback agli eventi lanciati dall'editor.
Dobbiamo quindi modificare il codice di Products.TinyMCE perché venga lanciato l'evento, oppure (in modo meno invasivo) agganciare l'evento con questi semplici comandi JavaScript:

$('.mce_editable').tinymce().onChange.add(monitorTinyMCEIconFont)

monitorTinyMCEIconFont è una funzione JavaScript che si occupa di:

  • analizzare il codice HTML dell'editor
  • trovare tutti gli elementi che usano uno stile di icon font
  • aggiungere a questi (se non già presente) l'attributo aria-hidden
  • aggiornare il contenuto dell'editor (solo se è stato modificato).

Segue la definizione:

function monitorTinyMCEIconFont(ed, l) {
var changesDone = false,
doc = $('<div id="fakeContainer">' + l.content + '</div>');
for (var i=0;i<classes_to_monitor.length;i++) {
doc.find('.' + classes_to_monitor[i] + ':not([aria-hidden="true"])').each(function() {
var element = $(this);
element.attr('aria-hidden', 'true');
changesDone = true;
});
}
if (changesDone) {
ed.setContent(doc.html());
}
};

Da notare il riferimento alla struttura dati classes_to_monitor, un array per limitare il numero di stili supportati.
Vista la configurazione lato server che introdurremo tra poco, definiamo l'array in questo modo:

var classes_to_monitor = ['icon-star', 'icon-envelope', 'icon-user', 'icon-ok', 'icon-remove'];

Attributi permessi di TinyMCE

Sebbene la configurazione dei filtri HTML di Plone non contenga nulla di particolare contro l'attributo aria-hidden, l'approccio qui sopra non funziona ancora: l'attributo viene eliminato senza pietà!

Filtri HTML del sitoIl problema è (di nuovo) in TinyMCE (...tu quoque, Tiny...).
Per quanto gli unici elementi di configurazione che trattano attributi siano relativi ad "Attributi eliminati" (quindi una black-list di attributi), la configurazione di default di TinyMCE permette comunque solo un certo insieme di attributi.

Troviamo questa configurazione nella definizione della ITinyMCE utility. Se prendiamo ad esempio come riferimento l'elemento SPAN che stiamo usando.

Troviamo:
...
'span': COMMON_ATTRS.copy(),
...

Dove COMMON_ATTRS risulta essere:

...
CORE_ATTRS = set('id style title class'.split())
I18N_ATTRS = set('lang dir'.split())
COMMON_ATTRS = CORE_ATTRS | I18N_ATTRS
...

Come potete capire quindi, per l'elemento span tutti gli attributi non compresi in questa lista verranno eliminati dall'editor.
La nostra unica possibilità è modificare l'utility (definendone una nuova) che cambi questo comportamento:

CORE_ATTRS = set('id style title class'.split())
I18N_ATTRS = set('lang dir'.split())
ACCESSIBILITY_ATTRS = set('aria-hidden'.split() )
COMMON_ATTRS = CORE_ATTRS | I18N_ATTRS | ACCESSIBILITY_ATTRS

...e anche questo problema è risolto.

Effetto finale

Non è stato esattamente semplice ma siamo arrivati a una soluzione!
Ecco come viene infine generato il nostro HTML:

Esempio di applicazione FontAwesome accessibile

Alla prossima!

Easter egg

In questo articolo è nascosto un messaggio segreto! Riuscite a capire cosa dice?!

comments powered by Disqus