h5bp / html5-boilerplate

A professional front-end template for building fast, robust, and adaptable web apps or sites.
https://html5boilerplate.com/
MIT License
56.48k stars 12.24k forks source link

IE conditional comments around html tag adds Compat View icon to address bar #378

Closed DingoEatingFuzz closed 13 years ago

DingoEatingFuzz commented 13 years ago

Even though the doctype is HTML5 recommended and the X-UA-Compatible meta tag is present, by putting the HTML tag in a series of IE conditional comments, IE refuses to believe that the website is indeed "modern" and puts the dreaded "Compatibility View" button in the address bar.

The way I get around this is by using JavaScript to add the ie6/7/whatever classes.

Example:

<html class="no-js" lang="en">
...
<!--[if lt IE 7 ]>
    <script src="js/libs/dd_belatedpng.js"></script>
    <script> DD_belatedPNG.fix('img, .png_bg'); var ie = "ie6"; </script>
<![endif]-->        
<!--[if IE 7 ]> <script> var ie = "ie7"; </script> <![endif]-->
<!--[if IE 8 ]> <script> var ie = "ie8"; </script> <![endif]-->
...
if(typeof ie !== 'undefined') $('html').addClass(ie); // in js/script.js

I'm sure there are better ways to handle this, but this works as expected.

chuanxshi commented 13 years ago

hmmm, i can't replicate the issue, would you mind provide a test case?

DingoEatingFuzz commented 13 years ago

Thanks for the quick update.

Here are a couple pages that isolate the problem:

Using comments (has compatibility view button)

Not using comments (no compatibility view button)

Themble is an example of a complete site with the problem:

Themble

I noticed that the html5-boilerplate site doesn't have the problem. It could also be htaccess related.

chuanxshi commented 13 years ago

yea, it happens without htaccess, there is the following in the htaccess that fixes this

BrowserMatch MSIE ie
Header set X-UA-Compatible "IE=Edge,chrome=1" env=ie
DingoEatingFuzz commented 13 years ago

It might be a good idea to note that on the site or in the documentation for the folks who aren't using Apache :)

gabor commented 13 years ago

hmm, maybe i'm misunderstanding something, but doesn't this mean that the http-equiv=x-ua-compatible solution in the html is useless?

if you have to put in the http header, then you do not need the html-tag...

MartinMa commented 13 years ago

I think so too. The X-UA-Compatible meta tag is in fact useless here and could as well be removed from index.html of the boilerplate. Why was this issue closed again?

DingoEatingFuzz commented 13 years ago

Not gonna lie: I accidentally closed it by clicking the "comment and close" button rather than the "comment" button. And now I don't know how to reopen it. Kind of a github noob.

From what I have noticed, the X-UA-Compatible meta tag in this scenario is useless, since without the htaccess redundancy, it doesn't work (or at least doesn't work fully). As mentioned originally, if the IE comments aren't wrapped around the html tag (they can still be used elsewhere) the meta tag works as expected. It seems to me like the HTML 5 boilerplate should be pushing for HTML(5) solutions. Not Apache ones.

paulirish commented 13 years ago

reopened..

paulirish commented 13 years ago

I just retitled the issue as "IE conditional comments around html tag adds Compat View icon to address bar"

Agreed this sucks. I don't think it'll make the 1.0 but let's figure out how best to address this for 1.1

paulirish commented 13 years ago

Also I could repro in IE9 RC.. I imagine this is also present in IE8 final? Can someone confirm?

DingoEatingFuzz commented 13 years ago

Confirmed: http://i.imgur.com/rChH7.jpg

ghost commented 13 years ago

The fix is as simple as getting that <meta http-equiv... /> in before the conditional comments. So to resolve it, we could do something like this:

<!doctype html>
<html class="no-js" lang="en">
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <title>ie test</title>
    </head>
    <!--[if lt IE 7 ]> <body class="ie6"> <![endif]-->
    <!--[if IE 7 ]>    <body class="ie7"> <![endif]-->
    <!--[if IE 8 ]>    <body class="ie8"> <![endif]-->
    <!--[if (gte IE 9)|!(IE)]><!--> <body> <!--<![endif]-->
        <p>test</p>
    </body>
</html>

But it might be worth mentioning that "X-UA-Compatible" is not valid HTML5, so I think it's perfectly acceptable to remove it all together.

MartinMa commented 13 years ago

I vaguely remember that there has been a reason for moving the conditional comments from the body tag to the html tag in the first place. Something with deferred loading of scripts in IE8?

Update: Ah, here it is http://webforscher.wordpress.com/2010/05/20/ie-6-slowing-down-ie-8/

MartinMa commented 13 years ago

