Menu icon Foundation
Foundation 5 and IE8

Firstly, I know, I know, IE8 is nearly dead and the recommended way to use Foundation on it is to stick with version 3. However, I have a new site build coming up which unfortunately requires IE8 support, and I'd really like to use the new Foundation 5 with it. So I've had a bit of a play!

The 2 main issues seem to be IE8's lack of media query support, and also lack of support for rem units in CSS.

I've managed to overcome both with a few simple polyfills!

To fix the media query issue, just add this to your head:

<!--[if lt IE 9]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.2/html5shiv.js"></script>
  <script src="//s3.amazonaws.com/nwapi/nwmatcher/nwmatcher-1.2.5-min.js"></script>
  <script src="//html5base.googlecode.com/svn-history/r38/trunk/js/selectivizr-1.0.3b.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.1.0/respond.min.js"></script>
<![endif]-->
            

         

Then to fix the rem issue, just add a link to this polyfill js file at the bottom of your body tag: https://github.com/chuckcarpenter/REM-unit-polyfill

(Note: there is currently a bug in the REM polyfill that seems to stop it working on an element if a property the element includes the !important rule, in the following screenshots I've just removed !important from .button in foundation.css, until the bug can be fixed)

FOUNDATION 5 IN IE8 BEFORE:

Screen shot 2013 11 22 at 16.13.47

FOUNDATION 5 IN IE8 AFTER:

Screen shot 2013 11 22 at 16.14.41

Not bad eh?!

Now, that's just the CSS side working, I doubt it will be as simple to get any of the Foundation 5 JavaScript working as it relies on jQuery 2.0 which is IE9+. But hopefully that will help out some people to get things looking better on IE8.

ie8Foundation 5usage

Firstly, I know, I know, IE8 is nearly dead and the recommended way to use Foundation on it is to stick with version 3. However, I have a new site build coming up which unfortunately requires IE8 support, and I'd really like to use the new Foundation 5 with it. So I've had a bit of a play!

The 2 main issues seem to be IE8's lack of media query support, and also lack of support for rem units in CSS.

I've managed to overcome both with a few simple polyfills!

To fix the media query issue, just add this to your head:

<!--[if lt IE 9]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.2/html5shiv.js"></script>
  <script src="//s3.amazonaws.com/nwapi/nwmatcher/nwmatcher-1.2.5-min.js"></script>
  <script src="//html5base.googlecode.com/svn-history/r38/trunk/js/selectivizr-1.0.3b.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.1.0/respond.min.js"></script>
<![endif]-->
            

         

Then to fix the rem issue, just add a link to this polyfill js file at the bottom of your body tag: https://github.com/chuckcarpenter/REM-unit-polyfill

(Note: there is currently a bug in the REM polyfill that seems to stop it working on an element if a property the element includes the !important rule, in the following screenshots I've just removed !important from .button in foundation.css, until the bug can be fixed)

FOUNDATION 5 IN IE8 BEFORE:

Screen shot 2013 11 22 at 16.13.47

FOUNDATION 5 IN IE8 AFTER:

Screen shot 2013 11 22 at 16.14.41

Not bad eh?!

Now, that's just the CSS side working, I doubt it will be as simple to get any of the Foundation 5 JavaScript working as it relies on jQuery 2.0 which is IE9+. But hopefully that will help out some people to get things looking better on IE8.

Matt Bainton over 3 years ago

@Jared, if you are using the Grunt + libsass version of Foundation 5, it is pretty trivial to fix the REM support issue by adding grunt-pixrem task to post-process your compiled css. That was one of the easiest parts of this puzzle.

Jordan Humphreys over 3 years ago

We are using some ECMAScript 5 features, like "Function.prototype.bind", that are not supported in IE8 for foundation 5. You could, however, use a polyfil to add support.

James Cocker over 3 years ago

Hi Daniel, see this Stack Overflow for an explanation of the polyfills used. http://stackoverflow.com/questions/16720043/how-do-you-use-mobile-first-with-in-ie8 I think you're correct that they're not all just for media queries.

Paul @ cactusoft over 3 years ago

We've found the easiest solution until IE8 disappears is to detect browser server side, and then serve a more conventional 'skin' that is not based on Foundation at all to IE8 and earlier hold outs.

Of course that older skin is not responsive, but nobody on IE8 or earlier is going to be on a tablet or mobile so it really doesn't matter. Things don't need to be perfect for IE8 or earlier, they just need to be usable.

Ty Cahill over 3 years ago

I'm in the same boat as many of you. My clients see about 10% of visits coming from IE8, which is a significant number. (Anyone at ZURB want to reduce their paycheck by 10%?)

I don't think IE8 is going to die away soon. I work a lot with government agencies who are stuck with IE 8 because their enterprise software won't run on anything else. Yes, it's stupid, but nothing we can do about that.

For now I must switch over to Bootstrap, although I really don't want to.

Foundation went too bleeding edge on us. Would have been better to make it work on IE 8 and progressive enhance for modern browsers. Even jQuery cautions people against using 2.x right now. I hope to return to Foundation in a couple years if the browser landscape changes significantly.

Trevor West over 3 years ago

I have to support IE8 and 7 also I am just going to do something simple like this with PHP

function foundationVersion() {
preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches);
if (count($matches) > 1) {
$foundation = ($matches[1] <= 8) ? 4 : 5;
} else {
$foundation = 5;
}
return $foundation;
}

I will load foundation 4 and 5 depending on the browser. The syntax of 4 and 5 is almost identical and shouldn't be too hard to just switch the javascript/css files around.

James Cocker over 3 years ago

A quick follow up. Sorry, this forum really needs e-mail notifications for replies!

Regarding the polyfils, respond.js is the main one you need. It gives IE8 support for media queries so that Foundation can display the large desktop view in IE8 rather than just the small mobile view.

REM.js is also required to give IE8 support for reading rem units which Foundation uses throughout it's CSS. The !important bug seems to nearly be fixed: https://github.com/chuckcarpenter/REM-unit-polyfill/issues/29

For anyone asking about JavaScript, my main post was about getting the CSS to work in IE8. The Foundation 5 JavaScript will likely not work in IE8, and will cause errors, as it requires jQuery 2.0 which requires IE9+. If you really want to use Foundation 5 in IE8, then you'll need to either not use any of the Foundation JavaScript features, or look at using the Foundation 3/4 JavaScript.

For anyone having trouble getting the base CSS version of Foundation 5 working on IE8, here is an example with it all working: www.pswd.biz/f5-ie8

Giorgos Grispos almost 3 years ago

Hello,

I've used many different solutions however that's the one and most complete solution for F5 / IE8

have test it a lot and seems more than fine.

http://www.kycosoftware.com/blog/article/getting-foundation-5-to-work-in-ie8

Cheers, Giorgos

R Fletch over 3 years ago

Reveal Modal working in IE8 with simple javascript in Zurb Foundation 5.

Add an onclick function to button which only works in IE8 and below. This works because IE8 and below don't support "addEventListener", only "addEvent".

Could use this same javascript workaround to "fix" other Foundation features in IE8.

<a href="#" data-reveal-id="signupModal" data-reveal>
  <div class="button radius" onclick="ie8modal();">Get Started Now</div>
</a>
 function ie8modal() {
  if (!document.addEventListener) {
    document.getElementById('signupModal').style.display = 'block';
    document.getElementById('signupModal').style.opacity = '0';
    document.getElementById('signupModal').style.visibility = 'visible';
  }
}

Gavin Thomas over 3 years ago

BTW Glenn Philp

Thanks a million for your code. It's worked an absolute treat. I'm importing the foundation settings file and it's working really well!

Glenn Philp over 3 years ago

Everything James Cooker mentioned worked exactly as planned.

However, it is possible to create a IE specific stylesheet using the modifications below. How is this possible? Using Chris Coyier's Conditional Media Queries Mixin and Sébastien Axinté's REM to PX Browser Function with SASS.

The first 2 variables control whether it is putting out media queries or only large and medium classes, plus converting REMs to PXs. It does create some redundant code (mainly with Columns and Row classes). I have spent weeks on this as I work for a medical institution that employees approximate 14,000 and although they recently updated to Windows 7, we are forced to stay on IE8 in IE7 compatibility mode so Foundation by itself just wouldn't work.

And supplying the scripts above are a solution, I feel this might even be better for the grid. It is by no where near perfect, so if you implement it remember IE 7 and 8 don't know box-sizing or the :last-child.

Also for those working with IE 8 you can implement jQuery 1.10 (preferably within a conditional). Not all items work, however, I can tell you the Reveal Modal works (doesn't center and the background shows solid, instead of see-thru) and the tabs work. The dropdown buttons and orbit slider aren't working currently. Instead I replaced the orbit slider with SlideMe and it is working across all browsers.

$MQs: true;
$px-only: false;
$text-direction: ltr;
$opposite-direction: right;
$default-float: left;
$rem-base: 16px !default;

// It strips the unit of measure and returns it
@function strip-unit($num) {
  @return $num / ($num * 0 + 1);
}

@function convert-to-rem($value, $base-value: $rem-base)  {
  $value: strip-unit($value) / strip-unit($base-value) * 1rem;
  @if ($value == 0rem) { $value: 0; } // Turn 0rem into 0
  @return $value;
}

@function rem-calc($values, $base-value: $rem-base) {
  $max: length($values);

  @if $max == 1 { @return convert-to-rem(nth($values, 1), $base-value); }

  $remValues: ();
  @for $i from 1 through $max {
    $remValues: append($remValues, convert-to-rem(nth($values, $i), $base-value));
  }
  @return $remValues;
}

// Create pixel fallback measurement for < IE 9
// Output to the appropriate stylesheet
// $pixelBase : 16; /* 1 */ Replaced with rem-base

@function parseInt($n) {
  @return $n / ($n * 0 + 1); /* 2 */
}


@function u($values){ /* 3 */
    $list: (); /* 4 */
    @each $value in $values { /* 5 */
        @if type-of($value) != 'number' {
            $list: append($list, $value);
        }
        @else {
            $unit : unit($value); /* 6 */
            $val  : parseInt($value); /* 2 */
            @if ($px-only) and ($unit == 'rem') { /* 7 */
                $list: append($list, ($val * $rem-base)); /* 7 */
            }
            @else if($unit == 'px') or ($unit == 'rem') or ($value == 0) { /* 8 */
                $list: append($list, $value); /* 8 */
            }
            @else if($unit == 'px'){
                $list: append($list, ($val / $pixelBase) + rem );
            }
            @else {
                  @warn 'There is no unit conversion for #{$unit}'; /* 9 */
            }
        }
    }
    @return $list(); /* 10 */
}

$modules: () !default;
@mixin exports($name) {
  @if (index($modules, $name) == false) {
    $modules: append($modules, $name);
    @content;
  }
}
// We use this to do clear floats
@mixin clearfix {
  *zoom:1;
  &:before, &:after { content: " "; display: table; }
  &:after { clear: both; }
}
// We use this to control whether or not CSS classes come through in the gem files.
$include-html-classes: true !default;
$include-print-styles: true !default;
$include-html-global-classes: $include-html-classes !default;


// Media Query Ranges
$small-range: (0em, 40em) !default;
$medium-range: (40.063em, 64em) !default;
$large-range: (64.063em, 90em) !default;
$xlarge-range: (90.063em, 120em) !default;
$xxlarge-range: (120.063em) !default;


$screen: "only screen" !default;

$landscape: "#{$screen} and (orientation: landscape)" !default;
$portrait: "#{$screen} and (orientation: portrait)" !default;

$small-up: $screen !default;
$small-only: "#{$screen} and (max-width: #{upper-bound($small-range)})" !default;

$medium-up: "#{$screen} and (min-width:#{lower-bound($medium-range)})" !default;
$medium-only: "#{$screen} and (min-width:#{lower-bound($medium-range)}) and (max-width:#{upper-bound($medium-range)})" !default;

$large-up: "#{$screen} and (min-width:#{lower-bound($large-range)})" !default;
$large-only: "#{$screen} and (min-width:#{lower-bound($large-range)}) and (max-width:#{upper-bound($large-range)})" !default;

$xlarge-up: "#{$screen} and (min-width:#{lower-bound($xlarge-range)})" !default;
$xlarge-only: "#{$screen} and (min-width:#{lower-bound($xlarge-range)}) and (max-width:#{upper-bound($xlarge-range)})" !default;

$xxlarge-up: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)})" !default;
$xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (max-width:#{upper-bound($xxlarge-range)})" !default;

//
// @variables
//
$include-html-grid-classes: $include-html-classes !default;

$row-width: u(rem-calc(1040)) !default;
$column-gutter: rem-calc(20) !default;
$total-columns: 12 !default;

//
// Grid Functions
//

// @FUNCTION
// $colNumber - Found in settings file
// $totalColumns - Found in settings file
@function grid-calc($colNumber, $totalColumns) {
  @return percentage(($colNumber / $totalColumns));
}

//
// @mixins
//

// For creating container, nested, and collapsed rows.
//
// 
// $behavior - Any special beavior for this row? Default: false. Options: nest, collapse, nest-collapse, false.
@mixin grid-row($behavior: false) {

  // use @include grid-row(nest); to include a nested row
  @if $behavior == nest {
    width: auto;
    margin-#{$default-float}: u(-($column-gutter/2));
    margin-#{$opposite-direction}: u(-($column-gutter/2));
    margin-top: 0;
    margin-bottom: 0;
    max-width: none;
  }

  // use @include grid-row(collapse); to collapsed a container row margins
  @else if $behavior == collapse {
    width: 100%;
    margin: 0;
    max-width: $row-width;
  }

  // use @include grid-row(nest-collapse); to collapse outer margins on a nested row
  @else if $behavior == nest-collapse {
    width: auto;
    margin: 0;
    max-width: none;
  }

  // use @include grid-row; to use a container row
  @else {
    width: 100%;
    margin-#{$default-float}: auto;
    margin-#{$opposite-direction}: auto;
    margin-top: 0;
    margin-bottom: 0;
    max-width: $row-width;
  }

  // Clearfix for all rows
  @include clearfix();
}

// Creates a column, should be used inside of a media query to control layouts
//
// $columns - The number of columns this should be
// $last-column - Is this the last column? Default: false.
// $center - Center these columns? Default: false.
// $offset - # of columns to offset. Default: false.
// $push - # of columns to push. Default: false.
// $pull - # of columns to pull. Default: false.
// $collapse - Get rid of gutter padding on column? Default: false.
// $float - Should this float? Default: true. Options: true, false, left, right.
@mixin grid-column(
  $columns:false, 
  $last-column:false, 
  $center:false, 
  $offset:false, 
  $push:false, 
  $pull:false, 
  $collapse:false, 
  $float:true) {

  position: relative;

  // If collapsed, get rid of gutter padding
  @if $collapse {
    padding-left: 0;
    padding-right: 0;
  }

  // Gutter padding whenever a column isn't set to collapse
  // (use $collapse:null to do nothing)
  @else if $collapse == false {
    padding-left: u($column-gutter / 2);
    padding-right: u($column-gutter / 2);
  }

  // If a column number is given, calculate width
  @if $columns {
    width: grid-calc($columns, $total-columns);

    // If last column, float naturally instead of to the right
    @if $last-column { float: $opposite-direction; }
  }

  // Source Ordering, adds left/right depending on which you use.
  @if $push { #{$default-float}: grid-calc($push, $total-columns); #{$opposite-direction}: auto; }
  @if $pull { #{$opposite-direction}: grid-calc($pull, $total-columns); #{$default-float}: auto; }

  // If centered, get rid of float and add appropriate margins
  @if $center {
    margin-#{$default-float}: auto;
    margin-#{$opposite-direction}: auto;
    float: none;
  }

  // If offset, calculate appropriate margins
  @if $offset { margin-#{$default-float}: grid-calc($offset, $total-columns) !important; }

  @if $float {
    @if $float == left or $float == true { float: $default-float; }
    @else if $float == right { float: $opposite-direction; }
    @else { float: none; }
  }

}

// Create presentational classes for grid
//
// $size - Name of class to use, i.e. "large" will generate .large-1, .large-2, etc.
@mixin grid-html-classes($size) {

  .column.#{$size}-centered,
  .columns.#{$size}-centered { @include grid-column($center:true, $collapse:null, $float:false); }

  .column.#{$size}-uncentered,
  .columns.#{$size}-uncentered {
    margin-#{$default-float}: 0;
    margin-#{$opposite-direction}: 0;
    float: $default-float;
  }

  .column.#{$size}-uncentered.opposite,
  .columns.#{$size}-uncentered.opposite {
    float: $opposite-direction;
  }

  @for $i from 1 through $total-columns - 1 {
    .#{$size}-push#{-$i} {
      @include grid-column($push:$i, $collapse:null, $float:false);
    }
    .#{$size}-pull#{-$i} {
      @include grid-column($pull:$i, $collapse:null, $float:false);
    }
  }

  .column,
  .columns { @include grid-column($columns:false); }


  @for $i from 1 through $total-columns {
    .#{$size}#{-$i} { @include grid-column($columns:$i,$collapse:null,$float:false); }
  }

  [class*="column"] + [class*="column"]:last-child { float: $opposite-direction; }
  [class*="column"] + [class*="column"].end { float: $default-float; }


  @for $i from 0 through $total-columns - 2 {
    .#{$size}-offset-#{$i} { @include grid-column($offset:$i, $collapse:null,$float:false); }
  }
  .column.#{$size}-reset-order,
  .columns.#{$size}-reset-order {
    margin-#{$default-float}: 0;
    margin-#{$opposite-direction}: 0;
    left: auto;
    right: auto;
    float: $default-float; 
  }
}

