mcpField
P
pseudo-elements

pseudo-elements

github.com/raphaelsalajaデザイン・UI42247 回インストール今日更新
リポジトリ

pseudo-elements について

pseudo-elements は、CSS と JavaScript を対象に、疑似要素の使い方や View Transitions API、ネイティブなスタイル設定を確認するレビュー用スキルです。問題をファイル名と行番号付きで報告します。

主な機能

  1. 01::before と ::after の確認
  2. 02View Transitions API のパターン確認
  3. 03ネイティブなスタイル設定の確認
  4. 04ファイル名と行番号付きの報告

活用シーン

  1. 01装飾用 CSS 疑似要素の監査
  2. 02View Transitions の実装レビュー
  3. 03ダイアログと入力欄のスタイル確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/raphaelsalaja/skill --skill pseudo-elements

インストール後、Claude Code で/pseudo-elementsを入力して読み込まれたか確認します。

詳細

疑似要素

CSS と JavaScript を確認し、疑似要素のベストプラクティスと View Transitions API の使用状況をチェックします。

仕組み

  1. 指定されたファイルを読み込みます(または、ユーザーにファイルやパターンを尋ねます)
  2. 以下のすべてのルールに照らして確認します
  3. 検出結果を file:line 形式で出力します

ルールのカテゴリ

優先度カテゴリ接頭辞
1Before/Afterpseudo-
2View Transitionstransition-
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-required2HIGH
pseudo-over-dom-node1MEDIUM
transition-name-cleanup1MEDIUM

参考資料

コメント