样式化input type="file"按钮

1072
如何为按钮添加样式?

<input type="file" />


我会添加我的答案,以展示我是如何做到的...但这里有一个基于Bootstrap的例子,可能会有所帮助。http://geniuscarrier.com/how-to-style-a-html-file-upload-button-in-pure-css/ - Vishnu Narang
这个元素的问题似乎是它不像其他类似的元素那样接受样式。比如 input type="submit">。我将相同的样式应用于两种输入类型,这就是我得到的结果:https://i.imgur.com/7MI1Poh.jpg。 - carloswm85
对我来说有效的方法是在输入元素上方放置一个 div 并将 div 样式设置为所需样式。然后将输入元素的不透明度设置为 0 并将其大小设置为与 div 相同。 - Ricardo Figueiredo
48个回答

1553

这个不需要 JavaScript!这是一个跨浏览器的解决方案:

查看示例! - 它在 Chrome/FF/IE (IE10/9/8/7)中工作。

最好的方法是使用一个自定义标签元素,该元素带有附加到一个隐藏文件输入元素上的for属性。(为了使其正常工作,标签的for属性必须与文件元素的id匹配)。

<label for="file-upload" class="custom-file-upload">
    Custom Upload
</label>
<input id="file-upload" type="file"/>

作为一种替代方式,您还可以直接使用标签将文件输入元素包装起来:(示例)

<label class="custom-file-upload">
    <input type="file"/>
    Custom Upload
</label>

在样式方面,只需使用属性选择器隐藏输入元素即可。1

input[type="file"] {
    display: none;
}

接下来你需要做的就是给自定义的 label 元素添加样式。 (示例).

.custom-file-upload {
    border: 1px solid #ccc;
    display: inline-block;
    padding: 6px 12px;
    cursor: pointer;
}

1 - 值得注意的是,如果你使用 display: none 来隐藏元素,在 IE8 及以下版本中将无法正常工作。另外要注意的是,默认情况下 jQuery validate 不会验证隐藏字段。如果这些问题对你有影响,以下是两种在这些情况下可用的隐藏输入框的方法 (1, 2)。


81
我确实有一个问题,当选择文件时,我们如何显示文件名? - Richlewis
28
如果 input[type=file]display: none 被设置了,如何显示所选文件的名称? - Sarthak Singhal
64
非常好的解决方案,但实际上您需要 JavaScript。如果您想显示文件名,就像其他人一样询问的那样,您需要在标签和隐藏的输入框之间添加一个 span 标签:<span id="file-selected"></span>。然后在更改事件中更新该 span 标签: $('#file-upload').bind('change', function() { var fileName = ''; fileName = $(this).val(); $('#file-selected').html(fileName); }) - Sam
23
出于无障碍考虑,你应该使用“position: absolute; left: -99999rem”而不是“display: none”。大多数情况下,如果使用“display: none”方法隐藏元素,屏幕阅读器将不会朗读它们。 - Capsule
54
我很惊讶地发现似乎没有人考虑到键盘可访问性。与buttoninput不同,label元素无法通过键盘访问。添加tabindex并不是解决方案,因为当用户按下回车键时,即使label具有焦点,它仍然无法被操作。我通过视觉上隐藏输入框来解决这个问题,这样它仍然可以聚焦,并在label的父元素上使用:focus-within:http://jsbin.com/fokexoc/2/edit?html,css,output - Oliver Joseph Ash
显示剩余22条评论

303

样式化文件输入框非常困难,因为大多数浏览器不会根据CSS或JavaScript更改其外观。

即使是输入框的大小也无法响应以下样式:

<input type="file" style="width:200px">

相反,你需要使用 size 属性:

<input type="file" size="60" />

如果你想要更为复杂的样式(比如改变浏览按钮的外观),你需要采用一种巧妙的方法,在原生文件输入框上叠加一个带有样式的按钮和输入框。rm在www.quirksmode.org/dom/inputfile.html中提到的文章是我见过的最好的。

