Using CSS Selectors
Over the last year I have been spending a lot of time re-learning how to use CSS. Since ASP.NET was released the use of Web Controls had made me CSS and HTML ignorant. With the advent of ASP.NET MVC and jQuery combined with the increasing demand for richer user experiences I knew I had to tackle this deficiency immediately. Hence my adventure into my Thin ASP.NET series. It took me a while because I just did not understand how CSS selectors actually work. When I started using jQuery it finally popped for me and I really started to get it. There are three fundamental CSS selectors that just about anyone that has done any web work understands, type, class and DOM Id.
The Type Selector
This should be the most obvious selector because it sets the default rule to be followed for the specified element (I really call them element selectors, but that is not technically correct, they are Type selectors). For example the following rule designates the text contained within a <P> element will be the size of the containing element's font size definition and the text's color will be black.
P{font-size
:1em;
color
:#000;
}
This is a good start. Today, sites that follow CSS best practices define a CSS Reset in the top of the file. Basically this is a set of rules that define the default layout behavior of those elements in the page. The driving reason behind this technique is to take control over the default rendering rules from the browser, hence eliminating many of the frustrating differences between browsers. Personally I have decided to adopt the YUI CSS Reset from Yahoo as my default reset, but there are many others available and of course you can define your own.
The Class Selector
This rule defines a CSS rule for any element that defines the class be applied. I see this technique almost abused at times by ASP.NET developers as we desperately try to overcome deficient ASP.NET control rendering. Like the previous example I can define a CSS class to enforce the same rendering logic:
.defaultText
{font-size
:1em;
color
:#000;
}
A CSS class is defined with a '.' prefix and can be named anything you want. To apply this rule to any HTML element all you need to do is include the class attribute and set it equal to the class name. Something I learned in the last year is the ability to define multiple class rules for an element in the class attribute. This comes in real handy when assigning jQuery plugins.
<
input
type
="text"
id
="txtFirstName"
class
="defaultText textField"
/>
For an ASP.NET web control you assign any class rules in the CSSClass property, which ultimately renders the class attribute with those values.
<
asp:TextBox
runat
="server"
id
="txtFirstName"
CSSClass
="defaultText textField"
/>
The ID Selector
The last selector type finds a DOM element by Id or the assigned name of the element. So in the examples above you can define a rule for the specific input element. The Id selector is prefixed with a '#' in the rule definition.
#txtFirstName{font-size
:1em;
color
:#000;
}
This time instead of needed the class attribute there is no need to set this value. The CSS Rule will just be automatically applied. In this example you most likely do not want to define a rule just for the txtFirstName element because this is too specific because the CSS rule would most likely need to be applied to many other elements as well. But there is nothing saying you cannot do this and I will show you some tricks to define the same rule for multiple selectors later in the post.
Combining Selectors
This is where I see CSS novices lose the effectiveness of CSS selectors on their page. Instead of leveraging the real power of CSS selectors they will litter their markup with class attributes that are duplicated over and over in a page. The following example is a simple login component with E-Mail and Password input elements. I am defining the class attributes for both in a very inefficient way by duplicating the effort.
<
ul
>
<
li
>
<
input
id
="txtEmail"
type
="text"
class
="loginText"
/>
</
li
>
<
li
>
<
input
id
="txtPassword"
type
="password"
class
="loginText"
/>
</
li
>
<
li
>
{Buttons}</
li
>
</
ul
>
The markup uses the class rule to ensure both the inputs look similar. But we have some wasted code here. What if I defined an id for the <ul> and combined a few element selectors for a CSS rule? That could be very efficient because I would just need a simple name and rule. In this case this is known as a descendant selector because it specifies this rule be applied to any INPUT element that is a child of a LI that is the descendant of a UL element called loginElements.
ul
#loginElementsli
input
{font-size
:1em;
color
:#000;
}
The markup could now look like this:
<
ul
id="loginElements">
<
li
>
<
input
id="txtEmail" type="text"/>
<
/li
>
<
li
>
<
input
id="txtPassword" type="password"/>
<
/li
>
<
li
>
{Buttons}<
/li
>
<
/ul
>
That is ultimately less text being sent to the browser on each page request and a more specific rule. It also helps us out by applying the same style to any other input fields we might want to add, think about adding an OpenId field or maybe a third identifier. This really comes in handy on longer forms.
The ability to combine multiple selectors can also be done with class names as well, in fact you can combine as many selectors as you want in just about any combination you can dream up. It does take a little practice but you can get real specific with your selectors and that ultimately gives you surgical precision to define how an element will render.
In the login form example I might not reference the element id, but maybe define class to follow in the <ul> element. In that case the CSS rule might look like the following:
UL.loginElements
LI INPUT{font-size
:1em;
color
:#000;
}
This is all well and good, but I forgot something! There are no labels in the form to tell the user what to enter, so lets add them.
<
ul
>
<
li
>
<
label
for
="txtEmail"
>
E-Mail</
label
><
input
id
="txtEmail"
type
="text"
class
="loginText"
/>
</
li
>
<
li
>
<
label
for
="txtPassword"
>
Password</
label
><
input
id
="txtPassword"
type
="password"
class
="loginText"
/>
</
li
>
<
li
>
{Buttons}</
li
>
</
ul
>
Now I need a CSS rule to define how the labels are going to render. No problem, I can define a similar rule as the input rule. In fact I am going to use the exact same rule by stacking the selectors on the rule.
UL.loginElements
LI LABEL,UL.loginElements
LI INPUT{font-size
:1em;
color
:#000;
}
I call it stacking because I think it reads better when they are stacked on top of each other. The official term is Grouping. But this is not good enough for me, I think I still need to define some more CSS rules for the label and the input elements to make them layout nicely. The following rules cause the labels to be 75 pixels wide and float left, meaning they will all line up along the left side. The text also aligns left.
UL.loginElements
LI LABEL,UL.loginElements
LI INPUT{font-size
:1em;
color
:#000;
}UL.loginElements
LI LABEL{width
:75px;
float
:left;
text-align
:left;
}UL.loginElements
LI INPUT{width
:100px;
float
:left;
}
Now the form is starting to look better! And I demonstrated another feature with CSS selectors, the ability to define more than one rule for a CSS selector. There is no limit to the number of rules you can define. If you read my last post on the Development Tools built into IE 8 you have seen it give you a visual trace of the CSS rules that are applied to an element and what selector applied the rule.
Sibling Selectors
Now I am just going to get fancy with you and show off. One of the coolest things in CSS selector syntax is the ability to define rules to be applied to an element based on elements that are sitting right next to it, or its siblings.
The way to define a sibling selector is to place a + between the left sibling and the right sibling. So a sibling rule looks like A + B where B is the target of the rule.
h1
+p
{background-color
:#3399FF;
color
:#000000;
font-family
: Arial, Helvetica, sans-serif;
font-size
:1em;
}
Applying that rule to the following Markup renders a paragraph with a blue background. The H1 and P tags are siblings within the parent DIV tag.
<
div
>
<
h1
>
CSS Selector Demo</
h1
>
<
p
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam tellus odio, cursus ...</
p
>
</
div
>
Unfortunately you cannot go the other way with siblings. So defining a rule for P + H1 will not allow you to define the style applied to an H1 tag that has a P next to it like the HTML above.
Similarly you can define descendant selectors where the first selector rule is immediately followed by a selector. So 'DIV P' designates any paragraph within a DIV element. You could also designate 'DIV > P' to select any paragraph that is the direct descendant of a DIV element.
Attribute Selectors
Attribute selectors are another pretty sweet selector trick I like to use. This gives you the ability to define a selector that applies to an element that contains an attribute meeting the criteria. You can define an selector that says the element just has to have the attribute defined [att]:
P[title
]
or an attribute with a specific value [att=val]:
input
[type=text]
or an attribute with at least one value matching a value [att~=val]:
P[title
~=Raleigh]
Finally you can match values based on language specification [att|=val]. This one is special because the value must be followed by a '. So you would typically match on the lang attribute. So a style of P[lang|=en] would match all English language types.
Pseudo-Class Selectors
Pseudo-classes enable you to designate a rule for an element based on some attribute that is not part of the document tree. Well that depends on the way you interpret the document tree model I guess because you can designate styles based on position below an element with selectors such as first-child, etc. So taking the example from the sibling selector you could define a selector that would only apply to the first paragraph within the parent DIV like the following:
div
>
p
:first-child {...}
Other pseudo-classes apply to <A> tags, :link, :visited. This gives you control over how links that have been visited differ from links that have not been visited by the user. These are probably pretty common to most web developers as are the :hover, :active and :focus pseudo-classes because examples of these have all been done for hyperlinks for as long as I can really remember.
They all give you more granular control over how style rules are applied to elements based on where the user's mouse or focus is placed on the page. You should note that :hover should be placed after :link and :visited because the color property would be hidden otherwise. Also pseudo classes can be combined like a:focus:hover.
Psuedo-Element Selectors
Similar to the Pseudo-class selectors there are selectors that really extend the ability to control rendering based on the position of the content within an element, pseudo-elements. This is how you see things like a very large capital letter at the beginning of a paragraph or a different font or background image for the first line. The :first-letter pseudo-element allows a specific rule for the very first character.
Adding the following selectors to the example changes the first character and first line of the paragraph:
h1
+p
:first-line{text-transform
:capitalize;
color
:#CCCCCC;
margin
-bottom
:4px;
font-size
:1.25em;
font-family
:'Times New Roman' , Times, serif;
}h1
+p
:first-letter{padding
:2px 5px 3px 5px;
background-color
:#0066FF;
color
:#333333;
font-family
: Arial, Helvetica, sans-serif;
font-size
:4em;
float
:left;
margin
-right
:8px;
}
Which produces the following effect when it is rendered:

Summary
With so much raw power at our disposal to control the layout and rendering of any page mastering CSS Selectors is a must have skill for any web developer. I hope this post can be used as a reference document for you going forward. And from now on I hope you have the confidence to control your layout with CSS and not control attributes or even worse inline style definitions. I think you will also find that your markup is much more maintainable. Changes to your layout will also be much easier to accomplish.
Look for another post on defining selectors to work with ASP.NET web controls and some of their quirks in the next few days.