Attribute Style CSS Programming

The Problem

At my job we don’t have a dedicated CSS/web design guy. Programmers do all of the design work themselves. That’s not to say that such a situation is unnatural, in desktop app development it is the norm. Programmers tend to approach any presentation technology as something that should be able to express their will exactly. HTML & CSS are notoriously bad at this because they are not a true presentation framework. HTML is a semantic document markup language and CSS can be overridden by browser specific behavior and user settings. That is as it was intended, the User Agent is in control of the final rendering, not the author. So a typical programmer reaction is to be even more specific to force the User Agent to display what we want. This might include using per-browser style sheets, absolute positioning of elements or tables for non tabular data. This tends to result in more markup, more CSS, more testing and more bugs to fix. The programmers gut reaction is at odds with the reality of the web.

So my goal is to give the programmers something they can live with that achieves these goals:

  • Reduce the number of cross browser bugs and testing
  • Minimize the amount of custom CSS we write for each new page
  • Have a single style sheet for all the browsers we support
  • Allow developers to build layouts that I haven’t thought of
  • Be ready to support mobile devices
  • Make the HTML and CSS maintainable

My first attempt was to try and get the team to adopt Yahoo’s YUI CSS for layouts. Adoption by the team didn’t go so well. It was hard to get the layout you wanted 100% of the time. Nesting of layouts would sometimes introduce bugs. No one liked the cryptic style names. So I went looking for a replacement and found Nichole Sullivan’s ‘Object Oriented CSS‘ framework. The code is much simpler than the yahoo framework and it’s a much closer fit for how we work.

The ideas behind Object Oriented CSS make a lot of sense but the name make almost no sense to me. I think it most closely resembles Attribute-Oriented Programming. You place attributes (CSS classes) on elements (Objects) in combination to achieve some desired effect. In programming Attributes can be used to mark Objects for later use by other code that acts on those objects. They can also describe some quality about an Object, like it being serializable or a database entity. Attributes are written in such a way that they combine gracefully and interact only when necessary. In programming an Attribute can have arguments. In CSS the arguments are the element on which the attribute is acting and the other attributes applied to that element. So now we have model for thinking about the problem.

CSS attributes combine to produce a wide variety of effects from comparatively little CSS code. To achieve a total effect you combine attributes together on an element. If the exact attribute you need is not available you can use the ones that do exist plus some small amount of style information to produce the effect.

This gives us a way of looking at CSS code and accessing it like we do other kinds of code. We can look for potential refactorings like we do in other kinds of code. Its just a way of looking at the problem.

One I got my head around this I realized that I couldn’t just take OOCSS to the programmers because there were things about it that needed to change. It needed to be come even more attribute oriented and it needed to be more consistent.

Sample Refactoring

Lets take an example from the OOCSS framework and improve on it by thinking in an Attribute Oriented way. In OOCSS there is a debugging style sheet that adds background colors to the grids. This is a great idea but using it is awkward. First you have to include a separate style sheet in the document. In a template system that means going and finding the template with the Head tag and modifying it. Once that’s done debugging is on for ALL the grids in the document, not just the two boxes you want to debug. Also debugging only works for grids, you cant debug some arbitrary elements.

So, lets define a ‘.debug’ attribute the we can use to mark elements we want to debug. For the grid classes it can have special behavior (Attribute behave differently depending on their input, remember?). For non grid elements we can also set a background so we can use ‘.debug’ on anything.