更新

虽然直接为<input>标签添加样式很困难,但是通过使用<label>标签可以轻松实现。请参考@JoshCrozier的答案:https://dev59.com/dXRB5IYBdhLWcg3wn4UL#25825731


7
刚刚找到一个基于这个脚本的jQuery解决方案:http://blog.vworld.at/2008/08/21/styling-an-input-typefile-using-jquery/。 - mtness
1
@TLK Ryan的答案在尝试使用iframe上传时在IE中无法工作。它会给你一个访问被拒绝的错误。对于普通上传,我同意它是最简单的! - frostymarvelous
3
比quirksmode的解决方案更简单的方法在这里被解释了此处链接。由于这个答案基本上只是一个链接,所以在这里只放置该链接。 - Joeytje50
13
对于任何对现代方法感兴趣的人,我建议查看这个答案。与其他答案不同,它也不需要JavaScript。 - Josh Crozier
3
@JoshCrozier发布了一种非常好的解决方案,甚至比模拟鼠标点击的解决方案更好。 - Lodewijk
我猜测有很好的安全原因使得浏览器以标准化、始终可识别的方式离开其沙盒。 - tObi

219

按照以下步骤,您可以为文件上传表单创建自定义样式:

  1. this is the simple HTML form(please read the HTML comments I have written here below)

    <form action="#type your action here" method="POST" enctype="multipart/form-data">
      <div id="yourBtn" style="height: 50px; width: 100px;border: 1px dashed #BBB; cursor:pointer;" onclick="getFile()">Click to upload!</div>
      <!-- this is your file input tag, so i hide it!-->
      <div style='height: 0px;width:0px; overflow:hidden;'><input id="upfile" type="file" value="upload"/></div>
      <!-- here you can have file submit button or you can write a simple script to upload the file automatically-->
      <input type="submit" value='submit' >
    </form>
    
  2. then use this simple script to pass the click event to file input tag.

    function getFile(){
         document.getElementById("upfile").click();
    }
    

    Now you can use any type of styling without worrying about how to change default styles.

我非常清楚这一点,因为我已经尝试了一个半月来更改默认样式。相信我,这非常困难,因为不同的浏览器有不同的上传输入标签。因此,请使用这个来构建您自定义的文件上传表单。以下是完整的自动化上传代码。

function getFile() {
  document.getElementById("upfile").click();
}

function sub(obj) {
  var file = obj.value;
  var fileName = file.split("\\");
  document.getElementById("yourBtn").innerHTML = fileName[fileName.length - 1];
  document.myForm.submit();
  event.preventDefault();
}
#yourBtn {
  position: relative;
  top: 150px;
  font-family: calibri;
  width: 150px;
  padding: 10px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border: 1px dashed #BBB;
  text-align: center;
  background-color: #DDD;
  cursor: pointer;
}
<form action="#type your action here" method="POST" enctype="multipart/form-data" name="myForm">
  <div id="yourBtn" onclick="getFile()">click to upload a file</div>
  <!-- this is your file input tag, so i hide it!-->
  <!-- i used the onchange event to fire the form submission-->
  <div style='height: 0px;width: 0px; overflow:hidden;'><input id="upfile" type="file" value="upload" onchange="sub(this)" /></div>
  <!-- here you can have file submit button or you can write a simple script to upload the file automatically-->
  <!-- <input type="submit" value='submit' > -->
</form>


