Estilo personalizado entre navegadores para el botón de carga de archivos [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Estoy tratando de diseñar un botón de carga de archivos a mis preferencias personales, pero no pude encontrar ninguna manera realmente sólida de hacer esto sin JS. Encontré dos otras preguntas sobre este tema, pero las respuestas allí JavaScript, o sugirió el enfoque de Quirksmode.

Mi mayor problema con este enfoque de Quirksmode es que el botón de archivo todavía tendrá las dimensiones definidas por el navegador, por lo que no se ajustará automáticamente a lo que se utiliza como botón que se coloca debajo de él. He hecho un poco de código, basado en él, pero solo ocupará el espacio que el botón de archivo normalmente ocuparía, por lo que no llenará el div padre como lo quiero a.

HTML:

<div class="myLabel">
    <input type="file"/>
    <span>My Label</span>
</div>

CSS:

.myLabel {
    position: relative;
}
.myLabel input {
    position: absolute;
    z-index: 2;
    opacity: 0;
    width: 100%;
    height: 100%;
}

Este violín demuestra cómo este enfoque es bastante defectuoso. En Chrome, al hacer clic en !! debajo del segundo botón de demostración se abrirá el diálogo de archivo de todos modos, pero también en todos los demás navegadores, el botón de archivo no ocupa las áreas correctas del botón.

¿Hay alguna forma más sólida de estilizar el botón de carga de archivos, sin ningún JavaScript, y preferiblemente usando tan poca codificación 'hacky' como posible (ya que la piratería generalmente trae otros problemas junto con él, como los que están en el violín)?

Author: Community, 2014-02-18

7 answers

Estoy publicando esto porque (para mi sorpresa) no había ningún otro lugar que pudiera encontrar que recomendara esto.

Hay una manera muy fácil de hacer esto, sin restringirte a las dimensiones de entrada definidas por el navegador. Simplemente use la etiqueta <label> alrededor de un botón oculto de carga de archivos. Esto permite aún más libertad en el estilo que el estilo permitido a través de el estilo incorporado de webkit[1].

La etiqueta fue hecha con el propósito exacto de dirigir cualquier haga clic en eventos en él para las entradas secundarias[2], por lo tanto, al usar eso, ya no necesitará ningún JavaScript para dirigir el evento de clic al botón de entrada. Usarías algo como lo siguiente:

label.myLabel input[type="file"] {
    position:absolute;
    top: -1000px;
}

/***** Example custom styling *****/
.myLabel {
    border: 2px solid #AAA;
    border-radius: 4px;
    padding: 2px 5px;
    margin: 2px;
    background: #DDD;
    display: inline-block;
}
.myLabel:hover {
    background: #CCC;
}
.myLabel:active {
    background: #CCF;
}
.myLabel :invalid + span {
    color: #A44;
}
.myLabel :valid + span {
    color: #4A4;
}
<label class="myLabel">
    <input type="file" required/>
    <span>My Label</span>
</label>

He utilizado una posición fija para ocultar la entrada, para que funcione incluso en versiones antiguas de Internet Explorer (IE8 emulado - se negó a trabajar en un visibility:hidden o display:none archivo de entrada). He probado en IE7 emulado y arriba, y funcionó perfectamente.


  1. No puedes usar <button> s dentro de las etiquetas <label> desafortunadamente, así que tendrás que definir los estilos para los botones tú mismo. Para mí, este es el único inconveniente de este enfoque.
  2. Si se define el atributo for, su valor se utiliza para activar la entrada con el mismo id que el atributo for en el <label>.
 262
Author: Joeytje50,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-22 21:07:53

A continuación encontrará una forma que funciona en todos los navegadores. Básicamente pongo la entrada en la parte superior de la imagen. Lo hago enorme usando font-size para que el usuario siempre haga clic en el botón cargar.

.myFile {
  position: relative;
  overflow: hidden;
  float: left;
  clear: left;
}
.myFile input[type="file"] {
  display: block;
  position: absolute;
  top: 0;
  right: 0;
  opacity: 0;
  font-size: 100px;
  filter: alpha(opacity=0);
  cursor: pointer;
}
<label class="myFile">
  <img src="http://wscont1.apps.microsoft.com/winstore/1x/c37a9d99-6698-4339-acf3-c01daa75fb65/Icon.13385.png" alt="" />
  <input type="file" />
</label>
 10
Author: regisbsb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-30 19:09:08

El mejor ejemplo es este, Sin ocultar, sin jQuery, es completamente puro CSS

Http://css-tricks.com/snippets/css/custom-file-input-styling-webkitblink /

.custom-file-input::-webkit-file-upload-button {
    visibility: hidden;
}

.custom-file-input::before {
    content: 'Select some files';
    display: inline-block;
    background: -webkit-linear-gradient(top, #f9f9f9, #e3e3e3);
    border: 1px solid #999;
    border-radius: 3px;
    padding: 5px 8px;
    outline: none;
    white-space: nowrap;
    -webkit-user-select: none;
    cursor: pointer;
    text-shadow: 1px 1px #fff;
    font-weight: 700;
    font-size: 10pt;
}

.custom-file-input:hover::before {
    border-color: black;
}

.custom-file-input:active::before {
    background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9);
}
<input type="file" class="custom-file-input">
 8
Author: Shamal Sandeep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-25 16:44:01

Esto parece ocuparse de los negocios bastante bien. Un fidde está aquí:

HTML

<label for="upload-file">A proper input label</label>

<div class="upload-button">

    <div class="upload-cover">
         Upload text or whatevers
    </div>

    <!-- this is later in the source so it'll be "on top" -->
    <input name="upload-file" type="file" />

</div> <!-- .upload-button -->

CSS

/* first things first - get your box-model straight*/
*, *:before, *:after {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

label {
    /* just positioning */
    float: left; 
    margin-bottom: .5em;
}

.upload-button {
    /* key */
    position: relative;
    overflow: hidden;

    /* just positioning */
    float: left; 
    clear: left;
}

.upload-cover { 
    /* basically just style this however you want - the overlaying file upload should spread out and fill whatever you turn this into */
    background-color: gray;
    text-align: center;
    padding: .5em 1em;
    border-radius: 2em;
    border: 5px solid rgba(0,0,0,.1);

    cursor: pointer;
}

.upload-button input[type="file"] {
    display: block;
    position: absolute;
    top: 0; left: 0;
    margin-left: -75px; /* gets that button with no-pointer-cursor off to the left and out of the way */
    width: 200%; /* over compensates for the above - I would use calc or sass math if not here*/
    height: 100%;
    opacity: .2; /* left this here so you could see. Make it 0 */
    cursor: pointer;
    border: 1px solid red;
}

.upload-button:hover .upload-cover {
    background-color: #f06;
}
 2
Author: sheriffderek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-18 04:52:05

Cualquier forma fácil de cubrir TODAS las entradas de archivos es simplemente darle estilo a su entrada [type = button] y soltarla globalmente para convertir las entradas de archivos en botones:

$(document).ready(function() {
    $("input[type=file]").each(function () {
        var thisInput$ = $(this);
        var newElement = $("<input type='button' value='Choose File' />");
        newElement.click(function() {
            thisInput$.click();
        });
        thisInput$.after(newElement);
        thisInput$.hide();
    });
});

Aquí hay algunos CSS de botón de muestra que obtuve de http://cssdeck.com/labs/beautiful-flat-buttons :

input[type=button] {
  position: relative;
  vertical-align: top;
  width: 100%;
  height: 60px;
  padding: 0;
  font-size: 22px;
  color:white;
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  background: #454545;
  border: 0;
  border-bottom: 2px solid #2f2e2e;
  cursor: pointer;
  -webkit-box-shadow: inset 0 -2px #2f2e2e;
  box-shadow: inset 0 -2px #2f2e2e;
}
input[type=button]:active {
  top: 1px;
  outline: none;
  -webkit-box-shadow: none;
  box-shadow: none;
}
 1
Author: Cymricus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-11 15:07:55

Acabo de encontrar este problema y he escrito una solución para aquellos de ustedes que están usando Angular. Puede escribir una directiva personalizada compuesta por un contenedor, un botón y un elemento de entrada con archivo de tipo. Con CSS a continuación, coloque la entrada sobre el botón personalizado, pero con opacidad 0. Se establece la altura y el ancho de los contenedores exactamente en el ancho y el alto de desplazamiento del botón y la altura y el ancho de la entrada al 100% del contenedor.

La directiva

angular.module('myCoolApp')
  .directive('fileButton', function () {
    return {
      templateUrl: 'components/directives/fileButton/fileButton.html',
      restrict: 'E',
      link: function (scope, element, attributes) {

        var container = angular.element('.file-upload-container');
        var button = angular.element('.file-upload-button');

        container.css({
            position: 'relative',
            overflow: 'hidden',
            width: button.offsetWidth,
            height: button.offsetHeight
        })

      }

    };
  });

Un jade plantilla si está utilizando jade

div(class="file-upload-container") 
    button(class="file-upload-button") +
    input#file-upload(class="file-upload-input", type='file', onchange="doSomethingWhenFileIsSelected()")  

La misma plantilla en html si está utilizando html

<div class="file-upload-container">
   <button class="file-upload-button"></button>
   <input class="file-upload-input" id="file-upload" type="file" onchange="doSomethingWhenFileIsSelected()" /> 
</div>

El css

.file-upload-button {
    margin-top: 40px;
    padding: 30px;
    border: 1px solid black;
    height: 100px;
    width: 100px;
    background: transparent;
    font-size: 66px;
    padding-top: 0px;
    border-radius: 5px;
    border: 2px solid rgb(255, 228, 0); 
    color: rgb(255, 228, 0);
}

.file-upload-input {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}
 0
Author: Benjamin Conant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-07 21:11:31

También es fácil estilizar la etiqueta si está trabajando con Bootstrap y LESS:

label {
    .btn();
    .btn-primary();

    > input[type="file"] {
        display: none;
    }
}
 -2
Author: sdvnksv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-20 08:13:52