Welcome to part 9 of my tour through ASP.NET 4.0. In this episode, we’ll conclude our look at the ways that ASP.NET has been tweaked in v4.0 to produce cleaner, leaner HTML that we can turn to our purpose without having to deal with some of the inconveniences of previous versions – control IDs and injected HTML we can’t control being two. More control over viewstate being a third.

ASP.NET 2.0: Only Technically Standards Compliant…

Even in 2005, the idea of producing pure HTML\CSS websites had gained quite a foothold. XHTML had been a W3C Recommendation since 2001 and CSS was evolving and being used more prevalently. Sites like CSS Zen Garden had been championing cross-browser sites and advanced layouts with this approach for a couple of years. All it required was control over the HTML generated by your site and some reasoned application of CSS.

Regrettably, ASP.NET 1.1 didn’t produce standards-compliant HTML at all, so ASP.NET 2.0 created a new setting in web.config called xhtmlConformance that would determine how its server controls were to be rendered as HTML. By default, controls would render markup compatible with the XHTML 1.0 Transitional standard (Transitional). Alternatively, the setting could be changed to have ASP.NET render markup compatible with XHTML 1.0 Strict (Strict) or as v1.1 (Legacy) has rendered it before. Websites upgraded from v1.1 to v2.0 were set to this Legacy mode.

Unfortunately, sites running in Legacy mode didn’t work with ASP.NET AJAX and while Transitional and Strict modes were technically compliant with the XHTML 1.0 standard, they could equally have been described as CSS-intolerant.

  • Menus were rendered as tables rather than lists (not only harder to work with in CSS, but semantically wrong too)
  • Several properties like border=0 or disabled=disabled were mandatorily added to various elements without a way to remove them.
  • For templated controls, you had full control over the templates themselves, but not over the outer table that surrounded the templates.

Technically correct, but not a good foundation to build standards compliant sites upon. The introduction of the ListView & DataPager controls in ASP.NET 3.5 and the out of band CSS Control Adapters release helped somewhat but it’s only because they’ve been able to go into System.Web for .NET 4.0 that Microsoft have been able to make ASP.NET (mostly) CSS-friendly. Indeed, emitting cleaner markup was one of the main goals for ASP.NET 4.0

ControlRenderingCompatibilityVersion

Like xhtmlConformance in ASP.NET 2.0, a new setting is now available in web.config to control how controls render HTML. It is called ControlRenderingCompatibilityVersion.

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="false" targetFramework="4.0" />
&lt;pages controlRenderingCompatibilityVersion=&quot;3.5&quot; /&gt;

</system.web>
</configuration>

CRCV, as we’ll call it, takes one of two values. Set it to 3.5 (the default for sites upgraded from ASP.NET 3.5) and all server controls will render as they did in ASP.NET 3.5. Set it to 4.0 (the default for new web site and web application projects) and the following happens

  • xhtmlConformance is set to Strict.
  • Menus are rendered as lists rather than tables
  • Extraneous properties like border=0 are removed from the emitted markup. Even the error text on validation controls is no longer set to red.
  • The rendering of the outer table for templated controls can now be controlled with the new RenderOuterTable property.

Let’s look at these changes in detail.

Menus

Let’s consider a very simple menu control with three items.

<asp:Menu runat="server" ID="testMenu">
  <Items>
    <asp:MenuItem Text="Menu Item 1" NavigateUrl="#"></asp:MenuItem>
    <asp:MenuItem Text="Menu Item 2" NavigateUrl="#"></asp:MenuItem>
    <asp:MenuItem Text="Menu Item 3" NavigateUrl="#"></asp:MenuItem>
  </Items>
</asp:Menu>

With CRCV set to 3.5, we get three CSS styles for the menu added to the HTML <head>, 53KB of script files added in by two calls to WebResource.axd (21KB for the standard script to handle postbacks, 32KB for a menu-specific script file), and the following HTML for the menu itself.

