:P

On this page:

When it comes to proper usage of CSS and HTML layout, I have to admit I’ve been somewhat slow to get up to speed. Although I’ve been fully aware of what ‘you’re supposed to be doing’ it’s been quite a different story from what I’ve actually been doing. Part of it is that a lot of the apps I work on are based on older code that didn’t pay close attention to CSS based layout and so it’s often hard to retrofit those apps. But slowly and gradually I’ve been drifting more to the ‘recommended’ approach to page layout with CSS isolation to style sheets and as little to no inline styling of any kind and of course have come to realize that this is a much better way to work.

I suspect there are more of you out there who are in the same boat especially if you’re using ASP.NET and Web forms. Web forms with its high level of abstraction doesn’t make it very easy to use pure CSS style layout. Controls have display properties that are just too easy to set on the controls themselves rather than setting them externally in styles and there’s no doubt doing it the right takes some diligence and is more work in the immediacy of creating pages. But there’s also no doubt that proper CSS layout makes it easier to maintain pages later and change the look of them as well as making it easier to reference content via script code.

There are also the ASP.NET CSS Control Adapters but they are a pretty intrusive change and I’ve actually had lots of issues just getting them installed on several machines.However, with a little bit of diligence even some of the badly rendering ASP.NET controls (especially the GridView) can be managed reasonably well with pure CSS layouts.

Those damn browser differences

One thing that I’ve been struggling with for a long time is browser differences even when using the strict XHTML schemas for layout. The XHTML doctypes are the first step for doing consistent layout as they force at least a reasonable baseline on all browsers (particularly IE) and force them to use certain rendering rules. But even with XHTML there are still major differences between different browsers and how they set their default settings for various CSS tags.

For example check out the following layout rendered in several browsers. The area in question is the bottom of the list where the ‘status bar’ sits.

Internet Explorer (nearly perfect fit because at the time it was set up for IE):

FireFox 3:

Safari Windows:

Opera:



Clearly IE creates its elements slightly bigger than the other browsers, but it looks like all 4 browsers are rendering slightly differently in terms of the size of this frame.

The layout for this frame looks like this (I've hardcoded the frame height and width here so it's easier to see where the heights etc are coming from):

< div id ="divListContainer" class ="blackborder" > < div class ="gridheader"> Project List </ div > < div class ="toolbarcontainer"> < small >< a href ="ShowProject.aspx" class ="hoverbutton">< img src ="images/punchin.gif" /> New </ a > | Filter: < select name ="ctl00$Content$lstFilter" onchange ="javascript:setTimeout('__doPostBack(\'ctl00$Content$lstFilter\',\'\')', 0)" id ="ctl00_Content_lstFilter" style =" width : 200px ; "> < option selected ="selected" value ="OpenProjects"> Open Projects </ option > < option value ="RecentProjects"> Recent Projects </ option > < option value ="AllProjects"> All Projects </ option > </ select > | Project Name: < input name ="ctl00$Content$txtNameFilter" type ="text" id ="ctl00_Content_txtNameFilter" style =" width : 75px ; " /> < input type ="submit" name ="ctl00$Content$btnGoFilter" value ="Go" id ="ctl00_Content_btnGoFilter" /> </ small > </ div > < div style =" height : 407px ; overflow : hidden ; overflow-y : scroll ; "> < div class ="itemtemplate" onclick ="showProject(38)" > < div class ="companydisplay">< small >< i > West Wind Technologies </ i ></ small ></ div > < div class ="projimg"></ div > < b >< a href ="ShowProject.aspx?id=38"> Conference Preparations </ a ></ b >< br /> < small > 08/01/07 Started </ small > </ div > < div class ="itemtemplate" onclick ="showProject(50)" > < div class ="companydisplay">< small >< i > Centiv </ i ></ small ></ div > < div class ="projimg"></ div > < b >< a href ="ShowProject.aspx?id=50"> TradeOne Integration </ a ></ b >< br /> < small > 01/24/08 Entered </ small > </ div >

