Finden Sie alle CSS-Regeln, die für ein Element gelten

Lesezeit: 14 Minuten

Viele Tools/APIs bieten Möglichkeiten zur Auswahl von Elementen bestimmter Klassen oder IDs. Es ist auch möglich, die vom Browser geladenen Roh-Stylesheets zu inspizieren.

Damit Browser jedoch ein Element rendern können, kompilieren sie alle CSS-Regeln (möglicherweise aus verschiedenen Stylesheet-Dateien) und wenden sie auf das Element an. Das sehen Sie mit Firebug oder dem WebKit Inspector – der vollständige CSS-Vererbungsbaum für ein Element.

Wie kann ich diese Funktion in reinem JavaScript reproduzieren, ohne zusätzliche Browser-Plugins zu benötigen?

Vielleicht kann ein Beispiel etwas verdeutlichen, wonach ich suche:

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

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

Hier werden auf das p#description-Element zwei CSS-Regeln angewendet: eine rote Farbe und eine Schriftgröße von 20 px.

Ich möchte die Quelle finden, aus der diese berechneten CSS-Regeln stammen (Farbe kommt aus der p-Regel und so weiter).

  • Gute Antworten auch unter Ist es möglich, CSS-Regeln aus einem HTML-Knoten über JavaScript zu finden?

    – Bergi

    24. September 2013 um 13:31 Uhr

  • In einem Browser anzeigen und die Entwicklertools des Browsers verwenden (z. B. Registerkarte „Elemente“ in Chrome)?

    – Ronnie Royston

    8. September 2018 um 18:45 Uhr


Finden Sie alle CSS Regeln die fur ein Element gelten
SB

Da diese Frage derzeit keine leichte (nicht bibliothekseigene), browserübergreifende kompatible Antwort hat, werde ich versuchen, eine zu geben:

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/

Berufung css(document.getElementById('elementId')) gibt ein Array mit einem Element für jede CSS-Regel zurück, die mit dem übergebenen Element übereinstimmt. Wenn Sie genauere Informationen zu jeder Regel erfahren möchten, lesen Sie die CSSRule-Objekt Dokumentation.

  • a.matches ist in dieser Zeile definiert: a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector. Das heißt, wenn es bereits eine (Standard-) “matches”-Methode für DOM-Knoten gibt, wird diese verwendet, andernfalls versucht es, die Webkit-spezifische (webkitMatchesSelector) zu verwenden, dann die von Mozilla, Microsoft und Opera. Hier kannst du mehr darüber lesen: developer.mozilla.org/en/docs/Web/API/Element/matches

    – SB

    5. Mai 2015 um 19:49 Uhr

  • Leider denke ich, dass diese Alternative nicht alle CSS-Regeln erkennt, die von übergeordneten Elementen in untergeordnete Elemente kaskadieren. Geige: jsfiddle.net/t554xo2L In diesem Fall wird die UL-Regel (die für das Element gilt) nicht in die angepasst if (a.matches(rules[r].selectorText)) Bewachungszustand.

    – Funforen

    6. Mai 2015 um 10:50 Uhr

  • Ich habe nie behauptet, dass es /geerbte/ CSS-Regeln auflistet – es listet nur CSS-Regeln auf, die mit dem übergebenen Element übereinstimmen. Wenn Sie auch die geerbten Regeln für dieses Element erhalten möchten, müssen Sie wahrscheinlich das DOM nach oben durchlaufen und aufrufen css() auf jedem der übergeordneten Elemente.

    – SB

    6. Mai 2015 um 12:58 Uhr

  • Ich weiß 🙂 Ich wollte nur darauf hinweisen, da Leute, die sich mit dieser Frage befassen könnten, davon ausgehen könnten, dass sie “alle CSS-Regeln enthält, die für ein Element gelten”, wie der Titel der Frage sagt, was nicht der Fall ist .

    – Funforen

    6. Mai 2015 um 13:38 Uhr


  • Wenn Sie möchten, dass alle Regeln, einschließlich der geerbten, derzeit auf das Element angewendet werden, sollten Sie getComputedStyle verwenden. In Anbetracht dessen denke ich, dass diese Antwort richtig ist und dass es richtig ist, keine von Eltern geerbten Stile einzubeziehen (z. B. die dem Elternteil zugewiesene Textfarbe). Was es jedoch nicht enthält, sind Regeln, die bedingt mit Medienabfragen angewendet werden.

    – Zittern

    21. März 2016 um 8:21 Uhr


