Jump to main navigation, main content

Archived entry | Matt Wilcox .net

Why CSS needs to borrow from programming languages

The job of CSS is to provide control over how the content of a document is displayed. Anything that falls under the remit of ‘controlling the display of content’ should fall under the abilities of CSS. Yet CSS lacks capabilities to allow truly flexible design, requiring layer upon layer of ‘tricks’ to accomplish certain objectives, requiring content to be structured ‘just so’ to achieve a display objective, or in the case of some designs proving instead to be completely incapable. Part of the trouble with CSS is the perception that it should be ’simple’, as though visual design and layout is a skill-set roughly equivalent to joining-the-dots and colouring in with a crayon. Yes, the syntax should be simple, but the capabilities of CSS should not. We as a community need to decide what CSS should be able to do, and petition the engineers to make it happen. Which itself would seem to require altering preconceptions of what ‘display’ and ‘design’ means on the web. A lot of people seem to be under a misconception that CSS should not have any ability to perform calculations, use variables, or perform logic tasks. That to do so would make it a programming language, and that CSS should not be a programming language (presumably because they feel a programming language is too complicated). But CSS most certainly should have these things, and without them it is destined to forever be a cludge, requiring cludges to wrangle the visual results we want.

Visual design is fundamentally about relationships between elements. For all of the artistic flourishes and creativity, it’s about relationships. ‘That yellow’ only grabs your attention because of its contrasting relationship with ‘that blue’. ‘This heading’ only works as a heading because of it’s exaggerated relationship to the size of the body text. And layout is perhaps the most fundamental (and most mathematical) area where relationships count for everything. There’s always a mathematical basis for how parts of the page appear in relation to other parts. That’s why good designers bang on about ‘the grid’ so often. That’s why good designers obsess over getting the right font sizes, the right line-height, the right column widths, the right size of thumbnail, the right number of thumbnails or panels on a row, etc. All of these things are about relationships of proportion. And CSS has no clue about relationships of proportion. CSS has no clue about relationships, period. And that’s why CSS as it stands right now, is not good enough. That’s why CSS without variables (true variables), without basic logic, without maths, can never be as flexible as we need it to be.

CSS’s positioning is a cludge. It’s a cludge because you can only position relative to the last positioned parent container. Well, that limitation in itself dictates that all positioning relies upon how the content is structured. And that means the presentation and the content are not truly separable. I understand why this is the case, it’s because the cascade works on the mark-up level - the cascade goes top-down but can’t traverse nodes. But that doesn’t change the fact that the problem still exists. Fundamentally, CSS should be able to traverse the DOM freely. We should be able to position any element relative to any other element. That’s the only way to achieve true separation of presentation from content.

CSS is ignorant of anything outside the cascade. CSS has no clue about any property or attribute of any element other than a parent element, from which it can inherit. So, if you have a three column layout where the two side columns are stylistically duplicates of each other, you have to specify everything twice. Because the two side columns are not aware of each other. And should you want them to both be the same height your choices involve faux columns, fixed heights, or some incredible hackery. Because you can’t tell CSS to make the height of the columns identical - because they don’t know about each other. CSS should be able to inspect the attributes on any element and apply those attributes back to the reference object. I should be able to write a rule for one div that tells it to look at another div and apply the same width, height, background colour, font face, and anything else I like. But I can’t, because CSS is ignorant of anything outside of the cascade.

CSS gives imperfect options for layout. Take the example of equidistant objects, have a look at what’s required to achieve this simple visual effect. Something as fundamental as this should not be so hard to achieve. And it wouldn’t be if CSS had basic math calculations combined with an awareness of the dimensions of boxes other than parents.

CSS gives imperfect options for layout. When designing on a grid, everything should line up with the grid. In this era of web design adaptive layouts are the norm, because they offer the best experience, but they are a bitch for retaining good proportion. An ordinary liquid layout is fine, as long as all the container elements are liquid too they’ll keep proportions. But that’s not good enough. If I want a grid layout, I want the display to adapt not pixel by pixel, but grid-unit by grid-unit. This requires basic logic and maths, perhaps even variables. But CSS doesn’t have these. Nor is it the job of JavaScript to make up for this lack of abilities. JavaScript is about interaction behaviour, and what we are talking about here is pure display logic. Not interaction logic.

While I’m picking fault with CSS, let me say that CSS3 Variables are not variables. A variable is by definition variable. It’s something a program takes and maps a value to, the value of which can change during parsing. CSS variables are in fact constants. You define them and they don’t change. That’s not a biggie, constants are better than no constants, but the misnaming rankles me and I just had to get that out of my system.

Looking through the CSS3 specifications, it’s a welcome step forward but it feels like shuffling along in an old mindset when we should be leaping for new solutions. Many of the new modules merely addressing specific issues on what I feel is the wrong level. Parts of CSS are becoming rather like a framework, in that they provide pre-build blanket solutions to specific issues, but in so doing don’t allow a great degree of control. Take the ‘Advanced Layout module’. It’s a template system that works by having you define the template grid (as ASCII art, unbelievably) in the CSS and then defining content into the slots. Well that’s great if your website is templateable and you are happy to have the slots always in that layout. But it’s a fixed and limited solution to a more fundamental problem. Instead of compartmentalising chunks of mark-up via div IDs, to later be slotted into visual locations that you must first pre-define (basically cutting up your HTML into chunks so you can whack it into a ‘display table’) - we should be able to put any element in any place on the fly.

