When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, November 29, 2006

Creating CSS Friendly Websites with ASP.NET 2.0

By Scott Mitchell


Introduction


One of the features of ASP.NET 1.0 was its adaptive rendering capabilities that allowed for the markup rendered by an ASP.NET web page to be appropriate for the visiting browser. In short, when an ASP.NET page is visited its Web controls are rendered into markup that is sent down to the browser and displayed. The markup generated by the Web controls, however, depends upon the browser being used to visit the page. When visited by an "uplevel browser" ASP.NET Web controls render HTML 4.0-compliant markup; for "downlevel" browsers, the Web controls render HTML 3.2-compliant markup. In ASP.NET 1.x, browsers were labeled as "uplevel" or "downlevel" via the <browserCaps> element in machine.config or web.config (one downside of ASP.NET 1.x was that, by default, only IE 4.0 and up was marked as "uplevel" meaning modern browsers like FireFox and Opera were flagged as downlevel). See A Look at ASP.NET's Adaptive Rendering for more information on ASP.NET 1.x's adaptive rendering functionality.

ASP.NET 2.0 provides the same adaptive rendering as ASP.NET 1.x, although a browser's capabilities are determined by Browser Definition Files rather than a <browserCaps> element. (<browserCaps> support still exists in ASP.NET 2.0 for backwards compatibility, but has been deprecated and its use should therefore be avoided.) In addition to adaptive rendering, ASP.NET 2.0's rendering framework also can be configured using control adapters. A control adapter is an optional class that, if present and properly configured, is used to render the Web control instead of using the control's default rendering logic. In short, using control adapters you can take the core functionality of a Web control, but completely customize the markup emitted. This is useful if you want to modify the default rendering for all browsers or if there are particular user agents - certain cell phones or portable devices, perhaps - for which you need to provide a customized rendering.

A good example of the power of ASP.NET 2.0's control adapters can be seen with the ASP.NET 2.0 CSS Friendly Control Adapters. This set of free control adapters, released by Microsoft, provide a set of control adapters that render a variety of built-in ASP.NET controls using preferred CSS techniques. For example, by default the Menu Web control renders as an HTML <table>; with the control adapters, however, the Menu is rendered as an unordered list using CSS positioning to appropriately display the menu. Moreover, the CSS control adapters ignore any control-level style settings that would get rendered as inline style elements in the rendered markup and instead require that style information be separated out and specified via CSS classes.

In addition to a control adapter for the Menu control, the CSS Friendly Control Adapters include adapters for the TreeView, GridView, DataList, DetailsView, Login, CreateUserWizard, and a variety of other controls. In this article we'll look at how to get started with the CSS Friendly Control Adapters and how they can clean up and improve the markup of your website. Read on to learn more!

- continued -

A Quick Primer on Control Adapters


When a user visits an ASP.NET web page, the end goal of the page is to render its contents into markup that can be sent back to the requesting client. An ASP.NET page generates its rendered content by walking through its control tree - its Web controls and static HTML content - and basically saying, "Hey, you, render yourself." Each control obediently renders itself and returns its rendered markup to the page. These rendered pieces are slapped together and then sent back to the requesting client.

When an ASP.NET 2.0 Web control is getting render itself, it stops and says, "Wait, do I have an adapter that I should be using?" A control adapter is implemented as a class that derives from the ControlAdapter class and has important rendering-related methods, like BeginRender(), Render(), RenderChildren(), EndRender() and so forth. If the Web control being rendered does not have a control adapter, then it handles the rendering interally (that is, it uses its default rendering logic rather than allowing an external control adapter to perform the rendering). Whether or not a control adapter is used depends on the settings in the Browser Definition Files, which include instructions as to what Web controls should use control adapters and for what browsers.

To use a control adapter in an ASP.NET web application, then, we need to perform two steps:

  1. Create (or download) the control adapter. Again, this is just a class that derives, either directly or indirectly, from the ControlAdapter base class. The .NET Framework already includes some classes that extend the ControlAdapter class - PageAdapter, WebControlAdapter, DataBoundControlAdapter, and so on - and these classes are often the ones derived from when building a control adapter.
  2. Configure or create a Browser Definition File to indicate that the control adapter should be used for a particular Web control and for a particular user agent. Browser Definition Files have the .browser extension; the default Browser Definition Files can be found in %WINDIR%\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers. This information can be customized for a particular web application by adding .browser files to the App_Browsers folder.
