Получить вычисленный стиль и опустить значения по умолчанию

Я пытаюсь получить текущий стиль выполнения элемента и отфильтровать свойства, которые имеют значения по умолчанию. Например, с разметкой следующим образом:

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


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

Я бы хотел, чтобы результат был:

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

Я пробовал window.getComputedStyle, но он возвращает много вещей, и я не уверен, как отфильтровывать значения по умолчанию. Любые указатели будут оценены.

Ответ 1

там вы идете, Я сделал это, добавив новый элемент DOM DOM, чтобы узнать, какие стили по умолчанию для любого элемента.

/**
 * 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' ) ) );

Примечания:

  • результат будет иметь некоторые дополнительные свойства, а не только те, которые вы упомянули.

демонстрационная консоль должна быть открыта

Ответ 2

Здесь более надежное решение, используя iframe. Это решение неэффективно для более чем одного элемента за раз, и в этом случае вы захотите использовать фрагмент для вставки пакетного элемента и передать массив имен тегов.

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 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;
};

Использование: getUniqueUserStyling(myElement).

Ответ 3

Я построил то, что я считаю более современным, полным и эффективным решением, основанным на ответе Mattsven.

Все, что вам нужно сделать, это вызвать метод getUserStyles с узлом в качестве параметра, например: Styles.getUserStyles(document.querySelector('#bar'))

Очевидно, этот фрагмент не был создан с учетом поддержки более старых браузеров, поэтому необходимо внести некоторые изменения, если вы хотите использовать его на общедоступном веб-сайте.

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 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 CSS that differ from the browser 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;
    }
};

Ответ 4

Здесь опция, если вам нужно использовать getPropertyValue впоследствии, как здесь

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

Используйте эту функцию:

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;
}

Ответ 5

Вы можете использовать, например:

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

Это вернет объект, содержащий все вычисленные стили для элемента с id 'bar.

Итак, например, вы могли бы сделать:

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

Обратите внимание, что значения цвета будут возвращены в формате RGBA.

Демо-скрипт

Ответ 6

Вот он.. с использованием чистого javscript.. Я только добавил jquery к скрипту, чтобы установить событие document.ready.

Вот код:

$(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);
        }
    }
});

Я использовал iframe для добавления к нему элемента, поэтому стиль добавленного элемента не будет зависеть от стилей по умолчанию для документа. И вот FIDDLE

Надеюсь, что это поможет...