LoginSignup
0
0

More than 1 year has passed since last update.

HTMLの文章を行ごとに(折り返し位置も)分割して装飾をつける

Last updated at Posted at 2022-04-22

おら、アクセシビリティのことはよくわかんねぇんだけど、
とりあえず見た目は動いたぞ。

レイアウト後の折り返し位置も考慮して、行ごとに分割してスタイルを当てたいなって1万年と2000年前から思ってたんで、実装できて個人的にうれしいんですよね。

test.html - Google Chrome 2022_04_22 23_49_35.png

<html>
  <head>
    <style>
      #tmp-box {
        position: absolute;
        left: -100000px;
        white-space: pre-line;
      }
      #text-box > div {
        border-bottom: dashed 1px #aaa;
      }
    </style>
  </head>
  <body>
    <div id="tmp-box"></div>
    <div id="text-box"></div>
    <script>
      const text =
        '素早い茶色の狐はのろまな犬を飛び越える。\n素早い茶色の狐はのろまな犬を飛び越える。素早い茶色の狐はのろまな犬を飛び越える。';
      const tmpBox = document.getElementById('tmp-box');
      const textBox = document.getElementById('text-box');
      // 画面外に逃がしたtmp-boxに、描画領域の幅を設定する
      tmpBox.style.width = textBox.clientWidth + 'px';
      // 一文字ずつspanでつつむ
      const chars = text.split('').map((c) => {
        const span = document.createElement('span');
        span.textContent = c;
        return span;
      });
      // 仮想DOM使わないと重くなる
      const div = document.createElement('div');
      div.append(...chars);
      tmpBox.append(div);
      // 行ごとのdivに変換
      const lines = chars
        .reduce((prev, span) => {
          const lastLine = prev[prev.length - 1];
          // offsetTopの値が変わっていれば改行しているはず
          if (lastLine && lastLine[0]?.offsetTop === span.offsetTop) {
            lastLine.push(span);
          } else {
            prev.push([span]);
          }
          return prev;
        }, [])
        .map((line) => line.map((c) => c.textContent).join(''))
        .map((line) => {
          const div = document.createElement('div');
          div.textContent = line;
          return div;
        });
      textBox.append(...lines);
    </script>
  </body>
</html>

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0