Подтвердить что ты не робот

Найти все правила CSS, которые применяются к элементу

Многие инструменты /API предоставляют способы выбора элементов определенных классов или идентификаторов. Также можно проверить загруженные браузером исходные таблицы стилей.

Однако, чтобы браузеры отображали элемент, они собирают все правила CSS (возможно, из разных файлов стилей) и применяют его к элементу. Это то, что вы видите с Firebug или WebKit Inspector - полное дерево наследования CSS для элемента.

Как я могу воспроизвести эту функцию в чистом JavaScript, не требуя дополнительных плагинов для браузера?

Возможно, пример может дать некоторые пояснения к тому, что я ищу:

<style type="text/css">
    p { color :red; }
    #description { font-size: 20px; }
</style>

<p id="description">Lorem ipsum</p>

Здесь элемент описания p # имеет два правила CSS: красный цвет и размер шрифта 20 px.

Я хотел бы найти источник, откуда берутся эти вычисленные правила CSS (цвет входит в правило p и т.д.).

4b9b3361

Ответ 1

Кажется, мне удалось ответить на мой вопрос после еще одного часа исследования.

Это так просто:

window.getMatchedCSSRules(document.getElementById("description"))

(Работает в WebKit/Chrome, возможно, и с другими)

Ответ 2

Поскольку этот вопрос в настоящее время не имеет легкого (небиблиотечного), совместимого с кросс-браузером ответа, я постараюсь предоставить один:

function css(el) {
    var sheets = document.styleSheets, ret = [];
    el.matches = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector 
        || el.msMatchesSelector || el.oMatchesSelector;
    for (var i in sheets) {
        var rules = sheets[i].rules || sheets[i].cssRules;
        for (var r in rules) {
            if (el.matches(rules[r].selectorText)) {
                ret.push(rules[r].cssText);
            }
        }
    }
    return ret;
}

JSFiddle: http://jsfiddle.net/HP326/6/

Вызов css(document.getElementById('elementId')) возвращает массив с элементом для каждого правила CSS, который соответствует переданному элементу. Если вы хотите узнать более конкретную информацию о каждом правиле, ознакомьтесь с документацией CSSRule.

Ответ 3

Посмотрите на эту библиотеку, которая делает то, что было предложено: http://www.brothercake.com/site/resources/scripts/cssutilities/

Он работает во всех современных браузерах прямо в IE6, может предоставить вам коллекции правил и свойств, такие как Firebug (на самом деле он более точный, чем Firebug), а также может рассчитать относительную или абсолютную специфичность любого правила. Единственное предостережение в том, что, хотя он понимает статические типы носителей, он не понимает медиа-запросы.

Ответ 4

Краткая версия 12 апреля 2017 г.

Появится Challenger.

var getMatchedCSSRules = (el, css = el.ownerDocument.styleSheets) => 
    [].concat(...[...css].map(s => [...s.cssRules||[]]))     /* 1 */
    .filter(r => el.matches(r.selectorText));                /* 2 */

Линия /* 1 */ строит плоский массив всех правил.
Строка /* 2 */ отменяет правила несоответствия.

На основе function css(el) by @S.B. на той же странице.

Пример 1

var div = iframedoc.querySelector("#myelement");
var rules = getMatchedCSSRules(div, iframedoc.styleSheets);
console.log(rules[0].parentStyleSheet.ownerNode, rules[0].cssText);

Пример 2

var getMatchedCSSRules = (el, css = el.ownerDocument.styleSheets) => 
    [].concat(...[...css].map(s => [...s.cssRules||[]]))
    .filter(r => el.matches(r.selectorText));

function Go(big,show) {
    var r = getMatchedCSSRules(big);
PrintInfo:
    var f = (dd,rr,ee="\n") => dd + rr.cssText.slice(0,50) + ee;
    show.value += "--------------- Rules: ----------------\n";
    show.value += f("Rule 1:   ", r[0]);
    show.value += f("Rule 2:   ", r[1]);
    show.value += f("Inline:   ", big.style);
    show.value += f("Computed: ", getComputedStyle(big), "(…)\n");
    show.value += "-------- Style element (HTML): --------\n";
    show.value += r[0].parentStyleSheet.ownerNode.outerHTML;
}

