State of CSS is an annual survey of the web developer community that maps trends, preferences, and development directions of CSS. It is an indispensable source of information about where web styling technology is heading.
CSS is constantly evolving, introducing increasingly advanced capabilities:
1/* Container Queries - container-based responsiveness */
2@container sidebar (min-width: 250px) {
3 .card {
4 display: flex;
5 flex-direction: row;
6 }
7}
8
9/* CSS Nesting - nesting in native CSS */
10.card {
11 background: white;
12 border-radius: 8px;
13
14 &:hover {
15 background: #f8f9fa;
16 }
17
18 .title {
19 font-size: 1.2rem;
20 font-weight: bold;
21
22 &.highlight {
23 color: #007bff;
24 }
25 }
26}
27
28/* CSS Cascade Layers - cascade control */
29@layer reset, base, theme, components, utilities;
30
31@layer reset {
32 * { margin: 0; padding: 0; }
33}
34
35@layer theme {
36 :root {
37 --primary: #007bff;
38 --secondary: #6c757d;
39 }
40}
41
42/* Subgrid - grid inheritance */
43.main-grid {
44 display: grid;
45 grid-template-columns: repeat(4, 1fr);
46 gap: 20px;
47}
48
49.card {
50 display: grid;
51 grid-template-rows: subgrid;
52 grid-row: span 3;
53}CSS Houdini allows developers to access the CSS Object Model:
1// Registering a custom property
2CSS.registerProperty({
3 name: '--gradient-angle',
4 syntax: '<angle>',
5 inherits: false,
6 initialValue: '0deg'
7});
8
9// Paint Worklet - custom drawing
10class CircleGradient {
11 paint(ctx, size, properties) {
12 const gradient = ctx.createRadialGradient(
13 size.width / 2, size.height / 2, 0,
14 size.width / 2, size.height / 2, size.width / 2
15 );
16
17 gradient.addColorStop(0, properties.get('--start-color'));
18 gradient.addColorStop(1, properties.get('--end-color'));
19
20 ctx.fillStyle = gradient;
21 ctx.fillRect(0, 0, size.width, size.height);
22 }
23}
24
25registerPaint('circle-gradient', CircleGradient);1/* Using Paint Worklet */
2.custom-background {
3 --start-color: #667eea;
4 --end-color: #764ba2;
5 background: paint(circle-gradient);
6}According to State of CSS research, the most popular new features are:
1const cssFeatureUsage = {
2 flexbox: {
3 usage: "94%",
4 satisfaction: "92%",
5 interest: "65%"
6 },
7 grid: {
8 usage: "89%",
9 satisfaction: "94%",
10 interest: "71%"
11 },
12 customProperties: {
13 usage: "87%",
14 satisfaction: "89%",
15 interest: "68%"
16 },
17 containerQueries: {
18 usage: "23%",
19 satisfaction: "91%",
20 interest: "89%"
21 },
22 cssNesting: {
23 usage: "31%",
24 satisfaction: "87%",
25 interest: "84%"
26 },
27 cascadeLayers: {
28 usage: "8%",
29 satisfaction: "73%",
30 interest: "76%"
31 }
32};
33
34// Growth trends
35const emergingFeatures = [
36 'Container Queries',
37 'CSS Nesting',
38 'Cascade Layers',
39 'CSS Subgrid',
40 'CSS Scroll-Driven Animations',
41 'View Transitions API'
42];1const cssFrameworksRanking = {
2 // Utility-first frameworks
3 tailwind: {
4 usage: "78%",
5 satisfaction: "84%",
6 retention: "87%",
7 trend: "rising"
8 },
9
10 // Component frameworks
11 bootstrap: {
12 usage: "45%",
13 satisfaction: "43%",
14 retention: "38%",
15 trend: "declining"
16 },
17
18 materialUI: {
19 usage: "32%",
20 satisfaction: "67%",
21 retention: "62%",
22 trend: "stable"
23 },
24
25 // CSS-in-JS solutions
26 styledComponents: {
27 usage: "41%",
28 satisfaction: "71%",
29 retention: "68%",
30 trend: "stable"
31 },
32
33 emotion: {
34 usage: "23%",
35 satisfaction: "73%",
36 retention: "69%",
37 trend: "stable"
38 }
39};1/* Positioning relative to an anchor */
2.anchor {
3 anchor-name: --my-anchor;
4}
5
6.positioned {
7 position: absolute;
8 position-anchor: --my-anchor;
9 top: anchor(bottom);
10 left: anchor(center);
11 margin-top: 10px;
12}
13
14/* Anchor queries - anchor-based responsiveness */
15@position-try --fallback {
16 top: anchor(top);
17 bottom: auto;
18 margin-top: -10px;
19}
20
21.positioned {
22 position-try-options: --fallback;
23}1/* Animations between views */
2::view-transition-old(root) {
3 animation: slide-out 0.3s ease-out;
4}
5
6::view-transition-new(root) {
7 animation: slide-in 0.3s ease-in;
8}
9
10@keyframes slide-out {
11 from { transform: translateX(0); }
12 to { transform: translateX(-100%); }
13}
14
15@keyframes slide-in {
16 from { transform: translateX(100%); }
17 to { transform: translateX(0); }
18}
19
20/* Named view transitions */
21.card {
22 view-transition-name: card-transition;
23}1// JavaScript API for View Transitions
2function navigateToPage(url) {
3 if (document.startViewTransition) {
4 document.startViewTransition(() => {
5 // Navigation logic
6 window.location.href = url;
7 });
8 } else {
9 // Fallback for browsers without support
10 window.location.href = url;
11 }
12}
13
14// Programmatic view transitions
15function updateContent(newContent) {
16 if (document.startViewTransition) {
17 document.startViewTransition(() => {
18 document.querySelector('.content').innerHTML = newContent;
19 });
20 } else {
21 document.querySelector('.content').innerHTML = newContent;
22 }
23}1/* Scroll-based animations */
2@keyframes reveal {
3 from {
4 opacity: 0;
5 transform: translateY(50px);
6 }
7 to {
8 opacity: 1;
9 transform: translateY(0);
10 }
11}
12
13.scroll-reveal {
14 animation: reveal linear;
15 animation-timeline: view();
16 animation-range: entry 25% cover 50%;
17}
18
19/* Progress bar based on scroll */
20.progress-bar {
21 animation: progress-bar linear;
22 animation-timeline: scroll(root);
23}
24
25@keyframes progress-bar {
26 from { width: 0%; }
27 to { width: 100%; }
28}
29
30/* Parallax effect with scroll timeline */
31.parallax-bg {
32 animation: parallax linear;
33 animation-timeline: scroll(nearest);
34 animation-range: exit -100% entry 100%;
35}
36
37@keyframes parallax {
38 from { transform: translateY(-50%); }
39 to { transform: translateY(50%); }
40}1/* New color functions */
2.advanced-colors {
3 /* Relative color syntax */
4 --primary: #007bff;
5 --primary-light: color(from var(--primary) srgb r g b / 0.5);
6 --primary-dark: color(from var(--primary) srgb calc(r * 0.8) calc(g * 0.8) calc(b * 0.8));
7
8 /* Color mixing */
9 --mixed-color: color-mix(in srgb, var(--primary) 70%, white);
10
11 /* Contrast color function */
12 --text-color: contrast-color(var(--primary));
13
14 /* Wide gamut colors */
15 --vibrant-red: color(display-p3 1 0.2 0.3);
16 --rec2020-green: color(rec2020 0.4 0.9 0.1);
17}
18
19/* Light-dark function */
20.theme-aware {
21 background: light-dark(white, #1a1a1a);
22 color: light-dark(#333, white);
23}1/* Utility-first approach (Tailwind style) */
2.btn-primary {
3 @apply inline-flex items-center px-4 py-2
4 bg-blue-600 border border-transparent
5 rounded-md font-semibold text-xs text-white
6 uppercase tracking-widest hover:bg-blue-700
7 focus:bg-blue-700 active:bg-blue-900
8 focus:outline-none focus:ring-2 focus:ring-indigo-500
9 focus:ring-offset-2 transition ease-in-out duration-150;
10}
11
12/* Component-first approach */
13.button {
14 --button-bg: var(--color-primary);
15 --button-text: var(--color-white);
16 --button-border: var(--color-primary);
17 --button-hover-bg: var(--color-primary-dark);
18
19 display: inline-flex;
20 align-items: center;
21 padding: 0.5rem 1rem;
22 background: var(--button-bg);
23 color: var(--button-text);
24 border: 1px solid var(--button-border);
25 border-radius: 0.375rem;
26 font-weight: 600;
27 font-size: 0.75rem;
28 text-transform: uppercase;
29 letter-spacing: 0.05em;
30 transition: all 0.15s ease-in-out;
31
32 &:hover {
33 background: var(--button-hover-bg);
34 }
35
36 &:focus {
37 outline: none;
38 ring: 2px solid var(--color-primary);
39 ring-offset: 2px;
40 }
41
42 &.secondary {
43 --button-bg: var(--color-secondary);
44 --button-border: var(--color-secondary);
45 --button-hover-bg: var(--color-secondary-dark);
46 }
47}1/* CUBE CSS methodology */
2/* Composition */
3.stack {
4 display: flex;
5 flex-direction: column;
6 gap: var(--space, 1rem);
7}
8
9.cluster {
10 display: flex;
11 flex-wrap: wrap;
12 gap: var(--space, 1rem);
13 align-items: var(--align, flex-start);
14 justify-content: var(--justify, flex-start);
15}
16
17/* Utilities */
18.visually-hidden {
19 position: absolute !important;
20 width: 1px !important;
21 height: 1px !important;
22 padding: 0 !important;
23 margin: -1px !important;
24 overflow: hidden !important;
25 clip: rect(0, 0, 0, 0) !important;
26 white-space: nowrap !important;
27 border: 0 !important;
28}
29
30.flow > * + * {
31 margin-top: var(--flow-space, 1em);
32}
33
34/* Block */
35.card {
36 background: var(--surface);
37 border-radius: var(--radius);
38 padding: var(--space-m);
39 box-shadow: var(--shadow);
40}
41
42/* Exception */
43.card[data-variant="ghost"] {
44 background: transparent;
45 box-shadow: none;
46 border: 1px solid var(--border);
47}1const buildToolsUsage = {
2 // CSS Processors
3 sass: {
4 usage: "71%",
5 satisfaction: "79%",
6 retention: "74%"
7 },
8 less: {
9 usage: "23%",
10 satisfaction: "61%",
11 retention: "45%"
12 },
13 stylus: {
14 usage: "8%",
15 satisfaction: "68%",
16 retention: "52%"
17 },
18
19 // PostCSS plugins
20 autoprefixer: {
21 usage: "84%",
22 satisfaction: "87%",
23 retention: "89%"
24 },
25 purgecss: {
26 usage: "45%",
27 satisfaction: "82%",
28 retention: "78%"
29 },
30 cssnano: {
31 usage: "52%",
32 satisfaction: "79%",
33 retention: "76%"
34 },
35
36 // Bundlers
37 webpack: {
38 usage: "68%",
39 satisfaction: "65%",
40 retention: "58%"
41 },
42 vite: {
43 usage: "67%",
44 satisfaction: "91%",
45 retention: "89%"
46 },
47 parcel: {
48 usage: "23%",
49 satisfaction: "78%",
50 retention: "71%"
51 }
52};1// Styled components approach
2const Button = styled.button`
3 background: ${props => props.primary ? '#007bff' : '#6c757d'};
4 color: white;
5 padding: 0.5rem 1rem;
6 border: none;
7 border-radius: 0.25rem;
8 cursor: pointer;
9
10 &:hover {
11 opacity: 0.9;
12 }
13
14 @media (max-width: 768px) {
15 font-size: 0.875rem;
16 }
17`;
18
19// Zero-runtime CSS-in-JS (Compiled, Vanilla Extract)
20import { style } from '@vanilla-extract/css';
21
22export const button = style({
23 background: '#007bff',
24 color: 'white',
25 padding: '0.5rem 1rem',
26 border: 'none',
27 borderRadius: '0.25rem',
28 cursor: 'pointer',
29
30 ':hover': {
31 opacity: 0.9
32 },
33
34 '@media': {
35 '(max-width: 768px)': {
36 fontSize: '0.875rem'
37 }
38 }
39});
40
41// Atomic CSS approach (Stitches)
42const Button = styled('button', {
43 background: '$blue600',
44 color: '$white',
45 padding: '$2 $4',
46 border: 'none',
47 borderRadius: '$md',
48 cursor: 'pointer',
49
50 '&:hover': {
51 opacity: 0.9
52 },
53
54 variants: {
55 size: {
56 small: {
57 padding: '$1 $2',
58 fontSize: '$sm'
59 },
60 large: {
61 padding: '$3 $6',
62 fontSize: '$lg'
63 }
64 }
65 }
66});1/* Critical CSS loading */
2@media (prefers-reduced-motion: reduce) {
3 *,
4 ::before,
5 ::after {
6 animation-delay: -1ms !important;
7 animation-duration: 1ms !important;
8 animation-iteration-count: 1 !important;
9 background-attachment: initial !important;
10 scroll-behavior: auto !important;
11 transition-duration: 0s !important;
12 transition-delay: 0s !important;
13 }
14}
15
16/* Container-based responsive design */
17.sidebar {
18 container-type: inline-size;
19 container-name: sidebar;
20}
21
22@container sidebar (min-width: 250px) {
23 .navigation {
24 display: block;
25 }
26}
27
28/* CSS containment for performance */
29.card {
30 contain: layout style paint;
31}
32
33.infinite-list-item {
34 contain: strict;
35 content-visibility: auto;
36 contain-intrinsic-size: 200px;
37}1<!-- Critical CSS inline -->
2<style>
3 /* Critical above-the-fold styles */
4 .hero { display: flex; min-height: 100vh; }
5 .header { position: fixed; top: 0; width: 100%; }
6</style>
7
8<!-- Non-critical CSS with media queries -->
9<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
10<noscript><link rel="stylesheet" href="styles.css"></noscript>
11
12<!-- CSS for specific components -->
13<link rel="stylesheet" href="components.css" media="print" onload="this.media='all'">1/* Feature detection with @supports */
2.grid-container {
3 display: flex;
4 flex-wrap: wrap;
5 gap: 1rem;
6}
7
8@supports (display: grid) {
9 .grid-container {
10 display: grid;
11 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
12 }
13}
14
15@supports (container-type: inline-size) {
16 .responsive-component {
17 container-type: inline-size;
18 }
19
20 @container (min-width: 300px) {
21 .component-content {
22 display: flex;
23 }
24 }
25}
26
27/* Graceful degradation for new color spaces */
28.vibrant-bg {
29 background: #ff6b6b; /* Fallback */
30 background: color(display-p3 1 0.4 0.4); /* Modern browsers */
31}
32
33/* Progressive enhancement for scroll animations */
34@media (prefers-reduced-motion: no-preference) {
35 @supports (animation-timeline: scroll()) {
36 .scroll-animation {
37 animation: fadeIn linear;
38 animation-timeline: view();
39 animation-range: entry 0% cover 40%;
40 }
41 }
42}1/* Respect user preferences */
2@media (prefers-color-scheme: dark) {
3 :root {
4 --bg-primary: #1a1a1a;
5 --text-primary: #ffffff;
6 --border-color: #404040;
7 }
8}
9
10@media (prefers-reduced-motion: reduce) {
11 * {
12 animation-duration: 0.01ms !important;
13 animation-iteration-count: 1 !important;
14 transition-duration: 0.01ms !important;
15 }
16}
17
18@media (prefers-contrast: high) {
19 :root {
20 --border-width: 2px;
21 --focus-ring-width: 3px;
22 }
23}
24
25/* Focus management */
26.button {
27 &:focus-visible {
28 outline: 2px solid var(--focus-color);
29 outline-offset: 2px;
30 }
31
32 &:focus:not(:focus-visible) {
33 outline: none;
34 }
35}
36
37/* Screen reader optimizations */
38.sr-only {
39 position: absolute;
40 width: 1px;
41 height: 1px;
42 padding: 0;
43 margin: -1px;
44 overflow: hidden;
45 clip: rect(0, 0, 0, 0);
46 white-space: nowrap;
47 border: 0;
48}
49
50/* Color contrast helpers */
51.ensure-contrast {
52 background: var(--bg-color);
53 color: contrast-color(var(--bg-color)); /* Future CSS function */
54}1const futureCSSTrends = {
2 shortTerm: [
3 'Widespread Container Queries adoption',
4 'CSS Nesting in all browsers',
5 'View Transitions API expansion',
6 'Better CSS Houdini support'
7 ],
8
9 mediumTerm: [
10 'CSS Anchor Positioning',
11 'Advanced color functions',
12 'Scroll-driven animations',
13 'CSS Modules native support'
14 ],
15
16 longTerm: [
17 'CSS Variables 2.0 with functions',
18 'CSS Layout API (Houdini)',
19 'CSS Parser API',
20 'Advanced typography controls'
21 ],
22
23 emerging: [
24 'CSS Container Style Queries',
25 'CSS Conditional Rules Level 4',
26 'CSS Spatial Navigation',
27 'CSS Environment Variables'
28 ]
29};
30
31// Developer priorities
32const developerWants = {
33 features: [
34 'Better debugging tools',
35 'Native CSS mixins',
36 'Improved CSS math functions',
37 'Cross-browser consistency'
38 ],
39
40 tooling: [
41 'Faster build tools',
42 'Better IntelliSense',
43 'Visual CSS editors',
44 'Performance analyzers'
45 ],
46
47 ecosystem: [
48 'Standardized design tokens',
49 'Better framework interop',
50 'Component sharing standards',
51 'CSS testing tools'
52 ]
53};1/* Future design token approach */
2@design-tokens {
3 --color-primary: #007bff;
4 --color-secondary: #6c757d;
5 --space-xs: 0.25rem;
6 --space-sm: 0.5rem;
7 --space-md: 1rem;
8 --typography-heading-1: {
9 font-family: Inter, sans-serif;
10 font-size: 2.5rem;
11 font-weight: 700;
12 line-height: 1.2;
13 };
14}
15
16/* Advanced component definition */
17@component button {
18 base: {
19 display: inline-flex;
20 align-items: center;
21 padding: var(--space-sm) var(--space-md);
22 border: none;
23 border-radius: 0.375rem;
24 cursor: pointer;
25 transition: all 0.15s ease;
26 };
27
28 variants: {
29 variant: {
30 primary: {
31 background: var(--color-primary);
32 color: white;
33 },
34 secondary: {
35 background: var(--color-secondary);
36 color: white;
37 }
38 },
39
40 size: {
41 small: {
42 padding: var(--space-xs) var(--space-sm);
43 font-size: 0.875rem;
44 },
45 large: {
46 padding: var(--space-md) var(--space-lg);
47 font-size: 1.125rem;
48 }
49 }
50 }
51}