おら、アクセシビリティのことはよくわかんねぇんだけど、
とりあえず見た目は動いたぞ。
レイアウト後の折り返し位置も考慮して、行ごとに分割してスタイルを当てたいなって1万年と2000年前から思ってたんで、実装できて個人的にうれしいんですよね。
<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>