In this article we won't be creating our own control adapters. Instead, we'll look at downloading and using the Microsoft's CSS Friendly Control Adapters.

Improving the Default Markup of ASP.NET Web Controls


Cascading Stylesheets (CSS) are a technique used in web development to specify presentation settings for a particular HTML element, for a class of HTML elements, or for all instances of a particular HTML element type (such as specifying display settings for all <div> elements). To specify presentation settings for a particular HTML element, the element's style attribute can be used. For example, the following markup specifies that the paragraph element's background color should be green:

<p style="background-color: Green;">
   This has a green background!
</p>

Ideally, though, presentation information can be specified using CSS classes. A CSS class defines the presentation style for a class of elements and are defined in the <style> element or through external CSS files that are associated with a page via the <link> element. Once a class has been defined, it can be associated with a particular HTML element via the element's class attrbute. The following markup adds a class named .Warning that makes the text appear in a red, bold font. The following <span> element is associated with the class and, consequently, would display as red, bold text when viewed through a browser.

<style type="text/css">
  .Warning {
     font-weight: bold;
     color: red;
  }
</style>

<span class="Warning">
  Danger! Danger!
</span>

The CSS class approach is preferred over using inline styles for a couple of reasons. First, it reduces the overall page's size because presentation information can be specified in one place - the <style> element or in a separate CSS file - and then applied in numerous spots on the page. If only inline styles are used, the presentation information must be re-applied with each control. Second, having the presentation information centralized also makes site redesigns or presentation changes much easier, since there's only once place where the settings need to be modified.

Unfortunately, ASP.NET's Web controls' style-related properties are rendered as inline styles. That is, if you add a Label Web control to the page and set its ForeColor property to Red, the Label renders markup like:

<span style="color: red;">Label Text</span>

Some controls, however, are intelligent enough to use classes as opposed to inline styles. The Menu control, for example, uses classes as opposed to inline styles when rendering its style-related properties. Moreover, all Web controls do offer a CssClass property which you should use instead, but using the inline properties is a tempting choice and one too many developers make.

Additionally, many of the ASP.NET Web controls render using HTML <table>s for positioning instead of using regular block elements (like <div>) with positioning applied through CSS. HTML <table>s were designed to store tabular data, not to be used for layout purposes, but that's exactly how they're used with Menus, TreeViews, and other built-in ASP.NET Web controls.

This behavior, however, can be overridden using control adapters. While these could be created from scratch, Microsoft has provided the ASP.NET 2.0 CSS Friendly Control Adapters that can be downloaded and plugged into your ASP.NET web applications with minimal effort. Once installed, the control adapters will no longer render inline style attributes (you need to use CSS classes) and replaces the <table> layouts of the Menu, TreeView, and other controls with CSS techniques.

Do You Use <table>s or CSS for Layout?
In my opinion, <table>s ought to be used for representing tabular data, like when listing data in a GridView, and should not be used for dictating page layout (such as using <table>s to arrange the page in a three-column, two-row layout). Ideally, CSS techniques should be used for page layout. However, I am being a bit of a hypocrit here because personally I use <table>s for layout more often than not, primarily because of the comfort factor - I know how to layout content with <table>s much moreso than with CSS. Overall I'm pretty apathetic to <table>s vs. CSS techniques for layout. Ideally, CSS should be used, but I'm not fanatic enough about it to divert time from my main tasks (which are 95% on the backend, anyway) to learn the breadth of material needed to completely forgo tables in favor of CSS with regards to layout. (Fortunately, tools like the CSS Friendly Control Adapters help make this move possible without having to worry about the learning curve.)

In contrast to my blase attitude on this subject, some people feel quite strongly one way or the other, and there are a plethora of articles and essays around the Web extolling one approach and decrying the other. I particularly enjoyed the presentation in Bill Merikallio and Adam Pratt's Why tables for layout is stupid. There's a more balanced look at the pros and cons of the two approaches at Tables vs. CSS: PROS and CONS.

Downloading and Integrating the CSS Friendly Control Adapters Into Your ASP.NET Website


To get started with building a CSS friendly ASP.NET website using the CSS Friendly Control Adapters, you need to first download the files from Microsoft. The latest version of the CSS Friendly Control Adapters are available online at http://www.asp.net/CSSAdapters/. A link to download Version 1.0 of the CSS Friendly Control Adapters is available at the end of this article.

These control adapters are shipped as a VSI file. Assuming you have Visual Studio 2005 or Visual Web Developer installed, simply run the VSI file once downloaded. This will add new templates to your Visual Studio installation. Version 1.0 of the CSS Friend Control Adapters contains a template for creating a new ASP.NET CSS Friendly Website and a Tutorial on the ASP.NET CSS Friendly Control Adapters. The Tutorial contains the core files needed along with detailed examples for all of the adapters, while the website template contains the core files and only an abbreviated set of examples. You can also peruse the examples online from http://www.asp.net/CSSAdapters/.

To use these templates, fire up Visual Studio 2005 and choose to create a "New Web Site". From the New Web Site dialog box you'll see the ASP.NET CSS Friendly Website and Tutorial on ASP.NET CSS Friendly Control Adapters.

The New Web Site dialog box.

Using either template creates a website with, at minimum, the core files needed to use the control adapters. These include the control adapter class files in the App_Code folder, a CSSFriendlyAdapters.browser Browser Definition File in the App_Browsers folder that instructs that each of the control adapters be used for all browsers, and some JavaScript files in the JavaScript folder (used primarily by the Menu and TreeView controls for providing client-side functionality that is sensitive to the rendered output). To turn an existing ASP.NET website into a CSS friendly website, simply copy over these three folders.

Examining the Rendered Markup for a Menu Using the CSS Friendly Control Adapters


To see the difference in output when using the CSS Friendly Control Adapters, let's look at a concrete example. Imagine that we had a Menu Web control defined to display a menu with a single top-level menu item that has four children menu items. Such a structure can be statically defined in the Menu Web control using the following declarative markup:

<asp:Menu ID="ProductMenu" runat="server" Orientation="Horizontal">
    <Items>
        <asp:MenuItem Text="Products">
            <asp:MenuItem Text="Beverages" />
            <asp:MenuItem Text="Condiments" />
            <asp:MenuItem Text="Confections" />
            <asp:MenuItem Text="Dairy/Milk" />
        </asp:MenuItem>
    </Items>
</asp:Menu>

Also note that the Menu's BackColor property is set to Yellow and the child menu items' BackColors to Pink. The resulting HTML rendered when using the default rendering logic for the Menu control follows:

<table id="ProductMenu" class="ProductMenu_2" cellpadding="0" cellspacing="0" border="0">
   <tr>
      <td onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ProductMenun0"><table cellpadding="0" cellspacing="0" border="0" width="100%">
         <tr>
            <td style="white-space:nowrap;"><a class="ProductMenu_1" href="javascript:__doPostBack('ProductMenu','Products')">Products</a></td><td style="width:0;"><img src="/CSSControlAdapters/WebResource.axd?d=chn_rjDXviMiG52QjFyPeTtWQOV3vwPBosett_KzYtE1&t=632965002926288600" alt="Expand Products" style="border-style:none;vertical-align:middle;" /></td>
         </tr>
      </table></td>
   </tr>
