Do Complex User Interface Modules Necessitate Complex CSS?
CSS, or Cascading Stylesheets, are one of the best things to have ever happened web development. They provide a very clean, elegant way to style your interfaces without having to muckup your actual markup. CSS is so intuitive, in fact, that I have applied it to completely separate domains, such as styling Excel documents in my POI library. With the elegance of CSS, I think there is, at least from my own personal point of view, a belief that the CSS itself should be simple. That, combined with all the buzz about "semantic" markup, and I easily get the feeling that I should be able to thoroughly style my user interfaces with raw HTML plus a few choice classes.
Lately, however, I have been really struggling to refactor some Javascript-powered interfaces and it's got me thinking about CSS. I've started to wonder if the concept of "simple" really has anything to do with "CSS"? I've tried to adopt an OO-CSS (Object-Oriented CSS) mentality, which attempts to view interface modules like "OO" classes which can then be sub-classed. But, we all know that "OO" is not "simple" - if it were, I'd be an OO-master, which I clearly am not.
So, maybe, CSS doesn't imply simplicity. Sure, it can be simple (and often is); but, what I'm starting to believe is that complex layouts actually necessitate more complex CSS. To give you a little context on where I am coming from, one of the modules that I have been working on refactoring is a data table. In my software, my data tables can range from very simple to very complex, complete with AJAX-powered, DHTML drill-downs with nested data-tables. Here is a rough graphical idea of what I am talking about:
|
|
|
||
|
|
|||
|
|
|
In these mock-ups, going from a simple data table to a "mini" data table seems like a straightforward sub-classing; the mini data table would just update the styles for things like padding and font-size. But, going to a complex table with dynamic drill-downs and we now have not only a more complex interface but a radically different markup; with a complex data grid, I actually use separate TBODY elements for each unit consisting of a row "summary" and a row "drill down". Furthermore, the drill down may contain nested TABLE elements.
This is very complex for my amateur CSS architecting mind. This opens up all kinds of issues with cascading styles; even with the concept of sub-classing, I think it's important to think about overriding meaningful styles and not simply applying resets at the nested level. For example, let's say I have a generic, base rule for TD on simple tables:
table.data-grid tbody td {}
... this has a completely different intent in a simple data grid (where one TBODY element in used) than it does in a complex data grid (where multiple TBODY elements are used). Furthermore, if we have a complex data grid, the above rule will not only apply to the closest descendent TDs, but also to the potentially nested data tables, which, in turn, might be sub-classed.
Like I said, this UI is complex; but, this is all to say that I am starting to believe that it's OK to have complex CSS with explicit classes favored over contextual styles IF that is what the markup requires for long-term stability and flexibility.
I know this was more of a rant than anything else; but, I'm really just looking for some feedback and pointers. Any comments would be appreciated.
NOTE: I still need to support IE6.... unfortunately.
Reader Comments
NOTE: "simple", "mini", and "complex" aren't my class names, per say; they are just meant to imply that different class names would be used. I'm still trying to figure out what they would be called.
Also, not that jQuery UI is the end-all, be-all of CSS frameworks; but, if you look at how they markup the DOM, they add numerous classes. I don't view this in a negative way at all - it gets the job done effectively.
This is where you think globally but act locally. If you have a layout that you know will have nested layout sections you have to really think about and plan your class/ID structure. Use a global class which only carries the styles that won't clash with child structures in addition to a more semantic/relevant class/ID that you can target for specific declarations/overrides. It can feel wonky at times, but that's where the cascade and levels of specificity come in. Sometimes it's a matter of carefully crafting which element gets the class so that you're not declaring styles in too global a way that you're forced to override later on a child structure.
@Michael,
That's exactly where I am right now in my refactoring. I've fumbled my way through enough use cases to get a good sense of the full(ish) range of the UI elements that I am dealing with. Now, I'm trying to figure out what they have in common and what the sub-classing should be and how it should best be applied.
It's certainly not easy :)
The words Nested and Nasty are close in appearance for good reason. They even sound alike if you try. I've done battle with nested tables + CSS on more than one occasion (*cough*SharePoint*cough*). I want to comment more on this later, but for now I'll say that styling possibly nested items is indeed an art with CSS, and it takes a fine attention to detail to get it just right. You also have to keep those pesky IE6 differences in mind when you're trying to get cute with descendants, etc.
@Aaron,
Yeah, if I could use the direct descendant ">" selector, then things would be a bit different. But, I am working on a system where IE6 is still a requirement. I've looked at that IE7 plugin stuff, but apparently it doesn't play well with AJAX stuff (loaded after the DOM is ready).
Yes, I think that complex UI modules necessitate complex CSS. The CSS can be straightforward from the perspective of someone who understands the application, but I don't think you can arrange it so that the CSS file or include is short, particularly not if you want the UI to look reasonable in older browsers. (And as for IE 6 ... it might almost be easier to have two completely separate style sheets, one for normal browsers and one for IE 6.)
Think about your table. Even the simplest data table should have at least two formats: numeric and not-purely-numeric data, usually meaning left- and right-justified data. If you want it to look good, though, you'll probably want to add center justification, probably decimal, and maybe additional currency formats if you display money. (Look at the options Excel offers.) A localized application would need additional options.
Depending on what else you are doing with the tables, you could have a whole range of formats: standard (left/right/center/decimal/currency/currency-with-separator), selected, marked for deletion, maybe drag-and-drop ... is that a lot of styles? Yes, but that's what styles are supposed to do: save you the trouble of writing a massive switch-case statement.
As long as you organize the style sheet well, it should be clear enough that someone else can follow what you're doing (like you, in a few months after you've touched other projects). It's not simple, but then they don't tend to pay us for simple projects, do they?
table.data-grid tbody td {}
is very "global" in it's scope, since it declares that any TDs inside a TBODY inside TABLE.data-grid will get whatever styles are declared.
If you could class the TBODY, you could then do something like:
table.data-grid tbody.primary-grid > td {}
targeting just the child elements, but you said you also need to support IE6 so that won't work.
You could also try classing the primary (outermost) TD so that the styles don't cascade.
table.data-grid tbody td.primary-cell {}
Other than that, what you're left with is overriding all the inherited styles on the nested structures. (not fun)
Two ways to go about that. you either do:
table.data-grid tbody td {}
table.data-grid tbody td td {} // overrides + specific styles
or you try to subclass the nested structure to give you added specificity:
table.data-grid tbody td {}
table.data-grid tbody td .subdata-grid td {}
No way around that.
@Dave,
Sometimes, I wish I got paid for simple stuff ;) Oh well, who am I kidding - as much as this can be frustrating, I love it.
@Michael,
What I am experimenting with now is going the much-less contextual route and using more explicit styling on key elements. This way, I can using the sub-classing off of the root element, but I won't have to rely on context of the embedded elements.
... we'll see how long this road lasts.
@Ben,
If there was nothing to figure out, we wouldn't enjoy this stuff. It takes a special mindset to enjoy it, but I wear it like my own little gold star anyway.
The more I work on mobile Webkit applications, the more I realize how much non-compliant browsers hold us back from answering these questions the right way. CSS3 includes a bevy of features that address exactly the issues you're grappling with, as another commenter mentions. As long as we're stuck supporting antiquated browsers, I fear your assessment -- that complex interfaces demand complex CSS -- will continue to be accurate.
Woohoo! Rebecca "YayQuery" Murphey commented on my blog... sweeeet.
@Rebecca,
I agree with what you're saying. Better CSS support would quickly alleviate a number of these concerns.
Fortunately, in one of my projects that I'm working on, I won't be supporting IE6. Especially as this is being started from scratch, and IE6 is being EOLed by Microsoft sometime in the middle of 2010 . . .
@Lola,
I can't wait to stop working with IE6. I'm so glad that some of the "big guys" have already stopped supporting it. It makes it easier for the rest of us to make such decisions.
I remember how great life was when we decided to stop supporting Netscape :)
@Ben
It appears from your comments that Javascript is an acceptable requirement on the site. Have you considered using child selectors in your CSS and then for IE 6 having a conditional comment script block that injects the styles using matching jQuery selectors and css method? Not the most performant option for IE6 users, but your "support" them while not degrading the experience for everyone else, or your sanity.
@lola
IE6 will be supported for many years to come. Windows 2000 is being retired in July, at which point every supported version of Windows has an upgrade path from IE6. (Although in my experience there are more XP IE6 users than Windows 2000.)
@zestmonkey,
See this page: http://support.microsoft.com/gp/lifesupsps/#Internet_Explorer
@lola
They certainly don't make it easy to understand.
http://support.microsoft.com/gp/lifesupsps/#Windows says that Windows XP Service Pack 3 was released 21-Apr-2008. http://support.microsoft.com/?pr=lifecycle says "5 years Mainstream Support at the supported service pack level for Consumer/Hardware/Multimedia products"
That takes support for XP SP3 to 20-Apr-2013. Since Windows XP service packs will always ship with IE6, 2013 is the current eol for IE6, but another service pack for XP will extend that.
The link you provide has a "Service Pack Retired" of "Not Applicable See Note". That should just be "See Note" as it is on Windows LSS link above.
Unless I'm missing something, that seems to be the generally accepted interpretation of the mess that is MS support policies.
BTW: the dates on those pages don't add up, but I suspect there's differences between initial availability and general availability at play. Since SP2 should be retired 24 months after SP3 was released, but 21-Apr-2008 + 24 months is not 13-Jul-2010.
I sry for the comment in your thread, but I couldn't find anything else where I thought it might could suit.
Ehm I hope you or everybody else can help me.
I have a formular - form and in these form ive included a selct with option. I also dont know if its possible to post a html code in your comments.
But back to my question:
I want to change the background-color from the select option e.g.
in html:
select name="bland" id="bland"
option a /option
option b /option
etc.
in css:
#bland
{
background-color: black;
color: green;
}
But nothing happen, can someone give me an hint or a solution?
Thx ahead!
@zestmonkey,
I have thought about using Javascript to "make up" for the lack of CSS selectors; but, I have not tried it yet. It's a hard thing for me to wrap my head around. If I'm gonna use Javascript to make up some CSS, then should it just do that for all browsers? Or do I have to worry now about only using that approach for only certain browsers?
It's definitely something that I have thought about, but have not been sure quite how to approach it.
@Lars,
I don't think you can change the background color of the SELECT itself - you need to change the background color of the OPTION elements.
#bland option
{
background-color: black;
color: green;
}
It would be possible to use the js implementation for all browsers. The two main considerations are that there may be people with javascript turned off; and the javascript will take longer to parse than the js, so it's possible to see the wrong styles and watch them be replaced as the js loads. Not the best situation, so I'd recommend leaving that experience to those who don't embrace modern browsers.
Here's a very rough example. Missing headers, etc and you'd probably want to put the css and js in external files, but hopefully this explains the concept.
<style>
li {color:green;font-weight:normal;}
.toplist > li {color:red;font-weight:bold;}
</style>
<!--[if lte IE 6]>
<script>
$(document).ready(function(){
$(".toplist > li")
.css("color", "red")
.css("font-weight", "bold");
});
</script>
<![endif]-->
<ul class="toplist">
<li>some text</li>
<li>
more text
<ul><li>sublist</li><ul>
</li>
</ul>
As you can see, it's just a matter of adding a few extra characters to the definitions and away you go.
If you're adding elements to the dom that will need to be styled then you'll want to put the style js in a function and call that after adding the elements, but for general styling, the above code should suffice.
@zestmonkey,
I see what you're saying. I think it makes sense on a small scale; but my fear is that when your modules get more complex and start to get sub-classed, duplicating styles in CSS and in Javascript might just get too complicated to maintain.
@Ben
For me, I think I would spend more time creating constructs to get around the use of less commonly supposed (lcs) selectors than I would searching through the css files and making sure those selectors are represented in a separate js file.
Knowing the proper use of selectors and this trick should enable your design to work everywhere. Otherwise you need to know the intricacies of every rendering engine and how to combine those all to make a working site.
An additional benefit is that once support for IE? is no longer a requirement then the additional js file can be deleted and you're left with a nice standard layout.
I haven't had to create any designs that heavily relied on lcs selectors, but I have used jQuery and the altered definition of "support" that goes along with the site http://dowebsitesneedtolookexactlythesameineverybrowser.com/ to simplify things greatly.
Anyway, thanks for your contributions to the web dev community, I'm an avid reader.
@Ben.
Ah! Okay, thanks.
Yeah I test it and thanks it works.
But I also have a question.
Do you know where I can set the background-color and color at the start-valued?
thx Lars.
@Ben,
http://dean.edwards.name/IE7/
Ehm,
does someone also know, where I can position a free text in the header?
div id="head"
this is my text!
/div
maybe with marign, like?
#head{
margin: xpx; ?
}
thx Lars!
@Zestmonkey,
Yeah, you make a good point. I tend to overthink things a bit; I wish I could just stop using IE6 - then my life would be better.
@Lars,
I am not sure what you mean by "start-value"?