CSSを書いていると「ここだけ色を変えたい」「この項目だけ強調したい」「HTMLに余計なタグは増やしたくない」という場面が本当によく出てきますよね。
とくに現場では、後からマークアップをいじれない・デザイナーがCSSだけで差し込みたい・CMSの中身は触れない…といった制約が多いので、擬似クラスと擬似要素を知っているかどうかで表現の自由度が大きく変わります。
「名前は聞いたことあるけど、:hover くらいしか使ってない…」「::before と ::after の違いがふわっとしてる…」という方でも読めるように、基礎から順番に、そして2025年に押さえておきたい新しめの指定まで一気にまとめます。
ここにある内容をひととおり触っておけば、初学者向けの教材としてもそのまま使えるはずです。
目次
この記事でできるようになること
- 擬似クラスと擬似要素の違いが説明できる
- :hover / :focus / :nth-child() などよく使うものが整理できる
- 2025年でも現場で出てくる
:focus-visible/:is()/:has()を理解できる ::before/::afterで装飾テキストやアイコンを追加できる- フォームの状態に応じて見た目を変える「気が利いたUI」が書ける
1. 擬似クラスと擬似要素のちがい
最初にここをおさえておくと、あとの説明が迷子になりません。
- 擬似クラス(:) … 「状態」でスタイルを当てる
例)マウスを乗せたときだけ / 1番目の要素だけ / 入力が正しいときだけ - 擬似要素(::) … 「要素の一部分」または「見た目の子要素」にスタイルを当てる
例)先頭文字だけ大きくする / 文章の前にラベルを足す
書式は基本的にこうです。
/* 擬似クラス */
button:hover { ... }
/* 擬似要素 */
p::before { ... }
古い書き方で :before でも動くことはありますが、新規で書くときは ::before にしておくのがおすすめです。
2. ユーザー操作に反応する擬似クラス
2-1. :hover
.button:hover {
background: #e0f2fe;
cursor: pointer;
}
マウスを乗せたときだけ反応させる基本の書き方です。
ただし スマホでは「タップして別のところを触るまで反応したまま」になることが多いので、ホバー前提のUIはモバイルで確認しておきましょう。
2-2. :active
.button:active {
transform: translateY(1px);
}
押しているあいだだけ効く状態です。
ボタンを「押したっぽく」見せるのに便利です。
スマホのタップ用に :hover と組み合わせておくと自然です。
2-3. :focus
.input:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
フォームにカーソルが入ったとき、またはキーボードでTab移動したときに効きます。
アクセシビリティ的にはとても大事なので、消してしまうのではなく「見た目を整える」方向で使ってください。
2-4. :focus-visible(2025でも推奨)
button:focus-visible,
a:focus-visible {
outline: 3px solid #f97316;
outline-offset: 4px;
}
- マウスクリックのときは枠を出さない
- キーボードで移動してきたときは枠を出す
という「ユーザーにとって見えた方がいいときだけ表示する」スマートなフォーカスです。
最近の設計ではこちらを使うことが増えてきています。
3. 並び順に応じてスタイルする擬似クラス
リストやカード一覧で「何番目だけ」をCSSでやりたいときに使います。
3-1. :first-child / :last-child / :nth-child()
.list li:first-child {
font-weight: 700;
}
.list li:last-child {
margin-bottom: 0;
}
.list li:nth-child(odd) {
background: #f8fafc;
}
ポイントは 「兄弟としてそこにいる要素を全部カウントする」ところです。
途中に別のタグがあるとうまく当たらなくなるので注意してください。
3-2. :first-of-type / :nth-of-type()
article p:first-of-type {
font-size: 1.1rem;
}
こちらは「pだけ数える」ので、間に別タグが混ざっていても安定して当たります。
記事本文や複雑なレイアウトではこちらを使う場面が多いです。
3-3. :not() で「それ以外」をまとめて指定
.card *:not(h2) {
color: #555;
}
「これとこれとこれは除きたい」というときに便利です。
クラスを増やさずに済みます。
4. フォームの状態に応じて変える
実務で「おっ」と思わせやすいのがここです。
<div class="field">
<input type="email" required placeholder="メールアドレスを入力">
</div>
/* 子にフォーカスが入ったら親を光らせる */
.field:focus-within {
outline: 2px solid #3b82f6;
outline-offset: 4px;
}
/* 入力がOKなら緑、NGなら赤 */
input:valid {
border: 2px solid #22c55e;
}
input:invalid {
border: 2px solid #ef4444;
background: #fee2e2;
}
/* チェックされたときだけ */
input[type="checkbox"]:checked + label {
font-weight: bold;
}
:focus-within… 中のどれかにフォーカスが当たったら親もスタイルできる:valid/:invalid… ブラウザのバリデーション結果に合わせて装飾できる:checked… チェックボックスやラジオがONのときだけ変える
これらはJavaScriptを書かなくても「入力の状態に連動した見た目」が作れるので、初心者さんにもおすすめです。
5. 2025年に覚えておきたい新しめのセレクタ
5-1. :is() と :where()
複数のセレクタをまとめるための書き方です。
/* よくある書き方 */
h1.title,
h2.title,
h3.title {
margin-bottom: 1.5rem;
}
/* まとめて書く */
:is(h1, h2, h3).title {
margin-bottom: 1.5rem;
}
似たものに :where() があります。
違いは詳細度で、:where() は「常に弱い」ので、あとから上書きしやすいのがメリットです。
:where(section, article, aside) h2 {
margin-top: 2.5rem;
}
5-2. :has() ― 子の状態で親を選ぶ
これが出てから「これまでJSでやってたやつ、CSSだけでいいじゃん」というケースが増えました。
/* 無効なinputを含む行を赤くする */
.form-row:has(input:invalid) {
background: #fee2e2;
}
/* カード内に画像があるときだけ上の余白を詰める */
.card:has(img) {
padding-top: 0;
}
いまは主要ブラウザでかなり使えるので、「条件つきで親を変えたい」ときはまずこれを思い出すといいです。
6. 擬似要素で「見た目のパーツ」を増やす
HTMLに触れなくても、CSSだけで文章の前後にテキストやアイコンを差し込めます。
6-1. ::before / ::after の基本
.before-text::before {
color: red;
font-weight: bold;
content: "[Beforeで挿入!]";
}
.after-text::after {
color: red;
font-weight: bold;
content: "[Afterで挿入!]";
}
contentがないと何も表示されません(ここがつまずきポイント)- あくまで“見た目の子”なので、HTMLソースには出てきません
- スクリーンリーダーで読ませたいテキストは本体側に書きましょう
画像を足したいときはこうします。
.icon-text::before {
content: "";
display: inline-block;
width: 1.2rem;
height: 1.2rem;
margin-right: .4rem;
background: url(/img/check.svg) no-repeat center / contain;
}
6-2. リストのマーカーを直接いじる ::marker
ul.feature li::marker {
color: #6366f1;
content: "◆ ";
font-size: 1.1em;
}
list-style-image を使わなくてもポチをデザインできるので、デザイン寄りのコーディングではかなり使えます。
6-3. 選択時の色を変える ::selection
::selection {
background: #fde68a;
color: #1f2937;
}
「選択したら全部青くなって読めない」を防げる、ちょっとしたUX改善です。
6-4. input[type=”file”] を整える ::file-selector-button
input[type="file"]::file-selector-button {
padding: .5rem 1rem;
border: 1px solid #ddd;
border-radius: .375rem;
background: #fff;
}
以前はブラウザごとにバラバラでしたが、今はかなりきれいに揃えられます。
管理画面系や問い合わせフォームで使えます。
6-5. dialogの背景を変える ::backdrop
dialog::backdrop {
background: rgba(15, 23, 42, .55);
backdrop-filter: blur(4px);
}
モーダルの「後ろだけ」をぼかして高級感を出したいときに。
7. 擬似要素を使うときの注意点
- JavaScriptからは直接触れない
見た目の要素なので、document.querySelector('::before')のようには取れません。JSで何かしたいならクラスを本体に付ける構成にします。 - contentは必ず書く
::before/::afterは中身がないと表示されません。content: "";でもOKです。 - 意味のあるテキストはHTML側へ
バリデーションメッセージなど「絶対に読んでほしい文言」は擬似要素に入れず、本体の中に入れてCSSで表示/非表示を切り替えるほうが安全です。
8. aタグの擬似クラスの並び順(LVHA)
リンクに関しては古典的なルールですが、今でも使われています。
a:link { ... } /* 未訪問 */
a:visited { ... } /* 訪問済み */
a:hover { ... } /* マウスを乗せたら */
a:active { ... } /* クリック中 */
この順番(Link → Visited → Hover → Active)で書くと意図した見た目になりやすいです。
:visited はプライバシー上の理由でできる装飾が制限されることも覚えておくと安心です。
9. まとめ:どう使い分ける?
- 状態で変える → 擬似クラス(:hover / :focus-visible / :checked / :has() …)
- 一部分だけ・飾りを足す → 擬似要素(::before / ::after / ::marker / ::selection …)
- コードを短くしたい → :is() / :where()
- 親を子の状態で変えたい → :has()
- フォームをちょっとリッチにしたい → :focus-within + :valid / :invalid
おわりに
「擬似クラス・擬似要素っていっぱいあって覚えきれない」と感じるときは、まず「状態」と「部分」を分けて考えるようにするとスッと入ってきます。
そして、全部を一度に暗記しようとしなくて大丈夫です。今回紹介した中から
:hover:focus-visible:nth-of-type()::before/::after:has()
この5つだけでも習得すれば、ほとんどの「ちょっとした装飾」は書けるようになります。
「HTMLはいじれないけど、ここにアイコン置きたいんだよな…」みたいな現場あるあるのとき、今日の ::before / ::after がきっと役に立ちます。


