The fundamental problems with CSS3
This post brings to a head a lot of my thoughts and feelings with regard to CSS3 and the way the W3C is developing it. It does not aim to look at specific topics in detail, but to step back and question some fundamental issues that I feel need to be addressed.
What was CSS created to do?
I need to establish a little history, but if you’ve been a web designer a long time, you can skip this section.
CSS1 was released 12 years ago, in 1996. At that time the current version of HTML was HTML 2 (HTML 3 wouldn’t be out until the year after). HTML controlled the layout, the look, and the information of the page - it did everything. Tables were the only way to do any layout, and web design consisted of slicing up graphics which were then placed into table cells to position them.
CSS was created to provide a better tool for developers to control the styling of HTML elements. That’s a carefully written statement. CSS was not designed to “control the visual presentation of a web page”; it was designed to control the visual properties of specific elements that existed in the mark-up. i.e., CSS offered a way to control fonts, colours, and sizes, all in one place. But that was all it was really meant to do. If you look at the specification there was only one property in CSS1 that could be used to effect layout -
position didn’t even exist, and in HTML 2 neither did
<div>, the two essential tools without which no modern design could be achieved (without resorting to tables). When CSS was released, using it for the layout of an entire page was barely even a concept, and it certainly wasn’t possible.
What are the design implications of how CSS works?
CSS was designed to work with whatever HTML was in the page. You point it at a specific element and you tell it specific things about that element to style: “look for paragraphs and change their colour to green”. The Cascade is a critical part of how this is managed. And because all CSS was designed to do was change a few visual properties of existing elements, there was no need for anything more complex than that.
The continuing omission of anything more powerful than the Cascade is the one serious hold-over that cripples the entire Web Stack to this day: CSS’s only tool for inspecting the DOM is the passive method of the Cascade. The result is that an element knows only about its direct ancestor elements, and can only do “simple” inheritance (my parent is green, therefore I am green. My parent has been positioned, therefore I take my position reference from my parents’ origin point). The limitation of the cascade is the single biggest problem with the Open Web technologies today, and it’s the one problem the W3C refuse to address.
Why the Cascade is no longer enough
HTML has been re-purposed to represent only the semantic properties of the page. Because CSS is only capable of cascading through the DOM, that means CSS can only be applied to elements that have semantic meaning. The trouble is that web-design today is more art than decoration. I’m not taking one wall and painting it green, I’m taking one canvas and painting a complete scene on it.
- There are many times where a designer wants to create or manipulate a visual element for which there is no semantic hook.
- Because CSS can not query, freely traverse, nor manipulate the DOM, we are forced to add non-semantic hooks to the HTML.
- Because CSS can not query, freely traverse, nor manipulate the DOM, designs are dependent on the structure of the mark-up.
CSS’s fundamental weakness means that true separation of presentation from content is not achievable even today.
How are we working around CSS’s lack of capability?
Even discounting this problem of requiring “wrapper” mark-up, CSS still fails us; allow me to give a few examples of fundamental things which are impossible with CSS:
- Create a tabbed pane such that an unknown number of tabs can adjust their dimensions to ensure the tab-row always occupies a total given width. e.g., I want the tab row to always be 800px wide, whether there are three tabs or five tabs. (display:table is not an option, for the reasons given here)
- Ensure that one semantically arbitrary (but visually linked) content block is the same height as another. e.g., ensure the “news” pane and the “poll” pane are the same height as they are visually linked, despite them having different ancestors and not being siblings in the mark-up.
- Position a given element relative to another given element, that is not itself a positioned ancestor. e.g., move the “copyright” message that’s at the end of the mark-up to be directly below the
<h2>near the top of the mark-up.
- Create a layout that adapts by grid unit.
If you are thinking of a solution to any of those problems which involves re-organising or re-writing the mark-up that is exactly the problem.
What does CSS need to overcome these problems?
First let me say what I think it really does not need. It does not need more ill thought out modules that provide half-baked solutions to explicitly defined problems and take a full decade to mature. We do not need the Working Group to study individual problem cases and propose a pre-packaged “solution” that either misses the point, is fundamentally wrong, or is inflexible (Advanced Layout Module, Marquee Module, display:table;, - I am looking at you). Here’s what we do need:
- DOM traversal, reference, and injection on the same order provided by jQuery. There’s a damned good reason why designers are flocking to jQuery.
- Programmatic variables, and basic Math
The crux of the issue is that W3C seem to try providing high-level “solutions” instead of low-level tools. It’s a limiting ideology. With the CSS3 WG strategy as it’s been over the last decade, they would have to look at all of the problem points I proposed above, and come up with a module to provide a solution to each. But by giving CSS an ability to traverse and manipulate the DOM, we designers can build out own solutions to all of them, and innumerable other issues we have right now, and in the future. Allow me to give an example; take the first “impossible” CSS challenge above, the unknown number of tabs that must fill a given width. It’s impossible - but the Multi Column Module does in fact allow the exact same functionality - you can specify a container of a given width and then specify a given number of columns (which you can change), and CSS will do the math internally to get the right widths! But I can’t use that module to achieve what I need with the tabs, despite it having the same basic function! Because they’ve provided a pre-packaged “solution” to a very specific problem instead of giving a more abstracted set of tools with which I could build my own solution.
All of the “impossible” CSS tasks set above can be solved by providing CSS an ability to inspect and modify the DOM, and use basic Math. And I can think of a dozen other impossible things that would rock if I had those tools in my CSS.
The CSS WG argue that CSS is meant to be simple, whilst missing the point that CSS is not meant to be anything. It’s a tool that must do a job, and the job has changed over time. CSS needs to keep up with requirements, and the best way to do that is provide adaptable tools rather than pre-packaged modules. There’s continual argument that maths, and dom traversal are too advanced for CSS, which is utter rubbish. I contest that if we are expected to understand selectors like
nth-child : 4n+3; (explained in the CSS3 spec as
an element that has an+b-1 siblings before it) then we can cope very well with creating and assigning variables, a little flow logic, and doing some simple adding. If we can handle jQuery, we can handle that.
The W3C attitude to non-specific architecture changes is summed up here (emphasis mine)…
On inspecting an object to determine a value and use that value on a reference object (e.g., create equal height columns that don’t rely on mark-up order):
I think we’d need a lot of detailed use cases to understand exactly why something this complicated and this powerful is needed
On positioning relative to another element:
A feature like this would be extremely complex and difficult to design and implement. Without concrete use cases to define the problem, there no way to even understand the requirements for creating such a feature
I think the problem is exactly the opposite. Step back and look at how CSS is making separation of semantics/display/behaviour impossible and understand how those suggestions fix that and allow massive flexibility. The problem with CSS isn’t that I can’t always do fancy things (though often it is), but much more importantly, that I can’t do many things at all without corrupting the web-stack in the first place. I’m talking about fundamental architectural problems, not petty display grudges.
Just in case this hefty post hasn’t bored you silly, and you find this article interesting, you may be interested in a couple of related older posts: Why CSS needs to borrow from programming languages, The fundamental problem with CSS is it’s reliance on the DOM, and CSS Tables for layout are a bad idea.