1646251514 802 Finden Sie alle CSS Regeln die fur ein Element gelten
cgbystrom

BEARBEITEN: Diese Antwort ist jetzt veraltet und funktioniert nicht mehr in Chrome 64+. Aufbruch zum historischen Kontext. Tatsächlich verweist dieser Fehlerbericht auf diese Frage, um alternative Lösungen für die Verwendung dieser Frage zu finden.


Anscheinend habe ich es geschafft, meine eigene Frage nach einer weiteren Stunde Recherche zu beantworten.

So einfach ist es:

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

(Funktioniert in WebKit/Chrome, möglicherweise auch in anderen)

  • Nun, das nützt nicht viel, wenn es nur von Chrom unterstützt wird. Es funktioniert für weniger als 5 % aller Besucher (abhängig von der Demografie).

    – Tomas

    15. September 2010 um 21:06 Uhr

  • @diamandiev: Seit Juni 2012 ist der Chrome-Nutzungsanteil auf über 32 % gestiegen (und ist etwas höher als die IE-Nutzung!). gs.statcounter.com

    – Roy Tinker

    25. Juni 2012 um 19:28 Uhr

  • getMatchedCSSRules zeigt Ihnen NICHT die endgültigen Stile, die für das Element gelten. Es gibt ein Array aller anwendbaren CSSStyleRule-Objekte in der Reihenfolge zurück, in der sie erscheinen. Wenn Sie responsives Webdesign über CSS-Medienabfragen durchführen oder mehr als ein Stylesheet laden (wie eines für IE), müssen Sie trotzdem jeden der zurückgegebenen Stile durchlaufen und die CSS-Spezifität für jede Regel berechnen. Berechnen Sie dann die endgültigen Regeln, die gelten. Sie müssen das reproduzieren, was der Browser natürlich tut. Um dies in Ihrem Beispiel zu beweisen, stellen Sie Ihrer Stildeklaration “p {color: blue !important}” voran.

    – mrbinky3000

    25. Juli 2012 um 17:41 Uhr

  • Dies ist jetzt in Chrome 41 veraltet. Siehe code.google.com/p/chromium/issues/detail?id=437569#c2.

    – Daniel Darabos

    18. Februar 2015 um 14:23 Uhr

  • Das war endlich in Chrome 63 entfernt (offizieller Blogbeitrag – der auf diese Frage zurück weist)

    – Brichins

    20. Oktober 2017 um 22:47 Uhr


Finden Sie alle CSS Regeln die fur ein Element gelten
7vujy0f0hy

Kurzfassung12. April 2017

Herausforderer erscheint.

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

Linie /* 1 */ erstellt ein flaches Array aller Regeln.
Linie /* 2 */ verwirft nicht übereinstimmende Regeln.

Basierend auf der Funktion css(el) von @SB auf der gleichen Seite.

Beispiel 1

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

Beispiel 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>

Mängel

  • Keine Medienhandhabung, nein @import, @media.
  • Kein Zugriff auf Stile, die aus domänenübergreifenden Stylesheets geladen wurden.
  • Keine Sortierung nach Selektor „Spezifität“ (Ordnung der Wichtigkeit).
  • Keine von den Eltern geerbten Stile.
  • Funktioniert möglicherweise nicht mit alten oder rudimentären Browsern.
  • Ich bin mir nicht sicher, wie es mit Pseudoklassen und Pseudoselektoren umgeht, scheint aber in Ordnung zu sein.

Vielleicht werde ich diese Mängel eines Tages ansprechen.

Lange Version12. August 2018

Hier ist eine viel umfassendere Implementierung aus jemandes GitHub-Seite
(davon abgezweigt Originalcodeüber Bugzilla). Geschrieben für Gecko und IE, soll aber angeblich auch mit Blink funktionieren.

