Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the computed style and omit defaults

Tags:

javascript

css

I'm trying to get the current runtime style of an element and filter out properties that have default values. For example, with markup like this:

<style>
    .foo { background: red }
    span { font-size:30px }
</style>


<div style="color: blue">
    <span id="bar" class="foo">hello</span>
</div>

I'd like the result to be:

 background-color: red;
 color: blue;
 font-size: 30px;

I tried window.getComputedStyle, but it returns a lot of stuff and I'm unsure how to filter out defaults. Any pointers will be appreciated.

like image 619
gog Avatar asked Apr 07 '14 08:04

gog


2 Answers

there you go, i did this by adding a new dummy DOM element, to know which styles are default for any element.

/**
 * IE does not have `getComputedStyle` 
 */

window.getComputedStyle = window.getComputedStyle || function( element ) {
  return element.currentStyle;
}

/**
 * get computed style for an element, excluding any default styles
 *
 * @param {DOM} element
 * @return {object} difference
 */

function getStylesWithoutDefaults( element ) {

  // creating an empty dummy object to compare with
  var dummy = document.createElement( 'element-' + ( new Date().getTime() ) );
  document.body.appendChild( dummy );

  // getting computed styles for both elements
  var defaultStyles = getComputedStyle( dummy );
  var elementStyles = getComputedStyle( element );

  // calculating the difference
  var diff = {};
  for( var key in elementStyles ) {
    if(elementStyles.hasOwnProperty(key)
          && defaultStyles[ key ] !== elementStyles[ key ] )
    {
      diff[ key ] = elementStyles[ key ];
    }
  }

  // clear dom
  dummy.remove();

  return diff;
}


/**
 * usage
 */

console.log( getStylesWithoutDefaults( document.getElementById( 'bar' ) ) );

Notes:

  • the result will have some extra properties, not only those you've mentioned.

demo - console should be opened

like image 200
Anas Nakawa Avatar answered Oct 27 '22 04:10

Anas Nakawa


Here's a more robust solution to this, using an iframe. This solution is inefficient for more than one element at a time, in which case you'll want to use a fragment to batch element insertion and pass in an array of tag names.

var getDefaultStyling = function(tagName){
    if(!tagName) tagName = "dummy-tag-name";

    //  Create dummy iframe

    var iframe = document.createElement("iframe");

    document.body.appendChild(iframe);

    //  Create element within the iframe's document

    var iframeDocument = iframe.contentDocument;
    var targetElement = iframeDocument.createElement(tagName);

    iframeDocument.body.appendChild(targetElement);

    //  Grab styling (CSSStyleDeclaration is live, and all values become "" after element removal)

    var styling = iframe.contentWindow.getComputedStyle(targetElement);
    var clonedStyling = {};

    for(var i = 0, len = styling.length; i < len; i++){
        var property = styling[i];

        clonedStyling[i] = property;
        clonedStyling[property] = styling[property];
    }

    //  Remove iframe

    document.body.removeChild(iframe);

    //  Return cloned styling

    return clonedStyling;
};

var getUniqueUserStyling = function(element){
    var allStyling = window.getComputedStyle(element);
    var defaultStyling = getDefaultStyling(element.tagName);

    var userStyling = {};

    for(var i = 0, len = allStyling.length; i < len; i++){
        var property = allStyling[i];
        var value = allStyling[property];
        var defaultValue = defaultStyling[property];

        if(value != defaultValue){
            userStyling[property] = value;
        }
    }

    return userStyling;
};

Usage: getUniqueUserStyling(myElement).

like image 39
mattsven Avatar answered Oct 27 '22 03:10

mattsven