Come leggi i valori delle regole CSS con JavaScript?


116

Vorrei restituire una stringa con tutti i contenuti di una regola CSS, come il formato che vedresti in uno stile inline. Mi piacerebbe essere in grado di farlo senza sapere cosa è contenuto in una regola particolare, quindi non posso semplicemente estrarli dal nome dello stile (come .style.widthecc.)

Il CSS:

.test {
    width:80px;
    height:50px;
    background-color:#808080;
}

Il codice finora:

function getStyle(className) {
    var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules
    for(var x=0;x<classes.length;x++) {
        if(classes[x].selectorText==className) {
            //this is where I can collect the style information, but how?
        }
    }
}
getStyle('.test')

per favore controlla anche questo. stackoverflow.com/questions/53592919/...
Mithilesh Kumar

Risposte:


91

Adattato da qui , basandosi sulla risposta di scunliffe:

function getStyle(className) {
    var cssText = "";
    var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules;
    for (var x = 0; x < classes.length; x++) {        
        if (classes[x].selectorText == className) {
            cssText += classes[x].cssText || classes[x].style.cssText;
        }         
    }
    return cssText;
}

alert(getStyle('.test'));

11
Nota che className deve corrispondere esattamente al selettore utilizzato nel file CSS. Ad esempio getStyle (". Article a") non troverà nulla se uno stile è stato descritto in questo modo ".article a, article a: hover {color: #ccc;}".
Vilius Paulauskas

1
Questo non funziona in Chrome, ma funziona in Firefox, quale potrebbe essere il problema ??
Johnydep

13
se ci sono più fogli di stile, dovrai anche scorrere anche quelli. for (var i = 0; i <document.styleSheets.length; i ++) {var s = document.styleSheets [i];}
surya

@surya Vedi la mia risposta per una soluzione di lavoro completa adattata
amico

2
@ Johnydep var classesdovrebbe essere document.styleSheets[0].rules[0].cssRulesin Chrome. Questo potrebbe essere aggiunto (creativamente) allo spessore nella risposta.
Henrik Christensen

23

Poiché la risposta accettata da "nsdel" è disponibile solo con un foglio di stile in un documento, questa è la soluzione di lavoro completa adattata:

    /**
     * Gets styles by a classname
     * 
     * @notice The className must be 1:1 the same as in the CSS
     * @param string className_
     */
    function getStyle(className_) {

        var styleSheets = window.document.styleSheets;
        var styleSheetsLength = styleSheets.length;
        for(var i = 0; i < styleSheetsLength; i++){
            var classes = styleSheets[i].rules || styleSheets[i].cssRules;
            if (!classes)
                continue;
            var classesLength = classes.length;
            for (var x = 0; x < classesLength; x++) {
                if (classes[x].selectorText == className_) {
                    var ret;
                    if(classes[x].cssText){
                        ret = classes[x].cssText;
                    } else {
                        ret = classes[x].style.cssText;
                    }
                    if(ret.indexOf(classes[x].selectorText) == -1){
                        ret = classes[x].selectorText + "{" + ret + "}";
                    }
                    return ret;
                }
            }
        }

    }

Avviso: il selettore deve essere lo stesso del CSS.


global_è solo un alias per l'oggetto finestra. Ho modificato lo snippet di codice. Dovrebbe funzionare ora
amico

3
il tuo codice fallisce se un foglio di stile non ha regole o cssRules (cosa che può succedere!) aggiungi if (! classes) continue; dopo var classes = styleSheets [i] .rules || StyleSheets [i] .cssRules; var classesLength = classes.length; vedi la mia modifica
kofifus

1
funziona, ma dovrebbe restituire un oggetto invece di una stringa
brauliobo

@kofifus Il tuo approccio è stato aggiunto
amico

Nota che questo non funziona dalla versione GC 64.0: stackoverflow.com/questions/48753691/…
Shalev Levi

18

SOLUZIONE 1 (CROSS-BROWSER)

