You Are Here: Home » CSS Tutorials » Stile css per un input type="file"

Stile css per un input type="file"

Questo articolo è una traduzione della versione originale in inglese intitolata Styling an input type=”file” e pubblicato su questo sito con l’autorizzazione del autore.

Il credito di questa tecnica va interamente a Michael McGrady, chi l’ha inventata.

NB: Il browser deve supportare la proprietà opacity per applicare questa tecnica. Per quello, non funzionerÃà con Internet Explorer 5.0 sia su Windows che Mac e Opera.

Di tutti i campi di forma, il ‘file upload’ è uno dei peggiori quando viene a li dare stile css.
Windows Explorer offre poche possibilità di stile, Mozilla un po di meno e nulla per altri browsers.
Specialmente il pulsante ‘Sfoglia’ è completamente inaccessibile allo stile css.

Il problema

Prendendo un esempio concreto, per un sito è necessario un campo d’input come di seguito:



Il designer vuole lo stesso stile, più un immagine ‘seleziona’ (select) da applicare a tutti i campi di tipo input file. Però, quando sono applicate le normale regole css ai campi di tipo ‘input’, i campi di tipo ‘file’, non funzionano correttamente. Ci sono grande differenze d’interpretazione tra i vari browsers e dare stile css al pulsante di default è impossibile.

Vediamo le differenze.

Preview campi input file

Non si può dire che sia un campo di input stilizzato per bene!
Ma fino a poco tempo fa, era il meglio che si poteva ottenere.

Anche da notare, la differenza fondamentale con Safari.
Il team di Safari avranno probabilmente deciso di adottare questa soluzione per disabilitare l’opzione di digitare manualmente il nome d’un file e evitare cose del genere. Un problema è che l’utente non può decidere di non caricare un file dopo averlo selezionato.

La soluzione

Per fortuna, un lettore Michael McGrady ha inventato un veramente bel trucco che ci permette (più o meno) di dare un stile css ai campi input di tipo ‘file’.
I crediti di questa soluzione presentata su questa pagina sono suoi, è stato solo aggiunto il position: relative;, qualche note e prove extra, e portato il tutto a Javascript.

Senza questa tecnica, il vostro browser reagisce come di seguito:


Usando la tecnica di McGrady, siamo stati capace il seguito campo d’input di tipo file:


Molto più bello, no? (sempre considerando che il vostro browser supporta la proprietà css opacity)

La tecnica creata da McGrady è elegante nella sua semplicità :

  1. Prendere un normalissimo <input type="file"> e aggiungerlo ad un elemento con position: relative.
  2. Allo stesso elemento genitore, aggiunge un normalissimo <input /> e un immagine, con il stilo coretto. Posizionare questi elementi in modo assoluto in modo che occupano lo stesso spazio che il <input type=”file”>.
  3. Impostare il z-index del <input type="file"> a 2 in modo che sia su un livello superiore a l’immagine ‘stilizzata’ (input).
  4. Finalmente, applicare la proprietà opacity a <input type="file"> con valore 0.
    Il <input type="file"> sarà adesso effettivamente invisibile e l’immagine stilizzata del input si vedrà attraverso, ma lasciando sempre la possibilità di cliccare sul pulsante ‘Sfoglia’. Se il pulsante è posizionato sopra l’immagine, l’utente sembra cliccare sull’immagine e la finestra per selezionare il file si aprirà  normalmente.
    NB: non possiamo usare visibility: hidden, perché un elemento puramente invisibile non è cliccabile mentre abbiamo la necessita che <input type="file"> lo sia.

Fino adesso, questo effetto può essere ottenuto solo usando puro css. Purtroppo, un opzione è mancante.

  • Quando l’utente ha selezionato un file, il finto campo d’input (quello visibile) dovrebbe mostrare il coretto path a quel file, come lo farebbe un normale <input type="file">.
    E semplicemente un fatto di passare il nuovo valore di <input type="file"> a il falso campo d’input. Per fare tale, abbiamo necessita di usare Javascript.

Per quella ragione, questa tecnica non funzionerà completamente senza Javascript. Più tardi, saranno spiegate le ragione per quale è stato scelto di appoggiare l’intera idea su Javascript.

Se siete disponibile a fare senza visualizzare il nome del file, potete applicare solamente la soluzione dimostrata prima in css. Non si sa quanto può essere una buona idea però.

La struttura HTML/CSS

Di seguito l’HTML/CSS scelto da applicare:

