| name | css-performance-guide |
| description | CSS performance optimization reference. Use when searching for performance patterns, Core Web Vitals optimization, or CSS efficiency techniques. |
CSS Performance Optimization Guide
Comprehensive reference for optimizing CSS performance, improving Core Web Vitals, and implementing efficient styling patterns.
Table of Contents
- Core Web Vitals Optimization
- Critical CSS Patterns
- Render-Blocking Elimination
- CSS Selector Performance
- Performance Measurement Tools
- Performance Anti-Patterns
- Optimization Decision Trees
- Performance Budget Templates
Core Web Vitals Optimization
Largest Contentful Paint (LCP)
Target: < 2.5 seconds
Optimization Checklist
LCP-Specific CSS Patterns
body {
margin: 0;
font-family: system-ui, -apple-system, sans-serif;
font-size: 16px;
line-height: 1.5;
}
.hero {
min-height: 100vh;
display: grid;
place-items: center;
}
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap;
font-weight: 400;
font-style: normal;
}
.hero-image {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.lcp-container {
contain: layout style paint;
content-visibility: auto;
}
Cumulative Layout Shift (CLS)
Target: < 0.1
Optimization Checklist
CLS Prevention Patterns
img, video {
max-width: 100%;
height: auto;
aspect-ratio: attr(width) / attr(height);
}
.responsive-image {
aspect-ratio: 16 / 9;
width: 100%;
object-fit: cover;
}
.ad-container {
min-height: 250px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.animated-element {
transform: translateX(100px);
opacity: 0.5;
will-change: transform, opacity;
}
.animated-element-bad {
}
@font-face {
font-family: 'WebFont';
src: url('/fonts/webfont.woff2') format('woff2');
font-display: optional;
size-adjust: 95%;
}
body {
font-family: 'WebFont', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
First Input Delay (FID) / Interaction to Next Paint (INP)
Target: < 100ms (FID), < 200ms (INP)
Optimization Checklist
FID/INP CSS Patterns
.button {
transition: transform 0.2s ease, opacity 0.2s ease;
}
.button:hover {
transform: scale(1.05);
opacity: 0.9;
}
.interactive-card {
contain: layout paint;
}
.interactive-list-item {
contain: layout style;
will-change: transform;
}
.scroll-container {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
}
.scroll-item {
contain: layout style paint;
content-visibility: auto;
}
Critical CSS Patterns
Inline Critical CSS Strategy
<!DOCTYPE html>
<html>
<head>
<style>
body{margin:0;font:16px/1.5 system-ui,sans-serif}
.header{height:60px;background:#fff;box-shadow:0 2px 4px rgba(0,0,0,.1)}
.hero{min-height:100vh;display:grid;place-items:center}
</style>
<link rel="preload" href="/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>
</head>
</html>
Critical CSS Extraction Patterns
.container {
padding: 0 1rem;
max-width: 100%;
}
@media (min-width: 768px) {
.container {
padding: 0 2rem;
max-width: 1200px;
margin: 0 auto;
}
}
.layout { display: grid; }
.layout { gap: 1rem; padding: 1rem; }
.layout { box-shadow: 0 4px 6px rgba(0,0,0,.1); }
Render-Blocking Elimination
Techniques to Eliminate Render-Blocking CSS
<link rel="preload" href="/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<link rel="stylesheet" href="/css/print.css" media="print" onload="this.media='all'">
<link rel="stylesheet" href="/css/desktop.css" media="(min-width: 1024px)">
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
font-family: 'Main';
src: url('/fonts/main.woff2') format('woff2');
font-display: swap;
}
</style>
<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="prefetch" href="/css/about.css">
CSS Loading Strategies
.nav { display: flex; }
@media (min-width: 1024px) {
.nav-desktop { display: grid; grid-template-columns: repeat(5, 1fr); }
}
:root {
--color-primary: #007bff;
--color-secondary: #6c757d;
--spacing-unit: 0.5rem;
--border-radius: 4px;
}
.button {
background: var(--color-primary);
padding: calc(var(--spacing-unit) * 2);
border-radius: var(--border-radius);
}
.header { }
.footer { }
CSS Selector Performance
Selector Performance Reference
Performance Ranking (Fast → Slow)
- ID Selectors:
#header (Fastest)
- Class Selectors:
.button
- Tag Selectors:
div
- Adjacent Sibling:
.item + .item
- Child Selectors:
.parent > .child
- Descendant Selectors:
.ancestor .descendant
- Universal Selectors:
*
- Attribute Selectors:
[type="text"]
- Pseudo-classes:
:hover, :nth-child()
- Complex Combinations:
.a .b .c:nth-child(2n+1) (Slowest)
Selector Optimization Patterns
.sidebar .nav .menu .item .link:hover {
color: blue;
}
.nav-link:hover {
color: blue;
}
* {
box-sizing: border-box;
}
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
.list-item:nth-child(3n+2):not(:last-child) {
margin-bottom: 1rem;
}
.list-item-spaced {
margin-bottom: 1rem;
}
[class*="btn-"] {
padding: 0.5rem 1rem;
}
[data-type="button"] {
padding: 0.5rem 1rem;
}
div.container > ul.list > li.item {
color: black;
}
.list-item {
color: black;
}
.card { }
.card__header { }
.card__body { }
.card--featured { }
.card__header--large { }
Performance Measurement Tools
Browser DevTools
performance.getEntriesByType('resource')
.filter(r => r.initiatorType === 'link' || r.name.endsWith('.css'))
.forEach(r => {
console.log(`${r.name}: ${r.duration.toFixed(2)}ms`);
});
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'layout-shift') {
console.log('Layout shift score:', entry.value);
}
}
});
observer.observe({ entryTypes: ['layout-shift'] });
performance.getEntriesByType('paint').forEach(entry => {
console.log(`${entry.name}: ${entry.startTime.toFixed(2)}ms`);
});
Lighthouse Metrics
performance_budget:
metrics:
- first-contentful-paint: 1800
- largest-contentful-paint: 2500
- cumulative-layout-shift: 0.1
- total-blocking-time: 300
- speed-index: 3400
resources:
- stylesheet: 100
- font: 200
- image: 500
- total: 1600
counts:
- stylesheet: 3
- font: 4
- third-party: 5
CSS Performance Testing Tools
npx cssstats styles.css
npx purgecss --css styles.css --content index.html --output purged.css
npx css-analyzer styles.css
npx critical index.html --base ./ --inline --minify
npx lighthouse https://example.com --view --preset=desktop
Real User Monitoring (RUM)
import {getCLS, getFID, getFCP, getLCP, getTTFB} from 'web-vitals';
function sendToAnalytics({name, delta, value, id}) {
gtag('event', name, {
event_category: 'Web Vitals',
event_label: id,
value: Math.round(name === 'CLS' ? delta * 1000 : delta),
non_interaction: true,
});
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
Performance Anti-Patterns
Common CSS Performance Mistakes
.header .nav .menu .item .link .icon {
width: 20px;
}
.nav-link-icon {
width: 20px;
}
@keyframes slide-in {
from { left: -100px; width: 0; }
to { left: 0; width: 300px; }
}
@keyframes slide-in {
from { transform: translateX(-100px) scaleX(0); }
to { transform: translateX(0) scaleX(1); }
}
@import url('reset.css');
@import url('typography.css');
@import url('layout.css');
.hero {
background: url('/images/hero-4k.jpg');
}
.hero {
background: url('/images/hero-mobile.webp');
}
@media (min-width: 768px) {
.hero {
background: url('/images/hero-desktop.webp');
}
}
// BAD
elements.forEach(el => {
el.style.width = el.offsetWidth + 10 + 'px'; // Read then write
});
// GOOD - Batch reads and writes
const widths = elements.map(el => el.offsetWidth); // Batch reads
elements.forEach((el, i) => {
el.style.width = widths[i] + 10 + 'px'; // Batch writes
});
.card {
box-shadow: 0 0 100px 50px rgba(0,0,0,0.5);
filter: blur(20px) brightness(1.5) contrast(2);
}
.card {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.article-section {
}
.article-section {
content-visibility: auto;
contain-intrinsic-size: 0 500px;
}
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.ttf');
}
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap;
unicode-range: U+0000-00FF;
}
Optimization Decision Trees
CSS Loading Strategy Decision Tree
START: Does CSS affect above-the-fold content?
│
├─ YES: Is CSS < 14KB?
│ ├─ YES: Inline in <head>
│ └─ NO: Is it critical for LCP?
│ ├─ YES: Extract critical CSS, inline it
│ │ Load full CSS async
│ └─ NO: Load async with preload
│
└─ NO: Is CSS needed on first interaction?
├─ YES: Preload with low priority
└─ NO: Lazy load on interaction or prefetch
Animation Performance Decision Tree
START: Need to animate element?
│
├─ What property to animate?
│ ├─ Transform/Opacity: Safe, GPU-accelerated
│ ├─ Color/Background: Moderate, paint only
│ └─ Width/Height/Position: Expensive, causes reflow
│
└─ Will it affect many elements?
├─ YES: Use CSS containment
│ will-change: transform
└─ NO: Standard GPU animation
transform + opacity
Selector Optimization Decision Tree
START: Writing CSS selector?
│
├─ How many elements will match?
│ ├─ 1-10: Class selector fine
│ ├─ 10-100: Avoid complex pseudo-classes
│ └─ 100+: Use simple class, avoid nesting
│
└─ What's the nesting depth?
├─ 0-2 levels: Good performance
├─ 3-4 levels: Consider refactoring
└─ 5+ levels: Definitely refactor
Performance Budget Templates
Budget 1: Small Marketing Site
assets:
css:
critical_inline: 14kb
total_css: 50kb
files: 2
fonts:
total_size: 100kb
families: 2
weights: 4
images:
hero: 150kb
total: 500kb
metrics:
lcp: 1500ms
fcp: 800ms
cls: 0.05
tbt: 150ms
Budget 2: E-commerce Site
assets:
css:
critical_inline: 14kb
page_css: 80kb
shared_css: 120kb
files: 4
fonts:
total_size: 200kb
families: 3
weights: 6
images:
product: 100kb
hero: 200kb
total_above_fold: 400kb
metrics:
lcp: 2500ms
fcp: 1200ms
cls: 0.1
tbt: 300ms
tti: 3500ms
Budget 3: Web Application
assets:
css:
critical_inline: 14kb
app_css: 150kb
vendor_css: 100kb
files: 5
fonts:
total_size: 150kb
families: 2
weights: 4
runtime:
max_bundle: 300kb
css_in_js: 50kb
metrics:
lcp: 2000ms
fcp: 1000ms
cls: 0.1
inp: 200ms
tbt: 200ms
Advanced Performance Patterns
Pattern 31: CSS Grid Performance Optimization
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
contain: layout style;
}
.grid-item {
contain: layout paint;
}
Pattern 32: Responsive Images with CSS
.responsive-img {
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
object-fit: cover;
content-visibility: auto;
background: linear-gradient(to bottom, #f0f0f0, #e0e0e0);
}
Pattern 33: Dark Mode Performance
:root {
--bg: #ffffff;
--text: #000000;
color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #000000;
--text: #ffffff;
color-scheme: dark;
}
}
body {
background: var(--bg);
color: var(--text);
transition: none;
}
Pattern 34: Virtual Scrolling with CSS
.virtual-scroll-container {
overflow-y: auto;
height: 600px;
contain: strict;
}
.virtual-scroll-item {
content-visibility: auto;
contain-intrinsic-size: 0 100px;
}
Pattern 35: Performance Monitoring CSS
.critical-image {
content: url('/hero.jpg') / 'high';
}
.lazy-background {
background: url('/pattern.jpg') / 'low';
}
Performance Metrics Glossary
Core Web Vitals
-
LCP (Largest Contentful Paint): Time to render largest content element
- Good: < 2.5s
- Needs Improvement: 2.5s - 4.0s
- Poor: > 4.0s
-
FID (First Input Delay): Time from first interaction to browser response
- Good: < 100ms
- Needs Improvement: 100ms - 300ms
- Poor: > 300ms
-
INP (Interaction to Next Paint): Responsiveness throughout page lifecycle
- Good: < 200ms
- Needs Improvement: 200ms - 500ms
- Poor: > 500ms
-
CLS (Cumulative Layout Shift): Visual stability metric
- Good: < 0.1
- Needs Improvement: 0.1 - 0.25
- Poor: > 0.25
Additional Metrics
- FCP (First Contentful Paint): Time to first text/image render
- TTI (Time to Interactive): Time until page is fully interactive
- TBT (Total Blocking Time): Total time main thread is blocked
- SI (Speed Index): How quickly content is visually displayed
CSS Performance Checklist
Pre-Development
Development
Build Process
Deployment
Post-Launch
Tools and Resources
Build Tools
- PurgeCSS: Remove unused CSS
- Critical: Extract critical CSS
- cssnano: CSS minification
- PostCSS: CSS transformations
- Autoprefixer: Vendor prefixes
Analysis Tools
- Chrome DevTools: Performance profiling
- Lighthouse: Comprehensive audits
- WebPageTest: Real-world testing
- Chrome UX Report: Field data
- web-vitals: Core Web Vitals library
Monitoring Services
- Google Analytics: Custom metrics
- Sentry: Performance monitoring
- New Relic: Application performance
- Datadog: Real-user monitoring
- SpeedCurve: Performance tracking
Quick Reference Tables
CSS Property Performance Impact
| Property | Layout | Paint | Composite | Performance |
|---|
| transform | No | No | Yes | Excellent |
| opacity | No | No | Yes | Excellent |
| color | No | Yes | No | Good |
| background | No | Yes | No | Good |
| box-shadow | No | Yes | No | Moderate |
| width/height | Yes | Yes | Yes | Poor |
| top/left | Yes | Yes | Yes | Poor |
| margin/padding | Yes | Yes | Yes | Poor |
File Size Targets
| Asset Type | Target Size | Maximum Size |
|---|
| Critical CSS | < 14 KB | 20 KB |
| Page CSS | < 50 KB | 100 KB |
| Total CSS | < 100 KB | 200 KB |
| Web Font | < 50 KB | 100 KB |
| Font Family | < 150 KB | 300 KB |
Loading Priority
| Priority | Strategy | Use Case |
|---|
| Critical | Inline | Above-fold styles |
| High | Preload | LCP elements |
| Medium | Normal link | Below-fold styles |
| Low | Async load | Print, themes |
| Defer | Prefetch | Next-page styles |
This comprehensive CSS performance guide provides 35+ optimization patterns, measurement strategies, and decision-making frameworks to achieve excellent Core Web Vitals scores and deliver fast, efficient web experiences.