Dynamically Varying Master Pages By Browser Type

One of the common scenarios that I heard at ApacheCon this week was to be able to dynamically modify/optimize a site's layout and style content based on browser version.  There was an interesting talk by someone who runs http://www.theregister.co.uk who talked about how they did this today using SSI's and mod_rewrite throughout the site.  One of the big goals of this was to avoid exposing device specific urls to clients, and instead be able to use SSI includes and url rewriting for CSS to do content negotiation on the server-side (each SSI points to a single content file -- which is then intercepted by mod_rewrite and re-pointed at a device specific content snippet).

As I was sitting in the audience, I thought about how easy it would be to do this instead with ASP.NET 2.0 and Master Pages.  Instead of having to use multiple SSI include files to pull in content all over a page (for example: a SSI include for the header that lays out the top level table, then a separate SSI for the footer, and maybe a few more for other content regions), you will instead be able to just create a master page with replaceable regions.

For example, here is a simple psuedo-sample demonstrating a master page with two replaceable regions:

ArticleMaster.master

<html>
     <head>
          Link to some CSS stylesheet
     </head>
     <body>
          Some Header content (including tables for layout)

          <form runat=server>
                
                 <asp:contentplaceholder id="ArticleTitle" runat="server"/>

                 <table>
                         <tr>
                            <td>
                               <asp:contentplaceholder id="ArticleContent" runat="server"/>
                            </td>
                  </table>

          </form>
     </body>
</html>

As everyone who has looked at ASP.NET 2.0 knows, you can then easily build multiple .aspx pages that are based on this master:

Article1.aspx:

    <%@ Page MasterPageFile="ArticleMaster.master" %>

    <asp:content id="ArticleTitle" runat="server">
          Dynamically Varying Master Pages By Browser Type
    </asp:content>

    <asp:content id="ArticleContent" runat="server">
          My article content...
    </asp:content>

ASP.NET 2.0 automatically compiles the two files the first time they are hit (you can also do this before a browser hits the site by using the precompile utility).  As such, the files are never parsed on subsequent requests and execute lightening fast.

Programatically Varying Master Pages

What is less well known is the fact that Master Pages -- in addition to being set statically like above -- can be dynamically switched on the fly as well.  As such, you could have multiple versions of a master page -- including ones optimized for different devices -- on your site.  For example:

    ArticleMaster.master
    ArticleMaster_IE.master
    ArticleMaster_FireFox.master
    ArticleMaster_Safari.master
    ArticleMaster_Opera.master

A page developer could then write code within the Page's PreInit event to update the Master template used for the page depending on what browser device hits it.  For example:

    void Page_PreInit(Object sender, EventArgs e) {
   
        if (Request.Browser.IsBrowser("IE")) {
           this.MasterPageFile = "ArticleMaster_IE.master";
        }
        else if (Request.Browser.IsBrowser("Mozilla")) {
           this.MasterPageFile = "ArticleMaster_FireFox.master";
        }
        else {
           this.MasterPageFile = "ArticleMaster.master";
        }
    }

Declaratively Varying Master Pages

A neat trick, though, is to use the new declarative device filter syntax in ASP.NET 2.0 to switch the master declaratively without having to write code at all.  Device filters are prefixes that can be used on all control properties and look like this:

    <asp:button id="Button1"
                       ie:text="Push me you IE user"
                       mozilla:text="Push me you FireFox user"
                       text="Push me you -- you are running neigher IE or Safari..."
                       runat="server"/>

The ASP.NET parser will automatically generate a switch statement when compiling markup like this, and insert logic to set the "text" property only once depending on the client that hits the page.  Prefix names can be defined within the ASP.NET browser capabilities system, and you can easily add your own entries as new devices come out.  Note that we goofed and didn't have a FireFox entry defined for Beta1 -- we will be adding that though for Beta2.  In the meantime you can use the built-in "Mozilla" one (which will fire when FireFox hits the site), or just add a new FireFox entry yourself.