function GetProperty(classOrId,property)
{ 
    var FirstChar = classOrId.charAt(0);  var Remaining= classOrId.substring(1);
    var elem = (FirstChar =='#') ?  document.getElementById(Remaining) : document.getElementsByClassName(Remaining)[0];
    return window.getComputedStyle(elem,null).getPropertyValue(property);
}

alert( GetProperty(".my_site_title","position") ) ;

SOLUZIONE 2 (CROSS-BROWSER)

function GetStyle(CLASSname) 
{
    var styleSheets = document.styleSheets;
    var styleSheetsLength = styleSheets.length;
    for(var i = 0; i < styleSheetsLength; i++){
        if (styleSheets[i].rules ) { var classes = styleSheets[i].rules; }
        else { 
            try {  if(!styleSheets[i].cssRules) {continue;} } 
            //Note that SecurityError exception is specific to Firefox.
            catch(e) { if(e.name == 'SecurityError') { console.log("SecurityError. Cant readd: "+ styleSheets[i].href);  continue; }}
            var classes = styleSheets[i].cssRules ;
        }
        for (var x = 0; x < classes.length; x++) {
            if (classes[x].selectorText == CLASSname) {
                var ret = (classes[x].cssText) ? classes[x].cssText : classes[x].style.cssText ;
                if(ret.indexOf(classes[x].selectorText) == -1){ret = classes[x].selectorText + "{" + ret + "}";}
                return ret;
            }
        }
    }
}

alert( GetStyle('.my_site_title') );

6

Alcune differenze del browser da tenere presente:

Dato il CSS:

div#a { ... }
div#b, div#c { ... }

e dato l'esempio di InsDel, le classi avranno 2 classi in FF e 3 classi in IE7 .

Il mio esempio lo illustra:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <style>
    div#a { }
    div#b, div#c { }
    </style>
    <script>
    function PrintRules() {
    var rules = document.styleSheets[0].rules || document.styleSheets[0].cssRules
        for(var x=0;x<rules.length;x++) {
            document.getElementById("rules").innerHTML += rules[x].selectorText + "<br />";
        }
    }
    </script>
</head>
<body>
    <input onclick="PrintRules()" type="button" value="Print Rules" /><br />
    RULES:
    <div id="rules"></div>
</body>
</html>

4

Ecco il codice per scorrere tutte le regole in una pagina:

function iterateCSS(f) {
  for (const styleSheet of window.document.styleSheets) {
    const classes = styleSheet.rules || styleSheet.cssRules;
    if (!classes) continue;

    for (const cssRule of classes) {
      if (cssRule.type !== 1 || !cssRule.style) continue;
      const selector = cssRule.selectorText, style=cssRule.style;
      if (!selector || !style.cssText) continue;
      for (let i=0; i<style.length; i++) {
        const propertyName=style.item(i);
        if (f(selector, propertyName, style.getPropertyValue(propertyName), style.getPropertyPriority(propertyName), cssRule)===false) return;
      }
    }
  }
}

iterateCSS( (selector, propertyName, propertyValue, propertyPriority, cssRule) => {
  console.log(selector+' { '+propertyName+': '+propertyValue+(propertyPriority==='important' ? ' !important' : '')+' }');
});


2
function getStyle(className) {
    document.styleSheets.item("menu").cssRules.item(className).cssText;
}
getStyle('.test')

Nota: "menu" è un ID elemento a cui hai applicato CSS. "className" un nome di classe CSS di cui abbiamo bisogno per ottenere il suo testo.


Sei sicuro che funzioni? (AFAIK il itemmetodo accetta un indice intero, non un className).
Julien Kronegg

assurdità completa
tnt-rox

2

Non ho trovato nessuno dei suggerimenti per funzionare davvero. Eccone uno più robusto che normalizza la spaziatura quando si trovano le classi.

