
Modern Web Design
- 1.8k installs
- 629 repo stars
- Updated November 20, 2025
- freshtechbro/claudedesignskills
modern-web-design is an agent skill that modern web design trends, principles, and implementation patterns for 2024-2025. use this skill when designing websites, creating interactive experiences, implementing design syst
About
modern-web-design is an agent skill from freshtechbro/claudedesignskills that modern web design trends, principles, and implementation patterns for 2024-2025. use this skill when designing websites, creating interactive experiences, implementing design systems, ensuring accessi. # Modern Web Design ## Overview Modern web design in 2024-2025 emphasizes performance, accessibility, and meaningful interactions. This skill provides comprehensive guidance on current design trends, implementation patterns, and best practices for creating engaging, accessible, and performant web experiences. This meta-skill synthesizes knowledg Developers invoke modern-web-design during build/integrations work for generative media tasks. The skill documents triggers, prerequisites, and step-by-step workflows grounded in SKILL.md. Compatible with Claude Code, Cursor, and Codex agent runtimes that load marketplace skills. Review the Security Audits panel on this listing before installing in production environments.
- This meta-skill synthesizes knowledge from all animation, interaction, and 3D skills in this repository to provide holis
- Core Design Principles (2024-2025)
- 1. Performance-First Design
- Philosophy**: Design decisions should prioritize Core Web Vitals and user experience on all devices.
- Largest Contentful Paint (LCP): < 2.5s
Modern Web Design by the numbers
- 1,781 all-time installs (skills.sh)
- +117 installs in the week ending Jul 29, 2026 (Skillselion tracking)
- Ranked #163 of 1,337 Generative Media skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 31, 2026 (Skillselion catalog sync)
modern-web-design capabilities & compatibility
- Capabilities
- this meta skill synthesizes knowledge from all a · core design principles (2024 2025) · 1. performance first design · philosophy**: design decisions should prioritize · largest contentful paint (lcp): < 2.5s
- Use cases
- orchestration
What modern-web-design says it does
This meta-skill synthesizes knowledge from all animation, interaction, and 3D skills in this repository to provide holistic design guidance.
**Philosophy**: Design decisions should prioritize Core Web Vitals and user experience on all devices.
- Interaction to Next Paint (INP): < 200ms
npx skills add https://github.com/freshtechbro/claudedesignskills --skill modern-web-designAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.8k |
|---|---|
| repo stars | ★ 629 |
| Security audit | 2 / 3 scanners passed |
| Last updated | November 20, 2025 |
| Repository | freshtechbro/claudedesignskills ↗ |
What it does
Modern web design trends, principles, and implementation patterns for 2024-2025. Use this skill when designing websites, creating interactive experiences, implementing design systems, ensuring accessi
Who is it for?
Developers working on generative media during build tasks.
Skip if: Tasks outside Generative Media scope described in SKILL.md.
When should I use this skill?
Modern web design trends, principles, and implementation patterns for 2024-2025. Use this skill when designing websites, creating interactive experiences, implementing design systems, ensuring accessi
What you get
Completed generative media workflow aligned with SKILL.md steps.
- UI patterns
- Accessibility guidance
- Library recommendations
Files
Modern Web Design
Overview
Modern web design in 2024-2025 emphasizes performance, accessibility, and meaningful interactions. This skill provides comprehensive guidance on current design trends, implementation patterns, and best practices for creating engaging, accessible, and performant web experiences.
This meta-skill synthesizes knowledge from all animation, interaction, and 3D skills in this repository to provide holistic design guidance.
Core Design Principles (2024-2025)
1. Performance-First Design
Philosophy: Design decisions should prioritize Core Web Vitals and user experience on all devices.
Key Metrics:
- Largest Contentful Paint (LCP): < 2.5s
- First Input Delay (FID): < 100ms
- Cumulative Layout Shift (CLS): < 0.1
- Interaction to Next Paint (INP): < 200ms
Implementation Guidelines:
- Defer non-critical animations until after page load
- Use CSS transforms/opacity for animations (GPU-accelerated)
- Implement lazy loading for images, videos, and 3D content
- Progressive enhancement: core content without JavaScript
Related Skills: gsap-scrolltrigger, motion-framer, lottie-animations for optimized animations
2. Bold Minimalism
Characteristics:
- Large, impactful typography (clamp() for fluid sizing)
- Ample white space (negative space as design element)
- Limited color palettes (3-5 primary colors)
- Intentional use of bold accent colors
- Geometric shapes and clean lines
Typography Scale (Modern fluid system):
/* Fluid typography using clamp() */
--font-size-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--font-size-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
--font-size-lg: clamp(1.25rem, 1.1rem + 0.75vw, 1.75rem);
--font-size-xl: clamp(1.75rem, 1.5rem + 1.25vw, 2.5rem);
--font-size-2xl: clamp(2.5rem, 2rem + 2.5vw, 4rem);
--font-size-3xl: clamp(3.5rem, 2.5rem + 5vw, 6rem);Color System (Accessibility-first):
/* WCAG AAA compliant color system */
--color-primary: oklch(50% 0.2 250); /* Blue */
--color-accent: oklch(65% 0.25 30); /* Coral */
--color-neutral-50: oklch(98% 0 0);
--color-neutral-900: oklch(20% 0 0);
/* Contrast ratio: minimum 7:1 for text */Related Skills: animated-component-libraries for UI components
3. Micro-Interactions
Definition: Small, purposeful animations that provide feedback, guide users, and enhance perceived performance.
Categories:
a) Hover States (Desktop):
- Scale transformations (1.05-1.1x)
- Color transitions (200-300ms)
- Shadow depth changes
- Cursor transformations
b) Loading States:
- Skeleton screens (better than spinners)
- Progressive image loading (blur-up technique)
- Optimistic UI updates
- Staggered content reveals
c) Interactive Feedback:
- Button press states (scale down 0.95x)
- Toggle switches with spring physics
- Form field validation (immediate, kind feedback)
- Success/error states with motion
Implementation Example (Framer Motion):
// Button with micro-interaction
<motion.button
whileHover={{ scale: 1.05, y: -2 }}
whileTap={{ scale: 0.95 }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
Click me
</motion.button>Related Skills: motion-framer, react-spring-physics, animejs for micro-interactions
4. Scrollytelling
Definition: Narrative-driven experiences where content reveals and transforms as the user scrolls.
Patterns:
a) Scroll-Triggered Reveals:
- Fade-in on scroll entry (with offset)
- Slide-in from sides with stagger
- Scale + opacity transitions
- Clip-path reveals
b) Scroll-Linked Animations:
- Parallax layers (different scroll speeds)
- Horizontal scrolling sections
- Pinned sections with scrubbing animations
- 3D object rotation tied to scroll
c) Progress Indicators:
- Reading progress bars
- Step-by-step visual guides
- Animated SVG paths following scroll
Implementation Example (GSAP ScrollTrigger):
// Scroll-linked 3D rotation
gsap.to(".cube", {
scrollTrigger: {
trigger: ".section",
start: "top top",
end: "bottom top",
scrub: 1, // Smooth scrubbing
},
rotationY: 360,
ease: "none"
});Related Skills: gsap-scrolltrigger, locomotive-scroll, scroll-reveal-libraries, react-three-fiber for 3D scrollytelling
5. Cursor UX
Evolution: Custom cursors that enhance interaction and provide contextual feedback.
Patterns:
a) Custom Cursor Shapes:
- Circle/dot followers (delayed with easing)
- Text-based cursors ("View", "Drag", "Click")
- Blend modes for visual interest
- Scale/morph on hover
b) Contextual Transformations:
- Expand on links/buttons
- Magnetic attraction to interactive elements
- Color inversion over images
- Custom icons for actions (play, zoom, expand)
c) Performance Considerations:
- Use CSS transforms only (no top/left)
- RequestAnimationFrame for JS cursors
- Disable on mobile/touch devices
- Respect
prefers-reduced-motion
Implementation Example:
// Simple smooth cursor follower
const cursor = document.querySelector('.cursor');
let mouseX = 0, mouseY = 0;
let cursorX = 0, cursorY = 0;
document.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
});
function updateCursor() {
// Smooth easing
cursorX += (mouseX - cursorX) * 0.1;
cursorY += (mouseY - cursorY) * 0.1;
cursor.style.transform = `translate(${cursorX}px, ${cursorY}px)`;
requestAnimationFrame(updateCursor);
}
updateCursor();Related Skills: gsap-scrolltrigger (for easing), motion-framer (for React cursor components)
6. Glassmorphism & Depth
Characteristics:
- Frosted glass effect (backdrop-filter)
- Layered UI with depth hierarchy
- Subtle shadows and borders
- Translucent backgrounds
Modern Glassmorphism (2024):
.glass-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border-radius: 16px;
}Depth System (Layering):
/* Elevation scale */
--elevation-1: 0 1px 3px rgba(0,0,0,0.12);
--elevation-2: 0 4px 8px rgba(0,0,0,0.15);
--elevation-3: 0 8px 16px rgba(0,0,0,0.18);
--elevation-4: 0 16px 32px rgba(0,0,0,0.2);Related Skills: animated-component-libraries for glassmorphic components
7. AI-Enhanced Personalization
Patterns:
a) Adaptive Content:
- Dynamic layout based on user behavior
- Personalized content recommendations
- Adaptive color schemes (system preference + user history)
- Smart defaults based on context
b) Intelligent Interactions:
- Predictive search with instant results
- Smart form completion
- Context-aware suggestions
- Progressive disclosure based on usage
c) Performance + Privacy:
- Client-side personalization (localStorage, IndexedDB)
- Edge computing for fast personalization
- Privacy-preserving analytics
- Transparent data usage
Implementation Considerations:
- Fallback to default experience
- No layout shift from personalization
- Respect "Do Not Track"
- GDPR/CCPA compliance
Common Design Patterns
Pattern 1: Immersive Hero Section
Use Case: Landing pages, product launches, portfolio sites
Characteristics:
- Full viewport height
- Subtle 3D background or animated gradient
- Large headline with fluid typography
- Smooth scroll indicator
- Parallax on scroll exit
Implementation (Combined approach):
HTML Structure:
<section class="hero">
<div id="bg-canvas"></div>
<div class="hero__content">
<h1 class="hero__title">Modern Design</h1>
<p class="hero__subtitle">Performance meets beauty</p>
<button class="hero__cta">Explore</button>
</div>
<div class="scroll-indicator">
<span>Scroll</span>
</div>
</section>Technologies:
- Background: Vanta.js WAVES effect (
lightweight-3d-effects) - Text animation: GSAP SplitText with stagger (
gsap-scrolltrigger) - Button: Framer Motion hover states (
motion-framer) - Scroll indicator: CSS animation + GSAP fade out on scroll
Related Skills: lightweight-3d-effects, gsap-scrolltrigger, motion-framer
Pattern 2: Horizontal Scroll Gallery
Use Case: Portfolio work, product showcases, case studies
Implementation (GSAP ScrollTrigger):
gsap.to(".gallery__track", {
x: () => -(document.querySelector(".gallery__track").scrollWidth - window.innerWidth),
ease: "none",
scrollTrigger: {
trigger: ".gallery",
pin: true,
scrub: 1,
end: () => "+=" + document.querySelector(".gallery__track").scrollWidth
}
});Enhancements:
- Lazy load images as they scroll into view
- Parallax within cards
- Scale transformation on active card
- Smooth momentum scrolling with Locomotive
Related Skills: gsap-scrolltrigger, locomotive-scroll
Pattern 3: 3D Product Viewer
Use Case: E-commerce, product marketing, showcases
Implementation (React Three Fiber):
import { Canvas } from '@react-three/fiber'
import { OrbitControls, useGLTF } from '@react-three/drei'
function ProductViewer() {
return (
<Canvas camera={{ position: [0, 0, 5], fov: 50 }}>
<ambientLight intensity={0.5} />
<spotLight position={[10, 10, 10]} angle={0.15} />
<Product />
<OrbitControls
enableZoom={false}
autoRotate
autoRotateSpeed={2}
/>
</Canvas>
)
}Enhancements:
- Material variants (color picker)
- Hotspots with annotations
- AR mode on mobile
- Screenshot/share functionality
Related Skills: react-three-fiber, threejs-webgl, model-viewer-component
Pattern 4: Animated Data Visualization
Use Case: Dashboards, analytics, infographics
Patterns:
- Count-up animations on scroll into view
- Animated chart reveals (progress bars, pie charts)
- Staggered grid animations
- Particle backgrounds representing data
Implementation (Framer Motion + IntersectionObserver):
function AnimatedStat({ end, label }) {
const [count, setCount] = useState(0);
const ref = useRef();
const isInView = useInView(ref, { once: true });
useEffect(() => {
if (isInView) {
// Count up animation
const duration = 2000;
const steps = 60;
const increment = end / steps;
let current = 0;
const timer = setInterval(() => {
current += increment;
if (current >= end) {
setCount(end);
clearInterval(timer);
} else {
setCount(Math.floor(current));
}
}, duration / steps);
}
}, [isInView, end]);
return (
<motion.div
ref={ref}
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6 }}
>
<h2>{count}+</h2>
<p>{label}</p>
</motion.div>
);
}Related Skills: motion-framer, pixijs-2d for canvas-based visualizations
Pattern 5: Page Transitions
Use Case: Multi-page apps, portfolio sites, storytelling experiences
Implementation (Barba.js + GSAP):
barba.init({
transitions: [{
name: 'slide',
leave(data) {
return gsap.to(data.current.container, {
xPercent: -100,
duration: 0.5
});
},
enter(data) {
return gsap.from(data.next.container, {
xPercent: 100,
duration: 0.5
});
}
}]
});Modern Alternatives:
- View Transitions API (Chrome 111+, progressive enhancement)
- Framer Motion's AnimatePresence for React SPAs
- Shared element transitions
Related Skills: barba-js, gsap-scrolltrigger, motion-framer
Pattern 6: Interactive Cursor Effects
Use Case: Creative agencies, portfolios, interactive experiences
Patterns:
- Text cursor that follows with delay
- Magnetic buttons (cursor attracted to elements)
- Blend mode cursor (inverts colors)
- Cursor that reveals content
Implementation (Vanilla JS + GSAP):
const links = document.querySelectorAll('a');
const cursor = document.querySelector('.cursor');
links.forEach(link => {
link.addEventListener('mouseenter', () => {
gsap.to(cursor, {
scale: 2,
duration: 0.3,
ease: "power2.out"
});
});
link.addEventListener('mouseleave', () => {
gsap.to(cursor, {
scale: 1,
duration: 0.3,
ease: "power2.out"
});
});
});Related Skills: gsap-scrolltrigger, motion-framer
Pattern 7: Staggered Content Reveals
Use Case: Feature sections, testimonials, team grids
Implementation (Framer Motion variants):
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
staggerChildren: 0.1
}
}
};
const item = {
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 }
};
function FeatureGrid() {
return (
<motion.div
variants={container}
initial="hidden"
whileInView="show"
viewport={{ once: true, amount: 0.3 }}
className="grid"
>
{features.map((feature, i) => (
<motion.div key={i} variants={item}>
{feature}
</motion.div>
))}
</motion.div>
);
}Related Skills: motion-framer, gsap-scrolltrigger, scroll-reveal-libraries
Integration with Other Skills
Animation Skills Integration
GSAP ScrollTrigger (gsap-scrolltrigger):
- Use for scroll-driven storytelling
- Pin sections for multi-step reveals
- Scrub animations tied to scroll position
- Batch animations for performance
Framer Motion (motion-framer):
- React component animations
- Page transitions with AnimatePresence
- Gesture-based interactions (drag, hover, tap)
- Layout animations (shared element transitions)
React Spring (react-spring-physics):
- Physics-based animations (more natural feel)
- Interactive springs (drag, pull)
- Trail animations (sequential reveals)
- Use for UI feedback that feels "real"
Anime.js (animejs):
- SVG path animations (line drawing)
- SVG morphing transitions
- Stagger grid animations
- Timeline-based sequences
Lottie (lottie-animations):
- Complex designer-created animations
- Icon animations and micro-interactions
- Loading states
- Scroll-driven playback
3D Skills Integration
Three.js (threejs-webgl):
- Custom 3D scenes and experiences
- Shader effects and post-processing
- WebGL-based particle systems
- Advanced lighting and materials
React Three Fiber (react-three-fiber):
- 3D in React applications
- Product viewers and configurators
- Interactive 3D UI components
- Scroll-driven 3D animations
Babylon.js (babylonjs-engine):
- Physics-based 3D experiences
- VR/XR applications
- Game-like interactions
- PBR materials for realism
Lightweight 3D (lightweight-3d-effects):
- Background effects (Vanta.js)
- Subtle 3D illustrations (Zdog)
- Tilt effects (Vanilla-Tilt)
- Performance-friendly 3D accents
Component Libraries
Animated Components (animated-component-libraries):
- Magic UI components (backgrounds, text effects)
- Pre-built interactive components
- Design system foundations
- Rapid prototyping
Scroll Reveals (scroll-reveal-libraries):
- Simple fade/slide on scroll
- AOS library integration
- Lightweight alternative to ScrollTrigger
- Quick implementation for basic reveals
Accessibility Best Practices
1. Motion & Animation
Respect User Preferences:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}JavaScript Detection:
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReducedMotion) {
// Disable or simplify animations
gsap.config({ nullTargetWarn: false });
// Skip scroll animations, use instant reveals
}2. Color Contrast
WCAG AAA Standards:
- Normal text: 7:1 contrast ratio
- Large text (18pt+): 4.5:1 contrast ratio
- Use OKLCH color space for perceptual uniformity
Testing:
// Check contrast ratio
function getContrastRatio(color1, color2) {
const l1 = getLuminance(color1);
const l2 = getLuminance(color2);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}3. Keyboard Navigation
Requirements:
- All interactive elements focusable
- Visible focus indicators (not outline: none)
- Logical tab order
- Skip links for long navigation
- Escape key closes modals/overlays
Focus Styles (Modern):
:focus-visible {
outline: 3px solid var(--color-accent);
outline-offset: 2px;
border-radius: 4px;
}
/* Remove focus ring for mouse users */
:focus:not(:focus-visible) {
outline: none;
}4. Screen Reader Support
Semantic HTML:
- Use proper heading hierarchy (h1-h6)
- Landmark regions (header, nav, main, footer)
- aria-labels for icon buttons
- aria-live regions for dynamic content
Animation Announcements:
<!-- Announce when content loads -->
<div role="status" aria-live="polite" aria-atomic="true">
Loading complete. 12 items displayed.
</div>5. Touch Targets
Minimum Size: 44x44px (iOS), 48x48px (Android)
Spacing: Minimum 8px between touch targets
Implementation:
.button {
min-height: 44px;
min-width: 44px;
padding: 12px 24px;
/* Tap target includes padding */
}Performance Optimization
1. Animation Performance
60 FPS Checklist:
- Use CSS transforms (translateX/Y/Z, scale, rotate) - GPU accelerated
- Use opacity for fades - GPU accelerated
- Avoid: top/left, width/height, margin, padding animations
- Use
will-changesparingly (memory cost) - RequestAnimationFrame for JS animations
GSAP Performance:
// Force GPU acceleration
gsap.set(element, { force3D: true });
// Use will-change during animation only
gsap.to(element, {
x: 100,
onStart: () => element.style.willChange = 'transform',
onComplete: () => element.style.willChange = 'auto'
});2. Loading Strategies
Critical Path:
- Inline critical CSS (above-the-fold)
- Defer non-critical CSS
- Async JavaScript loading
- Preload fonts and hero images
Progressive Enhancement:
<!-- Load essential styles first -->
<style>
/* Critical CSS inlined */
</style>
<!-- Defer non-critical styles -->
<link rel="preload" href="animations.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="animations.css"></noscript>3. Image Optimization
Modern Formats:
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description" loading="lazy">
</picture>Responsive Images:
<img
srcset="image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w"
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 50vw,
33vw"
src="image-800.jpg"
alt="Description"
loading="lazy"
>4. 3D Content Optimization
Loading Strategy:
- Show placeholder while loading
- Load low-poly model first
- Progressive enhancement with high-poly
- Lazy load 3D scenes below fold
Runtime Performance:
- Use object pooling
- Implement LOD (Level of Detail)
- Frustum culling
- Texture compression (Basis Universal)
Related Skills: threejs-webgl, react-three-fiber, babylonjs-engine
5. JavaScript Bundle Size
Code Splitting:
// Dynamic imports
const AnimationModule = lazy(() => import('./animations'));
// Route-based splitting
const Gallery = lazy(() => import('./pages/Gallery'));Tree Shaking:
- Use ES6 imports
- Import only what you need
- Use modern build tools (Vite, esbuild)
Common Pitfalls
Pitfall 1: Over-Animation
Problem: Too many animations distract from content and hurt performance.
Solution:
- Limit animations to meaningful interactions
- Use animation to guide attention, not demand it
- Follow the principle: "Animation with purpose"
- Measure performance impact (Chrome DevTools Performance tab)
Rule of Thumb: If you can't explain why an animation exists, remove it.
Pitfall 2: Ignoring Mobile Performance
Problem: Animations work on desktop but lag on mobile devices.
Solution:
- Test on real devices (not just simulators)
- Reduce animation complexity on mobile
- Disable expensive effects (parallax, 3D) on low-end devices
- Use
matchMediafor device-specific experiences
const isLowEndDevice = () => {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) &&
navigator.hardwareConcurrency < 4;
};
if (isLowEndDevice()) {
// Simplify or disable animations
}Pitfall 3: Missing Fallbacks
Problem: Experience breaks without JavaScript or on older browsers.
Solution:
- Progressive enhancement mindset
- Core content accessible without JS
- Feature detection before using modern APIs
- Polyfills for critical features
// Feature detection
if ('IntersectionObserver' in window) {
// Use scroll-triggered animations
} else {
// Show content immediately
}Pitfall 4: Accessibility Oversight
Problem: Forgetting keyboard users, screen readers, or motion-sensitive users.
Solution:
- Test with keyboard only
- Test with screen reader (NVDA, VoiceOver)
- Always check
prefers-reduced-motion - Use semantic HTML
- Maintain proper focus management
Checklist:
- [ ] All interactive elements keyboard accessible
- [ ] Focus indicators visible
- [ ] Color contrast meets WCAG AAA
- [ ] Motion can be disabled
- [ ] Screen reader announcements make sense
Pitfall 5: Ignoring Loading States
Problem: Blank screen or layout shifts during content load.
Solution:
- Skeleton screens for predictable layouts
- Smooth loading transitions
- Reserve space for dynamic content
- Show meaningful loading indicators
// Skeleton screen pattern
function ProductCard({ loading, data }) {
if (loading) {
return (
<div className="skeleton">
<div className="skeleton__image" />
<div className="skeleton__title" />
<div className="skeleton__price" />
</div>
);
}
return <ProductCardContent data={data} />;
}Pitfall 6: Scroll Hijacking
Problem: Overriding native scroll behavior frustrates users.
Solution:
- Preserve browser's native scroll (momentum, keyboard)
- Use ScrollTrigger/Locomotive without changing scroll physics
- Allow users to scroll at their own pace
- Never disable scroll entirely
- Avoid scroll-jacking for full-page sections
Good Practice: Enhance scroll, don't replace it.
Design System Architecture
Token Structure
Modern Design Tokens (CSS Custom Properties):
:root {
/* Colors - OKLCH for perceptual uniformity */
--color-primary: oklch(50% 0.2 250);
--color-accent: oklch(65% 0.25 30);
/* Spacing - Consistent scale */
--space-2xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.375rem);
--space-xs: clamp(0.5rem, 0.4rem + 0.5vw, 0.75rem);
--space-sm: clamp(0.75rem, 0.6rem + 0.75vw, 1.125rem);
--space-md: clamp(1rem, 0.8rem + 1vw, 1.5rem);
--space-lg: clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem);
--space-xl: clamp(2rem, 1.6rem + 2vw, 3rem);
--space-2xl: clamp(3rem, 2.4rem + 3vw, 4.5rem);
/* Typography - Fluid scale */
--font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
/* Animation - Consistent timing */
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
/* Easing - Natural motion */
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}Component Architecture
Atomic Design (Brad Frost): 1. Atoms: Buttons, inputs, labels 2. Molecules: Form fields, cards 3. Organisms: Navigation, hero sections 4. Templates: Page layouts 5. Pages: Specific instances
Related Skills: animated-component-libraries for component patterns
Resources
This skill references the following skills for implementation:
Animation & Interaction
gsap-scrolltrigger- Scroll-driven animations, pinning, scrubbingmotion-framer- React animations, gestures, layout animationsreact-spring-physics- Physics-based animationsanimejs- SVG animations, stagger effectslottie-animations- Designer-created animationsscroll-reveal-libraries- Simple scroll reveals (AOS)
3D & WebGL
threejs-webgl- Custom 3D scenes and effectsreact-three-fiber- 3D in React applicationsbabylonjs-engine- Physics-based 3D, VR/XRlightweight-3d-effects- Vanta.js backgrounds, Zdog illustrations
Page Transitions & Scroll
barba-js- Page transitionslocomotive-scroll- Smooth scrolling
Component Libraries
animated-component-libraries- Magic UI, React Bitspixijs-2d- Canvas-based 2D graphics
Detailed References
See the references/ directory for in-depth documentation:
design_trends_2024.md- Current web design trends and forecastsinteraction_patterns.md- Comprehensive micro-interaction catalogaccessibility_guide.md- WCAG compliance patterns and testingperformance_checklist.md- Optimization strategies and metrics
Scripts
The scripts/ directory includes tools for implementing design patterns:
pattern_generator.py- Generate design pattern boilerplatedesign_audit.py- Audit existing designs for compliance
Assets
The assets/ directory contains design system templates and starter files. See assets/README.md for details.
Modern Web Design Assets
Overview
This directory contains design system templates, starter files, and reusable assets for modern web development. All assets follow accessibility, performance, and modern design best practices.
Available Assets
1. Design Tokens
Location: Would be in tokens/ subdirectory
What's included:
- CSS custom properties (variables) for:
- Colors (OKLCH color space, AAA compliant)
- Typography scales (fluid sizing with clamp())
- Spacing scales (consistent rhythm)
- Shadows (elevation system)
- Border radius (consistent rounding)
- Animation timing (duration & easing)
Usage:
/* Import design tokens */
@import url('tokens/colors.css');
@import url('tokens/typography.css');
@import url('tokens/spacing.css');
/* Use in your styles */
.button {
background: var(--color-primary);
padding: var(--space-md) var(--space-lg);
font-size: var(--font-size-base);
transition: transform var(--duration-fast) var(--ease-out);
}2. Component Library
Location: Would be in components/ subdirectory
What's included:
- Button variants (primary, secondary, ghost, danger)
- Form components (inputs, textareas, select, checkbox, radio)
- Card layouts
- Navigation components
- Modal/Dialog components
- Toast notifications
- Loading states (spinners, skeletons, progress bars)
Features:
- Fully accessible (WCAG AAA where possible)
- Keyboard navigable
- Screen reader friendly
- Dark mode variants
- Responsive by default
3. Layout Templates
Location: Would be in layouts/ subdirectory
What's included:
- Landing page template
- Portfolio/Agency template
- Blog/Article template
- Dashboard/App template
- E-commerce template
Features:
- Modern CSS Grid & Flexbox
- Responsive breakpoints
- Print stylesheets
- Semantic HTML5
4. Animation Presets
Location: Would be in animations/ subdirectory
What's included:
- CSS keyframe animations
- Transition presets
- Easing functions
- GSAP animation snippets
- Framer Motion variants
Categories:
- Fade (in/out, up/down/left/right)
- Slide (all directions)
- Scale (grow/shrink)
- Rotate
- Bounce
- Elastic
- Custom easings
5. Icon System
Location: Would be in icons/ subdirectory
What's included:
- SVG icon set (inline-ready)
- Icon sprite sheet
- Icon font (optional)
Features:
- Accessibility ready (proper aria-hidden/labels)
- Consistent sizing
- Color customizable via CSS
6. Utility Classes
Location: Would be in utilities/ subdirectory
What's included:
- Display utilities (flex, grid, block, inline, none)
- Spacing utilities (margin, padding)
- Typography utilities (size, weight, align)
- Color utilities (text, background)
- Layout utilities (container, aspect-ratio)
- Accessibility utilities (sr-only, focus-visible)
Example:
<div class="flex items-center gap-md p-lg bg-primary text-white rounded-lg">
Content
</div>7. Reset & Base Styles
Location: Would be in base/ subdirectory
What's included:
- Modern CSS reset (based on modern-normalize)
- Base typography styles
- Accessible focus styles
- Print styles
---
How to Use These Assets
Option 1: Copy Individual Files
Copy only the files you need into your project:
# Copy design tokens
cp assets/tokens/colors.css src/styles/
cp assets/tokens/typography.css src/styles/
# Copy specific components
cp assets/components/button.css src/components/Option 2: Import Everything
Import the complete design system:
<link rel="stylesheet" href="assets/design-system.css">Or in your CSS:
@import url('../assets/design-system.css');Option 3: Use as Reference
Browse the assets to understand patterns and adapt them to your own design system.
---
Customization Guide
Colors
Modify color tokens to match your brand:
:root {
/* Update these values */
--color-primary: oklch(50% 0.2 250); /* Your brand blue */
--color-accent: oklch(65% 0.25 30); /* Your accent color */
/* System will generate variants automatically */
--color-primary-hover: oklch(45% 0.2 250);
--color-primary-active: oklch(40% 0.2 250);
}Typography
Adjust type scale for your design:
:root {
/* Base size (1rem = 16px by default) */
--font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
/* Adjust ratio for scale */
--font-scale-ratio: 1.25; /* Minor third */
/* Or use pre-calculated values */
--font-size-sm: clamp(0.875rem, ...);
--font-size-lg: clamp(1.25rem, ...);
}Spacing
Customize spacing scale:
:root {
/* 8px base unit */
--space-unit: 0.5rem;
/* Scale multiples */
--space-xs: calc(var(--space-unit) * 1); /* 8px */
--space-sm: calc(var(--space-unit) * 2); /* 16px */
--space-md: calc(var(--space-unit) * 4); /* 32px */
--space-lg: calc(var(--space-unit) * 6); /* 48px */
--space-xl: calc(var(--space-unit) * 8); /* 64px */
}---
Design System Principles
1. Mobile-First
All components are designed mobile-first with progressive enhancement for larger screens.
/* Mobile first */
.component {
font-size: 1rem;
}
/* Enhance for larger screens */
@media (min-width: 768px) {
.component {
font-size: 1.25rem;
}
}2. Accessibility First
- AAA color contrast ratios where possible (7:1)
- Keyboard navigable (visible focus states)
- Screen reader friendly (proper ARIA labels)
- Respects motion preferences
3. Performance Optimized
- CSS-only animations where possible
- GPU-accelerated transforms
- Minimal JavaScript
- Lazy-loadable components
4. Design Token Driven
Everything is configurable via design tokens:
- Easy rebranding
- Consistent visual language
- Dark mode support built-in
---
File Structure
assets/
├── README.md (this file)
├── tokens/
│ ├── colors.css
│ ├── typography.css
│ ├── spacing.css
│ ├── shadows.css
│ └── animation.css
├── base/
│ ├── reset.css
│ ├── typography.css
│ └── print.css
├── components/
│ ├── button.css
│ ├── card.css
│ ├── form.css
│ ├── modal.css
│ └── ...
├── layouts/
│ ├── landing.html
│ ├── dashboard.html
│ └── ...
├── animations/
│ ├── fade.css
│ ├── slide.css
│ └── gsap-presets.js
├── utilities/
│ └── utilities.css
└── design-system.css (imports all)---
Browser Support
Modern Browsers (recommended):
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
Fallbacks provided for:
- CSS Grid → Flexbox
- CSS custom properties → Fallback values
- Modern CSS functions → Static values
Progressive Enhancement:
/* Fallback */
.container {
padding: 2rem; /* Static value */
}
/* Enhanced */
@supports (padding: clamp(1rem, 5vw, 3rem)) {
.container {
padding: clamp(1rem, 5vw, 3rem);
}
}---
Contributing
When adding new assets:
1. Follow naming conventions: kebab-case for files, BEM for CSS classes 2. Include accessibility: ARIA labels, keyboard support, focus states 3. Document usage: Add examples and notes in component files 4. Test thoroughly: Cross-browser, keyboard, screen reader 5. Optimize: Remove unused code, minimize file size
---
Related Skills
For implementation guidance, reference:
gsap-scrolltrigger- Animation patternsmotion-framer- React component animationsanimated-component-libraries- Pre-built componentsthreejs-webgl- 3D backgrounds and effects
---
License
All assets follow the Apache 2.0 license (same as the skill).
---
Last updated: 2024
Web Accessibility Guide (WCAG AAA Compliance)
Overview
Comprehensive guide to web accessibility compliance following WCAG 2.1/2.2 Level AAA standards. This guide covers the most critical accessibility requirements for modern web design.
Target Standard: WCAG 2.1 Level AAA (where practical) with Level AA as minimum baseline.
---
Table of Contents
1. Color & Contrast 2. Typography & Readability 3. Keyboard Navigation 4. Screen Reader Support 5. Motion & Animation 6. Touch Targets & Mobile 7. Forms & Input 8. Focus Management 9. Semantic HTML 10. Testing & Auditing
---
Color & Contrast
WCAG Contrast Requirements
Level AA (Minimum):
- Normal text (< 18pt): 4.5:1 contrast ratio
- Large text (≥ 18pt or 14pt bold): 3:1 contrast ratio
Level AAA (Enhanced):
- Normal text: 7:1 contrast ratio
- Large text: 4.5:1 contrast ratio
Checking Contrast
Manual Calculation:
function getLuminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c = c / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}
function getContrastRatio(rgb1, rgb2) {
const l1 = getLuminance(...rgb1);
const l2 = getLuminance(...rgb2);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
// Example usage
const textColor = [0, 0, 0]; // Black
const bgColor = [255, 255, 255]; // White
const ratio = getContrastRatio(textColor, bgColor);
console.log(ratio); // 21:1 (AAA compliant)Tools:
- WebAIM Contrast Checker: https://webaim.org/resources/contrastchecker/
- Stark (Figma plugin)
- Chrome DevTools Accessibility Panel
Color System (AAA Compliant)
Using OKLCH Color Space:
:root {
/* Text on white background (AAA compliant) */
--color-text-primary: oklch(20% 0 0); /* #1a1a1a, 11.6:1 */
--color-text-secondary: oklch(40% 0 0); /* #666666, 7.3:1 */
/* Backgrounds */
--color-bg-primary: oklch(98% 0 0); /* Near white */
--color-bg-secondary: oklch(95% 0 0); /* Light gray */
/* Accent colors (AAA on white) */
--color-accent-blue: oklch(45% 0.2 250); /* 7.1:1 */
--color-accent-green: oklch(50% 0.15 140); /* 7.2:1 */
/* Interactive states */
--color-link: oklch(40% 0.2 250); /* Blue, 8.3:1 */
--color-link-hover: oklch(35% 0.25 250); /* Darker blue, 10.5:1 */
}Color Blindness Considerations
Avoid:
- Red-green as only distinguisher (affects 8% of males)
- Relying on color alone for meaning
Best Practices:
- Use patterns, shapes, or icons alongside color
- Test with color blindness simulators
- Provide high-contrast mode
Simulation Tools:
- Chrome DevTools: Rendering > Emulate vision deficiencies
- Colorblindly (browser extension)
- Stark (Figma)
---
Typography & Readability
Font Size Requirements
WCAG Guidelines:
- Body text: Minimum 16px (1rem)
- Small text: Minimum 14px (0.875rem)
- Users must be able to zoom to 200% without loss of functionality
Recommended Sizes:
:root {
/* Fluid typography */
--font-size-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
--font-size-lg: clamp(1.25rem, 1.1rem + 0.75vw, 1.75rem);
--font-size-xl: clamp(1.75rem, 1.5rem + 1.25vw, 2.5rem);
}
body {
font-size: var(--font-size-base);
line-height: 1.5; /* WCAG minimum for body text */
}Line Height & Spacing
WCAG 1.4.12 (Level AAA):
- Line height: Minimum 1.5× font size
- Paragraph spacing: Minimum 2× font size
- Letter spacing: Minimum 0.12× font size
- Word spacing: Minimum 0.16× font size
Implementation:
p {
font-size: 1rem;
line-height: 1.6; /* 1.5× minimum */
margin-bottom: 2rem; /* 2× font size */
letter-spacing: 0.01em; /* Slight increase */
word-spacing: 0.05em;
}Font Choices
Accessible Fonts:
- Sans-serif: Inter, Roboto, Open Sans, Atkinson Hyperlegible
- Serif: Georgia, Merriweather, Lora
- Avoid: Overly decorative, thin weights (< 300), all-caps for long text
Dyslexia-Friendly:
- OpenDyslexic
- Atkinson Hyperlegible
- Comic Sans (surprisingly good for dyslexia)
---
Keyboard Navigation
Requirements
All interactive elements must be:
- Focusable with Tab key
- Activatable with Enter or Space
- Dismissible with Escape (modals, dropdowns)
- Navigable with arrow keys (where appropriate)
Tab Order
Logical Tab Order:
<!-- Natural DOM order is best -->
<button tabindex="0">First</button>
<button tabindex="0">Second</button>
<button tabindex="0">Third</button>
<!-- Avoid tabindex > 0 (creates unpredictable order) -->
<button tabindex="3">Third</button> <!-- BAD -->
<button tabindex="1">First</button> <!-- BAD -->Skip Links:
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<nav>...</nav>
<main id="main-content">
<!-- Main content -->
</main>.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
text-decoration: none;
z-index: 100;
}
.skip-link:focus {
top: 0;
}Focus Indicators
WCAG 2.4.7 (Level AA):
- Focus indicator must be visible
- Minimum 2px thick
- Sufficient contrast (3:1 against background)
Modern Focus Styles:
/* Remove default outline */
*:focus {
outline: none;
}
/* Custom focus indicator */
:focus-visible {
outline: 3px solid var(--color-accent);
outline-offset: 2px;
border-radius: 4px;
}
/* Remove focus ring for mouse users */
:focus:not(:focus-visible) {
outline: none;
}
/* Button focus */
button:focus-visible {
outline: 3px solid #3b82f6;
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2);
}Keyboard Patterns
Modal Dialogs:
function trapFocus(element) {
const focusableElements = element.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
element.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstFocusable) {
e.preventDefault();
lastFocusable.focus();
} else if (!e.shiftKey && document.activeElement === lastFocusable) {
e.preventDefault();
firstFocusable.focus();
}
}
if (e.key === 'Escape') {
closeModal();
}
});
firstFocusable.focus();
}Dropdown Menus:
function handleDropdownKeys(e) {
const items = Array.from(dropdown.querySelectorAll('[role="menuitem"]'));
const currentIndex = items.indexOf(document.activeElement);
switch (e.key) {
case 'ArrowDown':
e.preventDefault();
const nextIndex = (currentIndex + 1) % items.length;
items[nextIndex].focus();
break;
case 'ArrowUp':
e.preventDefault();
const prevIndex = (currentIndex - 1 + items.length) % items.length;
items[prevIndex].focus();
break;
case 'Home':
e.preventDefault();
items[0].focus();
break;
case 'End':
e.preventDefault();
items[items.length - 1].focus();
break;
case 'Escape':
closeDropdown();
triggerButton.focus();
break;
}
}---
Screen Reader Support
ARIA Attributes
Essential ARIA:
Landmarks:
<header role="banner">
<nav role="navigation" aria-label="Main">
<!-- Navigation -->
</nav>
</header>
<main role="main">
<!-- Main content -->
</main>
<aside role="complementary" aria-label="Related articles">
<!-- Sidebar -->
</aside>
<footer role="contentinfo">
<!-- Footer -->
</footer>Buttons:
<!-- Icon button needs label -->
<button aria-label="Close menu">
<svg>...</svg>
</button>
<!-- Button with visible text -->
<button>
<svg aria-hidden="true">...</svg>
Submit
</button>Live Regions:
<!-- Announce loading state -->
<div role="status" aria-live="polite" aria-atomic="true">
Loading content...
</div>
<!-- Announce errors -->
<div role="alert" aria-live="assertive">
Error: Form submission failed.
</div>Custom Components:
<!-- Accordion -->
<div class="accordion">
<h3>
<button
aria-expanded="false"
aria-controls="panel-1"
id="button-1"
>
Section 1
</button>
</h3>
<div
id="panel-1"
role="region"
aria-labelledby="button-1"
hidden
>
Content...
</div>
</div>
<!-- Tab panel -->
<div role="tablist" aria-label="Content sections">
<button role="tab" aria-selected="true" aria-controls="panel-1">
Tab 1
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2">
Tab 2
</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
Panel content...
</div>Alt Text Guidelines
Images:
<!-- Informative image -->
<img src="chart.png" alt="Bar chart showing 50% increase in sales">
<!-- Decorative image -->
<img src="decorative.png" alt="" role="presentation">
<!-- Complex image -->
<img src="infographic.png" alt="Sales data for Q4" longdesc="sales-data.html">Best Practices:
- Describe the content/function, not "image of..."
- Keep under 150 characters (screen readers pause)
- Use empty alt (
alt="") for decorative images - Provide long descriptions for complex images
---
Motion & Animation
Reduced Motion Preference
WCAG 2.3.3 (Level AAA): Users must be able to disable non-essential motion.
Implementation:
/* Default: animations enabled */
.animated-element {
animation: slide-in 0.5s ease;
}
/* Respect user preference */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
/* Keep essential animations but reduce */
.loading-spinner {
animation-duration: 1s; /* Slower */
}
}JavaScript Detection:
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
if (prefersReducedMotion) {
// Disable or simplify animations
gsap.config({ nullTargetWarn: false, force3D: false });
// Skip scroll animations
ScrollTrigger.getAll().forEach(st => st.kill());
}Animation Guidelines
Safe Animations:
- Fade in/out (opacity)
- Slide short distances (< 50px)
- Scale small amounts (0.95-1.05)
- Avoid: flashing, rapid movement, parallax
Vestibular Disorders: Avoid animations that can cause dizziness or nausea:
- Large parallax effects
- Continuous rotation
- Zoom effects
- Perspective transforms
---
Touch Targets & Mobile
WCAG 2.5.5 (Level AAA)
Target Size: Minimum 44×44px (iOS) or 48×48px (Android)
Spacing: Minimum 8px between targets
Implementation:
button, a {
min-height: 44px;
min-width: 44px;
padding: 12px 24px;
/* Touch target includes padding */
}
/* Increase tap target without changing visual size */
button::before {
content: '';
position: absolute;
inset: -8px; /* Extends tap target by 8px all sides */
}Mobile Considerations
Viewport:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">Note: Allow zoom up to 5× (WCAG requirement)
Touch Gestures:
- Avoid complex gestures (multi-finger, long-press)
- Provide alternative interactions
- Don't rely on hover states
---
Forms & Input
Labels & Instructions
WCAG 3.3.2 (Level A): Every input must have a visible label.
Implementation:
<!-- Explicit label -->
<label for="email">Email address</label>
<input id="email" type="email" required aria-describedby="email-help">
<small id="email-help">We'll never share your email.</small>
<!-- Error state -->
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<div id="email-error" role="alert">
Please enter a valid email address.
</div>Form Validation
Accessible Validation:
function validateEmail(input) {
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.value);
if (isValid) {
input.setAttribute('aria-invalid', 'false');
input.removeAttribute('aria-describedby');
removeError(input);
} else {
input.setAttribute('aria-invalid', 'true');
input.setAttribute('aria-describedby', `${input.id}-error`);
showError(input, 'Please enter a valid email address.');
}
}
function showError(input, message) {
const errorElement = document.getElementById(`${input.id}-error`) ||
createErrorElement(input.id);
errorElement.textContent = message;
errorElement.setAttribute('role', 'alert'); // Announces to screen readers
}Required Fields
Indication:
<label for="name">
Full name
<abbr title="required" aria-label="required">*</abbr>
</label>
<input id="name" type="text" required aria-required="true">Visual + Programmatic:
- Visual indicator (asterisk, "required")
requiredattributearia-required="true"
---
Focus Management
Managing Focus States
After Modal Opens:
function openModal() {
modal.style.display = 'block';
modal.setAttribute('aria-hidden', 'false');
// Focus first focusable element
const firstFocusable = modal.querySelector('button, [href], input');
firstFocusable.focus();
// Trap focus
trapFocus(modal);
}After Modal Closes:
function closeModal() {
modal.style.display = 'none';
modal.setAttribute('aria-hidden', 'true');
// Return focus to trigger button
triggerButton.focus();
}Focus Order
Best Practices:
- Follow visual order (top to bottom, left to right)
- Group related elements
- Use
tabindex="-1"for programmatic focus only - Avoid
tabindex > 0(creates unpredictable order)
---
Semantic HTML
Heading Hierarchy
WCAG 1.3.1 (Level A): Use proper heading levels (h1-h6) without skipping.
Correct:
<h1>Page Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
<h3>Another Subsection</h3>
<h2>Another Section</h2>Incorrect:
<h1>Page Title</h1>
<h3>Section</h3> <!-- Skipped h2 -->Landmark Regions
Essential Landmarks:
<header>
<nav aria-label="Main navigation">
<!-- Primary nav -->
</nav>
</header>
<main>
<article>
<header>
<h1>Article Title</h1>
</header>
<!-- Article content -->
</article>
<aside aria-label="Related links">
<!-- Sidebar -->
</aside>
</main>
<footer>
<nav aria-label="Footer navigation">
<!-- Footer nav -->
</nav>
</footer>Lists & Tables
Lists:
<!-- Use proper list elements -->
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<!-- Not divs styled as lists -->Tables:
<table>
<caption>Sales Data Q4 2024</caption>
<thead>
<tr>
<th scope="col">Month</th>
<th scope="col">Sales</th>
</tr>
</thead>
<tbody>
<tr>
<td>October</td>
<td>$50,000</td>
</tr>
</tbody>
</table>---
Testing & Auditing
Automated Testing Tools
Browser Extensions:
- axe DevTools (Chrome/Firefox)
- WAVE (Web Accessibility Evaluation Tool)
- Lighthouse (Chrome DevTools)
Command Line:
# pa11y
npm install -g pa11y
pa11y https://example.com
# axe-core CLI
npm install -g @axe-core/cli
axe https://example.comManual Testing Checklist
Keyboard Navigation:
- [ ] Tab through all interactive elements
- [ ] Activate with Enter/Space
- [ ] Close modals with Escape
- [ ] Navigate dropdowns with arrow keys
Screen Reader Testing:
- [ ] Test with NVDA (Windows), VoiceOver (Mac), JAWS
- [ ] Check heading structure
- [ ] Verify alt text
- [ ] Test form labels and errors
Visual Testing:
- [ ] Zoom to 200%
- [ ] Test color contrast
- [ ] Check focus indicators
- [ ] Review with color blindness simulator
Motion Testing:
- [ ] Enable
prefers-reduced-motion - [ ] Verify animations are disabled/reduced
- [ ] Check for essential animations that remain
Screen Reader Testing Commands
NVDA (Windows):
- Toggle: Caps Lock or Insert
- Next heading: H
- Next landmark: D
- Read all: Caps Lock + Down Arrow
VoiceOver (Mac):
- Toggle: Cmd + F5
- Rotor: Ctrl + Option + U
- Next heading: Ctrl + Option + Cmd + H
JAWS (Windows):
- List headings: Insert + F6
- List links: Insert + F7
- Next heading: H
---
Common Accessibility Patterns
Accessible Modal
function AccessibleModal({ isOpen, onClose, children }) {
const modalRef = useRef(null);
const triggerRef = useRef(document.activeElement);
useEffect(() => {
if (isOpen) {
// Trap focus
trapFocus(modalRef.current);
// Focus first element
const firstFocusable = modalRef.current.querySelector('button, [href], input');
firstFocusable?.focus();
// Prevent body scroll
document.body.style.overflow = 'hidden';
} else {
// Return focus
triggerRef.current?.focus();
document.body.style.overflow = '';
}
// Listen for Escape key
const handleEscape = (e) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handleEscape);
return () => document.removeEventListener('keydown', handleEscape);
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div
className="modal-backdrop"
onClick={onClose}
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<div
ref={modalRef}
className="modal"
onClick={(e) => e.stopPropagation()}
>
<h2 id="modal-title">Modal Title</h2>
{children}
<button onClick={onClose} aria-label="Close modal">
×
</button>
</div>
</div>
);
}Accessible Accordion
<div class="accordion">
<h3>
<button
aria-expanded="false"
aria-controls="panel-1"
id="accordion-button-1"
>
<span class="accordion-title">Section 1</span>
<svg class="accordion-icon" aria-hidden="true">...</svg>
</button>
</h3>
<div
id="panel-1"
role="region"
aria-labelledby="accordion-button-1"
hidden
>
<p>Content for section 1...</p>
</div>
</div>function initAccordion() {
const buttons = document.querySelectorAll('.accordion button');
buttons.forEach(button => {
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
const panel = document.getElementById(button.getAttribute('aria-controls'));
button.setAttribute('aria-expanded', !expanded);
panel.hidden = expanded;
});
});
}---
WCAG Quick Reference
Level A (Must Have):
- Text alternatives (alt text)
- Keyboard accessible
- Color not only means of conveying info
- Labeled form inputs
- Proper heading hierarchy
Level AA (Should Have):
- 4.5:1 contrast for normal text
- 3:1 contrast for large text
- Resize text to 200%
- Focus visible
- Multiple ways to find pages
Level AAA (Nice to Have):
- 7:1 contrast for normal text
- 4.5:1 contrast for large text
- Target size 44×44px minimum
- No timing restrictions
- Help available
---
Last updated: 2024 Based on WCAG 2.1 and WCAG 2.2 standards
Web Design Trends 2024-2025
Overview
This document catalogs the dominant web design trends, aesthetic movements, and interaction paradigms shaping modern web experiences in 2024-2025. Updated regularly based on industry analysis, award-winning sites, and emerging patterns.
Visual Design Trends
1. Bold Minimalism
Definition: Minimalist foundations enhanced with bold typography, intentional color, and confident white space.
Key Characteristics:
- Ultra-large typography (80px-200px+ headlines)
- Limited color palettes (2-4 colors max)
- Generous white space (breathing room)
- High contrast (black/white, bold accent colors)
- Geometric shapes and clean lines
- Sans-serif dominance (Inter, Space Grotesk, Sora)
Examples:
- Apple product pages
- Linear.app
- Stripe documentation
- Vercel website
Implementation Tips:
/* Fluid typography for bold headlines */
h1 {
font-size: clamp(3rem, 8vw, 10rem);
font-weight: 700;
line-height: 0.95;
letter-spacing: -0.03em;
}
/* Generous spacing */
section {
padding: clamp(3rem, 10vw, 8rem) 0;
}Why It Works: Reduces cognitive load, focuses attention, loads fast, works across devices.
---
2. Kinetic Typography
Definition: Text that moves, transforms, and responds to user interaction.
Patterns:
a) Variable Font Animations:
- Weight transitions (100 → 900)
- Width morphing (condensed → expanded)
- Slant/italic transformations
- Multiple axes animating simultaneously
Implementation:
@font-face {
font-family: 'Inter';
src: url('Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
}
h1 {
font-variation-settings: 'wght' 300;
transition: font-variation-settings 0.3s;
}
h1:hover {
font-variation-settings: 'wght' 900;
}b) Text Split & Stagger:
- Reveal by character, word, or line
- Staggered entrance animations
- 3D text transformations
c) Scroll-Linked Text:
- Text color change on scroll
- Weight increase/decrease
- Size transformations
- Parallax text layers
Related Skills: gsap-scrolltrigger for text animations, motion-framer for React text effects
---
3. Glassmorphism 2.0
Evolution: Refined frosted-glass aesthetic with better accessibility and performance.
Modern Approach (2024):
.glass-card {
/* More subtle, accessible backgrounds */
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(12px) saturate(150%);
/* Higher contrast borders */
border: 1px solid rgba(255, 255, 255, 0.18);
/* Softer, more realistic shadows */
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.12),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
border-radius: 16px;
}
/* Dark mode variant */
@media (prefers-color-scheme: dark) {
.glass-card {
background: rgba(0, 0, 0, 0.4);
border: 1px solid rgba(255, 255, 255, 0.1);
}
}Accessibility Considerations:
- Ensure text has 4.5:1+ contrast on glass backgrounds
- Test with screen readers (ensure content is readable)
- Provide high-contrast mode alternative
Performance:
backdrop-filtercan be expensive on mobile- Use sparingly (2-3 glass elements max per viewport)
- Consider
will-change: backdrop-filterduring animations only
---
4. Gradient Mesh Backgrounds
Definition: Complex, multi-color gradients with organic blob shapes.
Tools:
- CSS:
background: radial-gradient()layering - SVG: Gradient mesh filters
- Canvas/WebGL: Shader-based gradients (Vanta.js)
Modern Gradient System:
:root {
/* Define gradient stops */
--gradient-1: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--gradient-2: radial-gradient(circle at 20% 50%, #f093fb 0%, #f5576c 100%);
--gradient-mesh:
radial-gradient(at 27% 37%, hsla(215, 98%, 61%, 1) 0px, transparent 50%),
radial-gradient(at 97% 21%, hsla(125, 98%, 72%, 1) 0px, transparent 50%),
radial-gradient(at 52% 99%, hsla(354, 98%, 61%, 1) 0px, transparent 50%),
radial-gradient(at 10% 29%, hsla(256, 96%, 67%, 1) 0px, transparent 50%);
}
.hero {
background: var(--gradient-mesh);
background-size: 400% 400%;
animation: gradient-shift 15s ease infinite;
}
@keyframes gradient-shift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}Animated Gradients (WebGL approach with Vanta.js):
- WAVES effect with custom colors
- CELLS effect for organic feel
- FOG for atmospheric backgrounds
Related Skills: lightweight-3d-effects (Vanta.js backgrounds)
---
5. Neumorphism (Evolved)
Status: Declining but still used for specific contexts (iOS apps, dashboards).
Modern Implementation (Improved contrast):
.neomorphic-card {
background: #e0e5ec;
box-shadow:
/* Light shadow */
8px 8px 16px rgba(163, 177, 198, 0.6),
/* Dark shadow */
-8px -8px 16px rgba(255, 255, 255, 0.8);
border-radius: 16px;
padding: 2rem;
/* CRITICAL: Ensure contrast for accessibility */
color: #1a1a1a; /* 11.6:1 contrast ratio */
}
/* Interactive state */
.neomorphic-card:active {
box-shadow:
inset 4px 4px 8px rgba(163, 177, 198, 0.6),
inset -4px -4px 8px rgba(255, 255, 255, 0.8);
}Why It's Declining: Accessibility concerns (low contrast), limited color palette, heavy shadows impact performance.
---
6. Dark Mode as Default
Trend: Many sites now default to dark mode with light mode as alternative.
Best Practices (2024):
/* Use system preference as default */
:root {
color-scheme: light dark;
}
/* Dark mode first */
:root {
--color-bg: #0a0a0a;
--color-text: #e5e5e5;
--color-accent: #3b82f6;
}
/* Light mode override */
@media (prefers-color-scheme: light) {
:root {
--color-bg: #ffffff;
--color-text: #171717;
--color-accent: #2563eb;
}
}
/* Manual toggle support */
[data-theme="light"] {
--color-bg: #ffffff;
--color-text: #171717;
}
[data-theme="dark"] {
--color-bg: #0a0a0a;
--color-text: #e5e5e5;
}Color Adjustments for Dark Mode:
- Reduce saturation by 10-20%
- Lower brightness for vibrant colors
- Use warmer blacks (#0a0a0a, not pure #000)
- Increase contrast for text (7:1+ ratio)
---
7. Asymmetric Layouts
Definition: Breaking the grid for visual interest and hierarchy.
Patterns:
- Split-screen layouts (60/40, 70/30)
- Overlapping elements with z-index
- Diagonal sections
- Off-grid text positioning
- Broken grid systems
CSS Grid Implementation:
.asymmetric-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 2rem;
}
.feature-1 {
/* Spans 7 columns, offset by 1 */
grid-column: 2 / 9;
grid-row: 1;
}
.feature-2 {
/* Overlaps with feature-1 */
grid-column: 8 / 13;
grid-row: 1;
margin-top: 4rem; /* Offset vertically */
z-index: 2;
}Examples:
- Awwwards winners (70%+ use asymmetry)
- Design agency portfolios
- Product launch pages
---
Interaction Trends
8. Micro-Interactions Everywhere
Definition: Small, delightful animations that provide feedback and enhance usability.
Categories & Examples:
a) Button Interactions:
- Hover lift (transform: translateY(-2px))
- Press down (scale: 0.98)
- Ripple effect on click
- Color shift transitions
b) Form Feedback:
- Input focus animations (border glow)
- Success/error state transitions
- Character count with progress ring
- Password strength indicator
c) Loading States:
- Skeleton screens (better than spinners)
- Progress indicators
- Optimistic UI updates
- Staggered content reveals
d) Navigation:
- Hamburger to X transitions
- Dropdown reveals with stagger
- Active state indicators
- Scroll progress bars
Implementation (Framer Motion):
const buttonVariants = {
idle: { scale: 1, y: 0 },
hover: { scale: 1.05, y: -2 },
tap: { scale: 0.98, y: 0 }
};
<motion.button
variants={buttonVariants}
initial="idle"
whileHover="hover"
whileTap="tap"
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
Click me
</motion.button>Related Skills: motion-framer, react-spring-physics, animejs
---
9. Scroll-Driven Storytelling
Definition: Content reveals, transforms, and tells a story as the user scrolls.
Techniques:
a) Pinned Sections with Scrubbing:
// Pin section while content scrubs through
gsap.to(".content", {
scrollTrigger: {
trigger: ".section",
start: "top top",
end: "+=3000", // 3000px of scroll
scrub: 1,
pin: true
},
opacity: 1,
scale: 1.2
});b) Horizontal Scroll Galleries:
- Card-based portfolios
- Timeline experiences
- Product showcases
c) Parallax Layers:
- Foreground, midground, background at different speeds
- 3D depth illusion
- Hero section parallax
d) Progress Indicators:
- Reading progress bars
- Section progress dots
- Animated SVG paths
Examples:
- Apple product pages (iPhone, MacBook)
- Stripe's annual reports
- Web agency showcases
Related Skills: gsap-scrolltrigger, locomotive-scroll
---
10. Cursor Effects & Custom Cursors
Trend: Custom cursors that enhance interaction and provide visual delight.
Patterns:
a) Dot Follower:
const cursor = { x: 0, y: 0 };
const follower = { x: 0, y: 0 };
document.addEventListener('mousemove', (e) => {
cursor.x = e.clientX;
cursor.y = e.clientY;
});
function updateCursor() {
// Smooth follow with easing
follower.x += (cursor.x - follower.x) * 0.1;
follower.y += (cursor.y - follower.y) * 0.1;
cursorDot.style.transform = `translate(${follower.x}px, ${follower.y}px)`;
requestAnimationFrame(updateCursor);
}b) Contextual Cursors:
- "View" on images
- "Drag" on sliders
- "Play" on videos
- Magnetic attraction to buttons
c) Blend Mode Cursors:
.cursor {
mix-blend-mode: difference;
/* Inverts colors underneath */
}Accessibility:
- Hide on touch devices
- Respect
prefers-reduced-motion - Don't hide native cursor completely (layer on top)
---
11. 3D Elements & WebGL
Status: Increasingly mainstream with improved performance and tooling.
Use Cases:
- Hero backgrounds (Vanta.js waves, particles)
- Product viewers (rotate, zoom, configure)
- Data visualization (3D charts, globes)
- Immersive experiences (games, virtual tours)
Performance-First Approach:
// Lazy load 3D content
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Load 3D scene
loadThreeJSScene();
observer.unobserve(entry.target);
}
});
});
observer.observe(document.querySelector('.3d-container'));Lightweight 3D Options:
- Vanta.js for backgrounds (uses Three.js)
- Zdog for flat-style 3D illustrations
- Spline for designer-friendly 3D
Full 3D Engines:
- Three.js for custom scenes
- React Three Fiber for React apps
- Babylon.js for physics and VR
Related Skills: threejs-webgl, react-three-fiber, lightweight-3d-effects
---
12. Voice & Conversational UI
Emerging Trend: Voice commands and conversational interfaces.
Patterns:
- Voice search integration
- Chatbot interfaces (natural language)
- Voice-controlled navigation
- Audio feedback for interactions
Implementation Considerations:
- Web Speech API for voice input
- Text-to-speech for feedback
- Fallback to text input
- Accessibility: don't require voice-only
---
Technical Trends
13. Performance-First Design
Core Web Vitals as Design Constraints:
LCP (Largest Contentful Paint) < 2.5s:
- Optimize hero images (WebP/AVIF)
- Inline critical CSS
- Preload key resources
- Avoid layout shifts
FID (First Input Delay) < 100ms:
- Defer non-critical JavaScript
- Split code bundles
- Use passive event listeners
- Minimize main thread work
CLS (Cumulative Layout Shift) < 0.1:
- Reserve space for images (aspect-ratio)
- Avoid inserting content above existing content
- Use CSS transforms, not position changes
Design Implications:
- Avoid web fonts that cause FOIT/FOUT
- Use system fonts for body text
- Lazy load below-fold content
- Progressive enhancement mindset
---
14. Component-Driven Design Systems
Approach: Design and build in reusable components.
Tools:
- Figma with variants and auto-layout
- Storybook for component documentation
- Design tokens (JSON format)
- Automated design-to-code (Figma plugins)
Component Architecture:
Design System/
├── Foundations/
│ ├── Colors (tokens)
│ ├── Typography (scales)
│ ├── Spacing (scales)
│ └── Shadows (elevation)
├── Components/
│ ├── Atoms (Button, Input, Icon)
│ ├── Molecules (SearchBar, Card)
│ ├── Organisms (Header, Footer)
│ └── Templates (PageLayout)
└── Patterns/
├── Navigation patterns
├── Form patterns
└── Animation patternsRelated Skills: animated-component-libraries
---
15. AI-Enhanced Design
Applications:
a) Content Generation:
- AI-written copy (with human editing)
- Image generation (Midjourney, DALL-E)
- Icon generation
- Design variations
b) Personalization:
- Dynamic layouts based on user behavior
- A/B testing with AI optimization
- Adaptive color schemes
- Content recommendations
c) Accessibility:
- AI-generated alt text
- Automatic color contrast adjustments
- Smart keyboard navigation
- Content simplification
Implementation:
- Edge functions for fast personalization
- Client-side ML models (TensorFlow.js)
- Privacy-preserving personalization
---
16. Progressive Web Apps (PWAs)
Status: Mainstream adoption, especially for mobile-first products.
Key Features:
- Offline functionality
- Install to home screen
- Push notifications
- Background sync
- Native-like performance
Design Considerations:
- Mobile-first responsive design
- Touch-friendly interactions (44px+ targets)
- Offline-first content strategy
- Loading states for sync
- Native-feeling animations
---
Color Trends
17. Color Palette Trends (2024-2025)
Trending Color Schemes:
a) High Contrast Duotone:
- Black + bright accent (electric blue, hot pink, lime green)
- Minimal, punchy, attention-grabbing
b) Muted Earth Tones:
- Terracotta, sage green, warm beige
- Natural, calming, sustainable aesthetic
c) Neon Gradients:
- Bright, saturated gradient meshes
- Cyberpunk aesthetic
- Gaming and tech brands
d) Monochromatic + Accent:
- Single hue with varying lightness
- One bold accent color
- Sophisticated, cohesive
Color Space Evolution:
/* OKLCH for perceptual uniformity */
:root {
--color-primary: oklch(60% 0.2 250);
/* 60% lightness, 0.2 chroma, 250° hue */
/* Benefits: */
/* - Perceptually uniform lightness */
/* - Wider color gamut than RGB */
/* - Easier to create accessible palettes */
}---
Typography Trends
18. Variable Fonts Mainstream
Adoption: Major sites now using variable fonts by default.
Popular Variable Fonts:
- Inter (UI text)
- Space Grotesk (headlines)
- Recursive (code & UI)
- Fraunces (display serif)
- Outfit (geometric sans)
Advantages:
- Single file, multiple weights/styles
- Animation possibilities
- Fine-grained control (weight: 347)
- Smaller file size than multiple weights
Implementation:
@font-face {
font-family: 'Inter';
src: url('Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap;
}
h1 {
font-family: 'Inter', sans-serif;
font-weight: 750; /* Any value 100-900 */
}---
19. Oversized Typography
Trend: Headlines at 100px-300px for desktop.
Fluid Typography System:
:root {
--font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
--font-size-lg: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
--font-size-xl: clamp(2rem, 1.5rem + 2.5vw, 4rem);
--font-size-2xl: clamp(3rem, 2rem + 5vw, 8rem);
--font-size-3xl: clamp(4rem, 2rem + 10vw, 12rem);
}
h1 {
font-size: var(--font-size-3xl);
line-height: 0.95;
letter-spacing: -0.03em;
}Design Considerations:
- Tight line-height (0.9-1.0)
- Negative letter-spacing (-0.02 to -0.04em)
- Strong font weight (700-900)
- Responsive scaling with clamp()
---
Layout Trends
20. Broken Grid Layouts
Definition: Intentionally breaking traditional grid systems for visual interest.
Techniques:
- Overlapping elements
- Off-grid positioning
- Diagonal layouts
- Negative space as design element
- Z-axis layering
CSS Grid + Subgrid:
.parent-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 2rem;
}
.child {
/* Subgrid inherits parent's columns */
display: grid;
grid-template-columns: subgrid;
grid-column: span 6;
}---
21. Single-Page Experiences
Trend: Entire site on one scrollable page.
Patterns:
- Section-based navigation (anchor links)
- Full-screen sections
- Scroll-driven reveals
- Smooth scrolling between sections
Benefits:
- Cohesive narrative flow
- No page load transitions
- Mobile-friendly (swipe to scroll)
- Performance (single bundle)
Challenges:
- SEO (use meaningful sections with h2-h6)
- Deep linking (use hash routing)
- Back button behavior
- Large bundle size
---
Emerging & Experimental
22. AI-Generated Visuals
Tools:
- Midjourney for illustrations
- DALL-E 3 for specific images
- Stable Diffusion for customization
Use Cases:
- Hero backgrounds
- Blog post headers
- Icon generation
- Abstract patterns
Ethical Considerations:
- Disclose AI-generated content
- Review for bias and appropriateness
- Ensure licensing rights
- Don't replace human designers for key visuals
---
23. Web3 Design Patterns
Characteristics:
- Wallet connection UIs
- NFT galleries
- Token-gated content
- Blockchain transaction states
- Decentralized identity
Design Challenges:
- Explaining complex concepts simply
- Transaction loading states (slow blockchains)
- Error handling (failed transactions)
- Gas fee transparency
---
24. Spatial Computing & 3D Interfaces
Future Trend: Preparing for AR/VR mainstream adoption.
Patterns:
- Depth-based layering
- 3D navigation
- Gesture controls
- Spatial audio cues
Implementation: WebXR API, A-Frame, Babylon.js
Related Skills: aframe-webxr, babylonjs-engine
---
Anti-Trends (What to Avoid)
Declining Patterns:
1. Carousels: Low engagement, poor accessibility 2. Auto-Playing Videos: Annoying, data-hungry 3. Hamburger Menus Only: Hide navigation 4. Stock Photos: Generic, unauthentic 5. Neumorphism: Accessibility issues 6. Long Scroll Animations: Frustrating on mobile 7. Overuse of Parallax: Motion sickness, poor performance 8. Chatbots as First Contact: Often unhelpful, annoying 9. Cookie Banners That Block Content: Poor UX 10. Infinite Scroll Without Pagination: SEO and UX issues
---
Resources & Inspiration
Award Sites:
- Awwwards.com (daily winners)
- CSS Design Awards
- The FWA
Trend Reports:
- Webflow's Annual Design Report
- Dribbble Year in Review
- Behance Featured Projects
Design Systems:
- Material Design 3 (Google)
- Fluent 2 (Microsoft)
- Polaris (Shopify)
- Carbon (IBM)
Tools:
- Figma (design)
- Webflow (visual development)
- Framer (design + code)
- Spline (3D design)
---
Forecasts (2025+)
Emerging Trends to Watch:
1. AI-Personalized Experiences: Every user sees a unique layout 2. Voice-First Interfaces: Beyond chatbots to full voice navigation 3. Spatial Web: 3D interfaces for AR/VR headsets 4. Sustainability Indicators: Carbon footprint of web experiences 5. Ethical Design Standards: Privacy, accessibility, inclusivity as default 6. Real-Time Collaboration: Multiplayer web experiences 7. Generative Art: Unique visuals for each visitor 8. Biometric Interfaces: Face/voice recognition for auth and personalization
Technology Shifts:
- WebGPU mainstream adoption (faster 3D)
- Container queries (component-based responsive design)
- View Transitions API (smooth SPA transitions)
- CSS Houdini (custom CSS magic)
---
Last updated: 2024 Review quarterly for updates
Micro-Interaction Patterns Catalog
Overview
Comprehensive catalog of micro-interactions for modern web interfaces. Each pattern includes implementation code, accessibility considerations, and performance notes.
Micro-interactions are small, purposeful animations that provide feedback, guide users, and enhance perceived performance.
---
Table of Contents
1. Button Interactions 2. Form & Input Interactions 3. Loading States 4. Navigation Interactions 5. Hover Effects 6. Toggle & Switch Interactions 7. Card Interactions 8. Scroll Interactions 9. Modal & Dialog Interactions 10. Toast & Notification Interactions
---
Button Interactions
1.1 Hover Lift
Effect: Button lifts up slightly on hover, creating depth.
Implementation (CSS):
.button-lift {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.button-lift:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.button-lift:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}Framer Motion:
<motion.button
whileHover={{ y: -2, boxShadow: "0 4px 12px rgba(0,0,0,0.15)" }}
whileTap={{ y: 0, boxShadow: "0 2px 4px rgba(0,0,0,0.1)" }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
Click me
</motion.button>Accessibility: Preserve for keyboard focus states.
---
1.2 Ripple Effect
Effect: Material Design-style ripple on click.
Implementation (JavaScript):
function createRipple(event) {
const button = event.currentTarget;
const ripple = document.createElement('span');
const rect = button.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = event.clientX - rect.left - size / 2;
const y = event.clientY - rect.top - size / 2;
ripple.style.width = ripple.style.height = `${size}px`;
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
ripple.classList.add('ripple');
button.appendChild(ripple);
setTimeout(() => ripple.remove(), 600);
}
document.querySelectorAll('.button-ripple').forEach(button => {
button.addEventListener('click', createRipple);
});CSS:
.button-ripple {
position: relative;
overflow: hidden;
}
.ripple {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
transform: scale(0);
animation: ripple-animation 0.6s ease-out;
}
@keyframes ripple-animation {
to {
transform: scale(4);
opacity: 0;
}
}Performance: Use will-change: transform sparingly.
---
1.3 Magnetic Button
Effect: Button magnetically attracts cursor on proximity.
Implementation (GSAP):
const button = document.querySelector('.magnetic-button');
const magneticStrength = 0.3;
button.addEventListener('mousemove', (e) => {
const rect = button.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const distanceX = (e.clientX - centerX) * magneticStrength;
const distanceY = (e.clientY - centerY) * magneticStrength;
gsap.to(button, {
x: distanceX,
y: distanceY,
duration: 0.3,
ease: "power2.out"
});
});
button.addEventListener('mouseleave', () => {
gsap.to(button, {
x: 0,
y: 0,
duration: 0.5,
ease: "elastic.out(1, 0.3)"
});
});Accessibility: Disable on mobile/touch devices.
---
1.4 Loading Button State
Effect: Button morphs into loading spinner.
Framer Motion:
function LoadingButton() {
const [isLoading, setIsLoading] = useState(false);
return (
<motion.button
onClick={() => setIsLoading(true)}
animate={isLoading ? "loading" : "idle"}
disabled={isLoading}
style={{ position: 'relative', overflow: 'hidden' }}
>
<motion.span
variants={{
idle: { opacity: 1 },
loading: { opacity: 0 }
}}
>
Submit
</motion.span>
<motion.div
className="spinner"
variants={{
idle: { opacity: 0, scale: 0 },
loading: { opacity: 1, scale: 1 }
}}
style={{ position: 'absolute', inset: 0 }}
>
<Spinner />
</motion.div>
</motion.button>
);
}Accessibility: Announce loading state to screen readers.
---
Form & Input Interactions
2.1 Floating Label
Effect: Label floats up when input is focused or filled.
Implementation:
.input-wrapper {
position: relative;
margin: 1rem 0;
}
.input-field {
width: 100%;
padding: 1rem;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
}
.input-field:focus {
outline: none;
border-color: #3b82f6;
}
.input-label {
position: absolute;
left: 1rem;
top: 1rem;
pointer-events: none;
transition: all 0.2s ease;
color: #666;
}
.input-field:focus + .input-label,
.input-field:not(:placeholder-shown) + .input-label {
top: -0.5rem;
left: 0.75rem;
font-size: 0.75rem;
background: white;
padding: 0 0.25rem;
color: #3b82f6;
}HTML:
<div class="input-wrapper">
<input
class="input-field"
type="text"
placeholder=" "
required
/>
<label class="input-label">Email address</label>
</div>---
2.2 Input Validation Feedback
Effect: Instant feedback on validation state.
React + Framer Motion:
function ValidatedInput({ label, validator }) {
const [value, setValue] = useState('');
const [isValid, setIsValid] = useState(null);
const handleChange = (e) => {
const newValue = e.target.value;
setValue(newValue);
setIsValid(validator(newValue));
};
return (
<div className="input-wrapper">
<motion.input
value={value}
onChange={handleChange}
animate={{
borderColor: isValid === null ? '#ccc' :
isValid ? '#10b981' : '#ef4444'
}}
transition={{ duration: 0.2 }}
/>
<AnimatePresence>
{isValid === true && (
<motion.div
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -10 }}
className="success-icon"
>
✓
</motion.div>
)}
{isValid === false && (
<motion.div
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -10 }}
className="error-icon"
>
✗
</motion.div>
)}
</AnimatePresence>
</div>
);
}Accessibility: Provide error messages, not just icons.
---
2.3 Password Strength Indicator
Effect: Visual indicator of password strength.
Implementation:
function PasswordStrengthIndicator({ password }) {
const strength = calculateStrength(password);
const variants = {
weak: { width: '33%', backgroundColor: '#ef4444' },
medium: { width: '66%', backgroundColor: '#f59e0b' },
strong: { width: '100%', backgroundColor: '#10b981' }
};
return (
<div className="strength-bar-container">
<motion.div
className="strength-bar"
variants={variants}
animate={strength}
transition={{ duration: 0.3 }}
/>
<p className="strength-label">
Password strength: <strong>{strength}</strong>
</p>
</div>
);
}
function calculateStrength(password) {
if (password.length < 6) return 'weak';
if (password.length < 10) return 'medium';
return 'strong';
}---
2.4 Character Count with Progress
Effect: Shows remaining characters with visual indicator.
Implementation:
function TextareaWithCount({ maxLength = 280 }) {
const [text, setText] = useState('');
const remaining = maxLength - text.length;
const percentage = (text.length / maxLength) * 100;
return (
<div>
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
maxLength={maxLength}
/>
<div className="count-indicator">
<motion.svg
width="40"
height="40"
style={{ transform: 'rotate(-90deg)' }}
>
<circle
cx="20"
cy="20"
r="16"
stroke="#e5e7eb"
strokeWidth="3"
fill="none"
/>
<motion.circle
cx="20"
cy="20"
r="16"
stroke={remaining < 20 ? '#ef4444' : '#3b82f6'}
strokeWidth="3"
fill="none"
strokeDasharray={`${2 * Math.PI * 16}`}
animate={{
strokeDashoffset: (1 - percentage / 100) * (2 * Math.PI * 16)
}}
/>
</motion.svg>
<span className="count-text">{remaining}</span>
</div>
</div>
);
}---
Loading States
3.1 Skeleton Screen
Effect: Content placeholder that mimics layout.
Implementation:
.skeleton {
background: linear-gradient(
90deg,
#f0f0f0 25%,
#e0e0e0 50%,
#f0f0f0 75%
);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: 4px;
}
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.skeleton-text {
height: 1rem;
margin-bottom: 0.5rem;
}
.skeleton-title {
height: 2rem;
width: 60%;
margin-bottom: 1rem;
}
.skeleton-image {
width: 100%;
aspect-ratio: 16 / 9;
}React Component:
function SkeletonCard() {
return (
<div className="card">
<div className="skeleton skeleton-image" />
<div className="skeleton skeleton-title" />
<div className="skeleton skeleton-text" />
<div className="skeleton skeleton-text" style={{ width: '80%' }} />
</div>
);
}---
3.2 Progress Bar
Effect: Linear progress indicator.
Framer Motion:
function ProgressBar({ progress }) {
return (
<div className="progress-container">
<motion.div
className="progress-bar"
initial={{ width: 0 }}
animate={{ width: `${progress}%` }}
transition={{ duration: 0.5, ease: "easeOut" }}
/>
</div>
);
}CSS:
.progress-container {
width: 100%;
height: 4px;
background: #e5e7eb;
border-radius: 9999px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
border-radius: 9999px;
}---
3.3 Spinner
Effect: Rotating loading indicator.
CSS:
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(59, 130, 246, 0.1);
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}Framer Motion (Advanced):
function Spinner() {
return (
<motion.div
className="spinner-container"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
>
<motion.div
className="spinner"
animate={{ rotate: 360 }}
transition={{
duration: 1,
repeat: Infinity,
ease: "linear"
}}
/>
</motion.div>
);
}---
Navigation Interactions
4.1 Hamburger Menu Animation
Effect: Hamburger transforms into X on click.
CSS:
.hamburger {
width: 30px;
height: 20px;
position: relative;
cursor: pointer;
}
.hamburger span {
display: block;
position: absolute;
height: 3px;
width: 100%;
background: #333;
border-radius: 3px;
transition: all 0.3s ease;
}
.hamburger span:nth-child(1) { top: 0; }
.hamburger span:nth-child(2) { top: 50%; transform: translateY(-50%); }
.hamburger span:nth-child(3) { bottom: 0; }
.hamburger.active span:nth-child(1) {
top: 50%;
transform: translateY(-50%) rotate(45deg);
}
.hamburger.active span:nth-child(2) {
opacity: 0;
}
.hamburger.active span:nth-child(3) {
bottom: 50%;
transform: translateY(50%) rotate(-45deg);
}---
4.2 Dropdown Menu Reveal
Effect: Dropdown slides down with stagger.
Framer Motion:
const menuVariants = {
closed: {
opacity: 0,
y: -20,
transition: { staggerChildren: 0.05, staggerDirection: -1 }
},
open: {
opacity: 1,
y: 0,
transition: { staggerChildren: 0.07, delayChildren: 0.1 }
}
};
const itemVariants = {
closed: { opacity: 0, x: -20 },
open: { opacity: 1, x: 0 }
};
function DropdownMenu({ isOpen }) {
return (
<AnimatePresence>
{isOpen && (
<motion.ul
className="dropdown"
variants={menuVariants}
initial="closed"
animate="open"
exit="closed"
>
{items.map((item) => (
<motion.li key={item} variants={itemVariants}>
{item}
</motion.li>
))}
</motion.ul>
)}
</AnimatePresence>
);
}---
4.3 Active Link Indicator
Effect: Animated underline follows active link.
Framer Motion:
function TabNavigation() {
const [activeTab, setActiveTab] = useState(0);
return (
<nav className="tabs">
{tabs.map((tab, index) => (
<button
key={tab}
onClick={() => setActiveTab(index)}
className={activeTab === index ? 'active' : ''}
>
{tab}
{activeTab === index && (
<motion.div
className="active-indicator"
layoutId="activeTab"
transition={{ type: "spring", stiffness: 300, damping: 30 }}
/>
)}
</button>
))}
</nav>
);
}CSS:
.tabs {
display: flex;
gap: 2rem;
border-bottom: 2px solid #e5e7eb;
}
.tabs button {
position: relative;
padding: 1rem 0;
background: none;
border: none;
cursor: pointer;
}
.active-indicator {
position: absolute;
bottom: -2px;
left: 0;
right: 0;
height: 2px;
background: #3b82f6;
}---
Hover Effects
5.1 Image Zoom on Hover
Effect: Image scales up slightly on hover.
CSS:
.image-container {
overflow: hidden;
border-radius: 8px;
}
.image-container img {
transition: transform 0.3s ease;
display: block;
width: 100%;
}
.image-container:hover img {
transform: scale(1.05);
}---
5.2 Tilt Effect
Effect: Card tilts based on mouse position.
Vanilla-Tilt:
VanillaTilt.init(document.querySelectorAll(".tilt-card"), {
max: 15,
speed: 400,
glare: true,
"max-glare": 0.3
});Manual Implementation:
const card = document.querySelector('.tilt-card');
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const rotateX = (y - centerY) / 10;
const rotateY = (centerX - x) / 10;
card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
});
card.addEventListener('mouseleave', () => {
card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0)';
});---
5.3 Reveal on Hover
Effect: Content reveals on hover with slide/fade.
CSS:
.card {
position: relative;
overflow: hidden;
}
.card-overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transform: translateY(100%);
transition: all 0.3s ease;
}
.card:hover .card-overlay {
opacity: 1;
transform: translateY(0);
}---
Toggle & Switch Interactions
6.1 Toggle Switch
Effect: Smooth toggle with spring animation.
Framer Motion:
function ToggleSwitch({ enabled, setEnabled }) {
return (
<motion.div
className="switch"
data-enabled={enabled}
onClick={() => setEnabled(!enabled)}
animate={{ backgroundColor: enabled ? '#3b82f6' : '#d1d5db' }}
>
<motion.div
className="switch-handle"
layout
transition={{ type: "spring", stiffness: 500, damping: 30 }}
style={{ justifyContent: enabled ? 'flex-end' : 'flex-start' }}
/>
</motion.div>
);
}CSS:
.switch {
width: 50px;
height: 28px;
border-radius: 14px;
padding: 4px;
cursor: pointer;
display: flex;
align-items: center;
}
.switch-handle {
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}---
Card Interactions
7.1 Card Expand
Effect: Card expands to full screen on click.
Framer Motion with `layout`:
function ExpandableCard() {
const [isExpanded, setIsExpanded] = useState(false);
return (
<motion.div
layout
className={isExpanded ? 'card-expanded' : 'card'}
onClick={() => setIsExpanded(!isExpanded)}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
>
<motion.h2 layout="position">Title</motion.h2>
<motion.p layout="position">Content</motion.p>
{isExpanded && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Additional content...
</motion.div>
)}
</motion.div>
);
}---
Scroll Interactions
8.1 Fade In on Scroll
Effect: Elements fade in as they enter viewport.
Framer Motion + `useInView`:
function FadeInSection({ children }) {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, amount: 0.3 });
return (
<motion.div
ref={ref}
initial={{ opacity: 0, y: 50 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6 }}
>
{children}
</motion.div>
);
}---
8.2 Scroll Progress Indicator
Effect: Shows reading progress.
Implementation:
function ScrollProgress() {
const [scrollProgress, setScrollProgress] = useState(0);
useEffect(() => {
const updateProgress = () => {
const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
const progress = (window.scrollY / scrollHeight) * 100;
setScrollProgress(progress);
};
window.addEventListener('scroll', updateProgress);
return () => window.removeEventListener('scroll', updateProgress);
}, []);
return (
<motion.div
className="progress-bar"
style={{ scaleX: scrollProgress / 100, transformOrigin: 'left' }}
/>
);
}---
Modal & Dialog Interactions
9.1 Modal Fade & Scale
Effect: Modal fades in and scales up.
Framer Motion:
function Modal({ isOpen, onClose, children }) {
return (
<AnimatePresence>
{isOpen && (
<>
<motion.div
className="modal-backdrop"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
/>
<motion.div
className="modal"
initial={{ opacity: 0, scale: 0.8, y: 50 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.8, y: 50 }}
transition={{ type: "spring", stiffness: 300, damping: 25 }}
>
{children}
</motion.div>
</>
)}
</AnimatePresence>
);
}Accessibility: Trap focus, close on Escape key, focus first element.
---
Toast & Notification Interactions
10.1 Toast Notification
Effect: Toast slides in from top/bottom with auto-dismiss.
Framer Motion:
function Toast({ message, type, onDismiss }) {
useEffect(() => {
const timer = setTimeout(onDismiss, 3000);
return () => clearTimeout(timer);
}, [onDismiss]);
return (
<motion.div
className={`toast toast-${type}`}
initial={{ opacity: 0, y: -50, scale: 0.8 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -50, scale: 0.8 }}
transition={{ type: "spring", stiffness: 400, damping: 25 }}
>
{message}
<button onClick={onDismiss}>×</button>
</motion.div>
);
}---
Accessibility Checklist
For all micro-interactions:
- [ ] Respect `prefers-reduced-motion`: Disable or simplify animations
- [ ] Keyboard accessible: All interactions work without mouse
- [ ] Focus indicators: Visible focus states
- [ ] Screen reader friendly: Announce state changes with
aria-live - [ ] Touch targets: Minimum 44x44px for mobile
- [ ] Escape key: Close modals/overlays
- [ ] Loading states: Indicate when actions are processing
- [ ] Error states: Clear error messages, not just visual indicators
---
Performance Checklist
- [ ] GPU-accelerated properties: Use
transformandopacityonly - [ ] Avoid layout thrash: Batch DOM reads/writes
- [ ] RequestAnimationFrame: For JavaScript animations
- [ ] Will-change sparingly: Only during active animations
- [ ] Debounce scroll/resize: Avoid excessive repaints
- [ ] Lazy load: Defer non-critical animations
- [ ] Test on low-end devices: Ensure 60 FPS
---
This catalog is a living document. Patterns are updated based on modern web standards and user research.
Web Performance Optimization Checklist
Overview
Comprehensive performance optimization guide targeting Core Web Vitals and 60 FPS experiences. This checklist covers measurement, optimization strategies, and modern best practices.
Performance Budget Targets:
- Largest Contentful Paint (LCP): < 2.5s
- First Input Delay (FID): < 100ms
- Cumulative Layout Shift (CLS): < 0.1
- Interaction to Next Paint (INP): < 200ms
- Time to Interactive (TTI): < 3.8s
- First Contentful Paint (FCP): < 1.8s
---
Table of Contents
1. Core Web Vitals 2. Animation Performance 3. Image Optimization 4. Font Loading 5. JavaScript Optimization 6. CSS Optimization 7. 3D & WebGL Optimization 8. Loading Strategies 9. Caching & CDN 10. Monitoring & Measurement
---
Core Web Vitals
Largest Contentful Paint (LCP)
Target: < 2.5 seconds
What it measures: Time until largest content element is visible.
Optimization Checklist:
- [ ] Optimize hero images (WebP/AVIF, < 100KB)
- [ ] Preload critical resources (
<link rel="preload">) - [ ] Eliminate render-blocking resources
- [ ] Use CDN for static assets
- [ ] Implement efficient server response time (< 200ms TTFB)
- [ ] Remove unused CSS/JS
- [ ] Enable compression (Brotli/gzip)
Implementation:
<!-- Preload critical resources -->
<link rel="preload" as="image" href="hero.webp" type="image/webp">
<link rel="preload" as="font" href="inter-var.woff2" type="font/woff2" crossorigin>
<!-- Modern image formats -->
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero" loading="eager" fetchpriority="high">
</picture>Debugging:
// Measure LCP
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.renderTime || lastEntry.loadTime);
}).observe({ entryTypes: ['largest-contentful-paint'] });---
First Input Delay (FID) / Interaction to Next Paint (INP)
Target: FID < 100ms, INP < 200ms
What it measures: Responsiveness to user interactions.
Optimization Checklist:
- [ ] Split long tasks (< 50ms each)
- [ ] Defer non-critical JavaScript
- [ ] Use web workers for heavy computation
- [ ] Implement code splitting
- [ ] Avoid long-running event handlers
- [ ] Debounce scroll/resize listeners
- [ ] Use passive event listeners
Implementation:
// Split long tasks
function yieldToMain() {
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
async function processLargeArray(array) {
for (let i = 0; i < array.length; i++) {
processItem(array[i]);
// Yield every 50 items
if (i % 50 === 0) {
await yieldToMain();
}
}
}
// Passive event listeners
window.addEventListener('scroll', handleScroll, { passive: true });
// Debounced resize handler
const debouncedResize = debounce(() => {
handleResize();
}, 150);
window.addEventListener('resize', debouncedResize);---
Cumulative Layout Shift (CLS)
Target: < 0.1
What it measures: Visual stability during page load.
Optimization Checklist:
- [ ] Reserve space for images (use
aspect-ratio) - [ ] Reserve space for ads and embeds
- [ ] Avoid inserting content above existing content
- [ ] Use CSS transforms instead of position changes
- [ ] Set explicit dimensions for iframes
- [ ] Avoid web fonts that cause FOUT/FOIT
- [ ] Use
font-display: swaporfont-display: optional
Implementation:
/* Reserve space for images */
img {
aspect-ratio: attr(width) / attr(height);
width: 100%;
height: auto;
}
/* Or explicit aspect ratio */
.hero-image {
aspect-ratio: 16 / 9;
}
/* Animations: use transform, not position */
.animated {
transform: translateX(0);
transition: transform 0.3s;
}
.animated.active {
transform: translateX(100px); /* Good */
/* left: 100px; Bad - causes layout shift */
}Debugging:
// Measure CLS
let clsValue = 0;
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
console.log('CLS:', clsValue);
}
}
}).observe({ entryTypes: ['layout-shift'] });---
Animation Performance
60 FPS Checklist
Target: < 16.67ms per frame
GPU-Accelerated Properties (Use These):
transform(translate, scale, rotate)opacityfilter(some, like blur - be careful)
Avoid Animating:
top,left,right,bottomwidth,heightmargin,paddingborder-width
Implementation:
/* Good: GPU-accelerated */
.animated {
transform: translateX(0);
opacity: 1;
transition: transform 0.3s, opacity 0.3s;
}
.animated.active {
transform: translateX(100px) scale(1.1);
opacity: 0.8;
}
/* Bad: triggers layout/paint */
.animated-bad {
left: 0;
width: 100px;
transition: left 0.3s, width 0.3s;
}Will-Change Optimization
Use Sparingly:
/* Only during animation */
.will-animate {
/* Don't set will-change here */
}
.will-animate.animating {
will-change: transform; /* Set on animation start */
}
.will-animate.done {
will-change: auto; /* Remove after animation */
}JavaScript Control:
element.addEventListener('mouseenter', () => {
element.style.willChange = 'transform';
});
element.addEventListener('mouseleave', () => {
// Remove after animation completes
element.addEventListener('transitionend', () => {
element.style.willChange = 'auto';
}, { once: true });
});RequestAnimationFrame
Always use for JavaScript animations:
// Good
function animate() {
element.style.transform = `translateX(${x}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
// Bad
setInterval(() => {
element.style.transform = `translateX(${x}px)`;
}, 16); // Not synced with browser paintPerformance Monitoring
Chrome DevTools:
// Mark start of expensive operation
performance.mark('animation-start');
// ... do animation work ...
// Mark end
performance.mark('animation-end');
// Measure duration
performance.measure('animation-duration', 'animation-start', 'animation-end');
// Get measurement
const measure = performance.getEntriesByName('animation-duration')[0];
console.log(`Animation took ${measure.duration}ms`);---
Image Optimization
Format Selection
Decision Tree: 1. Photos: AVIF > WebP > JPEG 2. Graphics/logos: SVG > WebP > PNG 3. Animations: WebP animated > GIF 4. Icons: SVG or icon fonts
Implementation:
<picture>
<!-- Modern browsers: AVIF (best compression) -->
<source srcset="image.avif" type="image/avif">
<!-- Fallback: WebP (good compression) -->
<source srcset="image.webp" type="image/webp">
<!-- Final fallback: JPEG -->
<img src="image.jpg" alt="Description" loading="lazy">
</picture>Responsive Images
Checklist:
- [ ] Use
srcsetfor multiple resolutions - [ ] Define
sizesattribute - [ ] Serve appropriately sized images (not full-res everywhere)
- [ ] Use lazy loading for below-fold images
- [ ] Set explicit dimensions to prevent CLS
Implementation:
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w,
image-1600.jpg 1600w
"
sizes="
(max-width: 640px) 100vw,
(max-width: 1024px) 50vw,
33vw
"
alt="Description"
loading="lazy"
width="1200"
height="800"
>Image Compression
Tools:
- CLI: ImageMagick, Sharp (Node.js)
- GUI: Squoosh (web), ImageOptim (Mac)
- Build tools: imagemin, @squoosh/lib
Example (Sharp):
const sharp = require('sharp');
await sharp('input.jpg')
.resize(1200, 800, { fit: 'cover' })
.webp({ quality: 80 })
.toFile('output.webp');
await sharp('input.jpg')
.resize(1200, 800, { fit: 'cover' })
.avif({ quality: 70 })
.toFile('output.avif');Lazy Loading
Native Lazy Loading:
<!-- Lazy load below-fold images -->
<img src="image.jpg" loading="lazy" alt="Description">
<!-- Eager load above-fold images -->
<img src="hero.jpg" loading="eager" fetchpriority="high" alt="Hero">Intersection Observer (Advanced):
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});---
Font Loading
Font Display Strategy
Options:
swap: Show fallback, swap when loaded (FOUT - Flash of Unstyled Text)optional: Use cached font if available, otherwise use fallbackfallback: Brief block, swap if fast, fallback if slow
Recommended:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-var.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap; /* Show fallback immediately */
}Font Subsetting
Reduce file size by including only needed characters:
Tools: pyftsubset (part of fonttools)
# Include only Latin characters
pyftsubset input.ttf \
--output-file=output.woff2 \
--flavor=woff2 \
--layout-features=* \
--unicodes=U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFDPreload Critical Fonts
<link
rel="preload"
as="font"
href="/fonts/inter-var.woff2"
type="font/woff2"
crossorigin
>System Font Stack
Performance-first approach:
body {
font-family:
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
sans-serif;
}---
JavaScript Optimization
Code Splitting
Route-based splitting:
// React Router
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Gallery = lazy(() => import('./pages/Gallery'));
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/gallery" element={<Gallery />} />
</Routes>
</Suspense>Component-based splitting:
// Load heavy components only when needed
const HeavyChart = lazy(() => import('./components/HeavyChart'));
function Dashboard() {
const [showChart, setShowChart] = useState(false);
return (
<div>
<button onClick={() => setShowChart(true)}>Show Chart</button>
{showChart && (
<Suspense fallback={<Skeleton />}>
<HeavyChart />
</Suspense>
)}
</div>
);
}Tree Shaking
Ensure tree shaking works:
// Good: Named imports
import { map, filter } from 'lodash-es';
// Bad: Default import (imports entire library)
import _ from 'lodash';Bundle Analysis
Webpack Bundle Analyzer:
npm install --save-dev webpack-bundle-analyzer
# Add to webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [
new BundleAnalyzerPlugin()
]Vite:
npm install --save-dev rollup-plugin-visualizer
# vite.config.js
import { visualizer } from 'rollup-plugin-visualizer';
export default {
plugins: [visualizer({ open: true })]
}---
CSS Optimization
Critical CSS
Inline above-the-fold CSS:
<style>
/* Critical CSS inlined */
body { font-family: sans-serif; }
.hero { height: 100vh; }
</style>
<!-- Defer non-critical CSS -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>Tools:
- Critical (npm package)
- Critters (Vite/Webpack plugin)
Remove Unused CSS
PurgeCSS:
// postcss.config.js
module.exports = {
plugins: [
require('@fullhuman/postcss-purgecss')({
content: ['./src/**/*.html', './src/**/*.jsx'],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
})
]
}CSS Containment
Improve rendering performance:
.card {
/* Isolate layout calculations */
contain: layout style paint;
}
.article {
/* More aggressive containment */
contain: strict;
}---
3D & WebGL Optimization
Loading Strategy
Checklist:
- [ ] Show placeholder while loading
- [ ] Load 3D content below fold lazily
- [ ] Use low-poly models initially
- [ ] Progressive enhancement with high-poly
Implementation:
// Lazy load Three.js scene
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadThreeJSScene();
observer.unobserve(entry.target);
}
});
});
observer.observe(document.querySelector('.3d-container'));Runtime Performance
Checklist:
- [ ] Implement object pooling (reuse objects)
- [ ] Use LOD (Level of Detail)
- [ ] Frustum culling (don't render off-screen objects)
- [ ] Texture compression (Basis Universal, KTX2)
- [ ] Reduce polygon count (< 100k for real-time)
- [ ] Limit draw calls (< 100 per frame)
- [ ] Use instancing for repeated geometry
Three.js Example:
// Object pooling
const objectPool = [];
function getObject() {
return objectPool.length > 0 ? objectPool.pop() : createNewObject();
}
function releaseObject(obj) {
objectPool.push(obj);
}
// LOD (Level of Detail)
const lod = new THREE.LOD();
lod.addLevel(highPolyMesh, 0); // 0-50m
lod.addLevel(mediumPolyMesh, 50); // 50-100m
lod.addLevel(lowPolyMesh, 100); // 100m+
scene.add(lod);
// Instancing
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial();
const count = 10000;
const mesh = new THREE.InstancedMesh(geometry, material, count);
scene.add(mesh);Texture Optimization
Checklist:
- [ ] Use power-of-two dimensions (512, 1024, 2048)
- [ ] Compress textures (Basis, KTX2)
- [ ] Use texture atlases
- [ ] Reduce texture resolution (don't use 4K everywhere)
- [ ] Enable mipmaps
---
Loading Strategies
Critical Rendering Path
Optimize the order:
1. HTML (initial) 2. Critical CSS (inlined) 3. Critical JavaScript (defer rest) 4. Fonts (preload, font-display: swap) 5. Images (lazy load below-fold)
Implementation:
<!DOCTYPE html>
<html>
<head>
<!-- Critical CSS inlined -->
<style>/* Critical styles */</style>
<!-- Preload critical resources -->
<link rel="preload" as="font" href="font.woff2" type="font/woff2" crossorigin>
<link rel="preload" as="image" href="hero.webp">
<!-- Defer non-critical CSS -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<!-- Defer JavaScript -->
<script defer src="main.js"></script>
</head>
<body>
<!-- Content -->
</body>
</html>Resource Hints
Preconnect (DNS, TCP, TLS):
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com">DNS-Prefetch:
<link rel="dns-prefetch" href="https://analytics.example.com">Prefetch (next page):
<link rel="prefetch" href="/next-page.html">---
Caching & CDN
HTTP Caching Headers
Static Assets (immutable):
Cache-Control: public, max-age=31536000, immutableHTML (revalidate):
Cache-Control: no-cacheAPI Responses:
Cache-Control: public, max-age=3600, must-revalidateService Worker Caching
Workbox:
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst } from 'workbox-strategies';
// Precache build assets
precacheAndRoute(self.__WB_MANIFEST);
// Cache images
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({ cacheName: 'images' })
);
// Network-first for HTML
registerRoute(
({ request }) => request.mode === 'navigate',
new NetworkFirst({ cacheName: 'pages' })
);---
Monitoring & Measurement
Real User Monitoring (RUM)
Web Vitals:
npm install web-vitalsimport { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics({ name, value, id }) {
// Send to your analytics endpoint
fetch('/analytics', {
method: 'POST',
body: JSON.stringify({ name, value, id })
});
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);Performance Budget
Lighthouse CI:
// lighthouserc.json
{
"ci": {
"collect": {
"numberOfRuns": 3
},
"assert": {
"assertions": {
"first-contentful-paint": ["error", {"maxNumericValue": 1800}],
"largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
"total-blocking-time": ["error", {"maxNumericValue": 200}]
}
}
}
}Chrome DevTools
Performance Panel: 1. Open DevTools (F12) 2. Performance tab 3. Click Record 4. Interact with page 5. Stop recording 6. Analyze flame chart
Look for:
- Long tasks (> 50ms)
- Excessive layout thrashing
- Forced synchronous layouts
- Paint flashing
---
Quick Wins Checklist
Immediate Impact:
- [ ] Enable Brotli/gzip compression
- [ ] Implement lazy loading for images
- [ ] Add
widthandheightto images (prevent CLS) - [ ] Use modern image formats (WebP/AVIF)
- [ ] Preload critical resources
- [ ] Defer non-critical JavaScript
- [ ] Use CDN for static assets
- [ ] Enable HTTP/2 or HTTP/3
- [ ] Minify CSS and JavaScript
- [ ] Remove unused CSS/JS
High Impact:
- [ ] Implement code splitting
- [ ] Optimize images (< 100KB)
- [ ] Use system fonts or preload web fonts
- [ ] Inline critical CSS
- [ ] Implement service worker caching
- [ ] Optimize animation performance (use transforms)
- [ ] Reduce JavaScript bundle size (< 200KB)
- [ ] Set up performance monitoring
---
Last updated: 2024 Benchmarks based on median 4G mobile connections
#!/usr/bin/env python3
"""
Modern Web Design Auditor
Audits HTML/CSS code for:
- Accessibility compliance (WCAG)
- Performance best practices
- Modern design pattern usage
- SEO basics
Usage:
./design_audit.py # Interactive mode
./design_audit.py --file index.html # Audit specific file
./design_audit.py --file index.html --report audit.txt # Save report
"""
import sys
import argparse
import re
from pathlib import Path
from collections import defaultdict
class DesignAuditor:
"""Audits web design code for best practices."""
def __init__(self, html_content):
self.html = html_content
self.issues = defaultdict(list)
self.warnings = defaultdict(list)
self.passes = defaultdict(list)
def audit(self):
"""Run all audits."""
self.audit_accessibility()
self.audit_performance()
self.audit_seo()
self.audit_responsive()
self.audit_modern_practices()
def audit_accessibility(self):
"""Audit for accessibility issues."""
category = 'Accessibility'
# Check for alt attributes on images
imgs_without_alt = re.findall(r'<img(?![^>]*alt=)[^>]*>', self.html, re.IGNORECASE)
if imgs_without_alt:
self.issues[category].append(
f"Found {len(imgs_without_alt)} images without alt attributes"
)
else:
self.passes[category].append("All images have alt attributes")
# Check for lang attribute
if not re.search(r'<html[^>]+lang=', self.html, re.IGNORECASE):
self.issues[category].append("Missing lang attribute on <html> element")
else:
self.passes[category].append("HTML lang attribute present")
# Check for semantic HTML
if '<div class="header"' in self.html or '<div id="header"' in self.html:
self.warnings[category].append("Consider using <header> instead of div with class/id 'header'")
if '<div class="nav"' in self.html or '<div id="nav"' in self.html:
self.warnings[category].append("Consider using <nav> instead of div with class/id 'nav'")
if '<div class="footer"' in self.html or '<div id="footer"' in self.html:
self.warnings[category].append("Consider using <footer> instead of div with class/id 'footer'")
# Check for proper heading hierarchy
h1_count = len(re.findall(r'<h1[^>]*>', self.html, re.IGNORECASE))
if h1_count == 0:
self.issues[category].append("No <h1> element found")
elif h1_count > 1:
self.warnings[category].append(f"Multiple <h1> elements found ({h1_count}). Consider using only one per page")
# Check for aria-labels on icon buttons
button_pattern = r'<button[^>]*>[\s]*<(?:svg|i|span)[^>]*>[\s]*</(?:svg|i|span)>[\s]*</button>'
icon_buttons = re.findall(button_pattern, self.html, re.IGNORECASE)
for button in icon_buttons:
if 'aria-label' not in button:
self.warnings[category].append("Icon button found without aria-label")
break
# Check for form labels
inputs = re.findall(r'<input[^>]*>', self.html, re.IGNORECASE)
for input_tag in inputs:
if 'id=' in input_tag:
input_id = re.search(r'id="([^"]+)"', input_tag)
if input_id:
label_pattern = f'for="{input_id.group(1)}"'
if label_pattern not in self.html:
self.warnings[category].append(f"Input with id='{input_id.group(1)}' has no associated label")
# Check for skip links
if not re.search(r'skip to (main |)content', self.html, re.IGNORECASE):
self.warnings[category].append("Consider adding a skip link for keyboard navigation")
def audit_performance(self):
"""Audit for performance issues."""
category = 'Performance'
# Check for inline styles (should be minimal)
inline_styles = re.findall(r'style="[^"]*"', self.html)
if len(inline_styles) > 10:
self.warnings[category].append(
f"Found {len(inline_styles)} inline styles. Consider moving to external CSS."
)
# Check for lazy loading
imgs = re.findall(r'<img[^>]*>', self.html, re.IGNORECASE)
lazy_imgs = [img for img in imgs if 'loading="lazy"' in img or "loading='lazy'" in img]
if imgs and not lazy_imgs:
self.warnings[category].append(
"Consider adding loading='lazy' to below-fold images"
)
# Check for modern image formats
if re.search(r'<img[^>]+src="[^"]+\.(jpg|jpeg|png)"', self.html, re.IGNORECASE):
if not re.search(r'<picture>|<source[^>]+type="image/webp"', self.html, re.IGNORECASE):
self.warnings[category].append(
"Consider using modern image formats (WebP/AVIF) with <picture> element"
)
# Check for preload/prefetch
if re.search(r'<link[^>]+rel="preload"', self.html, re.IGNORECASE):
self.passes[category].append("Using preload for critical resources")
# Check for async/defer on scripts
scripts = re.findall(r'<script[^>]*src="[^"]*"[^>]*>', self.html, re.IGNORECASE)
scripts_without_async_defer = [s for s in scripts if 'async' not in s and 'defer' not in s]
if scripts_without_async_defer:
self.warnings[category].append(
f"Found {len(scripts_without_async_defer)} script tags without async or defer attributes"
)
# Check for width/height on images (prevents CLS)
imgs_without_dimensions = [
img for img in imgs
if not ('width=' in img and 'height=' in img)
and 'aspect-ratio' not in self.html
]
if imgs_without_dimensions:
self.warnings[category].append(
f"Found {len(imgs_without_dimensions)} images without explicit dimensions (width/height). This can cause Cumulative Layout Shift."
)
def audit_seo(self):
"""Audit for SEO basics."""
category = 'SEO'
# Check for title tag
if not re.search(r'<title>[^<]+</title>', self.html, re.IGNORECASE):
self.issues[category].append("Missing <title> tag")
else:
title = re.search(r'<title>([^<]+)</title>', self.html, re.IGNORECASE)
if title and len(title.group(1)) < 10:
self.warnings[category].append("Title tag is too short (< 10 characters)")
else:
self.passes[category].append("Title tag present and sufficient length")
# Check for meta description
if not re.search(r'<meta[^>]+name="description"', self.html, re.IGNORECASE):
self.warnings[category].append("Missing meta description tag")
else:
self.passes[category].append("Meta description present")
# Check for viewport meta tag
if not re.search(r'<meta[^>]+name="viewport"', self.html, re.IGNORECASE):
self.issues[category].append("Missing viewport meta tag (required for mobile)")
else:
self.passes[category].append("Viewport meta tag present")
# Check for charset
if not re.search(r'<meta[^>]+charset=', self.html, re.IGNORECASE):
self.warnings[category].append("Missing charset declaration")
else:
self.passes[category].append("Charset declaration present")
def audit_responsive(self):
"""Audit for responsive design."""
category = 'Responsive Design'
# Check for viewport meta tag
if re.search(r'<meta[^>]+name="viewport"', self.html, re.IGNORECASE):
self.passes[category].append("Viewport meta tag present")
else:
self.issues[category].append("Missing viewport meta tag")
# Check for media queries in CSS
if re.search(r'@media[^{]+{', self.html, re.IGNORECASE):
self.passes[category].append("Media queries found (responsive CSS)")
else:
self.warnings[category].append("No media queries found. Consider adding responsive styles.")
# Check for clamp() or min/max functions (modern responsive approach)
if re.search(r'clamp\(|min\(|max\(', self.html, re.IGNORECASE):
self.passes[category].append("Using modern CSS functions (clamp/min/max) for fluid sizing")
def audit_modern_practices(self):
"""Audit for modern design practices."""
category = 'Modern Practices'
# Check for CSS custom properties
if re.search(r'--[a-z-]+:', self.html, re.IGNORECASE):
self.passes[category].append("Using CSS custom properties (variables)")
# Check for CSS Grid or Flexbox
if re.search(r'display:\s*(grid|flex)', self.html, re.IGNORECASE):
self.passes[category].append("Using modern layout (Grid or Flexbox)")
# Check for prefers-reduced-motion
if re.search(r'prefers-reduced-motion', self.html, re.IGNORECASE):
self.passes[category].append("Respecting prefers-reduced-motion preference")
else:
if re.search(r'animation:|transition:', self.html, re.IGNORECASE):
self.warnings[category].append(
"Animations found but no @media (prefers-reduced-motion) rule detected"
)
# Check for semantic HTML5 elements
semantic_elements = ['header', 'nav', 'main', 'article', 'section', 'aside', 'footer']
found_semantic = [el for el in semantic_elements if f'<{el}' in self.html.lower()]
if found_semantic:
self.passes[category].append(f"Using semantic HTML5 elements: {', '.join(found_semantic)}")
else:
self.warnings[category].append("No semantic HTML5 elements found. Consider using <header>, <nav>, <main>, etc.")
# Check for focus-visible
if ':focus-visible' in self.html:
self.passes[category].append("Using :focus-visible for keyboard navigation")
elif ':focus' in self.html:
self.passes[category].append("Using :focus styles (consider upgrading to :focus-visible)")
def generate_report(self):
"""Generate audit report."""
report = []
report.append("=" * 70)
report.append("Modern Web Design Audit Report")
report.append("=" * 70)
report.append("")
# Summary
total_issues = sum(len(v) for v in self.issues.values())
total_warnings = sum(len(v) for v in self.warnings.values())
total_passes = sum(len(v) for v in self.passes.values())
report.append("SUMMARY")
report.append("-" * 70)
report.append(f"❌ Issues: {total_issues}")
report.append(f"⚠️ Warnings: {total_warnings}")
report.append(f"✅ Passes: {total_passes}")
report.append("")
# Score calculation
score = (total_passes / (total_passes + total_warnings + total_issues)) * 100 if (total_passes + total_warnings + total_issues) > 0 else 0
report.append(f"Overall Score: {score:.1f}/100")
report.append("")
# Detailed results
categories = set(list(self.issues.keys()) + list(self.warnings.keys()) + list(self.passes.keys()))
for category in sorted(categories):
report.append(f"\n{category}")
report.append("-" * 70)
if category in self.issues:
report.append("\n❌ ISSUES (must fix):")
for issue in self.issues[category]:
report.append(f" • {issue}")
if category in self.warnings:
report.append("\n⚠️ WARNINGS (should fix):")
for warning in self.warnings[category]:
report.append(f" • {warning}")
if category in self.passes:
report.append("\n✅ PASSES:")
for passing in self.passes[category]:
report.append(f" • {passing}")
report.append("")
# Recommendations
report.append("\nRECOMMENDATIONS")
report.append("-" * 70)
if total_issues > 0:
report.append("1. Address all ISSUES first (accessibility and critical SEO)")
if total_warnings > 5:
report.append("2. Review WARNINGS and implement fixes where applicable")
if score < 70:
report.append("3. Consider a comprehensive design review")
else:
report.append("Good job! Your design follows many modern best practices.")
report.append("")
report.append("=" * 70)
return "\n".join(report)
def audit_file(filepath, output_file=None):
"""Audit a specific file."""
path = Path(filepath)
if not path.exists():
print(f"Error: File '{filepath}' not found.")
sys.exit(1)
if not path.suffix in ['.html', '.htm']:
print(f"Warning: File '{filepath}' is not an HTML file.")
print(f"Auditing: {path}")
print("Please wait...\n")
html_content = path.read_text()
auditor = DesignAuditor(html_content)
auditor.audit()
report = auditor.generate_report()
if output_file:
output_path = Path(output_file)
output_path.write_text(report)
print(f"✅ Audit complete!")
print(f" Report saved to: {output_path}")
else:
print(report)
def interactive_mode():
"""Interactive audit mode."""
print("\n" + "="*70)
print("Modern Web Design Auditor")
print("="*70)
print("\nThis tool audits HTML files for:")
print(" • Accessibility (WCAG compliance)")
print(" • Performance best practices")
print(" • SEO basics")
print(" • Responsive design")
print(" • Modern CSS/HTML practices")
print("")
filepath = input("Enter path to HTML file: ").strip()
if not filepath:
print("Error: No file path provided.")
sys.exit(1)
save_report = input("\nSave report to file? (y/n): ").strip().lower()
if save_report == 'y':
output_file = input("Enter output filename (e.g., audit-report.txt): ").strip()
if not output_file:
output_file = "audit-report.txt"
audit_file(filepath, output_file)
else:
audit_file(filepath)
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(
description='Audit web design code for best practices'
)
parser.add_argument(
'--file',
type=str,
help='HTML file to audit'
)
parser.add_argument(
'--report',
type=str,
help='Output file for audit report'
)
args = parser.parse_args()
if args.file:
audit_file(args.file, args.report)
else:
interactive_mode()
if __name__ == '__main__':
main()
Related skills
How it compares
Use modern-web-design for trend and UX direction, then pair with gsap-react or framework-specific skills for concrete animation code.
FAQ
What does modern-web-design do?
Modern web design trends, principles, and implementation patterns for 2024-2025. Use this skill when designing websites, creating interactive experiences, implementing design systems, ensuring accessi
When should I use modern-web-design?
During build integrations work for generative media.
Is modern-web-design safe to install?
Review the Security Audits panel on this listing before production use.