pseudo-elements について
pseudo-elements は、CSS と JavaScript を対象に、疑似要素の使い方や View Transitions API、ネイティブなスタイル設定を確認するレビュー用スキルです。問題をファイル名と行番号付きで報告します。
主な機能
- 01::before と ::after の確認
- 02View Transitions API のパターン確認
- 03ネイティブなスタイル設定の確認
- 04ファイル名と行番号付きの報告
活用シーン
- 01装飾用 CSS 疑似要素の監査
- 02View Transitions の実装レビュー
- 03ダイアログと入力欄のスタイル確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ raphaelsalaja/ skill --skill pseudo-elementsインストール後、Claude Code で/pseudo-elementsを入力して読み込まれたか確認します。
詳細
疑似要素
CSS と JavaScript を確認し、疑似要素のベストプラクティスと View Transitions API の使用状況をチェックします。
仕組み
- 指定されたファイルを読み込みます(または、ユーザーにファイルやパターンを尋ねます)
- 以下のすべてのルールに照らして確認します
- 検出結果を
file:line形式で出力します
ルールのカテゴリ
| 優先度 | カテゴリ | 接頭辞 |
|---|---|---|
| 1 | Before/After | pseudo- |
| 2 | View Transitions | transition- |
| 3 | ネイティブスタイル | native- |
ルール
Before/After のルール
pseudo-content-required
::before と ::after を表示するには、content プロパティが必要です。
不適合:
.button::before {
position: absolute;
background: var(--gray-3);
}
適合:
.button::before {
content: "";
position: absolute;
background: var(--gray-3);
}
pseudo-over-dom-node
装飾用のコンテンツには、追加の DOM ノードではなく疑似要素を使用します。
不適合:
<button className={styles.button}>
<span className={styles.background} /> {/* Unnecessary DOM node */}
Click me
</button>
適合:
<button className={styles.button}>
Click me
</button>
.button::before {
content: "";
/* decorative background */
}
pseudo-position-relative-parent
絶対配置の疑似要素を使う場合、親要素には position: relative を指定する必要があります。
不適合:
.button::before {
content: "";
position: absolute;
inset: 0;
}
/* .button has no position */
適合:
.button {
position: relative;
}
.button::before {
content: "";
position: absolute;
inset: 0;
}
pseudo-z-index-layering
コンテンツとの重なり順を適切にするには、疑似要素に z-index が必要です。
不適合:
.button::before {
content: "";
position: absolute;
inset: 0;
background: var(--gray-3);
}
/* Covers button text */
適合:
.button {
position: relative;
z-index: 1;
}
.button::before {
content: "";
position: absolute;
inset: 0;
background: var(--gray-3);
z-index: -1;
}
pseudo-hit-target-expansion
追加のマークアップを使わずにヒット領域を広げるには、負の inset 値を使用します。
不適合:
<div className={styles.wrapper}> {/* Extra wrapper for hit target */}
<a className={styles.link}>Link</a>
</div>
適合:
.link {
position: relative;
}
.link::before {
content: "";
position: absolute;
inset: -8px -12px;
}
View Transitions のルール
transition-name-required
View Transitions に参加する要素には view-transition-name が必要です。
不適合:
document.startViewTransition(() => {
// No view-transition-name assigned
targetImg.src = newSrc;
});
適合:
sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
sourceImg.style.viewTransitionName = "";
targetImg.style.viewTransitionName = "card";
});
transition-name-unique
トランジション中、各 view-transition-name はページ上で一意である必要があります。
不適合:
.card {
view-transition-name: card;
}
/* Multiple cards with same name */
適合:
// Assign unique name only to transitioning element
element.style.viewTransitionName = `card-${id}`;
transition-name-cleanup
トランジション完了後に view-transition-name を削除します。
不適合:
sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
targetImg.style.viewTransitionName = "card";
});
// sourceImg still has name, causes conflict on next transition
適合:
sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
sourceImg.style.viewTransitionName = "";
targetImg.style.viewTransitionName = "card";
});
transition-over-js-library
ページ遷移には JavaScript アニメーションライブラリよりも View Transitions API を優先します。
不適合:
import { motion } from "motion/react";
function ImageLightbox() {
return (
<motion.img layoutId="hero" /> // JS-based shared element transition
);
}
適合:
function openLightbox(img: HTMLImageElement) {
img.style.viewTransitionName = "hero";
document.startViewTransition(() => {
// Native browser transition
});
}
transition-style-pseudo-elements
カスタムアニメーションには、View Transition の疑似要素にスタイルを設定します。
不適合:
document.startViewTransition(() => { /* ... */ });
// Uses default crossfade
適合:
::view-transition-group(card) {
animation-duration: 300ms;
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
ネイティブスタイルのルール
native-backdrop-styling
ダイアログやポップオーバーの背景には、::backdrop 疑似要素を使用します。
不適合:
<>
<div className={styles.overlay} onClick={close} />
<dialog className={styles.dialog}>{children}</dialog>
</>
適合:
dialog::backdrop {
background: var(--black-a6);
backdrop-filter: blur(4px);
}
native-placeholder-styling
入力欄のプレースホルダーのスタイル設定には、ラッパー要素ではなく ::placeholder を使用します。
不適合:
<div className={styles.inputWrapper}>
{!value && <span className={styles.placeholder}>Enter text...</span>}
<input value={value} />
</div>
適合:
input::placeholder {
color: var(--gray-9);
opacity: 1;
}
native-selection-styling
テキスト選択時のスタイル設定には、::selection を使用します。
適合:
::selection {
background: var(--blue-a5);
color: var(--gray-12);
}
出力形式
ファイルを確認する際は、検出結果を次の形式で出力します。
file:line - [rule-id] description of issue
Example:
components/button/styles.module.css:12 - [pseudo-content-required] ::before missing content property
components/lightbox/index.tsx:45 - [transition-over-js-library] Using motion layoutId instead of View Transitions API
まとめ表
検出結果の後に、次のまとめを出力します。
| ルール | 件数 | 重大度 |
|---|---|---|
pseudo-content-required | 2 | HIGH |
pseudo-over-dom-node | 1 | MEDIUM |
transition-name-cleanup | 1 | MEDIUM |