Styliser le input file en CSS

Chaque navigateur possède son propre champ de <input type="file">, ce dernier n’est pratiquement pas modifiable en CSS. C’est fort dommage car d’une part, chaque navigateur possède son propre design de ce type de input, ce qui ne permet pas d’avoir une homogénéité entre les navigateurs, et d’autre part, cette impossibilité de le modifier via CSS ne permet pas d’adapter ce dernier au design de notre site. Notre objectif est donc de palier à cette lacune.

Cet article a initialement été écrit en 2013. En travaillant récemment sur la nouvelle version de Buzeo et en effectuant quelques recherches, je m’aperçois que chacun y va de sa propre technique. Par exemple, Pinterest utilise un simple bouton qui ouvre une popup avec cette fois l’input grossièrement stylisé… Pas ce que l’on cherche.

préférences buzeo

Panneau des préférences de Buzeo, lien au lieu du bouton input

Cependant, j’en retiens une qui me plaît beaucoup : elle est simple et full CSS ! Je laisse néanmoins également les techniques que j’avais précédemment identifié. Par ailleurs, il faut bien prendre en considération le support navigateur attendu. Dans le cas de Buzeo, je ne me soucie que des evergreen browsers.

Solution full CSS 2017

J’utilise cette technique pour les préférences utilisateur. Ce dernier a en effet la possibilité d’uploader une photo de profil. Dans le cas présent, l’input prend simplement la forme d’un lien, mais il ne tient qu’à vous d’en faire un bouton !

Vous le savez peut-être, mais les <label for="y"> permettent de mettre le focus sur un champ de formulaire. Nous allons donc tirer parti de cette spécificité pour déclencher l’explorateur de fichier de l’<input type="file">.

<!-- Nous avons ici notre label et l'input afférent -->
<label for="file" class="label-file">Choisir une image</label>
<input id="file" class="input-file" type="file">
// on personnalise le label comme on veut
.label-file {
    cursor: pointer;
    color: #00b1ca;
    font-weight: bold;
}
.label-file:hover {
    color: #25a5c4;
}

// et on masque le input
.input-file {
    display: none;
}

Et voilà, c’est tout. Super simple non ? Les explications ci-dessous concernent la technique que j’employais avant.

Une solution Full CSS

Avant que nous nous lancions dans la solution que je vais présenter ici, sachez qu’il existe une solution full CSS à ce petit problème. Cependant, il se trouve qu’elle n’est pas l’élue de mon cœur car elle présente un inconvénient que vous allez vite comprendre.

La solution full CSS, consiste à rendre le input transparent, et à placer un bouton sous lui. Simplissime !! En croyant cliquer sur le bouton, l’internaute clique alors sur votre input et déclenche l’ouverture du navigateur de fichiers. L’inconvénient à cela ? Le input recouvrant le bouton, vous ne pourrez jamais avoir d’effet CSS de type :hover, ou :focus, donc pas de retour visuel au survol de la souris. C’est dommage, d’autant plus si tout le reste de votre site présente cet effet. Ne cherche-t-on pas là justement à procurer une certaine homogénéité à notre site ?

La solution jQuery

Je le disais juste au dessus, il n’existe pas d’événement qui permette de déclencher l’ouverture du navigateur de fichier, mais on peut toujours utiliser la méthode clic() de jQuery pour déclencher un événement. En l’occurrence, nous voulons déclencher un clic sur le <input type="file"> lorsqu’on capture un clic sur notre bouton.

Le code voulez-vous ?

<div class="upload">
    <h1 class="browse">Sélectionnez des vidéos à charger :</h1>
    <input type="file" name="film" id="file" class="browse" multiple>
    <span id="file-select-button" class="browse button black">Sélectionnez des fichiers</span>
    <p class="browse"><strong>Taille maximale :</strong> 2 GB.</p>
    <p class="browse"><strong>Formats supportés :</strong> avi, flv, mp4, m4v, mkv, mov, mpg, mpeg, ogg, ogv, wmv, 3gp, 3g2.</p>
</div>

Nous avons donc notre <input type="file"> au dessus de notre bouton. Il va donc s’agir dans un premier temps de faire « disparaître » ce input. Attention toutefois, si je mets disparaître entre guillemets, c’est parce qu’on ne peut pas se permettre de le mettre en display: none;. En effet, pour des raisons de sécurité – la même raison d’ailleurs qui fait qu’on ne peut invoquer directement en JS l’explorateur de fichier du navigateur – il ne sera pas possible sur certains navigateurs de simuler un clic sur cet élément s’il est en display: none.

On le mettra donc en absolut, pour qu’il sorte du flux, une taille ridicule, et un z-index négatif, le tout afin qu’il soit caché derrière notre bouton. Voici mon petit bout de CSS :

.upload .browse input[type='file']{
    position: absolute;
    margin-top: 3px;
    margin-left: 3px;
    height: 1px;
    width: 1px;
    z-index: -5;
}

Enfin, en ce qui concerne l’élément de jQuery, il n’y a rien de sorcier. Il consiste juste à capturer le clic sur le span d’id file-select-button et de déclencher un clic sur notre input. Le tout en quelques lignes grâce à jQuery :

$('#file-select-button').click(function(){
    $('.upload input').click();
});

Je ne crois pas avoir besoin d’expliquer ce code là, niveau programmation, c’est pas trop ardu…

Déjà 4 réponses, rejoignez la discussion !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *