1

I want to be able to parse inline css and have it as object in key pairs. Something like:

<div background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">

{ 
  backgroundImage : "http://domain.com/images/image.jpg",
  backgroundSize: "cover",
  padding: "100px 0"
} 

This function works great for the most of the part. I'm having problem with background-image

it strips it completely and I end up with "url(http" instead.

function parseCss(el) {
    var output = {};

    if (!el || !el.attr('style')) {
        return output;
    }

    var camelize = function camelize(str) {
        return str.replace(/(?:^|[-])(\w)/g, function(a, c) {
            c = a.substr(0, 1) === '-' ? c.toUpperCase() : c;
            return c ? c : '';
        });
    }

    var style = el.attr('style').split(';');
    for (var i = 0; i < style.length; ++i) {
        var rule = style[i].trim();
        if (rule) {
            var ruleParts = rule.split(':');
            var key = camelize(ruleParts[0].trim());
            output[key] = ruleParts[1].trim();
        }
    }

    return output;
}

I'm pretty sure that "replace" function needs to be modified to make it work with image url

0

3 Answers 3

1

You might be able to do something like this, it would still fail for some edge cases with content. It is not running your camel case, but that is simple enough to call.

var x = document.getElementById("x");
var str = x.getAttribute("style"); //x.style.cssText;
console.log(str);
var rules = str.split(/\s*;\s*/g).reduce( function (details, val) {
    if (val) {
      var parts = val.match(/^([^:]+)\s*:\s*(.+)/);
      details[parts[1]] = parts[2];
    } 
    return details;
}, {});
console.log(rules);
div {
  font-family: Arial;
}
<div style="color: red; background: yellow; background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;" id="x">test</div>

Sign up to request clarification or add additional context in comments.

2 Comments

Your example does not parse all of the styles. In a snippet window it looks like: "repeat scroll 0% 0% / cover yellow"
just need to change the cssText line and use the attribute if you did not want them combined.
1

Instead of reading the the style attribute, you could iterate over the style properties. This way you avoid the problems with delimiters that are embedded in style values:

function parseCss(el) {
    function camelize(key) {
        return key.replace(/\-./g, function (m) {
            return m[1].toUpperCase();
        });
    }
    
    var output = {};
    for (var a of el.style) {
        output[camelize(a)] = el.style[a];
    }
    return output;
}
// Demo 
var css = parseCss(document.querySelector('div'));
console.log(css);
<div style="background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">
</div>

This does expand some consolidated styles you can have in the style attribute, such as padding, which splits into paddingLeft, paddingRight, ...etc.

With the use of some more ES6 features the above can be condensed to:

function parseCss(el) {
    let camelize = key => key.replace(/\-./g, m => m[1].toUpperCase());
    return Object.assign(
        ...Array.from(el.style, key => ({[camelize(key)]: el.style[key]})));
}
// Demo 
let css = parseCss(document.querySelector('div'));
console.log(css);
<div style="background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">
</div>

4 Comments

In your example every single object returns as "undefined" ` "backgroundImage": undefined, "backgroundSize": undefined, "paddingTop": undefined, "paddingRightValue": undefined,`
Which browser? I see the actual values in Chrome, FF and Edge.
Im using latest FF
Me too, it works for me on FF 50.0.2 and FF 49.0.1. That is puzzling. Is this what you get when running the snippet in the answer, or when you copy it into your project?
0

You can try with this, tested on few examples:

styleObj={};
style=$('div').attr('style');
rules=style.split(';');
rules = rules.filter(function(x){
  return (x !== (undefined || ''));
}); // https://solidfoundationwebdev.com/blog/posts/remove-empty-elements-from-an-array-with-javascript



for (i=0;i<rules.length;i++) {

rules_arr=rules[i].split(/:(?!\/\/)/g); // split by : if not followed by //
rules_arr[1]=$.trim(rules_arr[1]).replace('url(','').replace(')','');

if(rules_arr[0].indexOf('-')>=0) {
rule=rules_arr[0].split('-');
rule=rule[0]+rule[1].charAt(0).toUpperCase()+rule[1].slice(1);
}
else {
rule=rules_arr[0];
}
styleObj[$.trim(rule)]=rules_arr[1];

}

console.log(styleObj);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="font-size: x-large; color: #ff9900; background-image: url('http://placehold.it/100x100');">Using inline style sheets - or is that inline styles?</div>

Demo (easier for testing of different inline styles): https://jsfiddle.net/n0n4zt3f/2/

P.S. Trimming and camel case are left... can be added, of course...

1 Comment

This is much better, it would be perfect, if I could bug you just for came case option

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.