input要素のtype=”file”を装飾する方法

input要素のtype=”file”を装飾する方法

  • このエントリーをはてなブックマークに追加

こんにちは、Sonicmoov勤続5年弱のだってぃです。
いや~時がながれるのって本当に早いですね。
すっかりお局・・・いや、お局の男バージョンの言葉ってないんですかね?
まぁいい。別にお局でもいいや。
人生絶賛迷子中です。

気が付けば前回の記事「select要素を装飾するいくつかの方法」を書いてから1年半たっていますね。
・・・あれ?弊社のこのLab、人数的に考えて、半年に1度くらいは回ってくるはず
・・・ うん、まぁよしとしよう。もみ消そう!HAHAHA!

はい、今日は前回に引き続きフォーム関連要素の装飾のお話。
あの不可侵領域、input要素のtype=”file”の装飾方法をチェケラします。
デザイン変更できちゃうんですよ、実は。

ん?タイトル横の画像と内容が関係ないって?
はい、だって、ほら、input type=”file”っぽい画像って何?って感じですし。
でもアイキャッチ的な画像はあった方がいいって、たくさんの偉い人達が言ってますし。
しょうがないね。

まぁそれはいいとして、
図1

図2
になっちゃうんですよ!
素敵!!!!

その1.
Javascriptでinput type=”file”要素のイベントを・・・する方法

とりあえずデモを見てみる

結論からいいます、この方法はダメです。
なぜならばIEで動かない。
いや、一見動いているようにみえて実は・・・
フォーム送信されたときに値が入ってこない!!!

No more IE!!
No more IE!!!!

・・・・まぁでもこの方法の方が、楽ちん(そうか?)だし、まっとうな方法だと思うので、紹介するだけしておきます。

続きを読む

ざっくり手順

  1. 「ダミーとなるテキストフィールド(readonly)とボタン」実体となるinput type=”file”を配置。
  2. input type=”file”を非表示(display=”none”)
  3. javascriptでボタンと実体のクリックイベントをつなぎこみ

まぁ実際は値を取る手順があるのですが、考え方だけなら上記のとおりです。
あとはソースを見てもらった方が早い。
いや、違う、面倒くさいとかそうじゃなくて・・・そうじゃなくて・・・
はい、以下。

HTML

※わかりやすいように余計なタグはいれてません。

<div class="fileUploder">
	<input type="text" class="txt" readonly>
	<button class="btn">参照</button>
	<input type="file" class="uploader">
</div>

CSS

※わかりやすいように装飾系の指定はいれてません。

.fileUploder .uploader{
	display:none;
}

Javascript

※jQuery使ってます。

$(function(){
	fileUploader();
});
var fileUploader = function(){
	var self = this;
	//ラッパーのdiv
	var target = $('.fileUploder');
	
	//ボタンをクリックしたら、実体の方を起動
	this.setBtn = function(btn,txt,uploader){
		btn.bind('click',function(event){
			//イベントキャンセル
			event.preventDefault();
			//実体をクリックしたことに
			uploader.click();
			//テキストフィールドに値をいれる
			self.setTxt(txt,uploader);
			//一応モダンじゃないブラウザ用
			return false;
		});
	}	
	
	//テキストフィールドに値をいれる
	this.setTxt = function(txt,uploader){
		var timer = setTimeout(function(){
			//テキストフィールドに値が入っている時
			if(txt.val().length > 0){
				//タイマーをとめる
				clearTimeout(timer);
			}
			//テキストフィールドに値が入っていない時
			else{
				//実体の値を取得して、テキストフィールドに入れる
				txt.val(uploader.val())
				//もう一度実行
				self.setTxt(txt,uploader);
			}			
		},500)
	}
	
	//イベント割り当て
	target.each(function(){
		//ダミーのテキストフィールド
		var txt = $(this).find('.txt');
		//ファイルアップロードボタン
		var btn = $(this).find('.btn');
		//input[type=file]の実体
		var uploader = $(this).find('.uploader');
		
		//ボタンのイベントをセット
		self.setBtn(btn,txt,uploader);
	});
}

※jsはパパっと適当に書いたので、導入の際は自己流でやってみたほうがいいかも☆

実際に動いているものを見てみる

その2.
input type=”file”を透明にして上にかぶちゃう

とりあえずデモを見てみる

はい、こちらが本命。
本命の情報を後にもってきてしまった。
じらしテク。

ざっくり手順

  1. ダミーとなるテキストフィールド(readonly)とボタン、実体となるinput type=”file”を配置。
  2. ラッパーのdivをposition:relativeにして、適切な幅(デザイン依存)指定
  3. input type=”file”を絶対配置(position:absolute)にして、幅・高さを100%にしてラッパーのdivを覆い、透明化
  4. javascriptでinput type=”file”のonchangeイベントを拾い、ダミーのテキストフィールドに値をセット。

HTML

とりあえずHTMLはこんなん。
※その1と同じものです。

<div class="fileUploder">
	<input type="text" class="txt" readonly>
	<button class="btn">参照</button>
	<input type="file" class="uploader">
</div>

CSS

つぎにCSS・・・

.fileUploder{
	position:relative;
	/*↓幅はデザイン依存。場合によっては、指定しなくていい*/
	width:315px;
}
.fileUploder .uploader{
	position:absolute;
	top:0;
	right:0;
	/*↓念のため*/
	z-index:99;
	width:100%;
	height:100%;
	opacity:0;
}