4. Mai 2017: Der Spezifitätsrechner hatte kritische Fehler, die ich jetzt behoben habe. (Ich kann die Autoren nicht benachrichtigen, da ich kein GitHub-Konto habe.)

12. August 2018: Die letzten Chrome-Updates scheinen einen entkoppelten Objektbereich zu haben (this) aus Methoden, die unabhängigen Variablen zugeordnet sind. Daher Aufruf matcher(selector) funktioniert nicht mehr. Ersetzen durch matcher.call(el, selector) hat es gelöst.

// polyfill window.getMatchedCSSRules() in FireFox 6+
if (typeof window.getMatchedCSSRules !== 'function') {
    var ELEMENT_RE = /[\w-]+/g,
            ID_RE = /#[\w-]+/g,
            CLASS_RE = /\.[\w-]+/g,
            ATTR_RE = /\[[^\]]+\]/g,
            // :not() pseudo-class does not add to specificity, but its content does as if it was outside it
            PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g,
            PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g;
        // convert an array-like object to array
        function toArray(list) {
            return [].slice.call(list);
        }

        // handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same
        function getSheetRules(stylesheet) {
            var sheet_media = stylesheet.media && stylesheet.media.mediaText;
            // if this sheet is disabled skip it
            if ( stylesheet.disabled ) return [];
            // if this sheet's media is specified and doesn't match the viewport then skip it
            if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return [];
            // get the style rules of this sheet
            return toArray(stylesheet.cssRules);
        }

        function _find(string, re) {
            var matches = string.match(re);
            return matches ? matches.length : 0;
        }

        // calculates the specificity of a given `selector`
        function calculateScore(selector) {
            var score = [0,0,0],
                parts = selector.split(' '),
                part, match;
            //TODO: clean the ':not' part since the last ELEMENT_RE will pick it up
            while (part = parts.shift(), typeof part == 'string') {
                // find all pseudo-elements
                match = _find(part, PSEUDO_ELEMENTS_RE);
                score[2] += match;
                // and remove them
                match && (part = part.replace(PSEUDO_ELEMENTS_RE, ''));
                // find all pseudo-classes
                match = _find(part, PSEUDO_CLASSES_RE);
                score[1] += match;
                // and remove them
                match && (part = part.replace(PSEUDO_CLASSES_RE, ''));
                // find all attributes
                match = _find(part, ATTR_RE);
                score[1] += match;
                // and remove them
                match && (part = part.replace(ATTR_RE, ''));
                // find all IDs
                match = _find(part, ID_RE);
                score[0] += match;
                // and remove them
                match && (part = part.replace(ID_RE, ''));
                // find all classes
                match = _find(part, CLASS_RE);
                score[1] += match;
                // and remove them
                match && (part = part.replace(CLASS_RE, ''));
                // find all elements
                score[2] += _find(part, ELEMENT_RE);
            }
            return parseInt(score.join(''), 10);
        }

        // returns the heights possible specificity score an element can get from a give rule's selectorText
        function getSpecificityScore(element, selector_text) {
            var selectors = selector_text.split(','),
                selector, score, result = 0;
            while (selector = selectors.shift()) {
                if (matchesSelector(element, selector)) {
                    score = calculateScore(selector);
                    result = score > result ? score : result;
                }
            }
            return result;
        }

        function sortBySpecificity(element, rules) {
            // comparing function that sorts CSSStyleRules according to specificity of their `selectorText`
            function compareSpecificity (a, b) {
                return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText);
            }

            return rules.sort(compareSpecificity);
        }

        // Find correct matchesSelector impl
        function matchesSelector(el, selector) {
          var matcher = el.matchesSelector || el.mozMatchesSelector || 
              el.webkitMatchesSelector || el.oMatchesSelector || el.msMatchesSelector;
          return matcher.call(el, selector);
        }

        //TODO: not supporting 2nd argument for selecting pseudo elements
        //TODO: not supporting 3rd argument for checking author style sheets only
        window.getMatchedCSSRules = function (element /*, pseudo, author_only*/) {
            var style_sheets, sheet, sheet_media,
                rules, rule,
                result = [];
            // get stylesheets and convert to a regular Array
            style_sheets = toArray(window.document.styleSheets);

            // assuming the browser hands us stylesheets in order of appearance
            // we iterate them from the beginning to follow proper cascade order
            while (sheet = style_sheets.shift()) {
                // get the style rules of this sheet
                rules = getSheetRules(sheet);
                // loop the rules in order of appearance
                while (rule = rules.shift()) {
                    // if this is an @import rule
                    if (rule.styleSheet) {
                        // insert the imported stylesheet's rules at the beginning of this stylesheet's rules
                        rules = getSheetRules(rule.styleSheet).concat(rules);
                        // and skip this rule
                        continue;
                    }
                    // if there's no stylesheet attribute BUT there IS a media attribute it's a media rule
                    else if (rule.media) {
                        // insert the contained rules of this media rule to the beginning of this stylesheet's rules
                        rules = getSheetRules(rule).concat(rules);
                        // and skip it
                        continue
                    }

                    // check if this element matches this rule's selector
                    if (matchesSelector(element, rule.selectorText)) {
                        // push the rule to the results set
                        result.push(rule);
                    }
                }
            }
            // sort according to specificity
            return sortBySpecificity(element, result);
        };
}

