6

Is there any way to make this solution IE6 and IE7 compatible?

http://jsfiddle.net/kirkstrobeck/sDh7s/1/


Pulled from this question

I think I've found a real solution. I've made it into a new function:

jQuery.style(name, value, priority);

You can use it to get values with .style('name') just like .css('name'), get the CSSStyleDeclaration with .style(), and also set values - with the ability to specify the priority as 'important'. See https://developer.mozilla.org/en/DOM/CSSStyleDeclaration.

Demo

var div = $('someDiv');
console.log(div.style('color'));
div.style('color', 'red');
console.log(div.style('color'));
div.style('color', 'blue', 'important');
console.log(div.style('color'));
console.log(div.style().getPropertyPriority('color'));

Here's the output:

null
red
blue
important

The Function

// For those who need them (< IE 9), add support for CSS functions
var isStyleFuncSupported = CSSStyleDeclaration.prototype.getPropertyValue != null;
if (!isStyleFuncSupported) {
    CSSStyleDeclaration.prototype.getPropertyValue = function(a) {
        return this.getAttribute(a);
    };
    CSSStyleDeclaration.prototype.setProperty = function(styleName, value, priority) {
        this.setAttribute(styleName,value);
        var priority = typeof priority != 'undefined' ? priority : '';
        if (priority != '') {
            // Add priority manually
            var rule = new RegExp(RegExp.escape(styleName) + '\\s*:\\s*' + RegExp.escape(value) + '(\\s*;)?', 'gmi');
            this.cssText = this.cssText.replace(rule, styleName + ': ' + value + ' !' + priority + ';');
        } 
    }
    CSSStyleDeclaration.prototype.removeProperty = function(a) {
        return this.removeAttribute(a);
    }
    CSSStyleDeclaration.prototype.getPropertyPriority = function(styleName) {
        var rule = new RegExp(RegExp.escape(styleName) + '\\s*:\\s*[^\\s]*\\s*!important(\\s*;)?', 'gmi');
        return rule.test(this.cssText) ? 'important' : '';
    }
}

// Escape regex chars with \
RegExp.escape = function(text) {
    return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}

// The style function
jQuery.fn.style = function(styleName, value, priority) {
    // DOM node
    var node = this.get(0);
    // Ensure we have a DOM node 
    if (typeof node == 'undefined') {
        return;
    }
    // CSSStyleDeclaration
    var style = this.get(0).style;
    // Getter/Setter
    if (typeof styleName != 'undefined') {
        if (typeof value != 'undefined') {
            // Set style property
            var priority = typeof priority != 'undefined' ? priority : '';
            style.setProperty(styleName, value, priority);
        } else {
            // Get style property
            return style.getPropertyValue(styleName);
        }
    } else {
        // Get CSSStyleDeclaration
        return style;
    }
}

See https://developer.mozilla.org/en/DOM/CSSStyleDeclaration for examples of how to read and set the CSS values. My issue was that I had already set !important for the width in my CSS to avoid conflicts with other theme CSS, but any changes I made to the width in jQuery would be unaffected since they would be added to the style attribute.

Compatibility

For setting with the priority using the setProperty function, http://help.dottoro.com/ljdpsdnb.php says there is support for IE 9+ and all other browsers. I have tried with IE 8 and it has failed, which is why I built support for it in my functions (see above). It will work on all other browsers using setProperty, but it will need my custom code to work in < IE 9.

Community
  • 1
  • 1
Kirk Strobeck
  • 17,984
  • 20
  • 75
  • 114

3 Answers3

9

That looks needlessly complicated.. I would just use em based font size for the tags inside the container and adjust the container's font size using percents. That way all the tag inside container get automatically resized..

JsFiddle: http://jsfiddle.net/qqxe9/

CSS:

.container {
 font-size:100%;   
}

p {
 font-size:1em;   
}

JS

function changeFontSize(n)
{
    var size = $('.container').data('size');
    size += n * 10;
    $('.container').css('font-size',size+'%').data('size',size);
}