div.fileinputs {
position: relative;
}
div.fakefile {
position: absolute;
top: 0px;
left: 0px;
z-index: 1;
}
input.file {
position: relative;
text-align: right;
-moz-opacity:0 ;
filter:alpha(opacity: 0);
opacity: 0;
z-index: 2;
}
<div class="fileinputs">
<input type="file" class="file" />
<div class="fakefile">
<input />
<img src="search.gif" />
</div>
</div>

Il <div class="fileinputs"> contenitore è posizionato relativamente in modo di potere posizionare in modo assoluto il suo contenuto: il falso campo d’input file

Il <div class="fakefile">, con il falso campo d’input e il pulsante, è posizionato in modo assoluto e ha un z-index di valore 1, in modo che sia sotto il vero campo d’input file.

Il position: relative è anche applicato al vero campo d’input in modo di potere assegnare un
z-index. Dopo di tutto, il vero campo d’input dovrebbe trovarsi al di sopra del falso campo d’input.

Di seguito, aggiungiamo la proprietà opacity al vero campo d’input file con un valore pare a 0, per renderlo invisibile.

Da notare il text-align: right: visto che Mozilla rifiuta la proprietàwidth (larghezza) per il vero campo di file, dobbiamo essere sicuri che il pulsante ‘Sfoglia’ è anche posizionato sulla destra e si trova sotto il vero pulsante.

Avrete bisogno d’un sottile css per definire larghezze, altezze, bordi…non è incluso nel codice d’esempio. Potete visualizzare il sorgente di questa pagina per studiare l’approccio usato in questo particolare caso; la vostra pagina sarà comunque differente e questi valori dovranno essere modificati.

Perché JavaScript?

Dopo di tutto, è stato scelto di andare per una soluzione strettamente Javascript.

La prima ragione è che Javascript è comunque necessario per passare il valore del path del file al falso campo.

Secondo, una soluzione puramente basata su Javascript eviterà l’inutile uso di extra HTML:
il <div class="fakefile">. Il codice rimanerà più pulito.

Finalmente, i browser di più vecchia generazione non possono sempre interpretare le regole css applicate in modo perfetto, al punto che il campo d’input non è accessibile per Netscape e IE4 (per chi di voi sviluppa anche per tali browser). Invece se i css non sono per niente supportati, l’utente vedrà 2 campi d’input e non capirà l’uso del secondo.

Di seguito una soluzione puramente basata sui CSS:


Browse

Soluzione – JavaScript

In tutta la sua ‘cattiveria’, la soluzione è semplice: generare il finto input e pulsante via Javascript.

Il peggio che può succedere è che il script non funziona. In tale caso, l’utente vedrai solo il vero
<input type="file">. Sicuramente meno gradevole a l’occhio ma sempre accessibile.

L’HTML è ridotto a:

<div class="fileinputs">
<input type="file" class="file">
</div>

Gli altri elementi saranno aggiunti via Javascript.

Il script

Ecco il codice scritto:

var W3CDOM = (document.createElement && document.getElementsByTagName);
function initFileUploads() {
if (!W3CDOM) return;
var fakeFileUpload = document.createElement('div');
fakeFileUpload.className = 'fakefile';
fakeFileUpload.appendChild(document.createElement('input'));
var image = document.createElement('img');
image.src='button_select.gif';
fakeFileUpload.appendChild(image);
var x = document.getElementsByTagName('input');
for (var i=0;i<x.length;i++) {
if (x[i].type != 'file') continue;
if (x[i].parentNode.className != 'fileinputs') continue;
x[i].className = 'file hidden';
var clone = fakeFileUpload.cloneNode(true);
x[i].parentNode.appendChild(clone);
x[i].relatedElement = clone.getElementsByTagName('input')[0];
x[i].onchange = x[i].onmouseout = function () {
this.relatedElement.value = this.value;
}
}
}

Spiegazione

Se il browser non supporta il W3C DOM, non fare nulla.

