Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

HTML と CSS だけでコードエディタっぽいものを作る (contenteditable, CSS Counter, ::before pseudo-element, Flexbox)

More than 1 year has passed since last update.

行番号を右側に表示できてテキストを折り返して表示できる JS 不要の入力ボックスを作る。
完成品はこちら。

See the Pen Text Editor by Mizuki HAGIMOTO (@mizkichan) on CodePen.

編集可能な要素を作る

<textarea> はスタイリングが難しすぎる。<input type="text"> だと1行しか入力できず、複数並べて使おうとすると JS が必須になる。そこで contenteditable 属性1を使う。

index.html
<div id="editor" contenteditable="true"></div>

これで内容を編集できる <div> 要素が作れる。それぞれの行は <div> 要素で囲まれて <div id="editor"> の子ノードになる。たとえば foobar と入力すると

<div id="editor" contenteditable="true">
  <div>foo</div>
  <div>bar</div>
</div>

のような形で DOM に格納される2

行番号を表示する

行番号の計算と表示には CSS Counter が使える。counter-increment プロパティ3を使うと、このプロパティが適用される要素が現れるたびにカウンタを加算することができる。各行の <div> 要素にこのプロパティを適用することで、行番号カウンタ lineno が加算されるようにする。

style.css
#editor > div {
  counter-increment: lineno;
}

カウンタの値は counter() 関数4を使って文字列に変換でき、 content プロパティ5の値として用いることができる。各行の <div> 要素の ::before 疑似要素6にこれらのプロパティを適用することで、各行の直前に行番号を表示することができる。

style.css
#editor > div::before {
  content: counter(lineno);
}

レイアウト等を調整する

表示すべきものはこれで十分だが、行番号とテキストとの間に隙間が全くないし、行番号が2桁になるとその行からテキストの表示開始位置がズレてしまうし、テキストが長くなると折り返しが行番号の真下から始まってしまう。

まず行番号をどうにかしよう。::before 疑似要素は他のインライン要素と同様の仕方でスタイリングできる。インラインブロック要素に変更して、幅を指定して、右側にマージンをつけて、右寄せにする。

style.css
#editor > div::before {
  display: inline-block;
  width: 2em;
  margin-right: 1em;
  text-align: right;
}

テキスト折り返しを考慮しないなら7これだけでよいが、考慮するならもう一工夫いる。要するに、1行ごとに行番号とテキストが同じ高さで並ぶようにすればよい。Flexbox8 の出番である。この場合は単に display プロパティの値に flex を指定すればよい。先ほどの例の #editor > div::before { display: inline-block; } は削除されたい。

style.css
#editor > div {
  display: flex;
}

#editor > div::before {
  /* 削除: display: inline-block; */
}

おわりに

これだけでは勝手が悪い動作をするので何だかんだいっても JS でイベントを待機していじくり回す必要がある。がんばれ。


  1. https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable 

  2. 正確には、改行を入力しない場合は単一のテキストノードが <div id="editor"> の直接の子ノードになるという例外がある。この記事における実装では、改行なしの一行しかテキストがない場合のスタイルを用意していないので、その場合は行番号が表示されない。そもそも CSS でテキストノードないしはテキストノードしか含まない要素を選択する方法がない(と思う)。 

  3. https://developer.mozilla.org/en-US/docs/Web/CSS/counter-increment 

  4. https://developer.mozilla.org/en-US/docs/Web/CSS/counter 

  5. https://developer.mozilla.org/en-US/docs/Web/CSS/content 

  6. https://developer.mozilla.org/en-US/docs/Web/CSS/::before 

  7. white-space: nowrap; を指定する。https://developer.mozilla.org/en-US/docs/Web/CSS/white-space 

  8. https://developer.mozilla.org/en-US/docs/Glossary/Flexbox 

mizkichan
高専→文学部哲学科→文学研究科哲学専攻。
https://mizkichan.github.io
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away