Why Is CSS So Hard? Julia Evans' Deep Reflection

CSS isn't fundamentally flawed—it's solving inherently complex problems and deserves serious study.
Julia Evans' experience migrating from Tailwind back to native CSS sparks reflection: CSS has long been underestimated and belittled, but many former pain points (like centering) have long been solved by modern features like Flexbox and Grid. CSS's complexity stems from the inherent complexity of web layout itself, and its declarative design and fault tolerance embody the Web platform's core philosophy. Developers should seriously learn CSS rather than dismiss it based on decade-old perceptions.
From "CSS Is Too Hard" to "Taking CSS Seriously"
Julia Evans recently published an article about migrating away from Tailwind and relearning how to organize CSS. One particular reflection on CSS resonated widely. She wrote:
Over the past 10 years, I've learned to truly love and respect CSS as a technology.
This seemingly simple statement captures the journey many frontend developers have experienced. CSS has long been viewed as a "not hardcore enough" technology, even becoming a running joke in developer communities — "centering an element with CSS" was once classic complaint material. But Julia Evans chose a different path: rather than belittling CSS, she decided to learn it properly.

The Truth Behind "Centering in CSS Is Hard"
Julia Evans made a very insightful point in her article: after truly diving deep into learning CSS, she discovered that many of her past frustrations (like "centering is impossible") had actually been solved in CSS long ago.
The reason CSS centering became a classic problem is rooted in CSS's original design model — Document Flow. CSS was born in 1996, initially designed to add styles to academic documents, not to build complex application interfaces. In the traditional Block Formatting Context, vertical layout is automatically managed by document flow, and developers lacked direct means to control vertical alignment. Early developers had to rely on margin: 0 auto, text-align: center, line-height hacks, position: absolute combined with transform, and even display: table-cell — various tricks to achieve centering. Each method had its applicable scenarios and limitations, which was precisely the source of confusion. It wasn't until 2012 when the Flexbox specification stabilized that the combination of justify-content: center and align-items: center finally provided an intuitive, universal centering solution.
More importantly, Julia Evans realized that the concept of "centering" itself isn't always straightforward. Horizontal centering, vertical centering, centering in a flex container, centering in a grid layout, text centering, block-level element centering — these scenarios are all different. CSS providing multiple ways to center is actually sensible design, not a flaw.
This cognitive shift is crucial: CSS is complex because it's solving a problem that is inherently complex.
Why Developers Tend to Underestimate CSS's Difficulty
In the tech community, CSS has long occupied an awkward position. It doesn't have complex runtime logic like JavaScript, nor does it involve system architecture design like backend languages. Many developers tend to view CSS as "trivial styling stuff," believing it's not worth investing much effort to learn deeply.
This mindset spawned the popularity of numerous CSS frameworks and tools. The evolution of CSS frameworks is itself a microcosm of developers battling CSS complexity. Bootstrap, open-sourced by Twitter in 2011, adopted a component-based approach, providing predefined class names and style combinations so developers could quickly build pages by assembling components. But Bootstrap's problems lay in high style coupling, difficult customization, and pages that often bore an obvious "Bootstrap look." Tailwind CSS, launched by Adam Wathan in 2017, took a different path — Utility-First CSS, breaking each CSS property into independent utility classes (like flex, pt-4, text-center) to be combined directly in HTML. This approach dramatically increased development speed but also brought controversies around decreased HTML readability and weakened understanding of underlying CSS.
These tools certainly have their value, but if the motivation for using them is "I don't want to learn CSS," then there's a problem. Julia Evans' decision to migrate away from Tailwind represents exactly this kind of reassessment of trade-offs. When she decided to relearn how to organize native CSS, she found the technology far more elegant and powerful than she had previously believed.
Modern CSS Has Evolved Far Beyond What You Might Think
Modern CSS has undergone transformative changes.
Flexbox and Grid: A Layout Revolution
Flexbox and CSS Grid are the two most important paradigm shifts in CSS layout history. Before they appeared, developers primarily relied on the float property for layout — a property originally designed for text wrapping around images that was "abused" for over a decade. Float-based layouts required manual float clearing (clearfix hacks), couldn't easily achieve equal-height columns, and couldn't elegantly handle vertical alignment. These painful experiences shaped an entire generation of developers' negative impressions of CSS.
Flexbox was first proposed in 2009 with syntax stabilizing in 2012, focusing on space distribution and alignment in one dimension (row or column). CSS Grid gained mainstream browser support in 2017, providing true two-dimensional layout capabilities with simultaneous control over rows and columns. The two aren't replacements for each other but complementary: Flexbox is suited for flexible arrangement within components, while Grid is ideal for page-level structural layouts. The maturation of these two technologies made layouts that previously required JavaScript calculations or complex CSS hacks become declarative and intuitive.
Next-Generation CSS Features: Container Queries, :has(), and Subgrid
CSS Custom Properties (variables) brought unprecedented flexibility, and even more exciting is the series of new features continuously expanding CSS's capability boundaries.
Container Queries is a feature the CSS community advocated for nearly a decade, achieving full mainstream browser support in 2023. Unlike traditional Media Queries that respond based on viewport width, Container Queries allow components to adjust their styles based on their parent container's dimensions, making truly reusable responsive components possible. The :has() selector has been called CSS's "parent selector" — it allows selecting parent elements based on the state of child elements (e.g., div:has(> img) selects divs containing a direct child image), something previously achievable only through JavaScript. Subgrid solves the challenge of nested grid alignment, allowing child grids to inherit their parent grid's track definitions, making cross-level alignment simple.
The common trend among these features is: CSS is evolving from a pure "style description language" into a "style programming language" with logical judgment capabilities, its expressiveness already far exceeding many developers' awareness.
However, many developers' understanding of CSS remains stuck five or even ten years in the past. They remember the pain of float layouts and the nightmare of IE compatibility, but haven't kept up with CSS's rapid evolution. If you're still viewing CSS through a decade-old lens, it will indeed seem "both hard and poorly designed."
Take CSS Seriously, Don't Belittle It
Julia Evans' attitude offers us an important insight: when facing a technology that "seems hard," we have two choices — either belittle it and work around it, or seriously learn it and understand the design logic behind it.
Choosing the latter often brings unexpected rewards. When you understand why CSS is designed the way it is, you can not only write better style code but also gain deeper understanding of the Web platform's design philosophy itself. The Web platform's core principles are Progressive Enhancement and Fault Tolerance. Unlike programming languages that throw errors upon encountering unknown syntax, CSS's design principle is: silently ignore unrecognized properties or values and continue parsing. This design allows new features to be gradually adopted without breaking the basic experience on older browsers. Another core design principle of CSS is "declarative" rather than "imperative" — developers describe the desired result (like "this element should be centered") rather than specifying implementation steps (like "calculate the parent container width, subtract the child element width, divide by two, set as left margin"). This declarative model means browsers have greater freedom to optimize rendering, but it also means developers need to understand browser layout algorithms (such as BFC, IFC, Flex Formatting Context, etc.) to accurately predict results. This is precisely the fundamental reason CSS "appears simple yet is profoundly deep."
As Julia Evans said: CSS is hard because it's solving a hard problem. Acknowledging the complexity of the problem is the first step to solving it.
Key Takeaways
- Julia Evans shared her experience migrating from Tailwind back to native CSS, emphasizing that we should take CSS seriously rather than belittle it
- Many developers' past CSS frustrations (like centering issues) have long been solved by modern CSS; the historical root cause was that CSS was originally designed for document flow rather than application interfaces
- CSS is complex because it's solving an inherently complex problem — web layout and styling
- The evolution of modern CSS (Flexbox, Grid, Container Queries, :has() selector, etc.) is severely underestimated by many developers; CSS is evolving from a style description language into a style programming language with logical judgment capabilities
- CSS's declarative design philosophy and fault tolerance embody the Web platform's core principles; understanding these design logics can bring fundamental cognitive shifts
Related articles
Expert OpinionsThe Lazy Person's Productivity Theory: Why Being 'Lazy' Actually Drives Peak Performance
Explore the engineering philosophy behind 'lazy people are most productive': how constructive laziness drives automation, AI tools amplify efficiency, and systems thinking eliminates wasted effort.
Expert OpinionsOutdoor Coding: You Can Touch Grass AND Build Things
When AI coding assistants free developers from their desks, outdoor coding becomes a real trend. Explore how cloud IDEs, voice coding, and AI tools enable creativity in nature.
When AI Treats Humans as Subagents: Ro…
When AI Treats Humans as Subagents: Role Reversal and Hidden Risks in Human-AI Collaboration
Exploring the paradigm shift where humans become "subagents" in AI Agent architectures. Analyzes human node design in LangChain and AutoGen, and the risks of ceding control and cognitive atrophy.