//Inside closure so that the inner functions don't need regeneration on every call.
const getCssClasses = (function () {
    function normalize(str) {
        if (!str)  return '';
        str = String(str).replace(/\s*([>~+])\s*/g, ' $1 ');  //Normalize symbol spacing.
        return str.replace(/(\s+)/g, ' ').trim();           //Normalize whitespace
    }
    function split(str, on) {               //Split, Trim, and remove empty elements
        return str.split(on).map(x => x.trim()).filter(x => x);
    }
    function containsAny(selText, ors) {
        return selText ? ors.some(x => selText.indexOf(x) >= 0) : false;
    }
    return function (selector) {
        const logicalORs = split(normalize(selector), ',');
        const sheets = Array.from(window.document.styleSheets);
        const ruleArrays = sheets.map((x) => Array.from(x.rules || x.cssRules || []));
        const allRules = ruleArrays.reduce((all, x) => all.concat(x), []);
        return allRules.filter((x) => containsAny(normalize(x.selectorText), logicalORs));
    };
})();

Eccolo in azione dalla console Chrome.

inserisci qui la descrizione dell'immagine


1
Questo è il meccanismo di tutte le risposte in questa pagina. Vorrei anche arrivare a dire che dovrebbe essere su GitHub
Jacksonkr

Questo non funziona in IE11, perché Array.map () con la sintassi fornita non è supportato. Suggerirei di cambiarlo nella vecchia funzione () {return xxx; } sintassi per una migliore compatibilità. Altrimenti, ottima risposta!
Demonblack,

1
L'ho modificato per funzionare con IE11 (ad esempio ES5). Ecco una JSFiddle con tutto il necessario: jsfiddle.net/xp5r8961
Demonblack

1

Ho creato una funzione di supporto simile che mostra gli stili non necessari per questa pagina. aggiunge una <div>al corpo dell'elenco di tutti gli stili che non sono stati utilizzati.

(da utilizzare con la console firebug)

(function getStyles(){var CSSrules,allRules,CSSSheets, unNeeded, currentRule;
CSSSheets=document.styleSheets;

for(j=0;j<CSSSheets.length;j++){
for(i=0;i<CSSSheets[j].cssRules.length;i++){
    currentRule = CSSSheets[j].cssRules[i].selectorText;

    if(!document.querySelectorAll(currentRule).length){ 
       unNeeded+=CSSSheets[j].cssRules[i].cssText+"<br>"; 
  }       
 }
}

docBody=document.getElementsByTagName("body")[0];
allRulesContainer=document.createElement("div");
docBody.appendChild(allRulesContainer);
allRulesContainer.innerHTML=unNeeded+isHover;
return false
})()

1

Ho adattato la risposta di Julmot per ottenere un risultato più completo. Questo metodo restituirà anche gli stili in cui la classe fa parte del selettore.

//Get all styles where the provided class is involved
//Input parameters should be css selector such as .myClass or #m
//returned as an array of tuples {selectorText:"", styleDefinition:""}
function getStyleWithCSSSelector(cssSelector) {
    var styleSheets = window.document.styleSheets;
    var styleSheetsLength = styleSheets.length;
    var arStylesWithCSSSelector = [];

    //in order to not find class which has the current name as prefix
    var arValidCharsAfterCssSelector = [" ", ".", ",", "#",">","+",":","["];

    //loop through all the stylessheets in the bor
    for(var i = 0; i < styleSheetsLength; i++){
        var classes = styleSheets[i].rules || styleSheets[i].cssRules;
        var classesLength = classes.length;
        for (var x = 0; x < classesLength; x++) {
            //check for any reference to the class in the selector string
            if(typeof classes[x].selectorText != "undefined"){
                var matchClass = false;

                if(classes[x].selectorText === cssSelector){//exact match
                    matchClass=true;
                }else {//check for it as part of the selector string
                    //TODO: Optimize with regexp
                    for (var j=0;j<arValidCharsAfterCssSelector.length; j++){
                        var cssSelectorWithNextChar = cssSelector+ arValidCharsAfterCssSelector[j];

                        if(classes[x].selectorText.indexOf(cssSelectorWithNextChar)!=-1){
                            matchClass=true;
                            //break out of for-loop
                            break;
                        }
                    }
                }

                if(matchClass === true){
                    //console.log("Found "+ cssSelectorWithNextChar + " in css class definition " + classes[x].selectorText);
                    var styleDefinition;
                    if(classes[x].cssText){
                        styleDefinition = classes[x].cssText;
                    } else {
                        styleDefinition = classes[x].style.cssText;
                    }
                    if(styleDefinition.indexOf(classes[x].selectorText) == -1){
                        styleDefinition = classes[x].selectorText + "{" + styleDefinition + "}";
                    }
                    arStylesWithCSSSelector.push({"selectorText":classes[x].selectorText, "styleDefinition":styleDefinition});
                }
            }
        }
    }
    if(arStylesWithCSSSelector.length==0) {
        return null;
    }else {
        return arStylesWithCSSSelector;    
    }
}