<body>
  <div>
  <a href="#testMenu_SkipLink">
    <img alt="Skip Navigation Links" width="0" height="0" style="border-width:0px;"
      src="/CleanHtml/WebResource.axd?d=y4UEb5xFzNnwyKsjxERYdw2&amp;t=634013486901596851" />
  </a>
  <table id="testMenu" class="testMenu_2" cellpadding="0" cellspacing="0" border="0">
    <tr onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" 
      onkeyup="Menu_Key(this)" id="testMenun0">
      <td>
        <table cellpadding="0" cellspacing="0" border="0" width="100%">
          <tr>
            <td style="white-space:nowrap;width:100%;">
              <a class="testMenu_1" href="#">Menu Item 1</a>
            </td>
          </tr>
        </table>
      </td>
    </tr>
    <tr onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" 
      onkeyup="Menu_Key(this)" id="testMenun0">
      <td>
        <table cellpadding="0" cellspacing="0" border="0" width="100%">
          <tr>
            <td style="white-space:nowrap;width:100%;">
              <a class="testMenu_1" href="#">Menu Item 2</a>
            </td>
          </tr>
        </table>
      </td>
    </tr>
    <tr onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" 
      onkeyup="Menu_Key(this)" id="testMenun0">
      <td>
        <table cellpadding="0" cellspacing="0" border="0" width="100%">
          <tr>
            <td style="white-space:nowrap;width:100%;">
              <a class="testMenu_1" href="#">Menu Item 3</a>
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
  <a id="testMenu_SkipLink"></a>
  </div> 
  <script type="text/javascript"> 
    //<![CDATA[
    var testMenu_Data = new Object();
    testMenu_Data.disappearAfter = 500;
    testMenu_Data.horizontalOffset = 0;
    testMenu_Data.verticalOffset = 0;
    //]]>
  </script>
</body>

With CRCV set to 4.0, we get six CSS styles added to the <head> element, a single 27KB script file downloaded to the browser (a completely refactored version of the menu script) and the following HTML for the menu.

<body>
  <div>
    <a href="#testMenu_SkipLink">
    <img alt="Skip Navigation Links" width="0" height="0" style="border-width:0px;" 
      src="/CleanHtml/WebResource.axd?d=y4UEb5xFzNnwyKsjxERYdw2&amp;t=634013486901596851" />
    </a>
    <div id="testMenu">
    <ul class="level1">
      <li><a class="level1" href="#">Menu Item 1</a></li>
      <li><a class="level1" href="#">Menu Item 2</a></li>
      <li><a class="level1" href="#">Menu Item 3</a></li>
    </ul>
    </div>
    <a id="testMenu_SkipLink"></a>
  </div>
  <script type='text/javascript'>
    new Sys.WebForms.Menu({ 
      element: 'testMenu', 
      disappearAfter: 500, 
      orientation: 'vertical', 
      tabIndex: 0, 
      disabled: false });
  </script>
</body>

As you can see, not only is the rendered HTML semantically correct, the overall payload is smaller as well. Indeed you can reduce it further by setting the Menu control’s IncludeStyleBlock property to false. This will remove the six styles added to the <head> element for you to include in your own CSS files. Finally, note that you can set the Menu control’s RenderingMode property to either List, Table or Default. This will override the CRCV setting and render the menu as either List or Table as you’ve set it.

Extraneous HTML

The Image control is a good example of a control that in ASP.NET 3.5 added a property to the emitted HTML that wasn’t asked for and couldn’t be overridden. Take a very simple declaration

<asp:Image runat="server" ID="imgMorgan" ImageUrl="~/morgan.jpg" />

With CRCV set to 3.5, ASP.NET sets the image’s border-width to 0px.

<img id="imgMorgan" src="morgan.jpg" style="border-width:0px;" />

With CRCV set to 4.0, there’s no sign of the style property at all.

<img id="imgMorgan" src="morgan.jpg" />

Other controls, such as Table and GridView are similarly shed of their extraneous properties.

Removing The Outer Table From Some Composite Controls

For the most part, ASP.NET controls will render the HTML you want them to, but it looks like some of the more complex, composite controls haven’t been ‘sanitized’ in the same way as more commonly used controls such as the Image or DropDownList. However, it is worth noting that some of these controls now have a new property called RenderOuterTable which does address one particular markup issue. These are

  • FormView
  • Login
  • ChangePassword
  • PasswordRecovery

