行数に応じtextareaの高さを自動調節するjQueryプラグイン「jQuery.autoHeightTextarea」とサンプルコード。スクロールバーを常時非表示にして,行の折り返しも加味したheightをリアルタイムで設定する

textareaの高さを自動調節するjQueryプラグイン。

textareaの入力内容の量・行数などに応じて,
textareaの要素の高さを自動的に増減・調節し,
タイピング中に自動的にタテに伸びたり縮んだりして,スクロールバーが表示されないようにする。

そのようなjQueryプラグイン「jQuery.autoHeightTextarea」の紹介と,サンプルコード。

HTMLファイル


sample.html

<!doctype html>
<html>
<head>

	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>textareaの高さを自動調節するjQueryプラグインのサンプルコード</title>
	
	<script src="jquery-3.3.1.min.js"></script>
	<script src="jquery.auto_height_textarea.js"></script>

</head>
<body>


<h1>textareaの高さを自動調節するjQueryプラグインのサンプル</h1>

<br>

<textarea
  id="ta"
>ここに文章を入力します。行数を変えてみましょう。</textarea>


<script>

$(function(){

	// テキストエリアの高さを自動調節
	$("#ta").autoHeightTextarea({

		// 初期の幅(指定必須)
		initial_width  : "300px",
		
		// 初期の高さ(指定必須)
		initial_height : "30px",
		
		// 初期の高さを適用した後で,直後に高さの自動調節をするかどうか
		initial_height_auto : true,
		
		// 行高(指定必須)
		line_height    : "20px"
	});

});


function log(s){
	console.log(s);
}


</script>


</body>
</html>

jQueryプラグイン

jquery.auto_height_textarea.js


/*

	Textareaの高さを行数に応じて自動調節するjQueryプラグイン
	
	
	@author : id:SourceCode-Student
	
	ver0.1 : 2019/05/27
	
	MIT License

*/