A potential solution to this problem could be this arrangement:

    <!doctype html>
    <html class="no-js" lang="en">
        <head>
            <meta charset="utf-8">
            <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><![endif]-->
            <title>Non-blocking downloads in IE8</title>
            <link rel="stylesheet" href="css/some.css">
            <link rel="stylesheet" href="css/random.css">
            <link rel="stylesheet" href="css/files.css">
            <!--[if IE 6 ]><link rel="stylesheet" href="css/and.css"><![endif]-->
            <link rel="stylesheet" href="css/a.css">
            <link rel="stylesheet" href="css/couple.css">
            <link rel="stylesheet" href="css/more.css">
            <link rel="stylesheet" href="css/huzzah.css">
        </head>
        <!--[if lt IE 7 ]> <body class="ie6"> <![endif]-->
        <!--[if IE 7 ]>    <body class="ie7"> <![endif]-->
        <!--[if IE 8 ]>    <body class="ie8"> <![endif]-->
        <!--[if (gte IE 9)|!(IE)]><!--> <body> <!--<![endif]-->
            <h1 style='color:green'>Non-blocking downloads in IE8.</h1>
        </body>
    </html>

This doesn't block downloads in IE 8 (see test cases below) and removes the compat view icon (only tested in current IE9).

Non-blocking: http://www.webpagetest.org/result/110320_MW_6S9X/

Blocking: http://www.webpagetest.org/result/110320_W1_6S9H/

P.S. As a plus it validates as HTML5 :)

gabor commented 13 years ago

maybe the documentation could be changed a little (assuming the http-header method is bulletproof). currently in the html it is:

<!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
       Remove this if you use the .htaccess -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

we could change the html-comment to say something like you-should-do-this-in-htaccess-only-do-it-in-html-if-you-cannot-do-that...

MartinMa commented 13 years ago

@gabor I agree, the http-header method should be the way to do this. Although Google planned to lobby validators to tolerate "X-*" http-equiv values and keys according to the comments on this issue here: http://code.google.com/p/chromium/issues/detail?id=22795

On another note, my sample code from above doesn't invoke chrome frame so it has to be changed to this (on line 5):

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!--[if IE]><![endif]-->

The empty conditional comment is because of the blocking issue in IE8. This all is starting to get a little messy :)

irae commented 13 years ago

I also tested this issue and some combinations for resolving it. I believe that the better solution is to both move the conditional comments down and add the classes to with javascript:

<!doctype html>
<html class="no-js" lang="en">
<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta charset="utf-8">
  <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
       Remove meta X-UA-Compatible if you use the .htaccess -->

  <!--[if lt IE 7 ]> <script>document.documentElement.className+=' ie6';</script> <![endif]-->
  <!--[if IE 7 ]>    <script>document.documentElement.className+=' ie7';</script> <![endif]-->
  <!--[if IE 8 ]>    <script>document.documentElement.className+=' ie8';</script> <![endif]-->
  <!-- Always put your css and js below this line, see
       https://github.com/paulirish/html5-boilerplate/issues/issue/378 -->

  <title></title>

I've added a pull request with this solution. The only downside I can imagine is having to support IE < 9 with javascript disabled. And this would be such an edge case that pointing an URL to this issue should resolve the problem.

irae commented 13 years ago

I forgot to mention. AFAIK, Google Chrome frame docs advise putting the X-UA-Compatible as above in the document as possible. Since <meta charset="utf-8"> must be within the first 512 bytes it was necessary for it to be put before the X-UA-Compatible in previous versions.

So this time I changed the order, since the charset will not be affected by the conditional comments above it.

chuanxshi commented 13 years ago

@irae: it might be a nice idea, but is it too much of a hack? imo

ghost commented 13 years ago

I agree. I think the Javascript idea is very amateurish, especially since it seeks to resolve an issue caused by a piece of code that is not valid HTML5 in the first place. I would hate to see the HTML5 Boilerplate dragged away from the standards-compliance and best-practice foundation on which it was initially built.

