57
votes

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.

15
A test case in which you can reproduce this behavior would be most useful.BoltClock
Can you give the code, fiddle or url to the problem?Sven Bieder
Not enough code to make a good assumption.Christoph
Here's a live sample. imagorecords.com/~andy All that I'm concerned about is the ICONS in IE8. IF they work, reload the page and the become letters.Andy

15 Answers

71
votes

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

22
votes

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

18
votes

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!

5
votes

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!

4
votes

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;
    });
}
4
votes

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
votes

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);
});
1
votes

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.

1
votes

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

I.e.:

.icon:before {
   content: "\f108" !important;
}
0
votes

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.

0
votes

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
votes

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.

-1
votes

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

-1
votes

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.

-4
votes

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);