@include exports("grid") {
  @if $include-html-grid-classes {
    .row {
      @include grid-row;

      &.collapse {
         > .column,
         > .columns { @include grid-column($collapse:true); }

        .row {margin-left:0; margin-right:0;}
      }

      .row { @include grid-row($behavior:nest);
        &.collapse { @include grid-row($behavior:nest-collapse); }
      }
    }

    .column,
    .columns { @include grid-column($columns:$total-columns); }
    @if ($MQs) {
      @media #{$small-up} {
        @include grid-html-classes($size:small);
      }

      @media #{$medium-up} {
        @include grid-html-classes($size:medium);
        // Old push and pull classes
        @for $i from 1 through $total-columns - 1 {
          .push#{-$i} {
            @include grid-column($push:$i, $collapse:null, $float:false);
          }
          .pull#{-$i} {
            @include grid-column($pull:$i, $collapse:null, $float:false);
          }
        }
      }
      @media #{$large-up} {
        @include grid-html-classes($size:large);
        @for $i from 1 through $total-columns - 1 {
          .push#{-$i} {
            @include grid-column($push:$i, $collapse:null, $float:false);
          }
          .pull#{-$i} {
            @include grid-column($pull:$i, $collapse:null, $float:false);
          }
        }
      }
    }
    @else {
      @include grid-html-classes($size:large);
      @include grid-html-classes($size:medium);
      @include grid-html-classes($size:small);
    }
    // @media #{$xlarge-up} {
    //   @include grid-html-classes($size:xlarge);
    // }
    // @media #{$xxlarge-up} {
    //   @include grid-html-classes($size:xxlarge);
    // }
  }
}

