まだ重たいCMSをお使いですか?
毎秒1000リクエスト を捌く超高速CMS「adiary

2012/08/22(水)input type="text"等の自由リサイズスクリプト

Google ChromeやFirefoxには標準で<textarea>の自由リサイズ機能(マウスでのリサイズ機能)がありますが、input type="text"等のテキストボックスにはその機能がありません。

jQueryで実装してみました。

使い方

以下のCSSとJavaScriptを導入してください。あとは自動的に機能が導入されます。

  • jQueryを先にロードしてください。必要バージョンは分かりません(苦笑)
  • Google ChromeとFirefoxで動作確認しています。
  • CSSの width が掴める部分のサイズになります。
  • CSSの z-index の下3桁(1000で割った余り)がテキストボックスの最小サイズになります。*1
  • CSSの display:none を有効にするとフォームリサイズ機能を無効にできます。
    • テキストボックスの初期サイズの方が小さい場合はそちらが最小サイズになります。
  • IE6,7で動作しましたが、IE8,9では動作しませんでした(動作しないだけで不具合はありません)。
    • 手前にあるspanよりも裏側にあるテキストボックスが優先される謎の仕様のせいです。

*1 : 最小値16px

ソース

修正BSDライセンスとします。

//////////////////////////////////////////////////////////////////////////////
//●input[type="text"], input[type="password"]の自由リサイズ
//							(C)2011 nabe@abk
//////////////////////////////////////////////////////////////////////////////
// Under source is New BSD License

$(function(){
	$('input').each( function(){
		if (this.type != 'text'
		 && this.type != 'search'
		 && this.type != 'tel'
		 && this.type != 'url'
		 && this.type != 'email'
		 && this.type != 'password'
		) return;
		set_input_resize($(this));
	} )

function set_input_resize(obj) {
	// テーマ側でのリサイズ機能の無効化手段なので必ず先に処理すること
	var span = $('<span>').addClass('resize-parts');
	if(span.css('display') == 'none') return;

	// 基準位置とする親オブジェクト探し
	var par = obj.parent();
	for(var i=0; i<999; i++) {
		if(par.css('display') == 'table-cell') {
			// テーブルセルの場合は、セル全体をdiv要素の中に移動する
			var cell  = par;
			var child = cell.contents();
			par = $('<div />').css('position', 'relative');
			child.each( function() {
				$(this).remove;
				par.append(this);
			});
			cell.append(par);
			break;
		}
		if(par.css('display') == 'block') {
			par.css('position', 'relative');
			break;
		}
		if(par[0].tagName == 'BODY') break;
		//
		par = par.parent();
	}
	par.append(span);
	// append してからでないと span.width() が決まらないブラウザがある
	span.css("left", obj.position().left +  obj.outerWidth() - span.width());
	span.css("top",  obj.position().top );
	span.css("height", obj.outerHeight() );
	
	// 最小幅算出
	var width = obj.width();
	var min_width = parseInt(span.css("z-index")) % 1000;
	if (min_width < 16) min_width=16;
	if (min_width > width) min_width=width;
	span.mousedown( function(evt){ evt_mousedown(evt, obj, min_width) });
}

function evt_mousedown(evt, obj, min_width) {
	var span = $(evt.target);
	var body = $('#body');
	span.attr('data-drag-X',    evt.pageX);
	span.attr("data-obj-width", obj.width() );
	span.attr("data-span-left", span.css('left') );

	var evt_mousemove = function(evt) {
		var offset = evt.pageX - parseInt(span.attr('data-drag-X'));
		var width  = parseInt(span.attr('data-obj-width')) + offset;
		if (width<min_width) {
			width  = min_width;
			offset = min_width - parseInt(span.attr('data-obj-width'));
		}
		// 幅設定
		obj.width(width);
		span.css("left", parseInt(span.attr('data-span-left')) + offset);
	};
	var evt_mouseup = function(evt) {
		body.unbind('mousemove', evt_mousemove);
		body.unbind('mouseup',   evt_mouseup);
	}

	// イベント登録
	body.mousemove( evt_mousemove );
	body.mouseup  ( evt_mouseup );
}

///
});

CSS。こちらも必ず読み込んでください。

span.resize-parts {
	width:		12px;		/* つかめる幅 */
	position:	absolute;

	cursor:		col-resize;
	z-index:	10050;		/* 下3桁がinput type="text"の最小サイズ */

	/* display:	none;	*/	/* リサイズ機能を無効にする */
	/* border:	1px solid red;	*/
}

解説

テキストボックスの右端の上に、spanタグを「position: absolute」で上に乗せています。

通常は<body>タグを基準にしますが、ウィンドウサイズを変えたり他の部分の要素のサイズが変わってテキストボックスの位置がずれた時に上乗せしているspan要素がずれてしまいます。それを防止するため、テキストボックスの所属する最も近いブロック要素(display: block)を探索して、そのブロック要素を「position: relative」に書き換えて位置基準としています。

テーブル要素内にテキストボックスが配置されている場合は、所属するテーブルセル全体をdivの中に入れなおしています(teble-cellを「position: relative」にしても無効なため)。

このように直近のブロック要素を「position: relative」に書き換えるため、CSS側のデザインによっては不具合が出る可能性があります。その場合は、スクリプトに細工することなく、span.resize-partsの「display: none」を有効にするとスクリプトは動作しなくなります。

マウスの移動イベントをbodyに対して貼り付けているのは、spanタグに対して行うとマウスがはみ出て広い損なうことがあるためです。

仕組みを理解したい場合

「border: 1px solid red;」を有効にしてみてください。