これでいいはずだった・・・
そう・・・あいつさえいなければ・・・・
・・・・IE!!!

No more IE!!
No more IE!!!!

さて、IEの何が問題かというのを順を追ってみていきましょう。
まず、わかりやすいように上記のCSSの状態でopacity:0をとったものをIEでみてみましょう。

図3

おぉ・・・しっかりきっちりラッパーのdivに覆いかぶさって表示されてますね(わかりにくいけど)。

でも・・・でもね・・・・

img04

なんてこったい!!!!
なんで!なんでだよ、IE!!!!
ちなみにダブルクリックすれば、エクスプローラーが立ち上がります。
なんなんだその仕様。

てなわけで、IEは幅を指定しただけでは対応ができないんですよ、困ったことに。

さて、この問題をどう解決するかといいますと。
それは、ずばり!
font-size
です。

では実際にCSSを書き換えてみましょう。

.fileUploder{
	position:relative;
	/*↓幅はデザイン依存。場合によっては、指定しなくていい*/
	width:315px;
	/*↓はみ出した分隠す*/
	overflow:hidden;
}
.fileUploder .uploader{
	position:absolute;
	top:0;
	/*↓leftからrightに。ボタンが右にあるので、rightにしないとだめ。IE対策。*/
	right:0;
	/*↓念のため*/
	z-index:99;
	width:100%;
	height:100%;
	/*↓ここでフォームアイテムの大きさを調整。IE対策*/
	font-size:80px;	
}

これをIEで見ると。

図5

わかりにくいですが、確かに拡大されてます。
参照ってボタンの上がちょっと見えてるので、それでわかると思います。

ここでは、わかりやすいように80pxとしましたが、それだとまだクリックで反応しない部分が、かぶってきてしまっています。
なので、ここは思い切ってラッパーのdivの幅くらいのfont-sizeを指定してしまいましょう。
思いきり、大事。
人生と一緒ですね。

まさかのIEの壁を乗り越えた完全版CSSソースが以下!

.fileUploder{
	position:relative;
	/*↓幅はデザイン依存。場合によっては、指定しなくていい*/
	width:315px;
	/*↓高さ指定しないとIE7で領域がひろがる…?*/
	height:31px;
	/*↓はみ出した分隠す。IE対策*/
	overflow:hidden;
}
.fileUploder .uploader{
	position:absolute;
	top:0;
	/*↓leftからrightに。ボタンが右にあるので、rightにしないとだめ。IE対策。*/
	right:0;
	/*↓念のため*/
	z-index:99;
	width:100%;
	height:100%;
	/*↓ここでフォームアイテムの大きさを調整。IE対策*/
	font-size:315px;
	opacity:0;
	/*↓IE6,7対策*/
	filter:alpha(opacity=0);
	/*↓IE8対策*/
	-ms-filter:"alpha(opacity=0)";
}

これで、CSSはOKです。
細かい部分は要件によって変えてくださいませ。

Javascript

最後にjavascriptはまぁちゃちゃっと。
その1と違うのは実体のonchangeでやってるってことですかね。

$(function(){
	fileUploader();
});
var fileUploader = function(){
	//ラッパーのdiv
	var target = $('.fileUploder');
	
	//イベント割り当て
	target.each(function(){
		//ダミーのテキストフィールド
		var txt = $(this).find('.txt');
		//ファイルアップロードボタン
		var btn = $(this).find('.btn');
		//input[type=file]の実体
		var uploader = $(this).find('.uploader');

		//実体が変更された時
		uploader.bind('change',function(){
			//テキストフィールドに値をいれる
			txt.val($(this).val());
		});

		//ボタンのイベントは無効にしておく
		btn.bind('click',function(event){
			//イベントキャンセル
			event.preventDefault();
			//一応モダンじゃないブラウザ用
			return false;
		});
		
		//ホバー処理(上にかぶせているので反応しないため)
		//ここはデザインの都合上いれている処理のため適宜変更を
		//class切り替えでやったほうがいいです。
		$(this).bind('mouseover',function(){
			btn.css('background-position','0 100%');
		});
		$(this).bind('mouseout',function(){
			btn.css('background-position','0 0');
		});
		
	});	
}

※jsはパパっと適当に書いたので(ry

実際に動いているものを見てみる

おわりに

なんというか、やはり時代が流れようともIEとの泥臭い戦いは終わらないわけで。
XPのサポートが打ち切られても、IE8を完全に無視できるようになるのはいつの日か・・・
まぁ頑張っていきましょうねてなことで。

あと3か月でアラフォー突入のだってぃがお伝えしました~。
またいつか~~~~☆ミ

・・・・アラフォー・・・・(´・ω・`)

  • このエントリーをはてなブックマークに追加

記事作成者の紹介

だってぃ(フロントエンドエンジニア)

sonicmoovコーディング担当の、だってぃです。「ダッティ」よりも「だってぃ」という表記の方が好きです。平仮名ラヴ。

関連するSONICMOOVのサービス

フロントエンドエンジニア募集中!

×

SNSでも情報配信中!ぜひご登録ください。

×

SNSでも
情報配信中!
SONICMOOV Facebookページ SONICMOOV Twitter
Wantedly 採用情報はこちら

新着の記事

mautic is open source marketing automation