$(document).ready(function(){
        $('body').prepend(' \
            <div class="font-size-changer"> \
                <a href="#" class="decrease">A&darr;</a> \
                <!--<a href="#" class="reset">A</a>--> \
                <a href="#" class="increase">A&uarr;</a> \
                <a href="#" class="null">null</a> \
            </div> \
        ').find('> .container').data('size',100);
        
        
        $('.font-size-changer .increase').click(
            function() 
            {
                changeFontSize(1);  
            }
        );
        
        $('.font-size-changer .decrease').click(
            function() 
            {
                changeFontSize(-1);  
            }
        );
});

I've stripped the saving to cookie part but that's easy enough to re-apply..

The one trick is to save the initial percentage somewhere (i used data()) because if you try to retrieve it with .css('font-size') it'll give you the calculated size (e.g. '16px'). There might be a way to get the value as a percentage but can't remember how.

When re-applying the cookie saving part, remember to set the initial data() to the value in the cookie instead of 100%, then call changeFontSize(0) to apply it.

Anyway, this code works in IE6.

Camilo Martin
  • 37,236
  • 20
  • 111
  • 154
Ben
  • 20,737
  • 12
  • 71
  • 115
  • I have given an alternative approach, but I think this is the best way, and the way I've implemented similar features in the past. +1. – Tim Down Jan 30 '12 at 09:30
  • The main reason for this additional code was `!important` breaking things in IE6, does this code work with `!important`? – Kirk Strobeck Jan 30 '12 at 17:48
  • why do you need !important? it's hard to tell without knowing what you code looks like – Ben Jan 30 '12 at 21:25
  • Sincerely all the times I used `!important` I could most of the time have gotten away otherwise (and used it just because it was easier). This doesn't look like the case where it's necessary. – Camilo Martin Jan 31 '12 at 09:13
  • This is a great solution, but unfortunately I have to override a bunch of CSS that's already in place so this won't work for my use-case :\ – Kirk Strobeck Feb 03 '12 at 22:38
  • @KirkStrobeck That's a shame. Can't rewrite the css? Maybe Tim Down's version is what you need then.. – Ben Feb 04 '12 at 00:11
4

You won't be able to get this working in IE 6 or 7 as it is. I would suggest instead creating new style rules, which can include !important declarations and can be achieved in all major browsers using something like the following function. It would require your elements to be identifiable via a selector, such as an ID selector (which would necessitate adding IDs to the elements if not present), and only creates style rules rather than retrieving them, although this is fine for your example.

I've updated your example and it now works in all major browsers, including IE 6 and 7: http://jsfiddle.net/9ZZVP/1/

Style rule creation code:

var addRule;

if (typeof document.styleSheets != "undefined" && document.styleSheets) {
    addRule = function(selector, rule) {
        var styleSheets = document.styleSheets, styleSheet;
        if (styleSheets && styleSheets.length) {
            styleSheet = styleSheets[styleSheets.length - 1];
            if (styleSheet.addRule) {
                styleSheet.addRule(selector, rule)
            } else if (typeof styleSheet.cssText == "string") {
                styleSheet.cssText = selector + " {" + rule + "}";
            } else if (styleSheet.insertRule && styleSheet.cssRules) {
                styleSheet.insertRule(selector + " {" + rule + "}", styleSheet.cssRules.length);
            }
        }
    }
} else {
    addRule = function(selector, rule, el, doc) {
        el.appendChild(doc.createTextNode(selector + " {" + rule + "}"));
    };
}

function createCssRule(selector, rule, doc) {
    doc = doc || document;
    var head = doc.getElementsByTagName("head")[0];
    if (head && addRule) {
        var styleEl = doc.createElement("style");
        styleEl.type = "text/css";
        styleEl.media = "screen";
        head.appendChild(styleEl);
        addRule(selector, rule, styleEl, doc);
        styleEl = null;
    }
}

Example usage:

createCssRule("#foo", "background-color: purple !important;");
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • There's a helpful library for this type of thing: http://stackoverflow.com/a/5077782/405015 – thirtydot Jan 31 '12 at 01:05
  • @thirtydot: That looks good from a quick glance, and pretty similar to stuff I've thrown together myself for projects. – Tim Down Jan 31 '12 at 09:43
-1

Go to http://www.javascriptlint.com/online_lint.php

Paste your Javascript there.

You will see there are quite a few warnings. To start, fix all of the warnings. Once JavaScript Lint no longer generates warnings, test it in IE. That should at least get you started down the path of finding a solution.

Jonathan
  • 5,495
  • 4
  • 38
  • 53