Toby Stokes over 3 years ago

Worth mentioning here, as this was blocking IE8 rendering for me -
If you load any @font-face declarations via css, this will cause selectivizer polyfill to give a blank screen for IE8
http://stiankarlsen.me/blog/how-to-fix-selectivizr-in-ie8/
Foundation (used to at least) load the Open sans font, which can be disabled http://foundation.zurb.com/forum/posts/420-open-sans-font-import-and-slow-load-times

Corl DeLuna over 3 years ago

Hi James Cocker,

I was stunned when I learned that F4-5 didn't support IE8 with 10-20% market share. I've experienced this before when devs were too future focused and don't provide a safe fall back like this guy did http://www.jonikorpi.com/leaving-old-IE-behind/. But your solution seems to fix IE8. Thank you very much for sharing your solution.

As for the rem.js, was their a particular !important I need to remove for .button not the throw an error? It got a little confusing after 5,000 + lines of css.

@Mark Joseph Lape mentioned that the "canvas menu is popping out of the screen," Do you know if other JS functionality was lost?

Are all these polyfills required? I got it to render nicely with just respond.min.js and rem.js, but maybe I lost some functionality in the process?

@Nick Lane, Re local testing: Yes I got the same results, until I remembered that IE doesn't trust local files, but gladly accepts candy from strangers, so I hosted it on my server and it all rendered fast and fine in Browser Mode IE8.

