en un clic
pseudo-elements
// Audit CSS for pseudo-element best practices and View Transitions API usage. Use when reviewing hover effects, decorative layers, or page transitions. Outputs file:line findings.
// Audit CSS for pseudo-element best practices and View Transitions API usage. Use when reviewing hover effects, decorative layers, or page transitions. Outputs file:line findings.
Audit Motion/Framer Motion code for AnimatePresence best practices. Use when reviewing exit animations, modals, or presence state. Outputs file:line findings.
Build icon components where any icon morphs into any other through SVG line transformation. Use when asked to "create morphing icons", "build icon transitions", "animate between icons", or "transform icons".
Audit animation code for correct timing function selection. Use when reviewing motion implementations, debugging animations that feel wrong, or choosing between springs and easing. Outputs file:line findings.
| name | pseudo-elements |
| description | Audit CSS for pseudo-element best practices and View Transitions API usage. Use when reviewing hover effects, decorative layers, or page transitions. Outputs file:line findings. |
| license | MIT |
| metadata | {"author":"raphael-salaja","version":"2.0.0","source":"/content/taking-advantage-of-pseudo-elements/index.mdx"} |
Review CSS and JavaScript for pseudo-element best practices and View Transitions API usage.
file:line format| Priority | Category | Prefix |
|---|---|---|
| 1 | Before/After | pseudo- |
| 2 | View Transitions | transition- |
| 3 | Native Styling | native- |
pseudo-content-required::before and ::after require content property to render.
Fail:
.button::before {
position: absolute;
background: var(--gray-3);
}
Pass:
.button::before {
content: "";
position: absolute;
background: var(--gray-3);
}
pseudo-over-dom-nodeUse pseudo-elements for decorative content instead of extra DOM nodes.
Fail:
<button className={styles.button}>
<span className={styles.background} /> {/* Unnecessary DOM node */}
Click me
</button>
Pass:
<button className={styles.button}>
Click me
</button>
.button::before {
content: "";
/* decorative background */
}
pseudo-position-relative-parentParent must have position: relative for absolute pseudo-elements.
Fail:
.button::before {
content: "";
position: absolute;
inset: 0;
}
/* .button has no position */
Pass:
.button {
position: relative;
}
.button::before {
content: "";
position: absolute;
inset: 0;
}
pseudo-z-index-layeringPseudo-elements need z-index to layer correctly with content.
Fail:
.button::before {
content: "";
position: absolute;
inset: 0;
background: var(--gray-3);
}
/* Covers button text */
Pass:
.button {
position: relative;
z-index: 1;
}
.button::before {
content: "";
position: absolute;
inset: 0;
background: var(--gray-3);
z-index: -1;
}
pseudo-hit-target-expansionUse negative inset values to expand hit targets without extra markup.
Fail:
<div className={styles.wrapper}> {/* Extra wrapper for hit target */}
<a className={styles.link}>Link</a>
</div>
Pass:
.link {
position: relative;
}
.link::before {
content: "";
position: absolute;
inset: -8px -12px;
}
transition-name-requiredElements participating in view transitions need view-transition-name.
Fail:
document.startViewTransition(() => {
// No view-transition-name assigned
targetImg.src = newSrc;
});
Pass:
sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
sourceImg.style.viewTransitionName = "";
targetImg.style.viewTransitionName = "card";
});
transition-name-uniqueEach view-transition-name must be unique on the page during transition.
Fail:
.card {
view-transition-name: card;
}
/* Multiple cards with same name */
Pass:
// Assign unique name only to transitioning element
element.style.viewTransitionName = `card-${id}`;
transition-name-cleanupRemove view-transition-name after transition completes.
Fail:
sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
targetImg.style.viewTransitionName = "card";
});
// sourceImg still has name, causes conflict on next transition
Pass:
sourceImg.style.viewTransitionName = "card";
document.startViewTransition(() => {
sourceImg.style.viewTransitionName = "";
targetImg.style.viewTransitionName = "card";
});
transition-over-js-libraryPrefer View Transitions API over JavaScript animation libraries for page transitions.
Fail:
import { motion } from "motion/react";
function ImageLightbox() {
return (
<motion.img layoutId="hero" /> // JS-based shared element transition
);
}
Pass:
function openLightbox(img: HTMLImageElement) {
img.style.viewTransitionName = "hero";
document.startViewTransition(() => {
// Native browser transition
});
}
transition-style-pseudo-elementsStyle view transition pseudo-elements for custom animations.
Fail:
document.startViewTransition(() => { /* ... */ });
// Uses default crossfade
Pass:
::view-transition-group(card) {
animation-duration: 300ms;
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
native-backdrop-stylingUse ::backdrop pseudo-element for dialog/popover backgrounds.
Fail:
<>
<div className={styles.overlay} onClick={close} />
<dialog className={styles.dialog}>{children}</dialog>
</>
Pass:
dialog::backdrop {
background: var(--black-a6);
backdrop-filter: blur(4px);
}
native-placeholder-stylingUse ::placeholder for input placeholder styling, not wrapper elements.
Fail:
<div className={styles.inputWrapper}>
{!value && <span className={styles.placeholder}>Enter text...</span>}
<input value={value} />
</div>
Pass:
input::placeholder {
color: var(--gray-9);
opacity: 1;
}
native-selection-stylingUse ::selection for text selection styling.
Pass:
::selection {
background: var(--blue-a5);
color: var(--gray-12);
}
When reviewing files, output findings as:
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
After findings, output a summary:
| Rule | Count | Severity |
|---|---|---|
pseudo-content-required | 2 | HIGH |
pseudo-over-dom-node | 1 | MEDIUM |
transition-name-cleanup | 1 | MEDIUM |