asp.netinternet-explorerie8-compatibility-modex-ua-compatible

How to forcefully set IE's Compatibility Mode off from the server-side?


In a domain-controlled environment I'm finding that the compatibility mode is triggered on certain clients (winXP/Win7, IE8/IE9) even when we are providing a X-UA tags, a !DOCTYPE definition and "IE=Edge" response headers. These clients have the "display intranet sites in compatibility view" checkbox ticked. Which is precisely what I'm trying to override.

The following is the documentation that I've used to try understand how IE decides to actually trigger the compatibility mode.

http://msdn.microsoft.com/en-us/library/ff406036%28v=VS.85%29.aspx

http://blogs.msdn.com/b/ie/archive/2009/02/16/just-the-facts-recap-of-compatibility-view.aspx

Site owners are always in control of their content. Site owners can choose to use the X-UA-Compatible tag to be absolutely declarative about how they’d like their site to display and to map Standards mode pages to IE7 Standards. Use of the X-UA-Compatible tag overrides Compatibility View on the client.

This is an ASP.NET web app and includes the following definitions on the master page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<head>
   <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
</head>

and web.config

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <clear />
      <add name="X-UA-Compatible" value="IE=Edge" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

I've used Fiddler to check that the header is indeed being injected correctly.

My understanding is that with these settings I should be able override the "Display intranet sites in Compatibility View" browser setting. But depending on the client I've found that some of them will still trigger compatibility mode. It also seems to be down to the machine level rather a policy group setting, since I obtain different results even when I use with the same set of credentials on different clients.

Disabling the Compatibility View Settings checkbox does the trick. But the actual purpose is to make sure that the app is rendered exactly the same way regardless of the client settings.

Any thoughts and what I could be possibly missing? Is it possible at all to force IE to always render the pages without triggering Compat mode?

The site is currently in development and is of course not in Microsoft's compatibility list, but I've also checked just in case.


Solution

  • I found problems with the two common ways of doing this:

    1. Doing this with custom headers (<customHeaders>) in web.config allows different deployments of the same application to have this set differently. I see this as one more thing that can go wrong, so I think it's better if the application specifies this in code. Also, IIS6 doesn't support this.

    2. Including an HTML <meta> tag in a Web Forms Master Page or MVC Layout Page seems better than the above. However, if some pages don't inherit from these then the tag needs to be duplicated, so there's a potential maintainability and reliability problem.

    3. Network traffic could be reduced by only sending the X-UA-Compatible header to Internet Explorer clients.

    Well-Structured Applications

    If your application is structured in a way that causes all pages to ultimately inherit from a single root page, include the <meta> tag as shown in the other answers.

    Legacy Applications

    Otherwise, I think the best way to do this is to automatically add the HTTP header to all HTML responses. One way to do this is using an IHttpModule:

    public class IeCompatibilityModeDisabler : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.PreSendRequestHeaders += (sender, e) => DisableCompatibilityModeIfApplicable();
        }
    
        private void DisableCompatibilityModeIfApplicable()
        {
            if (IsIe && IsPage)
                DisableCompatibilityMode();
        }
    
        private void DisableCompatibilityMode()
        {
            var response = Context.Response;
            response.AddHeader("X-UA-Compatible", "IE=edge");
        }
    
        private bool IsIe { get { return Context.Request.Browser.IsBrowser("IE"); } }
    
        private bool IsPage { get { return Context.Handler is Page; } }
    
        private HttpContext Context { get { return HttpContext.Current; } }
    
        public void Dispose() { }
    }
    

    IE=edge indicates that IE should use its latest rendering engine (rather than compatibility mode) to render the page.

    It seems that HTTP modules are often registered in the web.config file, but this brings us back to the first problem. However, you can register them programmatically in Global.asax like this:

    public class Global : HttpApplication
    {
        private static IeCompatibilityModeDisabler module;
    
        void Application_Start(object sender, EventArgs e)
        {
            module = new IeCompatibilityModeDisabler();
        }
    
        public override void Init()
        {
            base.Init();
            module.Init(this);
        }
    }
    

    Note that it is important that the module is static and not instantiated in Init so that there is only one instance per application. Of course, in a real-world application an IoC container should probably be managing this.

    Advantages

    Disadvantages