/* all elements get a gray background as the default behavior*/
.debug {background-color:#e2e2e2;}
/* Extend the .debug attribute with special behavior for grids: */
.size1of1.debug {background-color:pink;}
.size1of2.debug {background-color:red;}
.size1of3.debug {background-color:orange;}
.size2of3.debug {background-color:yellow;}
.size1of4.debug {background-color:lime;}
.size3of4.debug {background-color:green;}
.size1of5.debug {background-color:aqua;}
.size2of5.debug {background-color:blue;}
.size3of5.debug {background-color:purple;}
.size4of5.debug {background-color:magenta;}

Now we have a debug attribute that works anywhere and we can quickly apply it to anything we want to debug.

Names Matter

The fixed size grids in OOCSS are focused on laying out the main chunks of the page. This is kind of unfortunate because there are a lot of places where they come in handy. This snipet comes from the file in OOCSS:

/* ====== Columns ====== */
.main{overflow: hidden;_overflow:visible;_zoom:1;}
.leftCol{float:left; width:250px;_margin-right:-3px;}
.rightCol{float:right; width: 300px;_margin-left:-3px;}

/* extend columns to allow for common column widths */
.gMail{width:160px;}
.gCal{width:180px;}
.yahoo{width:240px;}
.myYahoo{width:300px;}

Here is my proposed re-write:

/* Fixed Width Layouts */
.layout-fixed {clear: both;}  /* facilitate layout stacking */
.col-main {overflow:hidden; _overflow:visible; _zoom:1;}
.col-left {float:left; width:30px; _margin-right:-3px;}
.col-right {float:right; width:30px; _margin-left:-3px;}

/* Fixed pixel widths */
.width-160 {width:160px;}
.width-180 {width:180px;}
.width-240 {width:240px;}
.width-300 {width:300px;}
/* + more as you require... */

This is very subtle change. The ‘.col-left’ and ‘.col-right’ attributes now set the same default width. Not setting the width is an option but its better for the column to have some width so the programmer gets some kind of feedback that the attribute is working (default attribute behavior). Setting the same width on .col-left and .col-right promotes the feel of consistency. We programmers like it when things behave consistently. Changing the names of the specific width styles to ".width-NNN" has some nice effects. It’s easier to read in the code. ‘.width-300′ is more likely to be re-used than ‘.myYahoo’ because its easier to understand what it claims to do. It’s not clear that its safe to use ‘.myYahoo’ in other situations, it might have side effects or set other styles that you don’t want. ‘.width-300′ is a specific attribute which claims to do only one thing. Finally the ‘.width-NNN’ sets up a convention. Programmers will be encouraged to try ‘.width-500′ before they start writing a custom style for that width.

So the source for a two column layout would go from this:

<div>
	<div class="leftCol myYahoo"></div>
	<div class="main"></div>
</div>

To this:

<div class="layout-fixed">
	<div class="col-left width-300"></div>
	<div class="col-main last"></div>
</div>

The programmers in the crowd will see this as a big win for readability. The designers point out that this is more verbose and size matters. Designers, size wont matter at all if you cant get the programmers you work with to adopt the framework. If you get this into common usage then later you can do a global re-name to smaller names. Honestly for most sites, size does not matter that much. Programmers will implement zip compression on the web server before they do a re-name. Readability and maintainability are more important than page size. If page size really matters that much you can optimize it later. You cant optimize it later if the CSS is an inconsistent mess.

Integrating Fixed Width and Percentage Width Layouts

The naming for fixed width and percentage width layouts in OOCSS is very different. Attributes that have similar effects or usage usually have similar names. Certainly the declarations that determine the column widths could follow the ‘width-XXX’ convention.

.width-auto {width:auto;}
.width-1of1 {width:100%;}	/* set 100% width outside of layouts */
.col.width-1of1 {float:none; width: auto;}	/* this doesn't set width=100% so make this context sensitive */
.width-1of2 {width:50%;}
.width-1of3 {width:33.33333%;}
.width-2of3 {width:66.66666%;}
.width-1of4 {width:25%;}
.width-3of4 {width:75%;}
.width-1of5 {width:20%;}
.width-2of5 {width:40%;}
.width-3of5 {width:60%;}
.width-4of5 {width:80%;}

This leaves us with the core of the percentage width grid system. Again from OOCSS (grid.css):

.line, .lastUnit {overflow:hidden; _overflow:visible; _zoom:1;}
.unit {float:left; _zoom:1;}
.lastUnit {float:none; _position:relative; _left:-3px; _margin-right:-3px; width:auto;}

It doesn’t look much like the fixed width system. Lets say that we have a layout with two columns that are split up 1/3 to 2/3. The HTML looks like this:

<div class="line">
	<div class="unit size1of3"></div>
	<div class="unit lastUnit size2of3"></div>
</div>

Now lets say there is a requirements change and the developer needs to alter this layout. The new requirement is for the left column to be 300px wide and the right column is flexible. The code using OOCSS would look like this:

<div>
	<div class="leftCol myYahoo"></div>
	<div class="main"></div>
</div>

In addition to changing the width attribute you need to remember to remove the ‘lastUnit’ class and to change things from ‘unit’ to ‘col-’. We can make the ‘last’ marker harmless in the case where its used with fixed-width layouts so forgetting to remove it will not harm the presentation. Then we can tell developers to always include it. It wont be necessary in one case but it will be consistent and that will probably reduce frustration. Also lets name the attribute ‘last’ so that we can use this kind of marker attribute in other places as a convention, like the last row in a table or the last button in a button strip. In programming some attributes have no effect unless they are used in conjunction with another attribute or placed on a particular type. ‘last’ may get used widely but it wont have any default behavour. Its important to consider this when building your framework. If something has global effects its harder to make it have local effects later.

Then there is the ‘.line’ declaration. You cant forget to add that. I think it’s better if there is a declaration in both layout types so the programmer has to say what they mean, semantically, even if it not necessary. As it turns out it is necessary to make fixed width and percentage width layouts stack ontop of each other. Finally we can re-name ‘.unit’ to ‘.col’ so it looks more like the fixed width versions.

.layout-percent {clear:both;} /* facilitate layout stacking */
.layout-percent, .col.last {overflow:hidden; _overflow:visible; _zoom:1;}
.col {float:left; _zoom:1;}
/* make .last only apply to columns in percentage width layouts */
.col.last {float:none;_position:relative; _left:-3px; _margin-right: -3px; _width:auto;}

And now we have the two versions of the source again. First the percentage width version:

<div class="layout-percent">
	<div class="col width-1of3"></div>
	<div class="col width-2of3 last"></div>
</div>

And then the fixed width rewrite:

<div class="layout-fixed">
	<div class="col-left width-300"></div>
	<div class="col-main last"></div>
</div>

Thats a pretty substantial improvement in ease of use.

People Make Mistakes

As simple as this is, someone will get it wrong. They may have it totally wrong and think that the framework is at fault. They may also introduce subtle hard to find bugs. Some ‘clever’ developer will mix the fixed width and percentage width column attributes together in the same container and this could produce unexpected results that might not show up on the particular browser they are testing on. They will probably break IE-6 and not know about it till the customer tests it. To help them avoid this we can detect misuse of the framework and flag the offending element.

We can detect use of the wrong column type within a particular layout type. We can also detect some misplacement of the ‘.last’ attribute and enforce that its always present on the last block. The ‘.col-main’ has to be the last element in the source order and we can use adjacency selectors to check for this too. Unfortunately we can only flag the element that comes after ‘.col-main’ but this should be enough.

The selectors are written individually so that when a developer inspects the error with Firebug or the IE Developer Tools they can see the exact cause of the error. This beats having a huge list of potential errors to pick from. I also used a dashed red border so this error detection does not conflict with the debugging support. Developers should not be adding borders to layout elements because it will break the layout. Because borders add to the width of an element adding them will break any percentage width layout where the element widths add up to 100%. Note: 100% + 1px border > 100%, a fact that programmers tend to forget. In one case I have had to turned on a border and only turned it off when they get it right. This could all be included in a seperate css file and removed in a release build.

This technique has already proven to be usefull. I get colleages asking why all they got was this annoying red border and I was able to quickly spot the error. Think of it as a CSS compile time error checker.

/* Layout Error Detection Support (remove in a production environment) */
/* Detect misuse of the col-* and width-XXX classes based on their container */
/* needs !important because it can be turned off on the last column if .last is applied correctly */
.layout-percent > .col-main {border: dashed 8px red !important;}
.layout-percent > .col-left {border: dashed 8px red !important;}
.layout-percent > .col-right {border: dashed 8px red !important;}
.layout-fixed > .col {border: dashed 8px red !important;}
.layout-fixed > .width-1of1 {border: dashed 8px red !important;}
.layout-fixed > .width-1of2 {border: dashed 8px red !important;}
.layout-fixed > .width-1of3 {border: dashed 8px red !important;}
.layout-fixed > .width-2of3 {border: dashed 8px red !important;}
.layout-fixed > .width-1of4 {border: dashed 8px red !important;}
.layout-fixed > .width-3of4 {border: dashed 8px red !important;}
.layout-fixed > .width-1of5 {border: dashed 8px red !important;}
.layout-fixed > .width-2of5 {border: dashed 8px red !important;}
.layout-fixed > .width-3of5 {border: dashed 8px red !important;}
.layout-fixed > .width-4of5 {border: dashed 8px red !important;}
.col-left.last {border: dashed 8px red !important;}
.col-right.last {border: dashed 8px red !important;}

/* Check that no columns come after .col-main */
.col-main + .col-left {border: dashed 8px red !important;}
.col-main + .col-right {border: dashed 8px red !important;}	

/* Enforce that the .last attribute is set on the last column (only works in newer browsers!) */
.col:last-child {border: dashed 8px red;}
.col-main:last-child {border: dashed 8px red;}
.col:last-child.last, .col-main:last-child.last {border: none;}

Alternate Proposals

We do have two other competing ideas on how css should be used. I’m presenting them here with examples because it should be clear in either case that the approach is sub optimal. We have backers of either approach in house, either they activly advocate the solution or have rejected all alternate solutions. The point is I have seen these two ideas expressed by actual people in some way. It’s likely that you will face similar ideas when dealing with programmers in your work.

Class == 1 Style Rule

The first is to give the programmer attributes that map 1:1 with style rules:

.clear-both {clear:both;}
.overflow-hidden {overflow:hidden;}
.float-left {float:left;}
.width-300 {width:300px;}
<div class=&quot;clear-both overflow-hidden">
	<div class="float-left width-300"></div>
	<div class="overflow-hidden"></div>
</div>

We do have code like this being written right now. Its being targeted at IE6 and only IE6. Its not clear how this will be evolved in the future to support new browsers. There is nothing semantic about this. There is no way that you can safely change the way ‘float-left’ works in the future to support new browsers. ‘float-left’ does not indicate that a fixed width layout is being employed. You might as well go back to putting everything in the style tag. In the long term all of this code is going to have to be be rewritten.

The IE-6 compatibility style rules are not included. I left them out so you wouldn’t think I was being pathological. It’s not clear how to introduce them into this model. Should ‘.ie6-margin-right-hack’ be a class? If you define ‘.margin-right–3′ does that set a negative margin on all browsers or just in IE6? If you define ‘.overflow-hidden’ should that have the IE hack in its code or not? Let me at least try to give this a fair attempt:

.clear-both {clear:both;}
.float-left {float: left;}
.width-300 {width:300px;}
.overflow-hidden {overflow:hidden;}
.ie6-overflow-fix {_overflow:visible;}
.ie6-zoom-hack {_zoom:1;}
.ie6-width-auto-hack {_width:auto;}
.ie6-margin-fix {_left:-3px; _margin-right: -3px;}
<div class="clear-both overflow-hidden ie6-overflow-fix ie6-zoom-hack">
	<div class="float-left width-300 ie6-zoom-hack"></div>
	<div class="overflow-hidden ie6-overflow-fix ie6-zoom-hack ie6-width-auto-hack ie6-margin-fix"></div>
</div>

I am deeply uncomfortable with this approach. Its not semantic and we are back to programmers being a CSS experts, which they are not. Reuseability of the individual styles is high but they fail to capture knowledge about cross browser issues and make that re-usable. I think the example above should be sufficiently bad to deter anyone from going down this road.

Class == Result

The other proposal is at the other end of the spectrum. A 1:1 mapping with the desired result. E.g.

.col-left-300 div {overflow: hidden; _overflow:visible; _zoom:1;}
.col-left-300:first-child {float:left; width: 300px; _margin-right:-3px;}
<div class="col-left-300">
	<div></div>
	<div></div>
</div>

This style does a good job of capturing cross browser bugs and making that knowledge reusable. Its also clearly simple to use. That is the main argument for this style, its ’simple’.

The problem is its only simple for the programmer when they use the style correctly. It assumes much about how the document is structured. Its not re-usable in any other situation. If you want to define a ‘.col-left-250′ attribute you need to copy two existing style rules and modify them both. That’s pretty much the definition of violating the DRY principal. This is the same approach that YUI takes with their templates. They are difficult to modify if you want a specific pixel width layout. This is one of the reason why I stopped using YUI. The programmer/designer stuck maintaining the CSS has to write gallons of code. When the programmer making a new layout needs something custom they have no idea how to make that happen so they abandon the framework and use the style tag.

Here again I made the example above very simple. It gets increasingly complex if you want to use more than 2 columns in a layout. There is not enough browser support to make this happen using pseudo-selectors. The :last-child and :nth-child psudo-selectors are in CSS3 but are not supported in any flavor of IE, including IE8. It’s inevitable that more complex layouts will require additional attributes on the columns to mark their indexes. E.g.:

.three-column-150-200-auto first {float:left; width:150px; _margin-right:-3px;}
.three-column-150-200-auto second {float:left; width:200px; _margin-right:-3px;}
.three-column-150-200-auto third {overflow: hidden; _overflow:visible; _zoom:1;}
<div class="three-column-150-200-auto">
	<div class="first"></div>
	<div class="second"></div>
	<div class="third"></div>
</div>

This will lead to a huge CSS file with lots of duplicated code that cant be re-used. Programmers will have to be CSS experts to extend the framework. The long term maintainability of this approach is doubtful. I would say that I prefer this over the first alternative but its still not as optimal as the Attribute CSS approach.

Results

Attached (attribute css.zip) is the re-factored result of all this. It took most of my spare time over the weekend. Its got a test suite based on the OOCSS test pages. All the error detection cases are demonstrated as well as nesting of layout types. The jury is still out on how well this is accepted by the programmers I work with. I think I am on the right track though. Thinking in terms of attributes, providing debugging where appropriate, trying to make names and usage as consistent as possible. The CSS this produces makes sense, promotes css code re-use, captures cross browser bugs and looks maintainable. Nuff respect and thanks goes to Nichole Sullivan for giving me a 90% solution to start with.

This Weeks Flying Forecast

Monday: Heavy rain

Tuesday: Rain moving out and high winds moving in

Wednesday: Winds die down and heavy rain moves in

Thursday: Rain. Chance of nice weather after 6pm

Friday: Gusty winds up to 28mph, chance of rain

Saturday: More of the same

It’s going to be a great week to test fly and trim out an airplane…

Notes on Making Patties

I made a batch of patties and I wanted to capture what I learned so I keep improving the recipe.

First the easy part, the filling. This is the first time I used breadcrumbs in the filling and it really works well. I also put the ground beef through the food processor. Those two things totally nailed the texture of the filling that you get in Cayman. I put the beef in a big pot to cook with the breadcrumbs for an hour. I added enough water to make it easy to stir. The pattie is not some magic device, whatever filling you put in is exactly what you will get out when its done cooking.

My crust still sucks. Its not flaky & crunchy like the Island Taste/Tortuga patties. Its sort of crumbly. I’ve had good patties like that in Cayman, they are just a different style. I think the flaky style takes some additional work like puff pastry. I think you do some rolling and folding with a sheet of butter in the middle and the result is a flaky, crispy crust.

I’ve seen a couple of recipes suggesting the use of Annatto as the coloring in the pastry. All the other ones suggest using curry powder or turmeric (the stuff that makes curry yellow). I’ve noticed that the ones I make with turmeric stain everything they touch neon yellow. That’s not something I ever noticed about the genuine article. Turmeric also adds a subtle but weird flavor and the color never really gets all that red like the real ones. So next time I’ll try to have some Annatto on hand.

iPhone Review

I haven’t had a cell phone worth writing about for two years. My venerable Sony i610 is now history, enter iPhone 2.0. Joel just did his review of the Nokia n71 so I hope there is room for one more geeks perspective on the iPhone.

My last Apple device, a 40GB iPod, was not worth the price of admission. The hard disk failed before I got my moneys worth. With a phone, you just need it to remain reliable for the length of the contract. That’s a minimum requirement. We will see how this device holds up long term.

Size & Feel

It’s larger than my last phone but much thinner. Walking around with the device in my pocket feels more comfortable than the Sony. In my hand it feels too slippery. It could really use some texture around the edges to help the user keep hold of it. I’ll be getting some sort of slip cover to help with this.

It does get a bit warm if you start using the networking or push the CPU.

Keyboard

It’s no computer keyboard but it works well. I’m writing this entire post on the phone. Since it’s slower than a full sized keyboard it may be helping to keep the word count down. I’ve never had a cell phone/PDA with a full keyboard so I can’t compare it to that experience.

The auto correction works well. You can mostly trust it to do the right thing even if you fat finger stuff.

Usability

It rocks. I’ve given the phone to a few people to do simple tasks like take a photo. So far I haven’t had to show them how to do anything.

Battery Life

I was really worried about this because of the reviews I had read. I have used the device now in two very different ‘modes’ with very different battery life results.

First I went to a 4 day conference in Orlando.  This involved traveling for most of the day, using airport and hotel WiFi, G3 data when there was no wifi, push e-mail etc. At the conference I got about 5 hours of screen on time each day before the battery went out. It’s clear that the biggest battery sync is video. You can just watch the bar go down over as little as half an hour. On my 2 1/2 hour flight to Orlando I switched back over to audio to save the battery. If this sounds like your typical usage then you might want to consider another device. If I was going to use the device like this ever single day I would want to double the battery life.

If I use the iPhone like I used my old phone I can go 4 days between charges! The WiFi is left on but does not auto connect. I only use the phone to make a few calls and texts. Most of that time I was in an area with no G3 coverage so that may have helped. 4 days is better than my old phone so I’m pretty happy about that.

Overall I think this works out well for me. The device is powerful and I can use it in when I’m on the road to stay connected. When I’m near a computer (which is most of the time) I can set it to have long battery life. Its a nice trade off, a super powerful device in your pocket when you need it.

Gripes

When an app launches the browser you can’t return to that app from the browser. This is now a common task, send the user off to the Internet. Some mechanism needs to be added to return directly to the app that launched the browser. Twitterific is a great exception to this. The embedded apps need to learn from this.

The contacts interface sucks. I should be able to get to search from anywhere in the contacts list. As it is I have to scroll to the top of the list. In fact. Plus they have a bug where typing shows way down in contacts. The new 2.1 firmware totally fixed this issue. I would still prefer if the search view was the default view for contacts. I rarely scrolled through the contacts on my old phone.

If your using the Phone app and the phone rings, how do you answer it? There needs to be a button that indicates the current or incoming call.

Applications

This is really a mixed bag. Getting the UI right on the phone requires thought. I haven’t found the a todo app yet that I like, I may have to write one. A good note taker app would be nice too. The built in one is trying to be a little too much like paper.

The real kicker is the Remote app. This lets you manipulate iTunes over WiFi in your house! So if your in the garage all you need is some cheap speakers and an Airport Express and you are in business. Finally a good way to get online radio in the house.

Conclusion

It’s not as bad as some have said! Not for the serious 24-7 business user, ideal for more casual users. The 2.1 firmware fixed many issues. Go get one.