(function( $ ){


	// ---------- 公開メソッド ---------- 


	// jQueryオブジェクトのプロトタイプチェーンに,メソッドを登録する
	$.fn.autoHeightTextarea = function( obj )
	{
		// 初期化
		_init_textarea({
			initial_width  : obj.initial_width,

			initial_height : obj.initial_height,
			initial_height_auto : obj.initial_height_auto,

			line_height    : obj.line_height,
			
			jq_elem        : this
				// NOTE:
				// jQueryオブジェクトが渡るので,scrollHeightプロパティなどを
				// 直接読みだせない点に注意。(undefinedになる)
				// https://stackoverflow.com/questions/9392099/scrollheight-of-an-element-gives-undefined-value
		});
	};


	// ---------- 以下,非公開 ---------- 


	// 要素の初期化
	var _init_textarea = function( obj ){
		
		// 設定を取り出し
		var jq_elem        = obj.jq_elem;
		var initial_width  = obj.initial_width;
		var initial_height = obj.initial_height;
		if( ! initial_height ){
			// 指定し忘れると無限ループになるので
			initial_height = "20px";
		}
		var initial_height_auto = obj.initial_height_auto;
		var line_height = obj.line_height;
		
		// 属性を初期化
		jq_elem.css( "resize", "none" ); // 手動で高さを調節させない
		jq_elem.css( "width", initial_width );
		jq_elem.css( "lineHeight", line_height );
		jq_elem.height( initial_height ); // 初回自動調節の有無にかかわらず,指定は必須
			//log( "offsetHeight = " + jq_elem[0].offsetHeight + ", scrollHeight = " + jq_elem[0].scrollHeight );
		
		
		// 初回に高さを調節するか
		if( initial_height_auto ){

			// NOTE:
			// いったんsetTimeoutして処理を切らないと,
			// CSSの値が反映されないので
			// offsetHeightなどの値がブラウザ上で未計算でundefinedになり,
			// 無限ループになってしまう。
			setTimeout(function(){
				
				// 0ミリ秒後の遅延実行
				_adjust_textarea_height( jq_elem[0] );

			}, 0 );

		}

		// 入力イベントを登録
		jq_elem.on( "input", _onTextareaInput );
	};
	
	
	// 入力イベント発生時のリスナ
	var _onTextareaInput = function( evt ){
		
		// 対象要素
		var elem = evt.target;
			//log( "elem = " + elem );
		
		
		// 高さの調節を実行
		_adjust_textarea_height( elem );
	};
	
	
	// あるtextarea要素に,縦方向のスクロールバーが表示されてしまっているかどうか
	var _textarea_showing_scroll_bar  = function( elem ){

		// NOTE:
		//
		// ・scrollHeight : 
		// あふれた(overflowした)画面上に表示されていないコンテンツを含む
		// 要素の内容の高さ
		//
		// ・offsetHeight : 
		// 要素の height,padding,border を足したピクセル単位の数値
			//log( "elem.offsetHeight = " + elem.offsetHeight + ", elem.scrollHeight = " + elem.scrollHeight );
		
		// 要素の見かけ上の高さよりも,コンテンツ全体の高さのほうが長かったら
		// スクロールバーが表示されていることになる。
		return ( elem.offsetHeight < elem.scrollHeight );
		
	}
	
	
	// ある要素の高さを調節実行する
	var _adjust_textarea_height = function( elem ){
		
		// NOTE: 
		// 引数には,jQueryオブジェクトではなく
		// DOM要素が渡る点に注意する。
		
		
		// CSSの値が未計算ではないか?
		if(
			elem.offsetHeight
			&&
			elem.scrollHeight
		){
			// 値がセットされているのでOK
		}
		else
		{
			// 無限ループを避けるために逃げる
			return false;
		}

		
		// NOTE: 
		// これだけをやってもうまくいかない。・・・(★)
		// ENTERキーとBACKSPACEキーを交互に何度も押すと,
		// コンテンツの行数はそのままなのに,テキストエリアの高さだけが少しずつ増えてゆく。
		// なので,反復法による微調節が不可欠。
		//$( elem ).height( elem.scrollHeight );
		//return false;
		
		
		// textarea内にスクロールバーが表示されてしまっている?
		if( _textarea_showing_scroll_bar( elem ) )
		{
			// スクロールバーを消すために,要素を高くするべき
		
			// コンテンツの高さだけ,見かけも高くする
			$( elem ).height( elem.scrollHeight );
		}
		else
		{
			// textarea内にスクロールバーは表示されていないが,
			// 要素が高すぎるので
			// 低くすべき
		
			// textarea内の行高を取得
			var line_height = parseInt(
				$( elem ).css("lineHeight").split("px")[0], 
				10
			);
			
			// ちょっとずつ低くしてゆく
			var continue_flag = true;
			while( continue_flag ){
				
				// 現在の要素の高さ
				var current_height = $( elem ).height();
			
				// 1行低くする
				var new_height = current_height - line_height;
				$( elem ).height( new_height );
				
				// 要素を低くしたせいで,
				// textarea内にスクロールバーが表示されてしまっている?
				if( _textarea_showing_scroll_bar( elem ) )
				{
					// 要素の高さをコンテンツの高さに揃える
					$( elem ).height( elem.scrollHeight );
					
						// SOLVED: 謎
						// どうして初めからそうしないのか?↑
						// なぜ,わざわざ1行ずつ減らしてるの?ワカラ~ン 
						// →結果:上記(★)で理解しました。このwhileループは必須。
					
					continue_flag = false;
				}
			}
		}
	};


	// 参考資料
	
	// 入力内容の量に応じたtextareaの自動サイズ変更(whileで反復調節)
	// https://qiita.com/YoshiyukiKato/items/507b8022e6df5e996a59

	// 下記のコードはダメ。「lineHeight * 改行コードの個数」では,行が長く折り返した時に対応できない。
	// textareaを改行に応じて自動で高さが変わるようにする方法
	// https://qiita.com/ampersand/items/ceaa5066d44990d30df3
	
	// jQueryプラグインの作り方の参考
	// https://language-and-engineering.hatenablog.jp/entry/20121204/jQueryFakeTicTacToeJs

})( jQuery );

参考

入力内容の量に応じたtextareaの自動サイズ変更
https://qiita.com/YoshiyukiKato/items/507b8022e6df5e996a59

  • whileで反復調節


textareaを改行に応じて自動で高さが変わるようにする方法
https://qiita.com/ampersand/items/ceaa5066d44990d30df3

  • このコードはダメ。「lineHeight * 改行コードの個数」では,行が長く折り返した時に対応できないから。


jQueryプラグインの作り方の参考
https://language-and-engineering.hatenablog.jp/entry/20121204/jQueryFakeTicTacToeJs