Behobene Fehler

  • = match+= match
  • return re ? re.length : 0;return matches ? matches.length : 0;
  • _matchesSelector(element, selector)matchesSelector(element, selector)
  • matcher(selector)matcher.call(el, selector)

  • In getSheetRules musste ich if(stylesheet.cssRules === null) { return hinzufügen [] } damit es bei mir funktioniert.

    – Gwater17

    16. August 2018 um 21:15 Uhr

  • Getestet die “Langversion”. Funktioniert bei mir. Schade, dass getMatchedCSSRules() nie von Browsern standardisiert wurde.

    – Colin Mock

    9. November 2019 um 17:25 Uhr

  • Wie behandelt dies zwei Selektoren mit denselben Besonderheiten wie h1 und h1, div – wobei der zuletzt deklarierte verwendet werden sollte?

    – Stellan

    8. April 2020 um 18:59 Uhr

  • Vielleicht können wir hier eine Idee für den Umgang mit Pseudo bekommen? github.com/dvtng/jss/blob/master/jss.js

    – Herr1031011

    25. September 2020 um 14:24 Uhr

Schauen Sie sich diese Bibliothek an, die das tut, wonach gefragt wurde: http://www.brothercake.com/site/resources/scripts/cssutilities/

Es funktioniert in allen modernen Browsern bis zurück zu IE6, kann Ihnen Regel- und Eigenschaftssammlungen wie Firebug geben (tatsächlich ist es genauer als Firebug) und kann auch die relative oder absolute Spezifität jeder Regel berechnen. Der einzige Vorbehalt ist, dass es zwar statische Medientypen versteht, aber keine Medienabfragen.

1646251515 614 Finden Sie alle CSS Regeln die fur ein Element gelten
zittern

Hier ist eine Version der Antwort von SB, die auch übereinstimmende Regeln innerhalb übereinstimmender Medienabfragen zurückgibt. Ich habe die entfernt *.rules || *.cssRules Koaleszenz und die .matches Implementierungsfinder; Fügen Sie eine Polyfüllung hinzu oder fügen Sie diese Linien wieder ein, wenn Sie sie benötigen.

Diese Version gibt auch die zurück CSSStyleRule Objekte und nicht der Regeltext. Ich denke, das ist etwas nützlicher, da die Besonderheiten der Regeln auf diese Weise einfacher programmatisch untersucht werden können.

