Get the computed style and omit defaults

前端 未结 6 854
旧巷少年郎
旧巷少年郎 2020-12-28 19:57

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:



        
相关标签:
6条回答
  • 2020-12-28 20:19

    I have built what I believe to be a more modern, complete and efficient solution, based on mattsven's answer.

    All you have to do is call the getUserStyles method with the node as a parameter, as such: Styles.getUserStyles(document.querySelector('#bar'))

    Obviously, this snippet was not made with older browser support in mind, so some adjustments should be made if you are to use this on a public website.

    class Styles {
        // Returns a dummy iframe with no styles or content
        // This allows us to get default styles from the browser for an element
        static getStylesIframe() {
            if (typeof window.blankIframe != 'undefined') {
                return window.blankIframe;
            }
    
            window.blankIframe = document.createElement('iframe');
            document.body.appendChild(window.blankIframe);
    
            return window.blankIframe;
        }
    
        // Turns a CSSStyleDeclaration into a regular object, as all values become "" after a node is removed
        static getStylesObject(node, parentWindow) {
            const styles = parentWindow.getComputedStyle(node);
            let stylesObject = {};
    
            for (let i = 0; i < styles.length; i++) {
                const property = styles[i];
                stylesObject[property] = styles[property];
            }
    
            return stylesObject;
        }
    
        // Returns a styles object with the browser's default styles for the provided node
        static getDefaultStyles(node) {
            const iframe = Styles.getStylesIframe();
            const iframeDocument = iframe.contentDocument;
            const targetElement = iframeDocument.createElement(node.tagName);
    
            iframeDocument.body.appendChild(targetElement);
            const defaultStyles = Styles.getStylesObject(targetElement, iframe.contentWindow);
    
            targetElement.remove();
    
            return defaultStyles;
        }
    
        // Returns a styles object with only the styles applied by the user's CSS that differ from the browser's default styles
        static getUserStyles(node) {
            const defaultStyles = Styles.getDefaultStyles(node);
            const styles = Styles.getStylesObject(node, window);
            let userStyles = {};
    
            for (let property in defaultStyles) {
                if (styles[property] != defaultStyles[property]) {
                    userStyles[property] = styles[property];
                }
            }
    
            return userStyles;
        }
    };
    
    0 讨论(0)
  • 2020-12-28 20:21

    Here it is .. using pure javscript .. I only added jquery to the fiddle to set document.ready event.

    Here is the code:

    $(document).ready(function () {
        var div = document.getElementById('output');
        var x = document.getElementById('frame').contentWindow.document.createElement('x');
        document.getElementById('frame').contentWindow.document.body.appendChild(x);
        var defautlStyles = window.getComputedStyle(x);
        var barStyles = window.getComputedStyle(document.getElementById('bar'));
        for (i = 0; i < defautlStyles.length; i++) {
            if (defautlStyles["" + defautlStyles[i]] != barStyles["" + barStyles[i]]) {
                var p = document.createElement('p');
                p.innerText += barStyles[i] + ": " + barStyles["" + barStyles[i]];
                div.appendChild(p);
            }
        }
    });
    

    I used an iframe to add an element to it so the style of the added element won't be affected by the document default styles. And here is the FIDDLE

    Hope it helps...

    0 讨论(0)
  • 2020-12-28 20:24

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

    0 讨论(0)
  • 2020-12-28 20:35

    You can use, e.g:

    window.getComputedStyle(document.getElementById('bar'))
    

    This will return an object containing all the computed styles for the element with the id 'bar'.

    So, for example you could do:

    var styles = window.getComputedStyle(document.getElementById('bar'));
    styles = "background-color:" + styles['background-color'] + ";color:" + styles['color'] + ";font-size:" + styles['font-size'] + ";";
    console.log(styles);
    

    Note that color values will be returned in RGBA format.

    Demo Fiddle

    0 讨论(0)
  • 2020-12-28 20:43

    Here's an option if you need to use getPropertyValue afterwards, like here

    var computedStyles = getComputedStyles(document.body);
    var propertyValue = computedStyles.getPropertyValue("prop-name");
    

    Use this function:

    function getDefaultComputedStyles(el)
    {
        var temp = document.createElement("div");
        document.body.appendChild(temp);
        var defaultStyles = getComputedStyle(temp);
        var extraStyles = getComputedStyle(el);
        var foundStyles = [];
    
        for(var i=0; i<defaultStyles.length; i++)
        {
            var extraStyleIndex = extraStyles[i];
            var extraStyleValue = extraStyles.getPropertyValue(extraStyles[i]);
            if(defaultStyles.getPropertyValue(defaultStyles[i]) !== extraStyleValue)
            {
              foundStyles.push(JSON.parse(`{"${extraStyleIndex}":"${extraStyleValue}"}`));
            }
        }
        foundStyles.getPropertyValue = function(ind){
            var result = this.filter(el => (`${ind}` in el));
            return result[0]!=undefined ? result[0][Object.keys(result[0])] : null;
        }
    
        return foundStyles;
    }
    
    0 讨论(0)
  • 2020-12-28 20:45

    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

    0 讨论(0)
提交回复
热议问题