CSS has stagnated for years, and my worry is that the mindset of the people developing it is seemingly in the wrong place. CSS should be delivering low level tools with which we as designers can build high level solutions. It isn’t doing that, it’s providing high level solutions and foregoing giving us useful tools that we can adapt on our own. As such, there will always be designs that simply don’t work well enough, or that require hacks, in CSS.

Comments

skip to comment form
  1. regi e. posted 5hrs, 24min, 19sec after the entry and said:

    Hey Matt,
    Very insightful article, it is apparent that you have delve into the specs more then me. I still question adding logic to the scope of it all, but I guess when/if this all happen…the benefits will speak for themselves. I also agree that requirements are changing and CSS needs to get off its a$$ and catch up.

  2. Neal G posted 7hrs, 20min, 51sec after the entry and said:

    It sounds like you're refering to this blog entry from Peter. I personally welcome the new "constants" proposal. It's a step in the right direction, although perhaps there could be more stepping to be done. I do have a problem with webkits "animations" proposal. I believe that should probably be left to javascript since it is a behavior (although would probably be easier to do in CSS)

    Matt says: In principal I’ve no problem with CSS animation, though it rather depends on how people go about using it. After all, what is animation but the varying of a presentation over time? I think peole are used to CSS being static, but when you think about it an animation is simply two display states with a progression over time between the two. It makes sense that the presentation layer handles that. What the presentation layer should not do is provide a trigger for the animation. Because a trigger is behaviour. JS should provide the trigger, which then tells the CSS to do it’s thing. The tricky part is how people understand ‘behaviour’ - it doesn’t (in my understanding) mean how a page changes over time, but how it interacts dynamically with the user. That’s a crucial point.

  3. Dean Landolt posted 20 days, 8hrs, 25mins after the entry and said:

    Were you looking for something like this:

    http://www.shauninman.com/archive/2007/06/27/css_server_side_pre_processor

  4. Matt Wilcox posted 21 days, 4hrs, 13mins after the entry and said:

    Hi Dean,

    No, not really. I've been aware of Shaun's approach since he blogged it, but while it's a useful hack, it's still a hack. I want CSS itself to grow up.

    If anything though, Shaun's work shows very clearly that real world developers/designers do want this sort of functionality from CSS, so much so that they have made work-arounds themselves.

  5. rob posted 274 days, 7hrs, 34mins after the entry and said:

    matt:
    I thank you considerably for the new label for my every day drudgery: 'incredible hackery'. At least i can smile now while i'm all mucked up in css.

  6. Artyom Shalkhakov posted 1 years, 133 days, 22hrs after the entry and said:

    Hello Matt,

    A very good article you've written. I wholeheartedly agree with you.

    I've been thinking very hard about CSS today, having tried to express it's selectors using first-class pattern matching in Haskell, I turned to set theory and first-order logic.

    What's interesting here is that CSS selectors map to the aforementioned things very well, but it seems that they were never intended to. I believe there is a connection to logic programming. smiley icon: smile

    My motivation behind all this is to modularise HTML, JS and CSS (I'm just a fellow developer tired of banging my head against the very same wall). No, they aren't really modular, trust me. smiley icon: smile CSS has horrid rules ("specifity" and ordering of rule-sets and CSS files come to mind) which practically make it anti-modular: you can never say whether addition of this rule over here changes another thing over there or not. The same for HTML and JS; and no, template engines do not solve the problem – they work around it instead.

    Okay, I'll shut up now. smiley icon: smile

  7. SFFC posted 2 years, 65 days, 20hrs after the entry and said:

    I very much agree. CSS's purpose is to define how a web page should be displayed. Say you need to make #DivA half the width of #DivB. Currently, you'd do:

    div#DivA{ width: 200px; }
    div#DivB{ width: 100px; }

    But what if the with of #DivA changed during web page execution? Or what if the width of #DivA were not constant at all, like a table or a display:inline-block?

    Some would say, "hey programmer dude, if #DivA's width changes, have JavaScript change #DivB for you!" But JavaScript's purpose is to provide interaction, not style. And even if I did try to use JavaScript for this, JS only runs when an event is fired. What if no event was fired when #DivA changed width? And this still doesn't solve the problem of un-absolute widths on #DivA.

    Why not just write something like:

    #DivB{ width:#DivA$width/2; }

    Since CSS defines display, the browser will redraw #DivB such that its width is always 1/2 of #DivA. Why? Because the width of #DivB is defined as 1/2 the width of #DivA. It's not that hard to conceive.

    Another place where CSS lacks is combining different units of width (%, px, em, and so on). Wouldn't it be great if we could do something like this?

    .userPane{ right: 100% - 5px; }

    If designers are afraid of constants, logic, and arithmetic in their static, cascading environment, just ignore them. You don't have to use the features if you don't want to. Allowing dynamic concepts in CSS would make web design better and save developers many doses of aspirin.

    CSS really has to catch up with Web 2.0.

  8. lenovo thinkpad posted 3 years, 325 days, 4hrs after the entry and said:

    agreed, we need a bit more variables than class and id

From the archives

Other enteries filed under:

Web Development

Site information

Built with valid XHTML and CSS, designed with web standards and accessibility in mind. Best viewed in a modern browser [Firefox, Safari, Opera]

This domain and all content is a copy of my old website, for historical purposes only.