Inoltre, ho creato una funzione che raccoglie le definizioni di stile CSS nel sottoalbero di un nodo radice fornito (tramite un selettore jquery).

function getAllCSSClassDefinitionsForSubtree(selectorOfRootElement){
    //stack in which elements are pushed and poped from
    var arStackElements = [];
    //dictionary for checking already added css class definitions
    var existingClassDefinitions = {}

    //use jquery for selecting root element
    var rootElement = $(selectorOfRootElement)[0];
    //string with the complete CSS output
    var cssString = "";

    console.log("Fetching all classes used in sub tree of " +selectorOfRootElement);
    arStackElements.push(rootElement);
    var currentElement;

    while(currentElement = arStackElements.pop()){
        currentElement = $(currentElement);
        console.log("Processing element " + currentElement.attr("id"));

        //Look at class attribute of element 
        var classesString = currentElement.attr("class");
        if(typeof classesString != 'undefined'){
            var arClasses = classesString.split(" ");

            //for each class in the current element
            for(var i=0; i< arClasses.length; i++){

                //fetch the CSS Styles for a single class. Need to append the . char to indicate its a class
                var arStylesWithCSSSelector = getStyleWithCSSSelector("."+arClasses[i]);
                console.log("Processing class "+ arClasses[i]);

                if(arStylesWithCSSSelector != null){
                    //console.log("Found "+ arStylesWithCSSSelector.length + " CSS style definitions for class " +arClasses[i]);
                    //append all found styles to the cssString
                    for(var j=0; j< arStylesWithCSSSelector.length; j++){
                        var tupleStyleWithCSSSelector = arStylesWithCSSSelector[j];

                        //check if it has already been added
                        if(typeof existingClassDefinitions[tupleStyleWithCSSSelector.selectorText] === "undefined"){
                            //console.log("Adding " + tupleStyleWithCSSSelector.styleDefinition);
                            cssString+= tupleStyleWithCSSSelector.styleDefinition;
                            existingClassDefinitions[tupleStyleWithCSSSelector.selectorText] = true;
                        }else {
                            //console.log("Already added " + tupleStyleWithCSSSelector.styleDefinition);
                        }
                    }
                }
            }
        }
        //push all child elments to stack
        if(currentElement.children().length>0){
            arStackElements= arStackElements.concat(currentElement.children().toArray());
        }
    }

    console.log("Found " + Object.keys(existingClassDefinitions).length + " CSS class definitions");
    return cssString;
}

Si noti che se una classe viene definita più volte con lo stesso selettore, la funzione precedente prenderà solo la prima. Nota che l'esempio usa jQuery (ma cab può essere riscritto relativamente facilmente per non usarlo)


1
sarebbe fantastico avere una soluzione non jquery (e un jsfiddle ..)
kofifus

0

// funziona in IE, non sono sicuro degli altri browser ...

alert(classes[x].style.cssText);

0

