入力内容の量に応じたtextareaの自動サイズ変更

More than 3 years have passed since last update.

内容の分量に応じて、textareaの自動サイズ変更(高さ)をするスクリプトを書きました。

本来ならばjQuery Autosizeという素敵ライブラリがあるのですが、なぜだかこれが上手く動かなくて泣く泣く自前で作る羽目に。

一応、自分用にはjQueryを使って書いたんですが、jQueryを使わないバージョンも書いてみました。


index.html

<textarea id="ta"></textarea>



autoResize.js

//jquery使うバージョン

$("#ta").height(30);//init
$("#ta").css("lineHeight","20px");//init

$("#ta").on("input",function(evt){
if(evt.target.scrollHeight > evt.target.offsetHeight){
$(evt.target).height(evt.target.scrollHeight);
}else{
var lineHeight = Number($(evt.target).css("lineHeight").split("px")[0]);
while (true){
$(evt.target).height($(evt.target).height() - lineHeight);
if(evt.target.scrollHeight > evt.target.offsetHeight){
$(evt.target).height(evt.target.scrollHeight);
break;
}
}
}
});



autoResize.js

//jquery使わないバージョン

var ta = document.getElementById("ta");
ta.style.lineHeight = "20px";//init
ta.style.height = "30px";//init

ta.addEventListener("input",function(evt){
if(evt.target.scrollHeight > evt.target.offsetHeight){
evt.target.style.height = evt.target.scrollHeight + "px";
}else{
var height,lineHeight;
while (true){
height = Number(evt.target.style.height.split("px")[0]);
lineHeight = Number(evt.target.style.lineHeight.split("px")[0]);
evt.target.style.height = height - lineHeight + "px";
if(evt.target.scrollHeight > evt.target.offsetHeight){
evt.target.style.height = evt.target.scrollHeight + "px";
break;
}
}
}
});


ちなみに、heightだとかlineHeightだとかの項目は上記の例のようにプログラム中で指定するか、CSSで設定してあげる必要があります。

どちらもやってることは同じなので、jQueryの方を使って説明します。


1

//jquery使うバージョン

$("#ta").on("input",function(evt){
//...
});


まず、inputイベントに反応するようにリスナを設定します。


2

if(evt.target.scrollHeight > evt.target.offsetHeight){   

$(evt.target).height(evt.target.scrollHeight);
}

次に、scrollHeight(入力内容全体)とoffsetHeight(要素の大きさ)とを比較して、入力内容の方が大きい場合は、textareaのheightscrollHeightに合わせるようにします。これで、改行をしたり、文字数が増えて行を跨いだときなどに、自動的にtextareaのheightを増やし、入力内容の大きさに合わせてくれます。


3

else{          

var lineHeight = Number($(evt.target).css("lineHeight").split("px")[0]);
while (true){
$(evt.target).height($(evt.target).height() - lineHeight);
if(evt.target.scrollHeight > evt.target.offsetHeight){
$(evt.target).height(evt.target.scrollHeight);
break;
}
}
}

逆に、scrollHeightの方がoffsetHeightよりも小さい、あるいは同じ場合には、heightを減らしていきます。textareaのheightを1ラインずつ減らしていき、scrollHeightoffsetHeightよりも大きくなったところでheightscrollHeightに合わせるようにします。

なぜこんなことをしているかというと、offsetHeightからはみ出させないと、scrollHeightを入力内容の大きさとして扱えないからです。textarea内全ての入力内容がスクロールすることなく見えている場合、scrollHeightclientHeightと同じ値をとってしまいます。

以上です。

何かの参考になれば幸いです。

*参考*

jsStudio scrollHeight

MDN Element.scrollHeight

MDN HTMLElement.offsetHeight