57

UPDATE: I've written a blog post about what I've learned about this issue. I still don't fully understand it, but hopefully someone will read this and shed some light on my issue: http://andymcfee.com/2012/04/04/icon-fonts-pseudo-elements-and-ie8

I have a page where I'm using @font-face to import a custom font for icons. The icons are created with a class:

.icon {font-family: 'icon-font';}
.icon:before {content: 'A';}

And voila, I have whatever icon is used for "A". Pretty standard stuff, works in all browsers, including IE8.

However, in IE8, I have a bizarre bug. When the page loads, the font is not working. Instead of icons, I have letters all over the place. Once I hover OVER the page (body), half the letters become icons. The rest become icons when I hover over them.

SO the font-face is embedding properly. The font-family and content properties are both working, but something else is causing the icons to load only after hover.

So there's some sort of bug with @font-face in IE8 when you try to use the font with :before{content: 'a'} but I have no idea what the bug is.

I've searched for hours on here for a similar bug/IE8 issue/anything, but I've had no luck and I'm about to go crazy. ANY suggestions?

Let me know if I can provide anymore info that might be helpful.

EDIT: Updated the broken link to the blog post.

Andy
  • 671
  • 1
  • 6
  • 6

15 Answers15

71

I had the same bug.

I fixed it by executing this script on domready (only for IE8 of course):

var head = document.getElementsByTagName('head')[0],
    style = document.createElement('style');
style.type = 'text/css';
style.styleSheet.cssText = ':before,:after{content:none !important';
head.appendChild(style);
setTimeout(function(){
    head.removeChild(style);
}, 0);

This lets IE8 redraw all :before and :after pseudo elements

