| name | performance-analyzer |
| description | CSS performance analysis covering bundle size, selector complexity, render-blocking resources, critical CSS, and optimization strategies. Use when CSS performance is slow or bundle size is too large. |
| allowed-tools | Read, Grep, Glob, Bash |
Performance Analyzer Skill
This skill analyzes CSS performance and identifies optimization opportunities. I'll examine bundle size, selector efficiency, render performance, and suggest specific improvements to make your CSS faster.
What I Analyze
Bundle Analysis
- Total CSS file size
- Unused CSS percentage
- Duplicate rules
- Minification potential
- Compression ratios
Selector Performance
- Selector complexity
- Expensive selectors
- Over-specific rules
- Selector matching speed
Render Performance
- Render-blocking CSS
- Critical CSS opportunities
- Paint/layout triggers
- Animation performance
Loading Strategy
- CSS delivery method
- Code splitting potential
- Async loading opportunities
- Caching strategy
Performance Metrics
Key Indicators
First Contentful Paint (FCP)
- When first content appears
- Target: < 1.8s
Largest Contentful Paint (LCP)
- When main content visible
- Target: < 2.5s
Cumulative Layout Shift (CLS)
- Visual stability
- Target: < 0.1
CSS Bundle Size
- Total downloaded CSS
- Target: < 50KB gzipped for initial load
Unused CSS
- Percentage not used on page
- Target: < 20% unused
Bundle Size Analysis
File Size Audit
# Check CSS file sizes
ls -lh dist/*.css
# Example output:
# styles.css 250KB (uncompressed)
# styles.min.css 180KB (minified)
# styles.min.css.gz 45KB (gzipped)
Optimization Potential
Original: 250KB (100%)
Minified: 180KB (72%) - Remove whitespace, comments
Gzipped: 45KB (18%) - Compression
Unused removed: 30KB (12%) - Remove unused CSS
Optimized: 30KB (12%) - Final target
Potential savings: 88%
Bundle Composition
Analyze what's in your bundle:
Vendor CSS (Bootstrap, etc.): 120KB (48%)
Component styles: 80KB (32%)
Utility classes: 30KB (12%)
Global styles: 20KB (8%)
Recommendations:
1. Remove unused Bootstrap components
2. Use PurgeCSS for utilities
3. Split vendor from custom CSS
Selector Performance
Expensive Selectors
/* ❌ VERY SLOW - Universal selector with pseudo */
*:hover {
cursor: pointer;
}
/* ❌ SLOW - Descendant with universal */
.container * {
box-sizing: border-box;
}
/* ❌ SLOW - Complex attribute selectors */
[class^="icon-"][class$="-large"] {
font-size: 2rem;
}
/* ❌ SLOW - Deep nesting */
.nav ul li a span.icon {
color: blue;
}
/* ✓ FAST - Single class */
.icon-large {
font-size: 2rem;
}
/* ✓ FAST - Low specificity */
.nav-icon {
color: blue;
}
Selector Complexity Scoring
Complexity Score (Lower is better):
Single class: 1 point (.button)
Element selector: 1 point (div)
Class + element: 2 points (div.button)
Descendant: +1 per level (.nav .item .link = 3)
Pseudo-class: +1 (:hover)
Attribute: +2 ([type="text"])
Complex attribute: +3 ([class*="btn-"])
Universal: +5 (*)
Target: Average < 5 points per selector
Refactoring Examples
/* BEFORE: Complexity 8 */
.container .sidebar nav ul li a:hover {
color: blue;
}
/* Score: 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 8 */
/* AFTER: Complexity 2 */
.sidebar-link:hover {
color: blue;
}
/* Score: 1 + 1 = 2 */
/* BEFORE: Complexity 10 */
div[class^="card-"][class$="-featured"]:not(.disabled) {
border: 2px solid gold;
}
/* Score: 1 + 3 + 3 + 2 + 1 = 10 */
/* AFTER: Complexity 1 */
.card--featured {
border: 2px solid gold;
}
/* Score: 1 */
Render Performance
Properties That Trigger Reflow (Layout)
/* ❌ EXPENSIVE - Triggers layout recalculation */
.animated {
animation: move 1s;
}
@keyframes move {
from { left: 0; width: 100px; }
to { left: 100px; width: 200px; }
}
/* These properties trigger layout:
* width, height, padding, margin, border
* top, right, bottom, left
* font-size, line-height
* display, position, float
*/
Properties That Trigger Paint
/* ⚠️ MODERATE - Triggers repaint */
.animated {
animation: fade 1s;
}
@keyframes fade {
from { background: red; }
to { background: blue; }
}
/* These properties trigger paint:
* color, background, box-shadow
* border-radius, border-style
* visibility, outline
*/
Compositor-Only Properties (FAST)
/* ✓ OPTIMAL - GPU accelerated */
.animated {
animation: slide 1s;
}
@keyframes slide {
from { transform: translateX(0); opacity: 0; }
to { transform: translateX(100px); opacity: 1; }
}
/* These are compositor-only:
* transform (translate, rotate, scale)
* opacity
*/
Animation Performance Comparison
/* ❌ POOR PERFORMANCE */
@keyframes slideIn {
from { left: -100px; } /* Triggers layout */
to { left: 0; }
}
/* Performance impact:
* - Recalculates layout (expensive)
* - Repaints (expensive)
* - Composites (cheap)
* Total: ~50ms per frame
* Result: Janky animation < 60fps
*/
/* ✓ GOOD PERFORMANCE */
@keyframes slideIn {
from { transform: translateX(-100px); } /* Compositor only */
to { transform: translateX(0); }
}
/* Performance impact:
* - Composites (cheap)
* Total: ~1-2ms per frame
* Result: Smooth animation @ 60fps
*/
Critical CSS Strategy
What is Critical CSS?
CSS required for above-the-fold content. Should be inlined in <head> to eliminate render-blocking requests.
Critical CSS Identification
/* CRITICAL - Above the fold */
/* Inline these in <head> */
/* Reset */
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui;
}
/* Header (visible immediately) */
.header {
display: flex;
padding: 1rem;
background: white;
}
.logo {
font-size: 1.5rem;
}
.nav {
display: flex;
gap: 1rem;
}
/* Hero section (above fold) */
.hero {
min-height: 400px;
padding: 4rem 2rem;
background: #f0f0f0;
}
.hero-title {
font-size: 3rem;
margin: 0;
}
/* NON-CRITICAL - Load async */
/* Footer, modals, below-fold content */
Implementation
<!DOCTYPE html>
<html>
<head>
<!-- INLINE CRITICAL CSS -->
<style>
/* Critical CSS here (< 14KB) */
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: system-ui; }
.header { /* ... */ }
.hero { /* ... */ }
</style>
<!-- PRELOAD FULL STYLESHEET -->
<link rel="preload" href="/styles.css" as="style">
<!-- LOAD FULL STYLESHEET ASYNC -->
<link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>
<body>
<!-- Content -->
</body>
</html>
CSS Loading Optimization
Loading Strategy Analysis
/* ❌ POOR - Single large bundle, render-blocking */
<link rel="stylesheet" href="/styles.css"> <!-- 250KB -->
/* Issues:
* - Blocks rendering until entire file downloads
* - Contains unused CSS
* - No prioritization
*/
/* ✓ BETTER - Critical CSS inline + async full */
<style>/* Critical CSS */</style>
<link rel="preload" href="/styles.css" as="style">
<link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
/* Benefits:
* - Immediate rendering with critical CSS
* - Non-blocking full stylesheet load
* - Faster FCP
*/
/* ✓ BEST - Critical inline + route-based splitting */
<style>/* Critical CSS */</style>
<link rel="preload" href="/common.css" as="style">
<link rel="preload" href="/page.css" as="style">
<link rel="stylesheet" href="/common.css" media="print" onload="this.media='all'">
<link rel="stylesheet" href="/page.css" media="print" onload="this.media='all'">
/* Benefits:
* - Only loads CSS needed for current page
* - Common styles cached across pages
* - Optimal bundle size
*/
HTTP/2 Considerations
<!-- With HTTP/2, can load multiple files efficiently -->
<link rel="stylesheet" href="/reset.css"> <!-- 2KB -->
<link rel="stylesheet" href="/typography.css"> <!-- 5KB -->
<link rel="stylesheet" href="/layout.css"> <!-- 8KB -->
<link rel="stylesheet" href="/components.css"> <!-- 15KB -->
<!-- Advantages:
* Better caching (only changed files re-download)
* Parallel loading
* Selective loading possible
-->
Optimization Tools
Analysis Tools
# CSS Stats - Analyze CSS complexity
npx cssstats styles.css > stats.json
# Coverage - Find unused CSS (Chrome DevTools)
# DevTools → Coverage → Record → Reload
# Lighthouse - Performance audit
lighthouse https://example.com --only-categories=performance
# Bundle analyzer
npx webpack-bundle-analyzer stats.json
Optimization Tools
# Minification - Remove whitespace
npx cssnano styles.css styles.min.css
# PurgeCSS - Remove unused CSS
npx purgecss --css styles.css --content '**/*.html' --output dist/
# Critical - Extract critical CSS
npx critical index.html --base dist --inline > optimized.html
# Compression - Gzip/Brotli
gzip -9 styles.css # Gzip
brotli -q 11 styles.css # Brotli (better)
Performance Budget
Set Targets
# performance-budget.yml
# Bundle sizes
css-total: 50KB # Total CSS (gzipped)
css-critical: 14KB # Inline critical CSS
css-vendor: 20KB # Third-party CSS
# Metrics
first-contentful-paint: 1.8s
largest-contentful-paint: 2.5s
cumulative-layout-shift: 0.1
# Code quality
unused-css: 20% # Max unused CSS
avg-selector-depth: 3 # Max avg nesting
specificity-avg: 30 # Max avg specificity
Monitor & Enforce
# Add to CI/CD pipeline
npm run build
npm run analyze-bundle
# Check if bundle exceeds budget
if [ $(stat -f%z dist/styles.css.gz) -gt 51200 ]; then
echo "❌ CSS bundle exceeds 50KB limit"
exit 1
fi
Performance Checklist
Bundle Size
- Minified CSS (cssnano, clean-css)
- Gzip/Brotli compression enabled
- Unused CSS removed (PurgeCSS)
- Duplicate rules eliminated
- Bundle size < 50KB (gzipped)
Selectors
- Average depth < 3 levels
- No universal selectors in production
- Complex attribute selectors removed
- BEM or similar flat methodology
Rendering
- Animations use transform/opacity only
- No layout-triggering properties in animations
- will-change used appropriately (and removed)
- contain property used where appropriate
Loading
- Critical CSS inlined (< 14KB)
- Non-critical CSS loaded async
- CSS split by route/feature
- HTTP caching configured
Monitoring
- Performance budget set
- Lighthouse CI configured
- Bundle size tracked
- Metrics monitored
Example Analysis Report
Input: Analyze styles.css (250KB)
Report:
# CSS Performance Analysis
## Bundle Size 🔴
- **Uncompressed**: 250KB
- **Minified**: 180KB (28% savings)
- **Gzipped**: 45KB (82% total savings)
- **Status**: ❌ Exceeds 50KB budget
### Recommendations:
1. Remove unused CSS (estimated 70KB savings)
2. Split vendor CSS (Bootstrap) from custom
3. Implement code splitting by route
## Selector Performance ⚠️
- **Average depth**: 4.2 levels
- **Complex selectors**: 23 found
- **Universal selectors**: 5 found
### Top Issues:
1. `.container * { }` - Universal descendant (line 45)
2. `#nav ul li a span` - 5 levels deep (line 234)
3. `[class*="btn-"]:not(.disabled)` - Complex attribute (line 567)
### Recommendations:
1. Refactor to BEM methodology
2. Replace universal selectors with specific classes
3. Flatten deeply nested selectors
## Render Performance ✓
- **Layout-triggering animations**: 2 found
- **Paint-heavy properties**: 15 instances
- **Compositor-only**: 8 animations
### Issues:
1. `@keyframes slideIn` uses `left` property (line 890)
- **Fix**: Use `transform: translateX()`
2. `.animated` animates `width` (line 923)
- **Fix**: Use `transform: scaleX()`
## Critical CSS ⚠️
- **Above-fold CSS**: ~35KB
- **Currently inline**: 0KB
- **Render-blocking**: Yes
### Recommendations:
1. Extract critical CSS (header, hero, navigation)
2. Inline critical CSS (target < 14KB)
3. Load remaining CSS async
## Priority Actions:
1. 🔴 **HIGH**: Remove unused CSS (↓ 70KB)
2. 🟠 **MEDIUM**: Inline critical CSS (improve FCP by ~1s)
3. 🟡 **LOW**: Refactor selectors (improve maintainability)
## Expected Impact:
- Bundle size: 250KB → 50KB (80% reduction)
- FCP: 3.2s → 1.5s (53% improvement)
- LCP: 4.5s → 2.2s (51% improvement)
Just Ask!
Request performance analysis:
- "Analyze this CSS file for performance"
- "Find expensive selectors"
- "Identify critical CSS"
- "Check my animation performance"
- "Suggest bundle optimizations"
I'll provide actionable optimization recommendations!