Someone put in a pull request (might be the same guy; I don't remember) offering up the same bit of code. I would like to think that it isn't actually taken into serious consideration.

irae commented 13 years ago

I also agree that this is amateurish. But I have a project that I am writing the front end code and I will not have access to the server. I don't even know where they will host it, what technologies, etc. This is a solution, ugly as it is, that is working better then the current solution of conditional comments around the <html> tag. In this case I prefer this ugliness that's only comments to modern browsers to broken functionality.

If anyone comes up with a better idea, I will be glad to change in my working projects and remove my own pull request.

MartinMa commented 13 years ago

I noticed that my other comment on here is a bit distorted, so here are my two cents again.

  1. Either remove the meta tag altogether and refer to .htaccess (or other server config files).
  2. Or move the conditional comments down to the body tag. Like this:
    <!doctype html>
    <html class="no-js" lang="en">
        <head>
            <meta charset="utf-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
            <!--[if IE]><![endif]-->
            <title>Everybody here is a cloud</title>
        </head>
        <!--[if lt IE 7 ]> <body class="ie6"> <![endif]-->
        <!--[if IE 7 ]>    <body class="ie7"> <![endif]-->
        <!--[if IE 8 ]>    <body class="ie8"> <![endif]-->
        <!--[if (gte IE 9)|!(IE)]><!--> <body> <!--<![endif]-->
            <h1>Everybody here will evaporate</h1>
        </body>
    </html>

Like I said before, we need the empty conditional comment because of the newly introduced "IE8 blocking Issue". See test cases for details on that: Non-blocking: http://www.webpagetest.org/result/110320_MW_6S9X/ Blocking: http://www.webpagetest.org/result/110320_W1_6S9H/

Thoughts? I like this one better, because it involves no Javascript to add the classes.

edit: corrected a little slip in the code

necolas commented 13 years ago

@MartinMa: I think a problem with (2) is that a lot of CMS add id/classes to the body tag, which would create a lot of duplication. Furthermore, it could create problems for people writing IE6-specific styles because the browser doesn't really support chains of classes, e.g., ie6.mybodyclass {}

chuanxshi commented 13 years ago

or we remove 'h5bp stripped version' and make h5bp download rely more on boilerplate custom (aka initializr), if people tick the option to have conditional comments, then a warning says they must have the X-UA-Compatible in server config.

julienw commented 13 years ago

I use "" as the very first line in my HTML files. Then I use the "useful" conditional comments after the X-UA-Compatible meta.

IE8 is still in "IE8 Standards Mode". Didn't try with IE9 and I don't know how to check in IE7.

My 2 cents.

necolas commented 13 years ago

ignore me

julienw commented 13 years ago

I don't get it. I said I'm in standards mode event with these comments before the tag.

But some comments in this bug are saying that if you use some conditional comments around , then IE goes to quirks mode.

necolas commented 13 years ago

@julienw Apologies, I misread your previous comment. If you open up IE8's dev tools, please can you check if you have "Browser Mode" set to "Internet Explorer 8" or "Internet Explorer 8 Compatibility View". If it's the former, it shouldn't drop the doc into IE7 Standards. If it's the later, it should drop the doc into IE7 Standards when using conditional comments outside of the opening html tag.

julienw commented 13 years ago

I just checked using "IE8 Compatibility View", and it's still IE8 standards.

necolas commented 13 years ago

@julienw Please could you drop a reduced testcase in a pastebin and link to it here? Thanks

mathiasbynens commented 13 years ago

http://mathiasbynens.be/notes/safe-css-hacks#comment-13 may be of interest.

zachleat commented 13 years ago

Seems like there is a bit of confusion. Just because the button is showing doesn't mean that compatibility view is enabled. The button will be in a depressed state for that.

If the meta tag/http header is interpreted correctly, the button doesn't display at all (which is the desired behavior this ticket is trying to achieve).

necolas commented 13 years ago

OK! @julienw seems correct, here's a basic testcase of what he is describing. It doesn't drop IE8 into IE7 mode. But other issues related to use on body remain.

Ex 1 : http://pastie.org/1926628

Switching the conditional comments back to the html element but leaving the empty conditional comment above the doctype also prevents IE8 from dropping into IE7 mode without needing the X-UA-Compatible header being set on the server-side.

Ex 2 : http://pastie.org/1926635

julienw commented 13 years ago

Made this : http://pastie.org/1926658

Seems to trigger IE8 standards in both IE8 and IE8 Compat.

necolas commented 13 years ago

@zachleat You may well be right about the confusion. Would be great if you got involved in this issue, if you have time. Thanks

julienw commented 13 years ago

@zachleat @necolas in my code, I use document.documentMode to show the mode. Si I guess with this code there will be no confusion :)

zachleat commented 13 years ago

This seems to get rid of the button, maintaining Standards mode in both IE8 and IE9. https://gist.github.com/980895

You might also think that since we have a comment above the doctype, it might trigger quirks mode, but I tested it in IE7 too and it maintains Standards mode. IE must pre-process the conditional comments out prior to rendering, avoiding that bug somehow.

Please confirm, but take care to remove of any existing Compatibility View settings in your browser for intranet sites (Tools -> Compat View) or .htaccess rules that might interfere.

necolas commented 13 years ago

@zachleat That was what I found in the "Ex 2" pastie as well. Glad you can confirm it.

zachleat commented 13 years ago

@necolas Ah, apparently I'm horrible at reading. Sorry about that.

paulirish commented 13 years ago

so an empty CC before the doctype eh

cool hack.. what do you guys think? put into the BP? or document.. this one seems like a tough call..

irae commented 13 years ago

Is this safe to use? Does this work in feature phones browsers? Not that It would be a real problem, but it's best to know what kind of problem, if any, this could raise before inclusion.