@Foundation Devs, Thank you all for all your hard work and generosity in sharing Foundation.

With all due respect: are you so sure that IE8 will disappear 4-2014? XP has many more users besides institutions, apparently a shocking 32% of the world runs XP, and many people are happy enough not buying a new computer for a new OS and starting all over again. Sure that fits MS and Intel's business model, but... Plus, I hear that IE8 shipped with Win 7 too, that's another 50% globally, and MS won't stop supporting it until 2020.

Derek Paul about 2 years ago

@Sherry Just as an FYI, IE11 doesn't support the conditional statements that make most of this possible regardless of what view you're in. The only way to test that this works is to view it in IE8 and IE9 inside a VM. Microsoft dropped conditionals in IE10 so testing in IE11's dev tools won't help you.

Gavin Thomas about 2 years ago

Just use the sass code Glenn Phillip posted on page 3:

http://foundation.zurb.com/forum/posts/241-foundation-5-and-ie8?page=3

I've got foundation 5.4 working fine with IE8 using that along with

and that's it.

Gavin Thomas about 2 years ago

BTW.. i wouldn't use the rem polyfill. This is extremely memory hungry and isn't needed if you use Glen phillips code or grunt to convert px to rem units.

Derek Paul over 3 years ago

@meta vurt:

No, your assertion that IE8 is incompatible with Win7 is simply not true. In fact, Microsoft even offers a VM on their IE compatibility page that runs IE8 on Win7. So.... please stop circulating false info.