</table><div id="ProductMenun0Items" class="ProductMenu_0 ProductMenu_3">
   <table border="0" cellpadding="0" cellspacing="0">
      <tr onmouseover="Menu_HoverDynamic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ProductMenun1">
         <td><table cellpadding="0" cellspacing="0" border="0" width="100%">
            <tr>
               <td style="white-space:nowrap;width:100%;"><a class="ProductMenu_1" href="javascript:__doPostBack('ProductMenu','Products\\Beverages')">Beverages</a></td>
            </tr>
         </table></td>
      </tr><tr onmouseover="Menu_HoverDynamic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ProductMenun2">
         <td><table cellpadding="0" cellspacing="0" border="0" width="100%">
            <tr>
               <td style="white-space:nowrap;width:100%;"><a class="ProductMenu_1" href="javascript:__doPostBack('ProductMenu','Products\\Condiments')">Condiments</a></td>
            </tr>
         </table></td>
      </tr><tr onmouseover="Menu_HoverDynamic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ProductMenun3">
         <td><table cellpadding="0" cellspacing="0" border="0" width="100%">
            <tr>
               <td style="white-space:nowrap;width:100%;"><a class="ProductMenu_1" href="javascript:__doPostBack('ProductMenu','Products\\Confections')">Confections</a></td>
            </tr>
         </table></td>
      </tr><tr onmouseover="Menu_HoverDynamic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ProductMenun4">
         <td><table cellpadding="0" cellspacing="0" border="0" width="100%">
            <tr>
               <td style="white-space:nowrap;width:100%;"><a class="ProductMenu_1" href="javascript:__doPostBack('ProductMenu','Products\\Dairy/Milk')">Dairy/Milk</a></td>
            </tr>
         </table></td>
      </tr>
   </table><div class="ProductMenu_0" id="ProductMenun0ItemsUp" onmouseover="PopOut_Up(this)" onmouseout="PopOut_Stop(this)" style="text-align:center;">
      <img src="/CSSControlAdapters/WebResource.axd?d=qidxSK8lNw1v6pL8IQZxzZrT3SMuvVDHqZfjfzhu6MM1&t=632965002926288600" alt="Scroll up" />
   </div><div class="ProductMenu_0" id="ProductMenun0ItemsDn" onmouseover="PopOut_Down(this)" onmouseout="PopOut_Stop(this)" style="text-align:center;">
      <img src="/CSSControlAdapters/WebResource.axd?d=uuL5BWm1omFEgQuN_dcSXY3whrEsc7zS_QoWROKGtMo1&t=632965002926288600" alt="Scroll down" />
   </div>
</div>

As you can see, this markup uses <table> elements for each of the menu items. Not shown here are the references to external JavaScript files that handle displaying and hiding the child menu items.

By plugging in the CSS Friendly Control Adapters, the rendered markup is changed to the more legible markup:

<div class="AspNet-Menu-Horizontal" id="ProductMenu">
   <ul class="AspNet-Menu">
      <li class="AspNet-Menu-WithChildren">
         <a href="javascript:__doPostBack('ProductMenu','bProducts')" class="AspNet-Menu-Link">
            Products</a>
         <ul>
            <li class="AspNet-Menu-Leaf">
               <a href="javascript:__doPostBack('ProductMenu','bProducts\\Beverages')" class="AspNet-Menu-Link">
                  Beverages</a>
            </li>
            <li class="AspNet-Menu-Leaf">
               <a href="javascript:__doPostBack('ProductMenu','bProducts\\Condiments')" class="AspNet-Menu-Link">
                  Condiments</a>
            </li>
            <li class="AspNet-Menu-Leaf">
               <a href="javascript:__doPostBack('ProductMenu','bProducts\\Confections')" class="AspNet-Menu-Link">
                  Confections</a>
            </li>
            <li class="AspNet-Menu-Leaf">
               <a href="javascript:__doPostBack('ProductMenu','bProducts\\Dairy\\Milk')" class="AspNet-Menu-Link">
                  Dairy/Milk</a>
            </li>
         </ul>
      </li>
   </ul>
</div>

Each menu item is assigned an appropriately named CSS class (AspNet-Menu, AspNet-Menu-WithChildren, AspNet-Menu-Leaf, and so on). The presentation settings for these classes can be specified in the page's <style> element or, ideally, in a separate CSS file. See the CSS Friendly Control Adapters White Paper for a more detailed look at customizing the appearance of the controls rendered using the CSS Friendly Control Adapters.

Conclusion


ASP.NET provides a lot of flexibility in how controls (and therefore pages) are rendered. Controls automatically utilize adaptive rendering to emit the appropriate markup based on whether the visiting user has come with an uplevel or downlevel browser. The rendering can be completely customized, if needed, through control adapters. In this article examined the basics of control adapters and explored Microsoft's free ASP.NET 2.0 CSS Friendly Control Adatpers. You can plug these control adapters into your website to have your Menus, TreeViews, GridViews, DetailsViews, and other controls render using CSS techniques for layout. Furthermore, these control adapters force developers to use CSS classes for specifying presentation settings as they disregard control-level style settings that would result in inline styles in the rendered markup.

Happy Programming!

  • By Scott Mitchell


    Further Readings:


  • Architectural Overview of Adaptive Control Behavior
  • ASP.NET 2.0 CSS Friendly Control Adapters Homepage
  • ASP.NET 2.0 CSS Friendly Control Adapters: The White Paper
  • Control Adapters (an article from MSDN Magazine)

    Attachments


  • Download Version 1.0 of the CSS Friendly Control Adapters


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article