Take for example the Login control.

<asp:Login runat="server" ID="loginTest" />

Whether CRCV is set to 3.5 or 4.0, the default markup is the same.

<table cellspacing="0" cellpadding="1" border="0" 
  id="loginTest" style="border-collapse:collapse;">
  <tr>
    <td>
      <table cellpadding="0" border="0">
        <tr>
          <td align="center" colspan="2">Log In</td>
        </tr>
        <tr>
          <td align="right">
            <label for="loginTest_UserName">User Name:</label>
          </td>
          <td>
            <input name="loginTest$UserName" type="text" id="loginTest_UserName" />
            <span id="loginTest_UserNameRequired" title="User Name is required." 
              style="color:Red;visibility:hidden;">*</span>
          </td>
        </tr>
        <tr>
          <td align="right">
            <label for="loginTest_Password">Password:</label>
          </td>
          <td>
            <input name="loginTest$Password" type="password" id="loginTest_Password" />
            <span id="loginTest_PasswordRequired" title="Password is required." 
              style="color:Red;visibility:hidden;">*</span>
          </td>
        </tr>
        <tr>
          <td colspan="2">
            <input id="loginTest_RememberMe" type="checkbox" name="loginTest$RememberMe" />
            <label for="loginTest_RememberMe">Remember me next time.</label>
          </td>
        </tr>
        <tr>
          <td align="right" colspan="2">
            <input type="submit" name="loginTest$LoginButton" value="Log In" 
              onclick="…" id="loginTest_LoginButton" />
          </td>
        </tr>
      </table>
    </td>
  </tr>
</table>

A CSS-related issue with this in earlier versions of ASP.NET is the outer table which you haven’t previously been able to remove (but which ironically was added as a wrapper in to give you better control over your styles). Set the Login control’s RenderOuterTable property to false and this will lose that table no matter what CVCR is set to.

<table cellpadding="0" border="0">
  <tr>
    <td align="center" colspan="2">Log In</td>
  </tr>
  <tr>
    <td align="right">
      <label for="loginTest_UserName">User Name:</label>
    </td>
    <td>
      <input name="loginTest$UserName" type="text" id="loginTest_UserName" />
      <span id="loginTest_UserNameRequired" title="User Name is required." 
        style="color:Red;visibility:hidden;">*</span>
    </td>
  </tr>
  <tr>
    <td align="right">
      <label for="loginTest_Password">Password:</label>
    </td>
    <td>
      <input name="loginTest$Password" type="password" id="loginTest_Password" />
      <span id="loginTest_PasswordRequired" title="Password is required." 
        style="color:Red;visibility:hidden;">*</span>
    </td>
  </tr>
  <tr>
    <td colspan="2">
      <input id="loginTest_RememberMe" type="checkbox" name="loginTest$RememberMe" />
      <label for="loginTest_RememberMe">Remember me next time.</label>
    </td>
  </tr>
  <tr>
    <td align="right" colspan="2">
      <input type="submit" name="loginTest$LoginButton" value="Log In" 
        onclick="…" id="loginTest_LoginButton" />
    </td>
  </tr>
</table>

Not ground-shattering certainly, but definitely handy.

What We’ve Learnt

In today’s episode, we’ve learnt that Microsoft has taken the opportunity in ASP.NET 4.0 to clean up a great deal of the HTML emitted by its server controls, thus making it CSS-friendlier. A new setting in web.config called ControlRenderingCompatibilityVersion indicates whether controls should render as cleaner HTML or as they did in 3.5. We saw two example of the cleaner HTML in effect in the Menu and Image control and noted that while some of the more complex controls have not had their markup cleaned up, a subset of those now have a RenderOuterTable property which allows you to remove some of it manually.

Incidentally, for those of you with sites that you can’t upgrade to .NET 4.0, a group of enterprising souls are continuing to work on the CSS Friendly Adapters mentioned earlier. You’ll find this revitalization here on Google Code. Happy coding!