As I alluded to above, in addition to setting control properties via declarative filters you can also set <%@ Page %> directive values.  This means that you can declaratively vary the master page used on file by doing something like this with the article page:

    <%@ Page MasterPageFile="~/ArticleMaster.master"
                       ie:MasterPageFile="~/ArticleMaster_IE.master"
                       mozilla:MasterPageFile="~/ArticleMaster_FireFox.master" %>

    <asp:content id="ArticleTitle" runat="server">
          Dynamically Varying Master Pages By Browser Type
    </asp:content>

    <asp:content id="ArticleContent" runat="server">
          My article content...
    </asp:content>

This will execute the master page with an optimized IE or FireFox master template if hit by one of those broswers.  Failing that, it will fall back to render a browser neutral version.

Designers can then edit and create the master templates just like they do regular HTML (leaving replaceable regions for the parts to fill in).  Because the template can live in one file, and not need to be separated out in dozens of smaller SSI include snippets, this should be significantly easier to-do then before.

I think this should provide a nice clean solution...

11 Comments

  • Nice clean solution? Tables for layout? Come on! What about doing only one (standards based) browser neutral version and avoiding this mess completely?



    Nah, too simple. Development ought to be fun! Let's put some more fancy broken tables there, it looks too dull! Oh yes.

  • Great feature! And also a cool fact, that Microsoft now (at lease &quot;semi officially&quot;) recognizes other browsersthan IE.

  • adsf -- some sites feel the need to tailor their output to optimize for certain browsers. www.bbc.co.uk and www.theregister.co.uk were two examples that discussed this at ApacheCon last week (note: both of them run on non-MSFT technology).



    It would be great if this wasn't needed, but people still seem to be doing it.



  • Could someone please tell me what in heaven's name that table is doing there? Is table the universal wrapper that just have to bee the parent of all other elements? I think I missed that part of the HTML specification...



    When will Microsoft's web developers learn that table is puerly for tabular data, and that CSS is supposed to be used for layout? Hrmf..



    Other than that little frustration: good tip.

  • The table is there just as an example of static HTML (ASP.NET has no knowledge of it). You could remove it and include any other elements you wanted to instead to provide layout or other content in the page (including CSS).



    Hope this helps,



    Scott

  • well...

    i have implemented this method before i saw this article.



    but 1 thing is, i haven't tried it on other browswer other than IE.



    Nice tutorial...

  • It could be simpler:

    ArticleMaster_RightBrowsers.master

    ArticleMaster_IE.master

  • I apreciate all you do. But it seems for me that my application will spend a lot of time till every contentplaceholder will rebuild. And some of time for checking version of browser. And my clients will sleeping before they take usefull information. Is any way for activating our sutable code for any webbrowsers without contentplaceholder?

  • LukCAD -- ASP.NET controls will vary their output to ensure that they work with any browser that hits the site. So you don't need to use master pages to handle that situation.



    The tip is more useful for cases where you want more dramatic layout changes, or if you have radically different static HTML (for example: CSS vs. HTML 3.2 for downlevel browsers).



    You can also use this tip if you want to customize layout for different user-languages (example: English and German table widths often tend to be different because German words are longer). Note that ASP.NET 2.0 also has new localization support, so separate masters are not required to localize content. But in some cases where localization impacts sizing it might also be useful.

  • Dario -- although there is some valid true in your statement (I'm not a big fan of some of IE's html handling either), I think you are being a little generous in overlooking the problems other browsers have too.



    For example, I run both Safari and FireFox on one of my machines at home (a Mac Powerbook). There are *significant* html rendering differences between the two. Forgetting Windows for a moment -- if a content publisher wants to target the Mac market in a rich way they will potentially want to tweak their content to maximize the capabilities for the two most common browsers (Safari and FireFox) in use there.



  • yeah. It is understandly now(about localization and using of the master pages), thanx. But why all need to avoid exposing device specific urls to clients? Sometime when JavaScript turned off the knowledge about rigth url is very useful. Sometime all solid sites check web explorer's switcher about working state of JS of client's webbrowser and permit use the direct url if JS was turned off. (I must note - JS turned off usually into intranet (where we have a lot of computers in net and gate to internet (common for rest) and we afraid the virus code)).

Comments have been disabled for this content.