ausi
  • 7,253
  • 2
  • 31
  • 48
  • 2
    Is this snippet slightly misformed? It looks to me like there should be a closing `}` in the `cssText`. – David Tuite Nov 14 '12 at 13:12
  • 2
    No, it is not misformed. You can omit the last bracket as well as the last semicolon. This makes the code 2 bytes smaller. – ausi Nov 15 '12 at 08:12
  • 1
    Thanks for solution, and this should be attached to window.load not to domready as mentioned, because this script should run after the fonts are loaded – Roman Jan 11 '13 at 13:38
  • 1
    @RomanTheGreat i'm not sure. It worked for me with onDomready on many different websites without any problems. The best way would be to execute the script on domready and on load, because the onLoad event fires very late on big websites. – ausi Jan 12 '13 at 12:22
  • Thanks for the solution. We have hidden div to show and after each first show of a hidden div the script must be called. – Sébastien Barbieri Jul 11 '13 at 15:02
  • 6
    @ausi premature optimization much? – Steve Rice Aug 14 '13 at 22:35
  • @SteveRice what do you mean? – ausi Aug 15 '13 at 11:28
  • 13
    @ausi I would argue that a 2-byte savings is not worth the loss in readability. – Steve Rice Aug 15 '13 at 16:37
  • 2
    @SteveRice 2 bytes of a script that is only 223 bytes long are about 0.9%. Why is `...ant;}';` more readable than `...ant';`? – ausi Aug 17 '13 at 12:56
  • 35
    Case in point, developers like @DavidTuite who aren't familiar with such micro-optimizations see it and think there's a bug. That kind of optimization is fine, but it's better to let a build script generate it than affect the readability of the source. If such byte savings are so important at this stage, why are your variables named "head" and "style" instead of "h" and "s"? – Steve Rice Aug 21 '13 at 21:24
  • 1
    @SteveRice Because tools like YUI Compressor or Google Closure Compiler are able to rename the variables, but they are not able to remove the semicolon and the curly bracket in the CSS string. – ausi Aug 22 '13 at 06:04
  • If you wanted to shrink this, couldn't you remove the style.type declaration? – Doug Avery Dec 11 '13 at 19:58
  • 1
    @DougAvery No, the type declaration is required for IE8. If omitted IE8 would throw an error message like `'styleSheet' is null or not an object`. – ausi Dec 12 '13 at 00:04
  • @ausi Can you confirm how to call this function? What is the best way to detect IE8 and wait for DOM ready? Thanks for your help. – kdev Jan 08 '14 at 15:29
  • 1
    @kdev See http://stackoverflow.com/questions/5574842 and http://stackoverflow.com/questions/6902280 – ausi Jan 08 '14 at 17:39
  • 1
    This script fixed my issue. I did wrap it in since we were only having the problem in IE8 – Jimmy Bosse Aug 08 '14 at 13:37
  • Just because you can omit `;}` doesn't mean you should. You can technically omit all of the semi-colons in JavaScript as well without affecting the way your JavaScript is executed, but while functional this is actually considered a bug. – zykadelic Oct 20 '14 at 08:42
  • @zykadelic Omitting `;}` at the end of the stylesheet is described in the [CSS spec](http://www.w3.org/TR/CSS2/syndata.html#unexpected-eof) and is totally safe. The only valid point against omitting `;}` here is confusion of developers, as pointed out by @SteveRice. JavaScript is completely different, you cannot omit all semicolons without affecting how it gets executed, see [2ality.com](http://www.2ality.com/2011/05/semicolon-insertion.html). – ausi Oct 23 '14 at 08:10
  • @ausi Thanks for the links. I would still consider this a bug, though. Many browsers, including Safari, closes any HTML tags you've accidentally left open. This is a very kind thing for browsers to do, but relies on the browser being capable of handling that situation. While w3 encourages browsers to handle *this* situation, it is still technically invalid CSS. – zykadelic Oct 23 '14 at 15:09
  • Here's a variation to this kind of solution which you may prefer http://stackoverflow.com/a/33162245/4387229 – Simon Watson Oct 16 '15 at 04:09
21

I recently encountered this as well, and fixed it by including the @font-face twice in my CSS file. The first @font-face is used by IE and the second is used by other browsers.

@font-face {
  font-family: "SocialFoundicons";
  src: url("//www.tintup.com/public/css/foundation_icons_social/social_foundicons.eot");
  font-weight: normal;
  font-style: normal;
}

@font-face {
  font-family: "SocialFoundicons";
  src: url("//www.tintup.com/public/css/foundation_icons_social/social_foundicons.eot"),
       url("//www.tintup.com/public/css/foundation_icons_social/social_foundicons.eot?#iefix") format("embedded-opentype"),
       url("//www.tintup.com/public/css/foundation_icons_social/social_foundicons.woff") format("woff"), 
       url("//www.tintup.com/public/css/foundation_icons_social/social_foundicons.ttf") format("truetype"), 
       url("//www.tintup.com/public/css/foundation_icons_social/social_foundicons.svg#SocialFoundicons") format("svg");
  font-weight: normal;
  font-style: normal;
}

Source: http://www.boonex.com/n/ie8-icon-font-fix-and-unused-language-keys-2012-08-20

Ryo C.
  • 341
  • 3
  • 5
  • 1
    For me, this solution worked around 50% of the time. Every second time I loaded the page (using F5 to clear cache) the icons would not show up. I combined this solution with the one by ausi (which didn't work at all by itself for me) and now it's working 100% of the time. – Ben Feb 07 '14 at 01:37
  • are there CORS issues associated with the IE font-face? – nnnn Sep 17 '14 at 18:39
18

I was experimenting exactly the same problem. In IE8 the webfont icon (using pseudo-elements) sometimes renders the fallback font but when you hover it the webfont icon comes visible.

The icons were implemented using :after and :before with IE7 support, like this.

In my case, the project is developed in HTML5 and using htmlshiv to support the new HTML5 tags in older browsers.

The problem was ridiculously solved placing the html5shiv script tag below the main CSS:

<link rel="stylesheet" href="/stylesheets/main.css" type="text/css">
<!--[if lt IE 9]>
  <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

I'm happy now :) I hope that helps!

Community
  • 1
  • 1
vieron
  • 991
  • 7
  • 11
  • 1
    Going to try this out and I'll let you know how it works for me. – Andy Apr 10 '12 at 09:47
  • 2
    That worked for me at first, but I was curious how can HTML5shiv fix this, because this isn't HTML5 feature.I did some research and it turns out that this fixed problem because of *network latency*. In that way, you blocked page rendering for a few miliseconds so font could be loaded before content. – Boris Brdarić Dec 21 '12 at 12:38
5

I was having a similar issue where the font would not show up until I hovered over the parent element. I was able to fix this problem by triggering a focus event on the elements parent.

element.parent().trigger('focus');

Hope this helps someone!

Lakota Lefler
  • 151
  • 3
  • 7
  • This worked for me. The above methods work too but only on the initial page render on IE8. If there are enable/disable on glyphicons, then the transitions won't be smooth. – icedek Jan 29 '15 at 21:21
4

Workaround:

Find stylesheet and reload on document ready if IE8:

Sample HTML:

<!DOCTYPE html>
<html>
<head>
<!-- … -->
<link id="base-css" rel="stylesheet" href="/styles.base.css" type="text/css" />
<!-- … -->
</head>
<!-- … -->
</html>

Sample JavaScript:

// Reload stylesheet on document ready if IE8
if ($.browser.msie && 8 == parseInt($.browser.version)) {
    $(function() {
        var $ss = $('#base-css');
        $ss[0].href = $ss[0].href;
    });
}
lemats
  • 616
  • 6
  • 5
4

The above solutions didn't fix the issue for me when IE8 is refreshed. Also I found some problems where adding a stylesheet would break the IE8 background size fix backgroundsize.min.htc

So here's what I did:

Add ie8 class to html tag:

<!--[if IE 8 ]><html class="ie8"><![endif]-->

Add loading class to the body:

<body class='loading'>

Override the CSS content attribute only for IE8:

<style>
.ie8 .loading .icon:before {
    content: '' !important;
}
</style>

Now remove the loading class on DOM ready:

$( function() {
    $('body').removeClass('loading')
} );

Now it works!

2

Based on the answer from @ausi, you can refactor this with jQuery and CoffeeScript down to 4 lines:

$(document).ready ->
  $style = $('<style type="text/css">:before,:after{content:none !important}</style>')
  $('head').append $style
  setTimeout (-> $style.remove()), 0

or with JavaScript syntax:

$(document).ready(function() {
  var $style;
  $style = $('<style type="text/css">:before,:after{content:none !important}</style>');
  $('head').append($style);
  return setTimeout((function() {
    return $style.remove();
  }), 0);
});
rpearce
  • 1,720
  • 1
  • 21
  • 29
1

I had a similar glitch in Chrome. Here is my fix:

setTimeout(function(){
    jQuery('head').append('<style id="fontfix">*:before,*:after{}</style>');
    },100);

My guess is that the pseudo css styling was rendered before the webfont was ready, which resulted in blank glyphs. After the page loaded, hovering or altering the css in any way caused them to magically appear. So my fix just forces a css update that does nothing.

MrMattSim
  • 151
  • 1
  • 5
  • This is very similar to [my solution](http://stackoverflow.com/a/31122257/573634) and I guess it has to do with refreshing the CSS in some manner. – Hanna Jun 29 '15 at 17:48
1

For me, the problem was simply solved using the declaration !important on the content attribute.

I.e.:

.icon:before {
   content: "\f108" !important;
}
KhorneHoly
  • 4,666
  • 6
  • 43
  • 75
  • 1
    `!important` isn't always a good choice because it only can be overwritten with a even more specific selector with also an `!important` statement. Keep that in mind – KhorneHoly Jul 16 '14 at 13:11
  • 1
    yes true, but as long as you don't need to change the content it works fine. – user3845138 Jul 17 '14 at 06:53
0

Alright, so I've been trying to fix this issue for a while. Weirdly enough the icomoon demo kept working in IE8 but mine never did, even though I felt like I had pretty much the same thing in place. So I started boiling everything down (the icomoon demo as well as my own implementation) and what I found two things that needed to be there for this to work.

First, I found that I needed to keep the cachebuster on the filename.

So in my implementation I had:

@font-face {
    font-family: 'iconFont';
    src:url('icon_font.eot');
    src:url('icon_font.eot') format('embedded-opentype'),
        url('icon_font.woff') format('woff'),
        url('icon_font.ttf') format('truetype'),
        url('icon_font.svg') format('svg');
    font-weight: normal;
    font-style: normal;
}

But what I needed was:

@font-face {
    font-family: 'iconFont';
    src:url('icon_font.eot?-v9zs5u');
    src:url('icon_font.eot?#iefix-v9zs5u') format('embedded-opentype'),
        url('icon_font.woff?-v9zs5u') format('woff'),
        url('icon_font.ttf?-v9zs5u') format('truetype'),
        url('icon_font.svg?-v9zs5u#icomoon') format('svg');
    font-weight: normal;
    font-style: normal;
}

Second, and this one doesn't make sense, is that I needed something in the stylesheet that had a :hover pseudo selector. It doesn't matter what it's on or what the rules for it are, it just needed something and then the icons would appear when I hovered over them.

So I simply inserted [data-icon]:hover{} into my CSS stylesheet (just like that, without any rules).

I wish I could explain to you why this works, but I don't understand. My best guess is that this triggers some sort of refresh in IE8 and causes the icons to show up.

Hanna
  • 10,315
  • 11
  • 56
  • 89
0

My IE8 issue was solved by removing the double-colon in the pseudo-element selector.

Does not display an icon in IE8...

.icon::before {
    content: "\76";
}

Does display an icon in IE8...

.icon:before {
    content: "\76";
}
0

Ok so here's a variation of @ausi's solution that I've used which has worked for me. This solution comes from Adam's comment at the bottom of this article http://andymcfee.com/2012/04/04/icon-fonts-pseudo-elements-and-ie8/

I thought I'd put it here in more detail to make it quicker for others to use.

Set an extra class eg. ie-loading-fix on the html tag for IE8. Include all your CSS and then after that have a conditional JS file for IE8. For example:

<!DOCTYPE html>
<!--[if IE 8]>    <html class="ie-loading-fix"> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <html> <!--<![endif]-->
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- Include all your CSS before JS -->
    <link rel="stylesheet" type="text/css" href="css/main.css">

    <!--[if lt IE 9]>
    <script src="js/ie.js"></script>
    <![endif]-->
  </head>
  ...

Then at the top of your main CSS file include something like:

.ie-loading-fix :before,
.ie-loading-fix :after {
  content: none !important;
}

Then in your IE8 js/ie.js file include the following:

window.onload = function () {
  var cname = document.documentElement.className;
  cname = cname.replace('ie-loading-fix', '');
  document.documentElement.className = cname;
}

This JS will remove the ie-loading-fix styling which is hiding all :before and :after content and will force IE8 to redraw all :before and :after content once the page has loaded.

This solution fixed an issue I was having with Font Awesome v4.4 which would frequently switch IE8 into Compatibility View or crash even though I was explicitly setting the page to load in Edge mode using the meta tag.

Simon Watson
  • 1,550
  • 16
  • 16
-1

I did some research as per @vieron answer and it turns out that another way to fix this problem is to block page rendering for a few miliseconds so font could be loaded before content. Though, blocking page rendering isn't smartest way to solve this, because you can't know how much ms you should block.

I proved it by putting php file as source file for javascript.

<!--[if lt IE 9]>
<script src="/block.php"></script>
<![endif]-->

block.php

<?php
usleep(200000);
?>

If you have any external javascript libraries such as HTML5shiv, this happens automagically, except you are running site on local network (intranet or localhost) with very low latency and no scripts before content.

That explains the fact that the problem isn't more widespreaded and noticed.

I really tried hard to find an elegant solution, but I can't find something that excludes javascript or blocking page rendering for IE.

Community
  • 1
  • 1
Boris Brdarić
  • 4,674
  • 2
  • 24
  • 19
-1

If I am not wrong then IE doesn't reads TTF font, it requires EOT fonts

Nick
  • 287
  • 1
  • 5
  • 14
  • I'm using both the EOT and the EOT?#iefix as well. Again, once I hover, the font shows up. – Andy Mar 22 '12 at 08:34
-4

This is the fix, we have faced this issue with IE7, IE8 and IE9 when using ajax

setInterval(function(){
    var $ss = $('#base-css');
    $ss[0].href = $ss[0].href;
},300);