Cornelius Weidmann about 3 years ago

Thank you, this post has helped me a lot! For what it's worth I have compiled a list of steps I took to get Foundation 5 to work nicely with IE8. You can see the blog post here, hope it helps:

http://www.kycosoftware.com/blog/article/getting-foundation-5-to-work-in-ie8

Mhaddy almost 3 years ago

Just wanted to say thank you to @Giorgos Grispos for his awesome work on getting Foundation to be "usable" in IE8. I had tried half dozen different solutions previously and none worked as well as his as described here:

http://www.kycosoftware.com/blog/article/getting-foundation-5-to-work-in-ie8

Now to go in and tweak classes and "clean things up".

Chris Goers over 3 years ago

Here's how I got reveal-modals, accordions, and tabs to work in IE8 after downgrading jQuery to 1.11 and using some of the polyfills earlier in the thread:

 $(document).ready(function(){
  // REVEAL MODALS
  $('a[href="#"]').click(function(){
    var id = $(this).attr('data-reveal-id');
    $('#' + id).css({'display':'block', 'width':'600px', 'opacity':'1', 'visibility':'visible'});
  });
  $('.close-reveal-modal').click(function(){
    $(this).parent().css({'display':'none'});
  });
  // ACCORDION
  $('.accordion a').click(function(){
    var accid = $(this).attr('href');
    $('.accordion .content').removeClass('active');
    $(accid).addClass('active');
  });
  // TABS
  $('.tabs dd a').click(function(){
    var tabid = $(this).attr('href');
    $('.tabs dd').removeClass('active');
    $('.tabs-content .content').removeClass('active');
    $(this).parent().addClass('active');
    $(tabid).addClass('active');
  });
});

Of course you would modify the modal css to whatever suits your needs.