💎

ルビを含む文字列をコピーするときに、ルビのテキストは除外したい

に公開
2

表題通り、Web ページ上でルビを含む文字列をコピーするときに、ルビのテキストは削除したうえでコピーできるようにしたいです。

例えば、次のような HTML があるとします。

<p><ruby>亜米利加<rt>アメリカ</rt></ruby></p>

この HTML は、次のように展開されます。
(選択箇所にもよりますが、)「亜米利加」を選択・コピーしようとすると、ルビの「アメリカ」もクリップボードにコピーされてしまいます。

亜米利加|アメリカもコピー対象
ルビのアメリカまでクリップボードにコピーされてしまう。

解決方法1: user-select

最も簡単な解決方法は user-select でしょう。

先程の HTML を次のように修正します。
変更点は rt 要素に user-select: none を追加しています。

<p><ruby>亜米利加<rt style="user-select: none;">アメリカ</rt></ruby></p>

これでルビはコピー対象からハズれるようになりました。

亜米利加|アメリカもコピー対象から外れる

mdncan i use を見てみると、user-select は、主要ブラウザでサポートされているようですので、気兼ねなく利用できそうですね。

解決方法2: JavaScript でなんとかする

なんらかの理由で JavaScript で解消しなければならない場合についても、触れておきます。

…触れておきますと言いつつ、面倒なので AI に書いてもらいました。
AI に丸投げだとアレなので、コメントで補足文を置いておきます。

<p><ruby>亜米利加<rt>アメリカ</rt></ruby></p>
document.addEventListener("copy", (event) => {
  event.preventDefault();
  const selection = document.getSelection();
  if (selection.rangeCount > 0) {
    const range = selection.getRangeAt(0); // FireFox のような複数の要素を選択可能なブラウザでは getRangeAt(0) ではなく、すべての要素を取り出すよう調整した方が良い。
    const cloneContents = range.cloneContents();
    const rubies = cloneContents.querySelectorAll("rt"); // ルビをすべて選択して削除する
    rubies.forEach((ruby) => ruby.remove());

    const div = document.createElement("div"); // ルビ削除後のテキストを div に入れる
    div.appendChild(cloneContents);
    const text = div.innerText;

    event.clipboardData.setData("text/plain", text); // クリップボードに div のテキストを入れる
  }
});

ちなみに、この JavaScript の処理は、あくまで「選択範囲に存在するルビを削除する」なので、ルビそのものを選択した場合は、ルビのテキストはコピーされます。

次のように、ルビのみを選択したときが、そうですね。

亜米利加|ルビのアメリカのみ選択したとき

まとめ

以上、「ルビを含む文字列をコピーするときに、ルビのテキストは除外したい」でした。
てっきり JavaScript を使って実装するものと思っていましたが、意外と CSS だけで簡単にできるんですね。

では、また!

Discussion