6
感谢您的推荐。在这里,我使用了非常简单的JavaScript,无需使用像Jquery或PrototypeJS这样的框架。 - teshguru
7
我在IE9中提交表单时遇到了问题。使用JavaScript提交表单时,我会收到一个“拒绝访问”的错误。如果我通过UI点击提交按钮,则可以成功提交。有没有解决这个问题的方法? - Kevin
1
@kevin -> 请在 document.myForm.submit() 后尝试使用 event.preventDefault(),我已经对上述代码进行了更改。 - teshguru
1
在Chrome、Firefox、Safari和Opera中运行良好,但在IE9中无法正常工作。在IE9中,我会遇到与@Kevin相同的“访问被拒绝”错误,有时甚至会默默失败而没有任何错误提示。 - daveywc
10
在IE10(和可能是IE9等版本中),如果您尝试通过JavaScript在点击文件输入按钮后自动提交表单,则会收到“访问被拒绝”(或来自jQuery的无响应)。因此,只要用户仍然是提交表单的人,该方法就适用于样式化文件输入按钮。我花了一段时间才发现这个问题,我看到其他人也有同样的问题。请参见此处以获取更多信息https://dev59.com/V2865IYBdhLWcg3wM7u0#4335390。 - Jeff Widmer
显示剩余10条评论

141

::文件选择按钮

https://developer.mozilla.org/en-US/docs/Web/CSS/::file-selector-button

这是一个新的选择器,可以用来为文件选择按钮设置样式。
它在最新的浏览器版本上有完全支持。

input[type=file]::file-selector-button {
  border: 2px solid #6c5ce7;
  padding: .2em .4em;
  border-radius: .2em;
  background-color: #a29bfe;
  transition: 1s;
}

input[type=file]::file-selector-button:hover {
  background-color: #81ecec;
  border: 2px solid #00cec9;
}
<form>
  <label for="fileUpload">Upload file</label>
  <input type="file" id="fileUpload">
</form>

这里有另一个片段,展示了不同的样式:

.input_container {
  border: 1px solid #e5e5e5;
}

input[type=file]::file-selector-button {
  background-color: #fff;
  color: #000;
  border: 0px;
  border-right: 1px solid #e5e5e5;
  padding: 10px 15px;
  margin-right: 20px;
  transition: .5s;
}

input[type=file]::file-selector-button:hover {
  background-color: #eee;
  border: 0px;
  border-right: 1px solid #e5e5e5;
}
<form>
  <div class="input_container">
    <input type="file" id="fileUpload">
  </div>
</form>

我觉得有必要给出这个答案,因为这里的大多数答案都已经过时了。

自定义输入文本

如果您想要自定义文件选择按钮的文本,这里有一个代码片段:

document.querySelector("#files").onchange = function() {
  const fileName = this.files[0]?.name;
  const label = document.querySelector("label[for=files]");
  label.innerText = fileName ?? "Browse Files";
};
label {
  border: 1px solid #e5e5e5;
  border-radius: 10px;
  padding: 5px 10px;
  font-family: 'Helvetica', sans-serif;
  transition: .5s;
}

label:hover {
  background-color: #eee;
}
<div class="input_container">
  <label for="files" class="btn">Browse Files</label>
  <input id="files" style="display:none;" type="file">
</div>

我更喜欢使用简单的基本解决方案。如果你想要一个以上代码片段的jQuery版本,请查看这篇文章

6
这真的是人们想要的答案。非常感谢!点赞! - Front-end-developper-Diogo
1
能否更改按钮文本? - Alex78191
1
跨桌面和移动浏览器的最佳解决方案和出色支持。 - developing brandon
1
如何保留第二个布局并且仍然能够更改i18n的文本? - V. Sambor
1
此外,Bootstrap CSS https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.css 包含一些很好的基本样式。在文件中搜索 '::file-selector-button'。 - undefined

87
所有渲染引擎在创建<input type="file">时都会自动生成一个按钮。历史上,该按钮是无法进行样式设计的。然而,Trident和WebKit通过伪元素添加了钩子。 ::-ms-browse伪元素可以用于样式化IE10及以上版本中的文件输入按钮。基本上,所有应用到常规按钮的CSS规则都可以应用到这个伪元素。例如:

::-ms-browse {
  background: black;
  color: red;
  padding: 1em;
}
<input type="file">

在Windows 8上的IE10中,它的显示如下:

在Windows 8上的IE10中,它的显示如下:

WebKit

WebKit提供了一个伪元素::-webkit-file-upload-button用于其文件输入按钮。同样,几乎可以应用任何CSS规则,因此Trident示例在此也适用:

::-webkit-file-upload-button {
  background: black;
  color: red;
  padding: 1em;
}
<input type="file">

这在 OS X 上的 Chrome 26 中显示如下:

这在 OS X 上的 Chrome 26 中显示如下:


2
在你的回答中,使用CSS,如何隐藏<input type=file>标签中的“未选择文件”字样。请评论我。 - user2086641
我不知道,抱歉。 - Anselm
火狐浏览器中的选择器是什么? - rderoldan1
2
伪元素列表以样式化表单控件 - Anselm
2
如果有人想尝试样式,我在这里添加了一个JSFiddle链接:http://jsfiddle.net/peter_drinnan/r0gq6kw2/。 - Peter Drinnan
显示剩余3条评论

79

使用CSS隐藏它,并使用自定义按钮和 `$(selector).click()` 来激活浏览按钮。然后设置一个间隔来检查文件输入类型的值。该间隔可以为用户显示正在上传的内容。当表单提交时,间隔将被清除。[编辑]抱歉我一直很忙,本意是更新这篇文章,这里是一个例子

<form action="uploadScript.php" method="post" enctype="multipart/form-data">
<div>
    <!-- filename to display to the user -->
    <p id="file-name" class="margin-10 bold-10"></p>

    <!-- Hide this from the users view with css display:none; -->
    <input class="display-none" id="file-type" type="file" size="4" name="file"/>

    <!-- Style this button with type image or css whatever you wish -->
    <input id="browse-click" type="button" class="button" value="Browse for files"/>

    <!-- submit button -->
    <input type="submit" class="button" value="Change"/>
</div>

$(window).load(function () {
    var intervalFunc = function () {
        $('#file-name').html($('#file-type').val());
    };
    $('#browse-click').on('click', function () { // use .live() for older versions of jQuery
        $('#file-type').click();
        setInterval(intervalFunc, 1);
        return false;
    });
});

8
请注意,如果您使用此方法,它将在Internet Explorer中发生故障,因为这是一个安全异常。 - Rejinderi
1
感谢您的提示。当我使用IE时,它通常有一个单独的布局与其他所有东西不同。讨厌IE。但是我在IE中简化了一切。 - Ryan
1
使用FF20时,$('#file-type').click()似乎无法弹出“选择文件”对话框-实际上什么都没有发生。有任何想法吗? - andig
2
尝试在jQuery中使用触发器方法。此外,新的jQuery中.live已更改为.on()。 - Ryan
1
一旦您设置了该间隔,什么时候可以清除它?否则它将不断触发。 - Dave Haigh
显示剩余6条评论

74
对不起,我不能直接翻译代码。如果您有其他需要翻译的文本,请告诉我。
$('.new_Btn').click(function() {
  $('#html_btn').click();
});
.new_Btn {
  // your css propterties
}

#html_btn {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="new_Btn">SelectPicture</div><br>
<input id="html_btn" type='file' /><br>

你也可以使用普通的JavaScript而不是jQuery来达成你的目标。

现在,newBtn与html_btn链接起来了,你可以像想要的那样自定义你的新按钮 :D