Questa versione passerà attraverso tutti i fogli di stile su una pagina. Per le mie esigenze, gli stili erano solitamente dal secondo all'ultimo degli oltre 20 fogli di stile, quindi li controllo al contrario.

    var getStyle = function(className){
        var x, sheets,classes;
        for( sheets=document.styleSheets.length-1; sheets>=0; sheets-- ){
            classes = document.styleSheets[sheets].rules || document.styleSheets[sheets].cssRules;
            for(x=0;x<classes.length;x++) {
                if(classes[x].selectorText===className) {
                    return  (classes[x].cssText ? classes[x].cssText : classes[x].style.cssText);
                }
            }
        }
        return false;
    };

0

Ho aggiunto il ritorno dell'oggetto in cui gli attributi vengono analizzati stile / valori:

var getClassStyle = function(className){
    var x, sheets,classes;
    for( sheets=document.styleSheets.length-1; sheets>=0; sheets-- ){
        classes = document.styleSheets[sheets].rules || document.styleSheets[sheets].cssRules;
        for(x=0;x<classes.length;x++) {
            if(classes[x].selectorText===className){
                classStyleTxt = (classes[x].cssText ? classes[x].cssText : classes[x].style.cssText).match(/\{\s*([^{}]+)\s*\}/)[1];
                var classStyles = {};
                var styleSets = classStyleTxt.match(/([^;:]+:\s*[^;:]+\s*)/g);
                for(y=0;y<styleSets.length;y++){
                    var style = styleSets[y].match(/\s*([^:;]+):\s*([^;:]+)/);
                    if(style.length > 2)
                        classStyles[style[1]]=style[2];
                }
                return classStyles;
            }
        }
    }
    return false;
};

style.cssText.match(...).1è nullo o non è un oggetto
amico

Uncaught ReferenceError: classStyleTxt is not defined
Jacksonkr

0

Ho creato una versione che cerca in tutti i fogli di stile e restituisce le corrispondenze come oggetto chiave / valore. È anche possibile specificare startsWith per abbinare gli stili figlio.

getStylesBySelector('.pure-form-html', true);

ritorna:

{
    ".pure-form-html body": "padding: 0; margin: 0; font-size: 14px; font-family: tahoma;",
    ".pure-form-html h1": "margin: 0; font-size: 18px; font-family: tahoma;"
}

a partire dal:

.pure-form-html body {
    padding: 0;
    margin: 0;
    font-size: 14px;
    font-family: tahoma;
}

.pure-form-html h1 {
    margin: 0;
    font-size: 18px;
    font-family: tahoma;
}

Il codice:

/**
 * Get all CSS style blocks matching a CSS selector from stylesheets
 * @param {string} className - class name to match
 * @param {boolean} startingWith - if true matches all items starting with selector, default = false (exact match only)
 * @example getStylesBySelector('pure-form .pure-form-html ')
 * @returns {object} key/value object containing matching styles otherwise null
 */
function getStylesBySelector(className, startingWith) {

    if (!className || className === '') throw new Error('Please provide a css class name');

    var styleSheets = window.document.styleSheets;
    var result = {};

    // go through all stylesheets in the DOM
    for (var i = 0, l = styleSheets.length; i < l; i++) {

        var classes = styleSheets[i].rules || styleSheets[i].cssRules || [];

        // go through all classes in each document
        for (var x = 0, ll = classes.length; x < ll; x++) {

            var selector = classes[x].selectorText || '';
            var content = classes[x].cssText || classes[x].style.cssText || '';

            // if the selector matches
            if ((startingWith && selector.indexOf(className) === 0) || selector === className) {

                // create an object entry with selector as key and value as content
                result[selector] = content.split(/(?:{|})/)[1].trim();
            }
        }
    }

    // only return object if we have values, otherwise null
    return Object.keys(result).length > 0 ? result : null;
}

Lo sto usando in produzione come parte del progetto della forma pura . Spero che sia d'aiuto.


0