DingoEatingFuzz commented 13 years ago

Being the person who raised this issue, I obviously hate the compatibility view (aka, break your website) button a lot. However, I am also on the fence with this.

I honestly don't care about standards; I care about what makes my websites work. This part of me says put the hack in because it works.

The other part of me says don't put the hack in because boilerplate code isn't supposed to be bloated. If the average person is just going to delete the hack and opt for sending this via HTTP header then it shouldn't be in the code by default. It should just be documented.

So I guess my only question is, how many people will need/use this?

necolas commented 13 years ago

@DingoEatingFuzz and others who have reporting this issue : please can you test to confirm if this alternative code avoids the issue too. It should do because the conditional comments appear after the X-UA meta tag and the opening html tag will be replaced by those that are included in head.

Another bonus is that you can stick all html attributes you want (lang and facebook xmlns stuff) on the html tag that is not within the conditional comments...the extra class in the conditional comment is then added to the first html tag. DRYer :)

<!doctype html>
<html lang="en">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
        <!--[if IE 7]><html class="no-js ie7"><![endif]-->
        <!--[if IE 8]><html class="no-js ie8"><![endif]-->
        <!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->

        <meta charset="utf-8">
        <title>Document</title>
    </head>
    <body>
    </body>
</html>

vs

<!--[if IE]><![endif]-->
<!doctype html>
<html lang="en">
<!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
<!--[if IE 7]><html class="no-js ie7"><![endif]-->
<!--[if IE 8]><html class="no-js ie8"><![endif]-->
<!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta charset="utf-8">
        <title>Document</title>
    </head>
    <body>
    </body>
</html>
irae commented 13 years ago

@DingoEatingFuzz I think that the people who needs this code most are probably the ones with less advanced html skils and possibly less able to configure apache (or other httpd).

I vote for inclusion with inline comment about it's removal.

Why? Removing is easier then inserting it and forgetting or not caring to remove it is (probably) less harmful then forgetting or not caring to insert it.

(and I'm still wishing for some kind soul with many phones available to test this on older phones)

necolas commented 13 years ago

I've done a write up of @julienw's technique and the one I posted above http://nicolasgallagher.com/better-conditional-classnames-for-hack-free-css/

What do people think of these techniques?

julienw commented 13 years ago

I think we have to understand what IE does.

My view is that it does some heuristics with the beginning of a file. We already know this for determining the content-type of a file, either with the first bytes or with the meta charset. But maybe he does this too for "preloading" the conditional comments engine (that could be why conditional comments around don't trigger the 100ms penalty), or for finding the document mode.

Someone has to do some more systematic tests, and it won't be me as I'll soon have no access to computer. :-)

paulirish commented 13 years ago

Nice writeup.

To me, it seems like the best solution here is docs on setting this in your server config. Similar to the favicon stuff.. Set it back there and clean up the markup.

dougwaldron commented 13 years ago

@necolas I haven't tested it, but I think your double-<html>-tag idea should be written like so:

<!doctype html>
<html lang="en" class="no-js">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
        <!--[if IE 7]><html class="no-js ie7"><![endif]-->
        <!--[if IE 8]><html class="no-js ie8"><![endif]-->
        <!--[if gt IE 8]><html class="no-js"><![endif]-->
        <meta charset="utf-8">
        <title>Document</title>
    </head>
    <body>
    </body>
</html>

The difference is in the final conditional comment. Non-IE browsers will use the very first <html> tag and so don't need the extra one that shows up in the "gt IE 8" line. A further simplification is therefore possible:

<!doctype html>
<html lang="en" class="no-js">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
        <!--[if IE 7]><html class="no-js ie7"><![endif]-->
        <!--[if IE 8]><html class="no-js ie8"><![endif]-->
        <meta charset="utf-8">
        <title>Document</title>
    </head>
    <body>
    </body>
</html>

In this example, IE9 and up will use the original <html> tag just like non-IE browsers.

Finally, using the method in your most recent check-in on index.html, you could just write:

<!doctype html>
<html lang="en" class="no-js">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <!--[if lt IE 9]><html class="no-js oldie" lang="en"><![endif]-->
        <meta charset="utf-8">
        <title>Document</title>
    </head>
    <body>
    </body>
</html>

... and only old versions of IE would get the extra <html> tag. All other browsers (and validators) would see only the first.

necolas commented 13 years ago

@guitarzan That won't work because the IE-specific classes won't bubble up to the first <html> tag. You can't have a class on the uncommented tag for this to work.

dougwaldron commented 13 years ago

I see (I think). So this would work:

<!doctype html>
<html lang="en">
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <!--[if lt IE 9]><html class="oldie"><![endif]-->
        <meta charset="utf-8">
        <title>Document</title>
    </head>
    <body>
    </body>
</html>

... if you don't need the "no-js" class?