JavaScript
HTML5
jQuery

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

More than 1 year has 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