Monday, June 08, 2009

CSS for C# Developers: You should learn CSS

When I read Rob Conery's post about I suppose I'll just say it: You should learn ASP.NET MVC, it resonated strongly with me: the bloated abstraction of WebForms has placated developers into thinking they don't need to know HTML to build web applications.  We've spent the better half of this decade blissfully ignorant using server-side technology to "shoehorn" client-side concepts, and we (the asp.net developer) have been negligent on staying on top of the revolution that has been quietly happening client-side.

Thankfully, Microsoft's recent formal inclusion of jQuery for the ASP.NET MVC project has got developers discovering how powerful jQuery and client-side development can be, and that excitement is changing the way developers think about developing for the web.  I believe there's a new renaissance coming, one that isn't based on the bloated server-centric model of WebForms, but rather a new breed of sites with lean, semantic markup and rich client-side interactivity using JavaScript fuelled AJAX. Or at least, one can hope.

With all the attention client-side scripting is getting, there's never been a better time to learn CSS.  (If you're going to develop for the web, why not go all in?)  Until recently, I never did much user-interface development, but after a few short UI-centric projects I'm personally climbing onto the soapbox to challenge backend developers to drop their "I don't do pretty" attitude and learn this important skill.

So if you’ve secretly wanted to learn CSS but didn’t have a good reference point, this is my attempt at providing a crash course:

The basics

If you’re generally familiar with the basic concepts behind CSS, you can skip ahead, but no harm will come to you read it.

CSS Selectors

As developers, we love to think of the browser’s Document Object Model (DOM) as an object graph with pretty collections of childNodes and attributes that we can programmatically manipulate using imperative code instructions.  While this concept translates really well into technologies like XPath, it doesn’t fit CSS selectors so literally.  The syntax (is exactly the same syntax jQuery uses) is actually very straight-forward, and focuses primarily on all nodes of a specific criteria rather than targeting specific child nodes.

Type Selectors

Styles can be applied to all elements of a particular Type (or TagName):

/* single type (all h1 tags) */
h1 {
   color: blue;
}

/* multiple types (all h1, h2, and h3 tags) */
h1, h2, h3 {
   color: blue;
}
Id Selectors

The hash/pound/number symbol (#) is used as a selector to elements with a specific “id” attribute.  Note: This approach should only be applied to controls without the “runat=server” attribute since ASP.NET server-controls dynamically generate their IDs.

<style>
#title {
   color: blue;
}
</style>
<h1 id="title">Foo Heading</h1>
Class Selectors

Obviously, the more appropriate technique would be to assign the element a “class”, which in ASP.NET translates to our CssClass for most WebControls (otherwise you have to access this value through the Attribute collection under the appropriately named “class” key).  Note that the “class” is not tied to a specific type, and can be reused on other elements:

<style>
.title {
    color: blue;
}
</style>
<h1 class="title">Blue Heading</h1>
<p class="title">Blue paragraph</p>
Combine selectors to be specific

You can also get specific and limit the scope of a selector to a particular tag, by prefacing the selector with the tag name.  Note there is no space between the tag and class:

<style>
h1.title {
   color: blue;
}
p#description {
   color: green;
}
</style>
<h1 class="title">Blue Heading</h1>
<p id="description">Green Paragraph</p>
Child Selectors

You can also refer to child elements, which affords us the ability to provide additional formatting without having to modify our markup.

<style>
// all li elements under a ul with a "menu" class
ul.menu li {
   list-style-type: none;
   display: inline;
}
</style>
<ul class="menu">
   <li>inline 1</li>
   <li>inline 2</li>
   <li>inline 3</li>
</ul>
Applying multiple class selectors

Another important (and not well known) thing to point out is that you can have multiple class names for a single element, which can reduce duplication:

<style>
a.navLink {
   text-decoration: underline;
   color: red;
}
.selected {
   font-weight: bold;
}
</style>
<ul>
   <li><a class="navLink" href="#">one</a></li>
   <li><a class="navLink selected" href="#">two</a></li>
   <li><a class="navLink href="#">three</a></li>