... </ div > < div class ="toolbarcontainer"> < small >< span id ="ctl00_Content_lblStatus"> 11 projects </ span ></ small > </ div > </ div >

The height values are hardcoded so in theory there shouldn't be any discrepancies here, but as you can see the placement is slightly off - as much as 5 pixels between IE and Opera which are at both high and low ends.

Browser Reset to the Rescue

The trick to making this work well across browser is to use a browser reset style sheet. Again this may be old news to some of you, but I’ve been slow to catch on and haven’t been using resets until fairly recently. The above application was built early last year and it doesn’t use a reset.

A browser reset is meant to reset the browser’s CSS setting to a common default value set. Basically each browser has slightly different base settings mostly for margins, padding, borders etc. as well as many other settings that can affect browser rendering slightly and often results in the little inconsistencies like the ones above. The reset effectively is used to reset the browser to a common baseline, upon which any further CSS settings are based.

There are a number of different reset style sheets available. Following are a few links and references to a resets:

The last link compares various versions of resets and explains the differences. It’s a good read to see some of the tradeoff and comparisons.

After reviewing resets some time ago I’ve ended up with a slightly modified version of Eric Meyer’s reset with a few changes that affect default padding and list display. I tend to want some reasonable padding for table cells and expect list to render a certain way by default.

/* BROWSER RESET (based on Eric Meyer's Reset) */ html , body , div , span , applet , object , iframe , table , caption , tbody , tfoot , thead , tr , th , td , del , dfn , em , font , img , ins , kbd , q , s , samp , small , strike , strong , sub , sup , tt , var , h1 , h2 , h3 , h4 , h5 , h6 , p , blockquote , pre , a , abbr , acronym , address , big , cite , code , dl , dt , dd , ol , ul , li , fieldset , form , label , legend { padding : 0px ; margin : 0px ; border : 0px ; outline : 0px ; line-height : normal ; vertical-align : baseline ; font-family : inherit ; font-size : 100% ; } :focus { outline : 0 ; } body { background : white ; line-height : 1 ; color : black ; } ol , ul { list-style : disc ; margin : 20px ; } table { border-collapse : separate ; border-spacing : 0 ; } caption , th , td { font-weight : normal ; /* text-align: inherit; */ padding : 4px ; } blockquote:before , blockquote:after , q:before , q:after { content : "" ; } blockquote , q { quotes : "" "" ; margin : 15px ; } input , select , textarea { font-size : inherit ; font-weight : inherit ; font-style : inherit ; } /* END BROWSER RESET */

With the reset applied before any other styles the above ‘dialog’ renders properly in all browsers from IE to Chrome. Unfortunately just throwing a browser reset into an old applications that where designed with them in mind are also likely to cause a few rendering problems, because the main feature that these resets provide is to effectively remove all padding, margins and borders by default. This will cause things to render consistently but also often may end up producing very different results.

Hence you may have to – as I did at least for older apps – tweak the base Reset a little bit to make certain things render the way you’d assumed they would when the pages were created. The two main areas for me are the table columns render (I assumed a reasonable level of padding between cells), ordered and unordered lists which I assume to have standard list indentation and bullets and also blockquote margins. None of these are major changes but these three bit me most when just throwing in any of the browser resets I tried.

Resuable Stylesheets for most Apps?

Once a base reset exists I tend to use an additional standard style sheet that includes a host of custom styles that deal with common scenarios in ASP.NET style applications from things like gridheaders, alternating rows, dialogcontent, toolbarcontainer etc. that are more application specific but seem to show up just about in any common application.

This is absolutely a personal preference but I thought I’d share this here anyway, because I’ve found this sort of baseline extremely useful in getting layouts – especially for business type applications - done quickly.

