input type="file"をCSS3で装飾 改善版 IE7〜対応。
すごく昔に書いた、input type="file"をCSSとJavaScriptで綺麗に装飾するものの改善版を作りました。
Chrome23.0.1, Firefox17, Opera12, IE9,8,7で正常に表示されるのを確認。
■内容
・「参照」ボタンを押しても、textboxを押しても参照ダイアログが起動。
・ファイルを参照するとtextbox内にファイル名が入る。ファイル名が長い場合は「...」と省略される。
・「アップロード」ボタンがあった場合で作ってみた。押しても何も起こりませんが。
・画面内に複数入れたい場合は、"uploader"を複数入れることで対応可能。
・JavaScriptが無効な状態にも対応。無効な環境では普通のブラウザデフォルトのinput type="file"が出現し、 アップロードボタンの左に並びます。
IEは画像作ってないので必要であれば足してください。 ※IEのfilterでグラデ作ろうかとも思ったけど、あんまりすきじゃないので使ってません。
■ポイント
IE対策。trigger()で、潰して見えなくしたinput=fileをJavaScript経由でクリックさせる方法は IEには通用しないので(無効にされる)、力技でtextboxの上に透明にして重ねる方法を取りました。 ただ、IEのデフォルトのinput=fileは、
・参照したファイル名が入るテキストbox部分をクリックしても参照ダイアログが立ち上がらない。
・中身のテキストも修正可能
という罠があるので、font-sizeを大きくすることで「参照...」と書いてあるボタンのサイズを調整、 overflow: hiddenでカットという荒業で乗り切りました。
フェイクのinput要素(".text")は、 contenteditable="false" readonly="true"を付けることでタブキーなどでのフォーカスをお断りしています。
HTML
<div class="uploader no-js"> <input type="file" size="25"> <div class="fakeFile" contenteditable="false" readonly="true"> <p class="text"></p> <a href="javascript: void 0;" class="uiBtn browse" title="参照ボタンをクリックし写真選択後、アップロードボタンを押してください。">参照...</a> </div> <a href="javascript:void 0;" id="upload" class="uiBtn upload">アップロード</a> </div>
body { background: #272727; font-size: 12px; font-family: "メイリオ",Meiryo,"MS Pゴシック","MS PGothic",Tahoma,Verdana,Arial,'Hiragino Kaku Gothic Pro',sans-serif; } .uploader { position: absolute; top: 50%; left: 50%; width: 402px; margin: -15px 0 0 -200px; } /* // Fake file uploader ------------------------- */ .fakeFile { position: relative; float: left; height: 25px; overflow: visible; cursor: pointer; z-index: 1; } .no-js .fakeFile { display: none; } .fakeFile .text { float: left; width: 190px; height: 19px; margin: 1px 10px 0 0; padding: 1px 1px 1px 5px; border: 1px solid #000; border-radius: 2px; background: #161616; color: #ccc; line-height: 20px; white-space: nowrap; text-shadow: 0 0 -1px #333; overflow: hidden; text-overflow: ellipsis; cursor: pointer; box-shadow: inset 1px 1px 1px rgba(0,0,0,0.5), 1px 1px 0 rgba(255,255,255,0.1); } .uploader input[type="file"] { position: absolute; display: block; border: 0; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; z-index: 1; } .uploader.isIE input[type="file"] { position: absolute; left: 0; top: 0; width: 281px; height: 26px; margin: 0; font-size: 52px; opacity: .0; filter: alpha(opacity=0); -ms-filter: "alpha(opacity=0)"; cursor: pointer; z-index: 2; } .uploader.no-js input[type="file"] { width: auto; height: auto; display: inline; } /* IE7 */ *:first-child+html .uploader input[type="file"] { left: -7px; font-size: 72px; } /* // UI Parts: button ------------------------- */ .uiBtn:link, .uiBtn:visited { display: inline-block; padding: 6px 0; border: 1px solid #070a0d; border-radius: 2px; background: #363636; background: -moz-linear-gradient(top, #444, #262626); background: -webkit-linear-gradient(top, #444, #262626); background: -o-linear-gradient(top, #444, #262626); background: linear-gradient(to bottom, #444, #262626); color: #ddd; text-align: center; text-decoration: none; text-shadow: 0 -1px 0 #111; box-shadow: inset 0 0 2px rgba(100,100,100,0.5), 1px 1px 0 rgba(0,0,0,0.15); overflow: hidden; zoom: 1; } .uiBtn:hover, .uiBtn.hover { background: #444; background: -moz-linear-gradient(top, #525252, #2e2e2e); background: -webkit-linear-gradient(top, #525252, #2e2e2e); background: -o-linear-gradient(top, #525252, #2e2e2e); background: linear-gradient(to bottom, #525252, #2e2f30); color: #fff; } .uiBtn:active, .uiBtn.active { border-color: #000; background: #111; background: -moz-linear-gradient(top, #262626, #444); background: -webkit-linear-gradient(top, #262626, #444); background: -o-linear-gradient(top, #262626, #444); background: linear-gradient(to bottom, #262626, #444); color: #999; box-shadow: inset 1px 1px 1px rgba(0,0,0,0.3), 0 1px 0 rgba(255,255,255,0.1); } /* uiBtn overwrite */ a:link.browse, a:visited.browse, a:link.upload, a:visited.upload { display: block; float: left!important; width: 70px; height: 11px!important; line-height: 12px; border-radius: 0; } a:link.browse, a:visited.browse { border-top-left-radius: 2px; border-bottom-left-radius: 2px; } a:link.upload, a:visited.upload { width: 120px; margin-left: -1px; border-left-color: #161616; border-top-right-radius: 2px; border-bottom-right-radius: 2px; box-shadow: inset 0 0 2px rgba(100,100,100,0.5), inset 1px 0 0 rgba(150,150,150,0.3), 1px 1px 0 rgba(0,0,0,0.15); } a:active.upload { box-shadow: inset 1px 1px 1px rgba(0,0,0,0.3),1px 1px 0 rgba(255,255,255,0.1); } .no-js a:link.upload, .no-js a:visited.upload { display: inline-block; float: none!important; border-radius: 2px; box-shadow: inset 0 0 2px rgba(100,100,100,0.5), 1px 1px 0 rgba(0,0,0,0.15); }
$(function(){ $(".fakeFile").each(function(){ var $this = $(this), $browse = $this.children(".browse"), $file = $this.prev("input"); //JavaScript無効の状態ではno-jsを取る。Modernizrを入れていて<html>に".no-js"が付けている環境では、この記述は不要。 $this.parent().removeClass("no-js"); //IEはtrigger()でのクリックが効かないので対策。IE判定は横着してます--; if(/*@cc_on!@*/false) { $file .parent().addClass("isIE") .end() .bind({ click: function(e){ $(this).blur(); }, mousedown: function(){ $browse.addClass("active"); }, mouseup: function(){ $browse.removeClass("active"); }, mouseover: function(){ $browse.addClass("hover").tipsy("show"); }, mouseout: function(){ $browse.removeClass("hover active").tipsy("hide"); }, change: function(){ $(this).next().children(".text").text($(this).val()); } }); } else { //IE以外のブラウザではtriggerで。 $this.bind({ click: function(e){ $file.trigger("click"); }, mousedown: function(){ $browse.addClass("active"); }, mouseup: function(){ $browse.removeClass("active"); }, mouseover: function(){ $browse.addClass("hover").tipsy("show"); }, mouseout: function(){ $browse.removeClass("hover active").tipsy("hide"); } }); $file.change(function(){ $this.children(".text").text($(this).val()); }); } }); });