var W3CDOM = (document.createElement && document.getElementsByTagName);
function initFileUploads() {
if (!W3CDOM) return;

Crea il <div class="fakefile"> e il suo contenuto. Sarà duplicato tutte le volte necessarie.

var fakeFileUpload = document.createElement('div');
fakeFileUpload.className = 'fakefile';
fakeFileUpload.appendChild(document.createElement('input'));
var image = document.createElement('img');
image.src='button_select.gif';
fakeFileUpload.appendChild(image);

Controlla tutti gli inputs nella pagina e ignora quelli che non sono <input type="file">.

var x = document.getElementsByTagName('input');
for (var i=0;i<x.length;i++) {
if (x[i].type != 'file') continue;

Un altro controllo: se il <input type="file"> non ha un elemento genitore con un nome di classe fileinputs, ignorarlo.

if (x[i].parentNode.className != 'fileinputs') continue;

Adesso abbiamo trovato un <input type="file"> che ha bisogno di essere lavorato. Primo, aggiungiamo “hidden” al suo nome di classe.
Aggiungiamo le proprietà avanzate (opacity e position) a questa classe visto che possono causare problemi con i browser più vecchi.

x[i].className = 'file hidden';

Duplica il falso campo e aggiungerlo al nodo genitore di <input type="file">.

var clone = fakeFileUpload.cloneNode(true);
x[i].parentNode.appendChild(clone);

Adesso abbiamo stilizzato corettamente il <input type="file">.

Non abbiamo ancora finito. Dobbiamo essere sicuri che l’utente vede il path al file che vuole caricare.

Primo, creiamo una nuova proprietà per il <input type="file"> che punta al finto campo d’input:

x[i].relatedElement = clone.getElementsByTagName('input')[0];

Usiamo quello per accedere facilmente il finto campo appena l’utente cambia il vero <input type="file"> (es: selezionando un file), in modo di potere copiare il suo valore nel finto campo d’input.

Un problema qui: quale evento usare? Il più logico potrebbe essere l’evento change del campo di file: se il suo valore cambia, il finto campo d’input file dovrebbe anche cambiare.

Purtroppo Mozilla 1.6 non supporta l’evento change per i campi di tipo file. Per il bene di Mozilla,
è stato scelto l’evento mouseout che entrà in azione solo dopo che l’utente ha selezionato un file. (Funziona anche per Explorer ma non per Safari).

x[i].onchange = x[i].onmouseout = function () {
this.relatedElement.value = this.value;
}

Problemi e estensione

Un problema rimane: l’utente non può scegliere di caricare un file dopo di tutto.

Supponiamo che l’utente seleziona un file, poi in un secondo pensiero decide di non caricarlo.
In un normale <input type="file">, può semplicemente rimuovere il path e il file non sarà caricato.

Nel nostro esempio invece, è molto difficile farlo.
Provatelo, è fatibile ma non intuitivo.

Allora, quello che vogliamo fare è dare la possibilità a l’utente di selezionare e modificare il contenuto del finto campo d’input file e passare i cambiamenti al vero ‘file upload’.

Autorizzare la selezione è in una certa maniera possibile. Quando l’utente seleziona qualunque parte del vero ‘upload file’, selezioniamo l’intero valore del finto ‘upload file’.

x[i].onselect = function () {
this.relatedElement.select();
}

Sfortunatamente, le sicurezze Javascript non ci permettono di cambiare il valore di un <input type="file">. Di conseguenza, non possiamo lasciare l’utente cambiare manualmente il finto ‘input’. Di là, è stato scelto, di lasciare a perdere completamente l’evento onselect.

Una altra soluzione possibile sarebbe di aggiungere un pulsante ‘Clear’ al finto input, che aziona un script che completamente elimina il <input type="file"> e ne crea uno nuovo. E un pò confuso ma si potrebbe rimuovere completamente il file selezionato. Questa parte del script non è stato scritto e neanche è sicuro che potrebbe funzionare.

Tracciare l’evento click

Un lettore ha proposto di togliere tutto la parte complicata del CSS, completamente nascondere il campo del input file e ritracciare gli eventi ‘click’ sul finto campo di upload a quello vero. Un idea eccelente e molto più semplice di quella descritta sopra.

fakeField.onclick = function () {
realField.click()
}

Il metodo click() permette di simulare un ‘click’ su un campo del ‘form’. ‘Checkboxes’ sono azionati, pulsante ‘radio’ selezionati e cosi via. Purtroppo Mozilla e Opera non hanno aggiunto quel metodo per i campi di tipo ‘file upload’. Non si capisce il perche, aggiungerlo non sarebbe un rischio al livello sicurezza visto che il peggio che può succedere è che si apre la finestra popup per selezionare il file.

Per quella ragione, non possiamo usare questa soluzione proposta.

Sponsors of this article

About The Author

WebMaster

CEO e amministratore Network Flepstudio.org

Number of Entries : 85

Comments (2)

  • Pietro

    Gran bell’articolo. Peccato la traduzione orribile (scusa la franchezza, ma almeno controllare una volta ciò che si scrive)…

    Reply
  • Pharmd155

    Hello! dgebbdf interesting dgebbdf site! I’m really like it! Very, very dgebbdf good!

    Reply

Leave a Comment

© 2012 Powered By Flepstudio.org

Scroll to top