CSS の user-select プロパティを使うと、ユーザーがマウスやトラックパッドでテキストを選択(ドラッグして反転)できるかどうかを制御できます。ボタンのラベルをうっかり選択してしまうのを防いだり、逆にクーポンコードをワンクリックで丸ごと選択できるようにしたりと、UI の使い勝手を細かく調整できるプロパティです。この記事では、none / text / all といった各値の効果から、実用的な使いどころ、::selection との関係、そして「コピーを完全には防げない」という注意点までを解説します。フロントエンドを触り始めた初心者〜中級者の方を対象にしています。
目次
user-select で何ができるのか
user-select は、その要素のテキストをユーザーが選択できるかどうかを指定するプロパティです。Web ページ上の文字は初期状態ではドラッグして選択できますが、これを禁止したり、逆に「クリック1回で全体を選択」といった特別な挙動にしたりできます。
よく使われるのはボタンやUIラベルです。たとえばボタンの文字は、ダブルクリックや素早い連打でうっかり選択状態(青く反転)になってしまうことがあります。見た目が崩れて不格好なので、こうした「本来コピーする必要のない飾りのテキスト」に対して選択を禁止する、というのが代表的な使い道です。
まずは実際の挙動を見てみましょう。次のデモには none / text / all を指定した3つの段落があります。それぞれドラッグやクリックで選択を試して、挙動の違いを確かめてみてください。
<div class="demo">
<p class="box box--none">このテキストは user-select: none です。ドラッグしても選択できません。</p>
<p class="box box--text">このテキストは user-select: text です。通常どおり選択・コピーできます。</p>
<p class="box box--all">このテキストは user-select: all です。どこか1文字をクリックすると全体がまとめて選択されます。</p>
</div>.demo {
font-family: sans-serif;
line-height: 1.7;
}
.box {
margin: 0 0 12px;
padding: 12px 16px;
border-radius: 6px;
border: 1px solid #ddd;
}
/* テキストを選択できないようにする */
.box--none {
background: #fdecea;
-webkit-user-select: none; /* Safari 向けに今も必要 */
user-select: none;
}
/* 通常どおり選択できる(初期値に近い挙動) */
.box--text {
background: #e8f4fd;
-webkit-user-select: text;
user-select: text;
}
/* クリック1回でブロック全体が選択される */
.box--all {
background: #eafaf1;
-webkit-user-select: all;
user-select: all;
}基本の書き方
使い方はとてもシンプルで、選択を制御したい要素に値を1つ指定するだけです。もっともよく使うのは、テキスト選択を禁止する none です。
/* このボタンのラベルは選択できなくなる */
.button {
-webkit-user-select: none; /* Safari 向け */
user-select: none;
}
先頭に -webkit-user-select というベンダープレフィックス付きの記述がある点に注目してください。これが今も必要な理由は後半で詳しく触れますが、Safari では標準の user-select だけでは効かない場面があるため、2行セットで書いておくのが安全です。プレフィックス付きを先に、標準のプロパティを後に書くのが定石です。
指定できる値とその効果
user-select に指定できる主な値は次のとおりです。それぞれ「テキストを選択できるか」「どう選択されるか」が変わります。
| 値 | 効果 |
|---|---|
auto | 初期値。要素の種類や親の指定に応じて、ブラウザが選択可能かどうかを自動的に決める(通常のテキストは選択できる) |
none | その要素のテキストを選択できなくする。ドラッグしても反転しない |
text | テキストを選択できるようにする。親で none が指定されていても、この要素だけ選択可能に戻せる |
all | 要素内のどこか1か所をクリックすると、その要素の内容全体がまとめて選択される |
contain | 選択の開始点がその要素内にある場合、選択範囲を要素の内側に閉じ込める(外側へはみ出させない) |
auto は少し分かりにくいですが、「特に指定していない普段どおりの状態」だと考えれば十分です。実際にコードで明示的に使うことは少なく、多くの場面では none と text、そして次に紹介する all を押さえておけば困りません。なお contain は対応状況が限られるため、使う際は挙動を実機で確認することをおすすめします。
クリック1回で全選択できる user-select: all
all は少し変わった値で、要素内のどこか1文字をクリックしただけで、その要素の中身がまるごと選択状態になります。ドラッグして端から端まで正確になぞる必要がありません。
これが便利なのは、クーポンコードや招待コード、コマンドの一行などをユーザーにコピーしてもらいたい場面です。長い文字列を手作業で選択するのは地味に面倒なので、クリック1回で全選択できると「そのままコピー」までがスムーズになります。
/* クリックするとコード全体が選択される */
.coupon-code {
-webkit-user-select: all;
user-select: all;
padding: 8px 12px;
background: #f5f5f5;
font-family: monospace;
}
この .coupon-code を付けた要素は、ユーザーがどこをクリックしても中身全体が選択されるので、あとは右クリックやショートカットでコピーするだけです。上のデモの緑色の段落でも同じ挙動を試せます。
選択させたくない部分を狙って禁止する
実務では「ページ全体を禁止する」よりも、特定のパーツだけ選択できないようにするほうが多いはずです。前述のボタンやタブ、アイコンの隣に置いた飾りのラベル、コピーされると困る番号のプレフィックスなどが対象になります。
user-select は継承されるため、親要素に none を指定すると、その中の子要素もまとめて選択できなくなります。この性質を利用して、「カード全体は選択禁止にしつつ、中の本文だけは選択できるようにする」といった上書きも可能です。子要素に text を指定すれば、親の none を打ち消して選択可能に戻せます。
/* カード全体は選択禁止 */
.card {
-webkit-user-select: none;
user-select: none;
}
/* ただし本文だけは選択できるように戻す */
.card .card__body {
-webkit-user-select: text;
user-select: text;
}
::selection との関係
user-select とよく混同されるのが、擬似要素の ::selection です。この2つは役割がまったく違います。user-select は「選択できるかどうか」を制御するのに対して、::selection は「選択されたときの見た目(文字色や背景色)」を指定するものです。
たとえば選択部分の背景色を変えたいときは ::selection を使います。
/* 選択したときの色を変える(選択の可否は変えない) */
::selection {
background: #ffe08a;
color: #333;
}
関係を整理すると、user-select: none を指定した要素はそもそも選択できないので ::selection の見た目も現れません。「選択できるかどうか」は user-select、「選択されたときにどう見えるか」は ::selection と覚えておくと混乱しません。
-webkit-user-select が今も必要な理由
多くの CSS プロパティは、かつて必要だったベンダープレフィックスが不要になっています。しかし user-select については、Safari が標準の user-select をサポートしておらず、-webkit-user-select を必要とする状態が続いています。iOS の Safari も同様です。
そのため、Safari を含めて確実に効かせたい場合は、標準プロパティだけでなく -webkit-user-select も併記するのが現状では安全です。Chrome や Firefox はプレフィックスなしの user-select に対応しているので、次のように2行を並べておけば主要ブラウザをカバーできます。
.no-select {
-webkit-user-select: none; /* Safari / iOS Safari */
user-select: none; /* Chrome / Firefox / Edge */
}
Autoprefixer などのツールを使っているプロジェクトなら、標準プロパティだけ書けば -webkit- 版が自動で補われます。手書きで CSS を管理している場合は、上のように自分で併記しておきましょう。
コピーを完全に防ぐものではない
「user-select: none を指定すればコンテンツをコピーされなくなる」と期待されることがありますが、これは誤解です。あくまでマウスでのドラッグ選択という操作を止めるだけで、テキストそのものを守る仕組みではありません。
実際には、ブラウザの開発者ツールで HTML を直接見ればテキストは読めますし、CSS を無効化すれば選択も復活します。ページのソースを表示したり、JavaScript から要素の中身を取得したりする方法もあります。つまり user-select: none は「うっかり選択してしまうのを防ぐ」ための UI 上の配慮であって、著作権保護やコンテンツの流出防止の手段にはならない、という点を理解しておく必要があります。
むしろ、通常の本文にまで none を掛けてしまうと、読者が必要な箇所をコピーできず不便になります。禁止するのはボタンやUIラベルなど「選択する意味のない部分」に留めるのが、使い勝手を損なわないコツです。
まとめ
user-select は、テキスト選択の可否を制御するシンプルながら実用的なプロパティです。要点を振り返ると、none でボタンやラベルの誤選択を防ぎ、text で親の禁止を部分的に打ち消し、all でクーポンコードなどをワンクリック全選択にできます。見た目を変える ::selection とは役割が別で、Safari 対応には -webkit-user-select の併記が今も有効です。そして none はコピーを完全に防ぐものではない、という前提を押さえておけば、過度に頼らず適切に使い分けられます。