</ul>

There are a few more selectors I haven’t covered here, but you can more details and tutorials here:

Inheritance in CSS

From a pure developer perspective, inheritance in CSS is similar to inheriting classes:

  • all tags derive from a common ancestor
  • each Type (tag) has their own set of default properties.  (Each browser has a default style sheet that is loaded automatically)
  • each node inherits properties defined from its parent

However, CSS inheritance deviates from this analogy as properties are merged in combination from multiple sources (wildcard, class, id and type selectors), somewhat like multiple inheritance:

  • a node’s properties are overridden as selectors are matched, from least specific to exact matches.
  • style sheet documents are processed from top to bottom, and in order of appearance in the source HTML

While this sounds complicated and difficult to troubleshoot, tools like FireBug and Internet Explorer Developer Toolbar have made this a trivial task.  My deepest respect goes to the user-interface developers who painfully slugged this stuff out manually only a few years ago.

A simple inheritance example:

<style>
body {
   background: #fefef2; /* eggshell */
}
h1 {
   text-decoration: underline;
   background: #ffffff; /* white */
}
.title {
   color: #0000ff; /* blue */
}
</style>

<!-- titleeffective style applied after inheritance:
{
   text-decoration: underline; /* from h1 */
   background: #ffffff; /* from h1 */
   color: #0000ff; /* from .title */
}
-->
<h1 class="title">Underlined blue title with white background</h1>

Note that the only way to prevent inheriting settings from a parent node is to explicitly supply a value for the property.

<style>
body {
   background: #fefef2;
}
h1 {
  text-decoration: underline;
  background: #ffffff;
}
.title {
  text-decoration: none;
  background: #fef2f2;
  color: #0000ff;
}
</style>
<!-- effective style applied after inheritance:
{
   text-decoration: none; /* back to the default */
   background: #fef2f2; /* back to the default */
   color: #0000ff; /* new value */
}
-->
<h1 class="title">Blue title with eggshell color</h1>

DocType matters

Much like setting the content-type of a Response in ASP.NET so that the browser will understand what the content is, the DocType is a crude processing instruction at the top of the document that instructs the browser how they should process the markup.  Without this instruction, most browsers will assume the content is ancient and they will use the oldest rendering engine available.

As to which doctype you should use, it largely depends on the markup you have, but you should strive for the most compliant possible.

A List Apart has one of the best references on this topic.

The Box Model

The Box Model is another core concept of CSS.  All elements are contained in their own box and have margins, borders and padding.

Commit to memory: Margin, Border, Padding, Content.

  • The margin is the amount of space reserved as buffer between elements.  The margin is always transparent.
  • The border appears between the margin and the padding.  It has many different styling options.
  • Padding separates your border from your content.  It takes up visual space and is the color specified by the background – if you want your element to be larger or have more color, padding is what you want.

Commit to memory: Top, Right, Bottom, Left

When specifying values for padding, margins or border widths CSS provides two approaches.  Either declare each value separately (border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px) or inline as one statement in clockwise order starting at top (border: 0px 0px 0px 0px;).  This comes up frequently, so memorize now and thank me later.

Also note that there’s a shortcut for the shorthand, where top & bottom and left & right are the same values (border: 0px 0px;).

Fonts

Fonts can be tricky, and I tend to lean on the graphic designer to pick the typography for the site.  From a development perspective, although you can choose any font it must be available on the user’s machine, and only a few fonts are truly available across operating systems.  A great reference of browser surveys can be found here: http://www.codestyle.org/css/font-family/index.shtml

From a CSS perspective, you can supply a number of different fonts in comma-delimited format, and the browser will apply the first match from left to right.  Outside of actual Fonts, there are five generic fonts which all browsers implement.

Keep in mind that there is much debate on whether you should specify fonts in “em”, “pt”, “px” or “%” for font-sizes.  I won’t settle that debate here.

Digging Deeper