Go(...document.querySelectorAll("#big,#show"));
.red {color: red;}
#big {font-size: 20px;}
<h3 id="big" class="red" style="margin: 0">Lorem ipsum</h3>
<textarea id="show" cols="70" rows="10"></textarea>

Ответ 5

Здесь версия S.B. ответ, который также возвращает соответствующие правила в совпадающих медиа-запросах. Я удалил слияние *.rules || *.cssRules и поиск .matches; добавьте polyfill или добавьте эти строки, если они вам понадобятся.

Эта версия также возвращает объекты CSSStyleRule, а не текст правила. Я думаю, что это немного более полезно, так как специфика правил может быть легче диагностирована программно таким образом.

Кофе

getMatchedCSSRules = (element) ->
  sheets = document.styleSheets
  matching = []

  loopRules = (rules) ->
    for rule in rules
      if rule instanceof CSSMediaRule
        if window.matchMedia(rule.conditionText).matches
          loopRules rule.cssRules
      else if rule instanceof CSSStyleRule
        if element.matches rule.selectorText
          matching.push rule
    return

  loopRules sheet.cssRules for sheet in sheets

  return matching

JS:

function getMatchedCSSRules(element) {
  var i, len, matching = [], sheets = document.styleSheets;

  function loopRules(rules) {
    var i, len, rule;

    for (i = 0, len = rules.length; i < len; i++) {
      rule = rules[i];
      if (rule instanceof CSSMediaRule) {
        if (window.matchMedia(rule.conditionText).matches) {
          loopRules(rule.cssRules);
        }
      } else if (rule instanceof CSSStyleRule) {
        if (element.matches(rule.selectorText)) {
          matching.push(rule);
        }
      }
    }
  };

  for (i = 0, len = sheets.length; i < len; i++) {
    loopRules(sheets[i].cssRules);
  }

  return matching;
}

Ответ 6

var GetMatchedCSSRules = (elem, css = document.styleSheets) => Array.from(css)
  .map(s => Array.from(s.cssRules).filter(r => elem.matches(r.selectorText)))
  .reduce((a,b) => a.concat(b));

function Go(paragraph, print) {
  var rules = GetMatchedCSSRules(paragraph);
PrintInfo:
  print.value += "Rule 1: " + rules[0].cssText + "\n";
  print.value += "Rule 2: " + rules[1].cssText + "\n\n";
  print.value += rules[0].parentStyleSheet.ownerNode.outerHTML;
}

Go(document.getElementById("description"), document.getElementById("print"));
p {color: red;}
#description {font-size: 20px;}
<p id="description">Lorem ipsum</p>
<textarea id="print" cols="50" rows="12"></textarea>

Ответ 7

Обеспечение IE9 +, я написал функцию, которая вычисляет CSS для запрошенного элемента и его дочерних элементов и дает возможность сохранить его в новом классеName, если это необходимо в фрагменте ниже.

/**
  * @function getElementStyles
  *
  * Computes all CSS for requested HTMLElement and its child nodes and applies to dummy class
  *
  * @param {HTMLElement} element
  * @param {string} className (optional)
  * @param {string} extras (optional)
  * @return {string} CSS Styles
  */
function getElementStyles(element, className, addOnCSS) {
  if (element.nodeType !== 1) {
    return;
  }
  var styles = '';
  var children = element.getElementsByTagName('*');
  className = className || '.' + element.className.replace(/^| /g, '.');
  addOnCSS = addOnCSS || '';
  styles += className + '{' + (window.getComputedStyle(element, null).cssText + addOnCSS) + '}';
  for (var j = 0; j < children.length; j++) {
    if (children[j].className) {
      var childClassName = '.' + children[j].className.replace(/^| /g, '.');
      styles += ' ' + className + '>' + childClassName +
        '{' + window.getComputedStyle(children[j], null).cssText + '}';
    }
  }
  return styles;
}

Использование

getElementStyles(document.getElementByClassName('.my-class'), '.dummy-class', 'width:100%;opaity:0.5;transform:scale(1.5);');