Ho affrontato lo stesso problema. E con l'aiuto di ragazzi ho trovato una soluzione davvero intelligente che risolve completamente il problema (eseguito su Chrome).

Estrai tutte le immagini dalla rete

 function AllImagesUrl (domain){
  return  performance.getEntries()
    .filter( e=> 
       e.initiatorType == "img" &&
       new RegExp(domain).test(e.name) 
    )
  .map( e=> e.name.replace('some cleaning work here','') ) ```

0
const getStyle = query => [...document.querySelector(query).computedStyleMap().entries()].map(e=>(e[1]+=[],e)).map(e=>e.join`:`+';').join`\n`

In una riga, stampa il css generato per qualsiasi query.


-2

Sulla base della risposta di @dude, questo dovrebbe restituire stili pertinenti in un oggetto, ad esempio:

.recurly-input {                                                                                                                                                                             
  display: block;                                                                                                                                                                            
  border-radius: 2px;                                                                                                                                                                        
  -webkit-border-radius: 2px;                                                                                                                                                                
  outline: 0;                                                                                                                                                                                
  box-shadow: none;                                                                                                                                                                          
  border: 1px solid #beb7b3;                                                                                                                                                                 
  padding: 0.6em;                                                                                                                                                                            
  background-color: #f7f7f7;                                                                                                                                                                 
  width:100%;                                                                                                                                                                                
}

Questo tornerà:

backgroundColor:
"rgb(247, 247, 247)"
border
:
"1px solid rgb(190, 183, 179)"
borderBottom
:
"1px solid rgb(190, 183, 179)"
borderBottomColor
:
"rgb(190, 183, 179)"
borderBottomLeftRadius
:
"2px"
borderBottomRightRadius
:
"2px"
borderBottomStyle
:
"solid"
borderBottomWidth
:
"1px"
borderColor
:
"rgb(190, 183, 179)"
borderLeft
:
"1px solid rgb(190, 183, 179)"
borderLeftColor
:
"rgb(190, 183, 179)"
borderLeftStyle
:
"solid"
borderLeftWidth
:
"1px"
borderRadius
:
"2px"
borderRight
:
"1px solid rgb(190, 183, 179)"
borderRightColor
:
"rgb(190, 183, 179)"
borderRightStyle
:
"solid"
borderRightWidth
:
"1px"
borderStyle
:
"solid"
borderTop
:
"1px solid rgb(190, 183, 179)"
borderTopColor
:
"rgb(190, 183, 179)"
borderTopLeftRadius
:
"2px"
borderTopRightRadius
:
"2px"
borderTopStyle
:
"solid"
borderTopWidth
:
"1px"
borderWidth
:
"1px"
boxShadow
:
"none"
display
:
"block"
outline
:
"0px"
outlineWidth
:
"0px"
padding
:
"0.6em"
paddingBottom
:
"0.6em"
paddingLeft
:
"0.6em"
paddingRight
:
"0.6em"
paddingTop
:
"0.6em"
width
:
"100%"

Codice:

function getStyle(className_) {

    var styleSheets = window.document.styleSheets;
    var styleSheetsLength = styleSheets.length;
    for(var i = 0; i < styleSheetsLength; i++){
        var classes = styleSheets[i].rules || styleSheets[i].cssRules;
        if (!classes)
            continue;
        var classesLength = classes.length;
        for (var x = 0; x < classesLength; x++) {
            if (classes[x].selectorText == className_) {
                return _.pickBy(classes[x].style, (v, k) => isNaN(parseInt(k)) && typeof(v) == 'string' && v && v != 'initial' && k != 'cssText' )
            }
        }
    }

}

niente senza lodash in uso? _.pickBy non esiste altrimenti.
mpag

k & v sono invertiti in base a quello che stai chiedendo loro .... dovrebbe essere restituito_.pickBy(classes[x].style, (k,v) => isNaN(parseInt(k)) && typeof(v) == 'string' && v && v != 'initial' && k != 'cssText' )
mpag
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.