关于 pseudo-elements
pseudo-elements 是用于审查 CSS 和 JavaScript 的技能,检查伪元素实践、View Transitions API 用法及原生样式。它按文件和行号报告问题,适合 UI 代码审查。
主要功能
- 01检查 ::before 和 ::after 用法
- 02审查 View Transitions API 模式
- 03检查原生样式实践
- 04按文件和行号报告问题
适用场景
- 01审查装饰性 CSS 伪元素
- 02检查 View 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-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-required | 2 | HIGH |
pseudo-over-dom-node | 1 | MEDIUM |
transition-name-cleanup | 1 | MEDIUM |
参考资料
评论
支持 Markdown