mcpField
P
pseudo-elements

pseudo-elements

github.com/raphaelsalaja设计与 UI42247 次安装今天更新
代码仓库

关于 pseudo-elements

pseudo-elements 是用于审查 CSS 和 JavaScript 的技能,检查伪元素实践、View Transitions API 用法及原生样式。它按文件和行号报告问题,适合 UI 代码审查。

主要功能

  1. 01检查 ::before 和 ::after 用法
  2. 02审查 View Transitions API 模式
  3. 03检查原生样式实践
  4. 04按文件和行号报告问题

适用场景

  1. 01审查装饰性 CSS 伪元素
  2. 02检查 View 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-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

页面过渡优先使用 View Transitions API,而不是 JavaScript 动画库。

失败:

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

为视图过渡伪元素设置样式,实现自定义动画。

失败:

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

参考资料

评论

支持 Markdown