On attr() and calc()

I recently posted my first suggestion to www-style, the official W3 mailing list for CSS development. It was about allowing attr() values inside calc(). In this post I’ll describe in greater detail why I believe this is necessary, since not everyone follows www-style. If anyone has something to add in the discussion, you may post in the list, it’s public.

attr()

As you can easily find out in the specification, the W3 is planning for attr() to play a much bigger role in tomorrow’s CSS than it played in CSS 2.1, where it was originally defined, which opens up exciting possibilities. In a nutshell, we’re going to be able to use attr() in any property, for any type of value, let it be <length>, <number>, <color> or anything else. If the type is not obvious, we’re able to define it, via the second parameter and include a fallback value in the 3rd one. We might even be able to do things like float: attr(X); (keywords are still under consideration).

calc()

On the other hand, as you’re probably already aware of, since calc() is one of the hyped CSS3 features, we’re finally going to be able to do calculations with different types of units, for example calc(100% - 30px), which is something web designers requested for years.

calc(attr())

You can easily see from the grammar presented in the specification for calc() that it does not allow attr() values to be used as operands in the calculations. To me, this is an obvious oversight. Since attr() values can be used anywhere, including where lengths and numbers are allowed, not being able to use them in calc() is absurd. As David Storey pointed out, this could be enormously useful when used in conjunction with the new form control attributes (min, max, step and the like) or HTML5 custom data attributes (data-x).

Philosophically, it makes perfect sense that attr() should be allowed anywhere a <length> or <number> or <angle> or … is. We can’t expect attributes to only hold semantic and not presentational data, but expect these data to be ready to be utilized for presentation purposes, without any calculations whatsoever.

The first use case I can think of is the one that inspired me to suggest this. A while ago, I was researching CSS-based bar charts and progress bars. It turned out that there is no practical and purely semantic solution for specifying the bar widths. Either you have to include inline styles or you bloat your CSS with countless classes or ids, one for each width or —even worse— bar. In cases where you just want to use the displayed percentage of the bar as its width as well, attr() can actually help. However, as you can see, this is not always the case. Most of the times the bar values are not percentages or you want to also perform calculations on the percentage, for example include padding (because usually you display the number as well) or cut it in half to prevent the bar chart from appearing very big, etc, in which calc() combined with attr() could be a lifesaver.

One could argue that bar charts and progress bars are not legitimate CSS use cases but hacks that work around the lack of cross-browser SVG support, and it’s very possible that they are right (although the addition of elements like <progress> in HTML5 is by itself an argument for the opposite). However, the use cases are not limited to that. Αny kind of stylistic treatment that is supposed to convey some kind of fraction or number (progress, temperature, distance etc) will benefit from keeping the actual data in a data-x attribute and utilize them via attr() and calc().

Admittedly, coming up with more generic use cases is not very easy, since they greatly depend on the particular application. However, the same difficulty arises when trying to come up with use cases for the attr() function by itself when used for the numerical types (<number>, <length> etc), in properties other than content. Perhaps this is the reason that not even the specification contains any practical examples for it either. I guess almost any real-life use case for attr(*, number|integer|length|angle|frequency|em|px|…, *) is also a use case for this.

So far I’m optimistic about it, since almost all participants in the discussion were positive. However, calc() has already started being implemented (by Mozilla), so as time goes by, it will be increasingly harder to make changes to its grammar.

What do you think? How would you use it if it’s implemented?

Edit: Sometime in Spring 2012, the issue was brought up again, and the CSS WG agreed that attr() should be permitted in calc(). Now it’s just a matter of browsers catching up to the spec. :)

  • http://www.xanthir.com Tab Atkins

    Agreed; attr() should be allowed in calc(), no question. We can determine at parse time what the type of the value is going to be, so it’s perfectly compatible.

  • http://leaverou.me Lea Verou

    I’m so glad you agree!! The problem is, the www-style thread has kinda stopped getting responses, so unless someone brings it up again, I doubt it’s gonna get through. Especially with attr() being at-risk now :(

    By the way, I also think other function combinations should be permitted too, like counter() in calc().

  • http://www.xanthir.com Tab Atkins

    counter() would need a little bit of extra support – right now, the function always outputs a string. The counter itself is indeed a number, though.

    • http://leaverou.me Lea Verou

      Maybe it could get an extra argument, like attr(). Although maybe it’s not worth it that much (I remember needing such a thing only once, and I can’t even remember the use case). attr() in calc() is much more useful.

  • Pingback: A polyfill for HTML5 progress element, the obsessive perfectionist way | Lea Verou

  • Pingback: SWL-Projekt » A polyfill for HTML5 progress element, the obsessive perfectionist way

  • Pingback: Cross Browser HTML5 Progress Bars In Depth « Zirkan

  • http://www.facebook.com/stephenr85 Stephen Rushing

    I completely agree. I ran across your post while I was trying to create a proof of concept for handling images in a responsive design. It is strange to me that we’re not able to nest function calls…not even url( attr(___) )!? It seems like a fundamental flaw to me. All limitations aside, here’s the proof of concept, as far as I could get it: http://jsfiddle.net/stephenr85/ejMHE/1/

    • http://lea.verou.me/ Lea Verou

      Stephen, you just reminded me to make an edit. Check the addition at the end of the article. ;)

    • http://www.dynamicsitesolutions.com/ Kravimir

      I had a similar use case in mind today. I would like to be able to use the value of an img element’s width and height attributes in calc() to responsively reposition the element. Without this CSS3 feature I’ll either have to hardcode the dimensions in the CSS (which may cause a maintenance issue later) or use some JavaScript.

  • Michał Gołębiowski

    I’m late to the party; I discovered calc() just a few days ago, it’s wonderful! Especially vertical aligning is so much simpler with calc(attr()) available compared to the damn-ugly creating lots of divs using table and table-cell just to be able to use vertical-align! (There isn’t any simple JavaScript-less way to do that without calc/attr, is it?)

    The only thing that saddens me now is that Opera hasn’t implemented it yet as the only major browser so I can’t really use it yet. :(

  • Pingback: 译:深度跨浏览器的HTML5进度条 | Junyi's Blog