1
只是好奇,它能在新一代的浏览器中工作吗,比如Firefox、IE、Opera、Safari、Chrome等? - Wh1T3h4Ck5
这对我来说是最简单的解决方案!至少在IE 9、Chrome 23和FF 16与jQuery 1.7.2中,所以使用更新版本应该可以工作。 - Dani bISHOP
有人知道如何在用户选择了图像的情况下更改.new_Btn吗?现在它只显示相同的类。有人知道如何跟踪吗?谢谢。 - Ando
2
@MehdiKaramosly 它甚至可以在IE 6上运行 - 但这只适用于jQuery 1.x,jQuery 2.x+不支持旧版IE。 - jave.web
1
@Ando 通过Javascript/jQuery => 文件输入的值为空或包含本地文件路径 => 使用onchange事件并测试val() :) 参见http://jsfiddle.net/ZrBPF/ - jave.web
document.getElementById('id_inputButtonReal').files.item(0).name 给出上传的文件名。将来参考 -- https://dev59.com/ZnI95IYBdhLWcg3wtwRe#43209669 - Aseem

43
如果您正在使用Bootstrap 3,这对我有用:
请参见https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/

.btn-file {
  position: relative;
  overflow: hidden;
}
.btn-file input[type=file] {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 100%;
  min-height: 100%;
  font-size: 100px;
  text-align: right;
  filter: alpha(opacity=0);
  opacity: 0;
  outline: none;
  background: white;
  cursor: inherit;
  display: block;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />

<span class="btn btn-primary btn-file">
    Browse...<input type="file">
</span>

它会生成以下文件输入按钮:

Example button

认真地,看看https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/

2
这保留了拖放功能,这非常棒:),大多数答案不接受拖放文件。 - A1rPun
那个链接已经失效了 :/ - Decapitated Soul
不要忘记在 span 标签中添加 role="button"。 - ONE_FE

34

这里提供原生拖放支持的工作示例:https://jsfiddle.net/j40xvkb3/

当样式化文件输入框时,不能破坏该输入框提供的任何原生交互功能

display: none 方法会破坏原生的拖放支持。

为了不破坏任何功能,你应该使用 opacity: 0 方法来处理输入框,并将其通过相对/绝对定位方式置于包装器中。

使用此技术,您可以轻松地为用户样式化一个单击/拖放区域,并在 dragenter 事件上添加自定义类以更新样式并向用户提供反馈,让他看到可以拖放文件。

HTML:

<label for="test">
  <div>Click or drop something here</div>
  <input type="file" id="test">
</label>

CSS:

input[type="file"] {
  position: absolute;
  left: 0;
  opacity: 0;
  top: 0;
  bottom: 0;
  width: 100%;
}

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ccc;
  border: 3px dotted #bebebe;
  border-radius: 10px;
}

label {
  display: inline-block;
  position: relative;
  height: 100px;
  width: 400px;
}

这里有一个可用的示例(包括处理 dragover 事件和接收文件的额外JS代码)。

https://jsfiddle.net/j40xvkb3/

希望这能有所帮助!


感谢您的帖子,如果添加了multiple="multiple"属性,这个功能是如何工作的?我拖动了2张图片,但只看到了第一张图片的路径。 - PirateApp
你在这里漏掉了代码。在 fiddle 上还有更多。使用了哪个库? - ctrl-alt-delor
在实施了这个解决方案并进行了进一步测试后,它似乎在Edge中也无法正常工作。 - ChrisA
@Tom 我从未遇到过这种技术问题。 - kevcha
1
啊,好的,我在你的回答中错过了带有相对定位的包装器 - 是我的错。如果输入在屏幕尺寸以下,浏览器会尝试滚动到它,并在此过程中将滚动容器向上移动页面。这里是一个演示:https://stackblitz.com/edit/input-file-overflow?file=style.css(只是没有完全展示绝对定位是行为的原因) - Tom
显示剩余4条评论

27

我可以使用下面的纯CSS代码完成它。我使用了Bootstrap和Font Awesome。

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet" />

<label class="btn btn-default btn-sm center-block btn-file">
  <i class="fa fa-upload fa-2x" aria-hidden="true"></i>
  <input type="file" style="display: none;">
</label>


哦,愿上帝保佑你,卡尔蒂克。 - Bamagujen_Bahaushe.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接