Congrats on reading thus far, if you skipped ahead, no cookie for you.

Pseudo Selectors

While pseudo selectors are bordering on advanced topics, a crash course in CSS would be incomplete without mention of some pretty important CSS selectors:  a:link, a:visited, a:active, a:hover.  These are special selectors that can be applied to anchor tags for their various states.  The first two (“:link” and “:visited”) allow you to specify the style of the anchor tag based on the user’s history; the latter refer to user actions with the hyperlinks.  The “:active” selector is applied the user is clicking on the hyperlink; the “:hover” selector is applied when the user moves the mouse over the anchor.

Astute developers pick up that “:hover” allows you to define styles that would normally be applied using “onmouseover” and “onmouseout” events using JavaScript.  One of my favorite applications of the “:hover” tag is to change the background image of an element when the user hovers over it.  With some extra effort, you can change the relative position of the background image to achieve a “sprite” effect.

Some trivia: there is no equivalent of these selectors as an inline style attribute, they can only be defined in a style block or style sheet.  Also, the “:hover” tag can be applied to other tags, but only anchor tags are supported in IE 6.

Background Images on Elements

CSS provides the ability to set the background property of an element to point to an image, which is major shift from standard HTML.  By moving our images from the markup into the CSS, we not only reduce the amount of markup required, but we separate presentation from content.  This technique is essential for creating impressive effects, such as drop shadows and nifty borders.

The syntax:

/*
element {
   background: color url(path) repeat attachment position
} */

div {
   background: transparent url(../images/bg.png) repeat-y fixed 0 0
}

By specifying the repeat value of an image, your image only needs to be a few pixels in size.  In addition, you can specify an offset in pixels to have the image indented.

Few key takeaways:

  • The path of the image is resolved from the location of the css file, not the requested page.
  • Remember to set “no-repeat” if you only want the image to appear once.
  • When adding background image to an element, the image size is not taken into consideration.  If you want more of the image to be displayed, adjust the padding of the element to suit.

Not everything is a div, dummy

The div tag is one of the most popular tags in XHTML/CSS as it's used to create logical sections for your layout.  While divs are preferred over tables, using divs exclusively to represent content isn't necessarily a good thing.  If you've fallen into this trap or have trouble knowing when you should use a div versus a span, I'm going to break you out of a bad habit by demystifying what the div tag is by looking at the how it's described by most browser's default style sheet:

div { 
    display: block; 
} 

That's it!  So maybe it would help us to understand what "display" does?

There are a bunch of settings for "display", but the short list is: "none", "block", and "inline".  Setting display to "none" basically means that the content won't take up any layout space and is thus invisible.  Elements with display set to "block" are considered a chunk of content that has a line break before and after, whereas "inline" means it's part of the content.  It's best described by looking at the default's for some tags:

Tag Display Default
body block
h1,h2,h3,h4 block
p block
div block
ul, li block
bold, strong inline
italic, em inline
a inline
span inline

A great breakdown of “display” and how it’s used, including support for all modern browsers, is available here.

If what you really need is a container for some content, P and UL are great substitutes.  You’ll be surprised at how quickly your content begins to look less like div-soup and more like xml.

<!-- before -->
<div id="contacts">
  <div class="person">
     <div class="details">
          <b>Person Name</b><br/>
          <i>555-1234</i>
     </div>
  </div>
</div>

<!-- after -->
<ul id="contacts">
   <li class="person">
        <h3>Person Name</h3>
        <ul class="details">
             <li class="phone">555-1234</li>
        </ul>
   </li>
</ul>

Start with a clean slate

Working with CSS can get tricky, especially managing the complexity of your style sheets to support multiple browsers.  One of the best approaches to minimize this complexity is to override the default settings for all elements to a minimalist state, and then slowly build up your styles to suit your needs.  This approach reduces duplication and helps ensure that your settings aren't inconsistent between browsers.

Here's a quick example that removes the padding and margin for all elements, and turns off the legacy blue-border around the image tag:

// remove all margins and padding from all elements
* { 
margin: 0; 
padding: 0; 
} 

// remove legacy border around images
img { 
    border: none; 
} 

Here are a few great starting points for a clean slate:

Floating

Using "floating" to position elements can be tricky, and there are certainly a few tricks to make it work for all browsers (I'm looking at you Internet Explorer 6), but mastering it means you'll never need to use tables to layout your content again.  Or at least, only use tables when representing data.

At a very high level, when an element has a float applied to it, it is no longer part of the normal flow of the document.  An element with a “float:left;” will float to the left until it meets the left edge of it’s containing block; likewise a “float:right;” implies the element will nestle up to the right of it’s container.  Floating can be turned off by setting a “float:none;” to the next element.

The secret to getting floating to work is ensuring that the element being floated has a width explicitly defined.  Likewise, setting a width to the parent element that contains the floating element solves many problems.

Still, as developers, we know from experience that this is a major cross-browser problem and it’s likely the principle reason why we leave CSS to the experts.  Truth is, every browser except Internet Explorer got the Box Model right, and the fix is shockingly simple: floating problems in Internet Explorer 6 are generally solved by ensuring that the floated element (in IE’s terms) “has a layout specified”.  In most cases, specifying “display:inline;” works:

.container
{
      float: left;
      display: inline;
}

A great reference on float theory can be found here: http://www.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/

Static, Relative and Absolute Positioning

A close relative to floating is the concept of “absolute and relative positioning”.  Personally, I’ve always felt that absolute position was a last resort when compared to using floats, but in concept may be easier to understand.

Since “static” is the default behavior for content, the real work is understanding that “absolute” and “relative” provide meaning to the css properties “top”, “left”, “right” and “bottom”.

When an element uses “absolute” for it’s positioning, the “top” and “left” properties can be used to position the element anywhere in the document, where (0,0) represents the top, left-hand corner of the document.

When an element uses “relative” positioning, the “top” and “left” properties indicate where the element appears in relation to the element that came before it.

And here’s the magic: if an element inside a “relative” positioned element specifies an “absolute” position, the “top” and “left” properties can be used to position the element anywhere within the containing element where (0,0) represents the top, left-hand corner of the relatively positioned element.

A great tutorial on positioning can be found here:  http://www.barelyfitz.com/screencast/html-training/css/positioning/

Don't trust your eyes

While the Internet Explorer 8 Developer Toolbar is considerably better than previous versions, FireBug, the popular addin for FireFox, is still the king.  Aside from being able to hack the CSS values in real time, one of the most useful features that FireBug provides is that it can highlight the contents of an element as you move your mouse over them.  The highlighted area, which uses different colours to represent padding versus margins, shows how the browser has reserved space for the visual element.  I've discovered there are times where FireFox renders the content correctly, but the overlaid highlight for margins and padding doesn't exactly match the visual appearance.  From my own experience, I've discovered that these discrepancies are often more apparent in other browsers.  If you can get FireBug's visual overlay to match the desired visual, you're less likely to have issues in other browsers.

The following example shows how FireBug highlights a paragraph with a width greater than it’s parent.

<style>
div {
  float: left;
  width: 300px;
}
p {
  width: 350px; /* bigger than parent! */
}
</style>

FireBug-Highlight

Learn Paint.NET

Lastly, while not a CSS tip, it would be an injustice to think that you as the developer are not capable of cutting and resizing images.  Let the graphic designer be responsible for producing the content, but as a developer you need to learn be independent and cut up the image yourself if needed.

Paint.NET is awesome, and when compared to Photoshop or GIMP, it's as easy to use as ms paint.  There are lots of tutorials online that hold your hand from start to finish on creating some impressive graphics.

Conclusion

Thanks for reading.  If you’re a backend developer who’s never spent any time in the user-interface, I hope this has help shine a light for you, please send me some feedback.  If you’re a front-end developer and I’m completely off my rocker, feedback is also appreciated.

Cheers.

No comments:

Post a Comment