Kaffee:

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

  • Wie könnte dies geändert werden, um es bei Kindern von Verstorbenen anzuwenden? element auch?

    – Kragalon

    9. April 2016 um 21:00 Uhr

  • Was ist Ihr Anwendungsfall? Ich sehe nicht wirklich, wo das nützlich wäre, da Regeln, die für Kinder gelten, nicht unbedingt für die Eltern gelten. Sie würden nur mit einem Haufen Regeln enden, die nichts Besonderes gemeinsam haben. Wenn Sie das wirklich wollen, können Sie einfach auf Kinder rekursiv gehen und diese Methode für jedes ausführen und ein Array aller Ergebnisse aufbauen.

    – Zittern

    10. April 2016 um 23:25 Uhr

  • Ich versuche nur zu machen cloneNode(true) Funktionalität, aber auch mit tief geklontem Styling.

    – Kragalon

    11. April 2016 um 22:48 Uhr

  • diese Bedingung: if (window.matchMedia(rule.conditionText).matches) {…} hat in meinem Fall eine Übereinstimmung verhindert, da “rule.conditionText” nicht definiert war. Ohne hat es funktioniert. Sie können dies anprobieren und testen news.ycombinator.com. „span.pagetop b“ hat eine Medienabfrageregel, die so wie sie ist nicht mit Ihrer Funktion übereinstimmt.

    – Ayal-Gele

    19. Mai 2016 um 17:41 Uhr


  • Chrome unterstützt die conditionText-Eigenschaft auf CSSMediaRule-Instanzen nicht.

    – Macil

    2. September 2016 um 0:20 Uhr


1646251515 76 Finden Sie alle CSS Regeln die fur ein Element gelten
Benutzer3896501

Hier ist meine Version von getMatchedCSSRules Funktion, die unterstützt @media Anfrage.

const getMatchedCSSRules = (el) => {
  let rules = [...document.styleSheets]
  rules = rules.filter(({ href }) => !href)
  rules = rules.map((sheet) => [...(sheet.cssRules || sheet.rules || [])].map((rule) => {
    if (rule instanceof CSSStyleRule) {
      return [rule]
    } else if (rule instanceof CSSMediaRule && window.matchMedia(rule.conditionText)) {
      return [...rule.cssRules]
    }
    return []
  }))
  rules = rules.reduce((acc, rules) => acc.concat(...rules), [])
  rules = rules.filter((rule) => el.matches(rule.selectorText))
  rules = rules.map(({ style }) => style)
  return rules
}

  • Wie könnte dies geändert werden, um es bei Kindern von Verstorbenen anzuwenden? element auch?

    – Kragalon

    9. April 2016 um 21:00 Uhr

  • Was ist Ihr Anwendungsfall? Ich sehe nicht wirklich, wo das nützlich wäre, da Regeln, die für Kinder gelten, nicht unbedingt für die Eltern gelten. Sie würden nur mit einem Haufen Regeln enden, die nichts Besonderes gemeinsam haben. Wenn Sie das wirklich wollen, können Sie einfach auf Kinder rekursiv gehen und diese Methode für jedes ausführen und ein Array aller Ergebnisse aufbauen.

    – Zittern

    10. April 2016 um 23:25 Uhr

  • Ich versuche nur zu machen cloneNode(true) Funktionalität, aber auch mit tief geklontem Styling.

    – Kragalon

    11. April 2016 um 22:48 Uhr

  • diese Bedingung: if (window.matchMedia(rule.conditionText).matches) {…} hat in meinem Fall eine Übereinstimmung verhindert, da “rule.conditionText” nicht definiert war. Ohne hat es funktioniert. Sie können dies anprobieren und testen news.ycombinator.com. „span.pagetop b“ hat eine Medienabfrageregel, die so wie sie ist nicht mit Ihrer Funktion übereinstimmt.

    – Ayal-Gele

    19. Mai 2016 um 17:41 Uhr


  • Chrome unterstützt die conditionText-Eigenschaft auf CSSMediaRule-Instanzen nicht.

    – Macil

    2. September 2016 um 0:20 Uhr


Finden Sie alle CSS Regeln die fur ein Element gelten
Thomas

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>

  • Sinnloses Duplikat einer alten Version meiner Antwort. Nur die Seite verschmutzen. Vollständige und aktuelle Version: hier.

    – 7vujy0f0hy

    12. April 2017 um 22:25 Uhr

915660cookie-checkFinden Sie alle CSS-Regeln, die für ein Element gelten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy