contenteditableを使う
input/textarea以外の要素も編集可能にするcontenteditable属性なるものを知った。
<div contenteditable="true"">ここは編集可能</div>
こんな感じ。改行すると要素の大きさに合わせてエリア自体も大きくなる。
「入力に合わせてテキストエリアの高さをもごもごする」記事では、テキストエリア要素を自動でリサイズしたけど、こっちのほうが使い勝手がよさそう。
(※ contenteditableで大きさが変わるときは、transitionでアニメーション出来ない)
contenteditableが持つ値
contenteditableはtrue/false/inherit/空文字の値がとれる。
true・空文字 | false | inherit |
---|---|---|
編集可能 | 編集不可 | 親要素の値を継承する |
<div contenteditable="true""><span contenteditable="false">ここは編集できない</span>編集可能テキスト編集可能テキスト</div>
基本的には親要素の設定を引き継ぐけど、contenteditable="true"
の要素の中に contenteditable="false"
の要素を入れることもできる。
その時はfalseにした要素の中身は編集できないけど、falseにした要素の存在自体は編集できるので
BackSpaceでテキストを消していくと、falseにした要素はぱっと消える。
使いドコロとしては、SNSとかで使うメンションとかがいいんじゃないかと。
placeholderを付けたい
textarea的に使うならplaceholderを付けたい。
が、placeholderは一部のinputとtextareaにのみ有効なので、データ属性でどうにかする。
<div contenteditable="true" class="editablePlaceholder" data-placeholder="placeholderテキストが入る"></div>
.editablePlaceholder[contenteditable=true]:empty:before { position: absolute; top: 2px; left: 5px; color: #aaa; content: attr(data-placeholder); }
contentプロパティの値には要素の属性値を取ることもできるので、data-placeholder
という属性を持たせて擬似要素に突っ込む。
擬似クラスの:emptyを併用して、要素の中身空の場合のみ表示させる。
入力値の改行
contenteditable="true"
の要素内で改行をすると、改行された文字ごとにdiv
もしくはp
で囲まれる。
Chrome / Firefox / Safariではdiv
、IEではp
になるよう……謎。
入力されたコメントを保存する時にbr
に置換するなりしないと、ユーザーのブラウザによってデータに差異が出ちゃいそう。。。
更に、最初の改行までの文字はdiv
もしくはp
で囲まれずにただの文字列として打ち込まれるので、
複数行入力するとこんなことになる。
<div contenteditable="true"> 一行目のテキストほげほげ <div>二行目のテキストほげほげ</div> <div>三行目のテキストほげほげ</div> <div>四行目のテキストほげほげ</div> </div>
これを回避するには最初から空のdiv
を入れておくと良さそう。
<div contenteditable="true"> <div></div> </div>
見た目は特に変化がないけどこうしておくと、一行目のテキストは用意されたdiv
に入り、二行目以降が新しく生成されたdiv
に入るようになる。
でもこれを使うと、要素の中身空の場合のみ表示させる:emptyが使えなくなるのでplaceholderの表示方法をJSとかで調整する必要がある。
classで擬似要素の有無を制御しつつ、要素に対してキー入力があった場合に中のテキストを取得→空ならclassを付けてplaceholderを表示する、とかね。
IE謎の空白文字問題
一度入力した文字を全て消した後に、入力エリアに半角スペースが幾つか出現する自体が発生。
どうやらインデントに使用していた半角スペースが出てくるらしく、contenteditable="true"
に子要素をもたせる場合はインデントを付けないようにしないとおかしなことになる。
<div contenteditable="true"><div></div></div>