body , table , td , th , input , textarea , select { font-family : verdana,sans-serif ; font-size : 10pt ; } pre { font-family : monospace,courier new ; font-weight : normal ; margin-top : 5px ; margin-bottom : 5px ; } h1 { background-color : #eeeeee ; color : navy ; font-size : 1.5em ; font-weight : bold ; padding : 5px ; text-align : center ; margin-bottom : 15px ; } h2 { color : maroon ; font-size : 1.4em ; font-weight : bold ; } h3 { color : steelblue ; font-size : 1.1em ; font-weight : bold ; } table.blackborder>tbody td { border : solid 1px lightgrey ; } th { border-collapse : collapse ; font-weight : bold ; text-align : center ; } a { color : #003399 ; } a:visited { color : darkred ; } a:hover { color : red ;} hr { color : navy ; background : navy ; border : 0 ; height : 1px ;} ul { margin-bottom : 0px ; margin-top : 2px ; padding-bottom : 2px ; padding-top : 2px ; } li { padding-top : 2px ; padding-bottom : 0px ; } img { border : 0px ; } .blackborder { border-style : solid ; border-width : 2px ; border-color : #003399 ; background : white ; text-align : left ; } p { margin : 10px 0px 10px 0px ; } small { font-size : 0.8em ; font-weight : normal ; } .bigtext { font-size : 1.8em ; font-weight : bold ; color : navy ; } /* block backgrounds for headers etc. */ .menuband , .gridheader , .gridheaderbig , .gridpager , .buttonlinks , .blockheader , .roundedbar_top , .roundedbar_bottom { color : cornsilk ; background-color : #003399 ; padding : 0px ; } /* alternate background color color to offset the background used for the category list and banner strips for color variety. should be a companion color to the block background colors (previous tag */ .alternatebackground { color : white ; background-color : #0066cc ; } /* used for any block tags like headers on tables etc. */ .blockheader { font-weight : bold ; } .menucolumn { padding : 5px ; border-bottom : solid 1px white ; } .menulink { color : white ; font-size : 0.8em ; font-weight : normal ; text-decoration : none ; display : block ; text-align : left ; padding-top : 3px ; padding-bottom : 3px ; padding-left : 5px ; border : solid 1px transparent ; } .menulink:visited { color : cornsilk ; } .menulink:hover { color : #003399 ; text-decoration : none ; font-weight : normal ; background : white url('images/menuhighlight.png') repeat-x ; } .menuband { font-weight : bold ; height : 20px ; padding-top : 5px ; text-align : center ; background : url('images/vertgradient.png') ; } .menulinkcontainer { padding : 5px ; } .submitbutton { border-style : none ; border-color : inherit ; border-width : 0px ; font-weight : bold ; height : 35px ; width : 200px ; background : url('images/submitbutton.gif') ; color : lemonchiffon ; } .submitbutton:hover { background : url('images/submitbuttonhover.gif') ; } .submitbutton:active { background : url('images/submitbuttonpressed.gif') ; } .smallbutton { border-style : none ; border-color : inherit ; border-width : 0px ; height : 22px ; width : 90px ; font-size : 0.8em ; color : navy ; background : url('images/smallbutton.gif') ; } .smallbutton:hover { background : url('images/smallbuttonhover.gif') ; } .smallbutton:active { background : url('images/smallbuttonpressed.gif') ; } .gridheader , .gridheaderbig , .gridheaderleft , .gridheaderright , .gridpager { padding : 4px ; background : #003399 url('images/vertgradient.gif') repeat-x 50% bottom ; text-align : center ; font-weight : bold ; text-decoration : none ; } .gridheader a , .gridheaderbig a { color : cornsilk ; text-decoration : none ; } .gridheaderleft { text-align : left ; } .gridheaderright { text-align : right ; } .gridheaderbig { background-image : url('images/vertgradient40.png') ; background-repeat : repeat-x ; background-position : 50% bottom ; } .gridnormal { background-color : #eeeeee ; } .gridalternate { background-color : #b5c7d6 ; } .gridhighlight { background-color : white ; background-image : url(images/lightorangegradient.png) ; background-repeat : repeat-x ; cursor : pointer ; border : solid 2px orange ; } .gridpager { font-weight : bold ; text-align : right ; color : White ; text-decoration : none ; } .gridpagerselectedpage { color : khaki ; font-size : 1.1em ; font-weight : bold ; } .gridpagerpage { text-decoration : none ; color : White ; } .groupheader { background : SteelBlue ; color : White ; padding : 4px ; margin-top : 10px ; margin-bottom : 5px ; font-weight : bold ; } .errormessage { font-weight : bold ; color : maroon ; } .errordisplay { font-weight : normal ; color : darkred ; border : solid 2px darkred ; background-color : cornsilk ; padding : 4px 5px 4px 10px ; line-height : 1.5em ; margin : 15px 0px 15px 0px ; } .errordisplay hr { color : darkred ; } .dialogwindow { margin : 0px ; background : #eeeeee ; font-size : 0.8em ; } .toolbarcontainer { background : #eeeeee ; border : solid 1px silver ; vertical-align : top ; padding : 5px ; } .hoverbutton { text-decoration : none ; padding : 2px ; font-size : 0.8em ; border : solid 1px transparent ; } .hoverbutton:hover { background : white url('images/menuhighlight.png') ; border : solid 1px silver ; } .hoverbutton a { text-decoration : none ; } .tabbutton , .selectedtabbutton { border-style : none ; border-color : inherit ; border-width : 0px ; font-size : 0.8em; background : url('images/tabnormal.gif') no-repeat ; text-align : center ; vertical-align : middle ; cursor : hand ; color : darkblue ; width : 120px ; margin : 0px ; padding : 0px ; } .tabbutton:hover { background : url('images/tabhover.gif') no-repeat ; } .selectedtabbutton { font-weight : bold ; color : white ; background : url('images/tabselected.gif') no-repeat ; cursor : default ; } .roundedbar_top { height : 20px ; width : 170px ; padding : 5px 0px 0px 0px ; font-weight : bold ; text-align : center ; background : url('images/roundedbar_top.png') no-repeat ; font-size : 1em ; } .roundedbar_bottom { height : 12px ; width : 170px ; background : url('images/roundedbar_bottom.png') no-repeat ; } .containercontent { padding : 20px ; } legend { text-align : center ; font-weight : bold ; background : #DE8079 ; color : White ; padding : 3px ; border : solid 1px darkred ; } fieldset { border : solid 1px silver ; margin-bottom : 15px ; } .fieldsetpadding { padding : 15px ; } input[type=text] , input[type=password] , textarea , select { border : solid 1px steelblue ; border-style : inset ; font-size : 1em ; background-color : #F5F7FA ; } input[type=button] , input[type=submit] { } .statusbar { position : fixed ; bottom : 5px ; left : 0px ; right : 0px ; height : 16px ; padding : 5px ; background : black ; color : white ; border : solid 1px lightgray ; opacity : .70 ; filter : alpha(opacity="70") ; z-index : 200 ; overflow : hidden ; overflow-y : auto ; } .statusbarhighlight { font-weight : bold ; background-color : khaki ; color : Maroon ; border : solid 1px silver ; } .statusbarclose { position : absolute ; right : 10px ; top : 2px ; color : red ; font-size : 1.2em ; font-weight : bold ; cursor : pointer ; }

The styles above cover a wide range of ‘control like’ scenarios that seem to be common in the business applications I tend to build or work with. For more document driven application or consumer style applications some of these things probably aren’t a good fit, but for most of the things I work on most of these styles actually are used regularly. The point isn’t so much the exact details of the items but the concept of having a style sheet that provides reusability for common UI scenarios.

Again I don’t claim to be a CSS expert – I’m mainly throwing this out here for discussion because I’m interested in what others are doing. What are you doing for ‘standard’ styling in your applications? What browser resets have you tried and which one are working for you? Do you have a standard style sheet with your own custom styles that you reuse in many applications and what do you put in there? What are your reusable styling scenarios. Reusability of base style sheets is something I don’t see discussed much, so I’d be interested to hear what other approaches are used.