53

Is there a way to determine whether or not a CSS class exists using JavaScript?

anthumchris
  • 8,245
  • 2
  • 28
  • 53
gidmanma
  • 1,464
  • 1
  • 16
  • 27
  • 2
    What do you mean by a class exists? That there is at least one element with that class or that there is at least one CSS rule that is applied on elements with that class? – Gumbo Jun 11 '09 at 20:53
  • 2
    Sorry, I mean... Does the class definition exist in the browser's memory? In other words, has the class been defined internally or in a loaded stylesheet? – gidmanma Jun 11 '09 at 20:57
  • hey I know it's an old question but did you find a code to solve this?I 've been trying for hours with no luck.Thanks – cssGEEK Jun 22 '16 at 22:13
  • I believe I ended up writing something myself using the accepted answer. It's been a long time though. I haven't had access to that code base in years. Sorry. – gidmanma Jun 23 '16 at 22:48
  • 1
    Solutions that loops stylesheets don't work well in Chrome and Firefox, which have same-origin check. The code is unable to read a stylesheet from another domain! – Gqqnbig Aug 22 '16 at 23:27

11 Answers11

37

This should be possible to do using the document.styleSheets[].rules[].selectorText and document.styleSheets[].imports[].rules[].selectorText properties. Refer to MDN documentation.

Community
  • 1
  • 1
Helen
  • 87,344
  • 17
  • 243
  • 314
  • 6
    Use the google cache link to see the Expert Exchange answer or do the search for "JavaScript: Checking if a CSS class exists" in Google to go there. Expert exchange is a little anal about showing answers you either need a Google referrer or use the Google Cache (otherways may work, but these i know!) http://209.85.229.132/search?q=cache:y8Pj_46Q6O0J:www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_21685655.html+JavaScript:+Checking+if+a+CSS+class+exists&cd=1&hl=en&ct=clnk – Shadi Almosri Jun 11 '09 at 21:41
  • Thanks, I found that link earlier and tried looking at the google cache but apparently didn't scroll far enough down the page. The first few responses all had the "register to view" text on them. – gidmanma Jun 11 '09 at 21:50
  • Code is listed on the link in Shadi's comment above. Basically you troll through the selectors in memory looking for the selector text. Thanks Helen Thanks Shadi – gidmanma Jun 11 '09 at 21:52
  • @Shadi Almosri: Thanks for the tip! I've updated the link in the answer. Actually, with Opera I never have problems viewing answers on experts exchange. :) But Google cache or Archive.org links should be more accessible, I agree. – Helen Jun 11 '09 at 21:53
  • 7
    The experts-exchange secret is to just keep scrolling. The answers are there below all their "sign up now!" text. – Hardwareguy Jun 11 '09 at 21:55
  • Answer is not on the page, even if you keep on scrolling >_> – Ash Blue Apr 12 '13 at 07:56
  • 2
    @AshBlue: Looks like EE changed their website design. Try the archive.org version: http://web.archive.org/web/20071210160927/http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_21685655.html. Alternatively, you can view answers on the "live" site by spoofing your user agent string to look like Googlebot (e.g. using Firefox's User Agent Switcher extension). – Helen Apr 12 '13 at 08:25
  • IE and firefox only cssRules : document.styleSheets[].cssRules[] – qxo Aug 16 '17 at 05:13
  • firefox only cssRules : document.styleSheets[].cssRules[] – qxo Aug 16 '17 at 05:24
14
function getAllSelectors() { 
    var ret = [];
    for(var i = 0; i < document.styleSheets.length; i++) {
        var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules;
        for(var x in rules) {
            if(typeof rules[x].selectorText == 'string') ret.push(rules[x].selectorText);
        }
    }
    return ret;
}


function selectorExists(selector) { 
    var selectors = getAllSelectors();
    for(var i = 0; i < selectors.length; i++) {
        if(selectors[i] == selector) return true;
    }
    return false;
}
Cau Guanabara
  • 179
  • 1
  • 2
  • 1
    doesn't work very well, at least on chrome.. 1. opened developer console (f12). 2. pasted the function getAllSelectors(). 3. called it right here on this page, all I got was: [".wmd-snippet-button span", ".wmd-snippet-button:hover span", "#newsletter-ad", "#newsletter-ad-header", "#newsletter-ad ul", "#newsletter-ad ul li", "#newsletter-signup-container", "#newsletter-preview-container", "#newsletter-email-input"]. <-- (this is obviously not all the selectors on this page) – Ronen Ness Aug 27 '15 at 21:15
  • Does not returns css rules from included stylesheets –  Mar 17 '17 at 21:08
  • Got: Uncaught DOMException: Failed to read the 'rules' property from 'CSSStyleSheet': Cannot access rules – Nathan B Jul 18 '21 at 12:41
  • ⚠️ This is too verbose. Please remove and upvote one of the existing, minimal solutions – anthumchris May 25 '23 at 17:08
4

Based on the answer, I created a javascript function for searching for a CSS class in the browser's memory -

var searchForCss = function (searchClassName) {
  for (let i = 0; i < document.styleSheets.length; i++) {
    let styleSheet = document.styleSheets[i];
    try {
      for (let j = 0; j < styleSheet.cssRules.length; j++) {
        let rule = styleSheet.cssRules[j];
        // console.log(rule.selectorText)
        if (rule.selectorText && rule.selectorText.includes(searchClassName)) {
          console.log('found - ', rule.selectorText, ' ', i, '-', j);
        }
      }
      if (styleSheet.imports) {
        for (let k = 0; k < styleSheet.imports.length; k++) {
          let imp = styleSheet.imports[k];
          for (let l = 0; l < imp.cssRules.length; l++) {
            let rule = imp.cssRules[l];
            if (
              rule.selectorText &&
              rule.selectorText.includes(searchClassName)
            ) {
              console.log('found - ',rule.selectorText,' ',i,'-',k,'-',l);
            }
          }
        }
      }
    } catch (err) {}
  }
};

searchForCss('my-class-name');

This will print a line for each occurrence of the class name in any of the rules in any of the stylesheets.

Ref - Search for a CSS class in the browser memory

Nithin Kumar Biliya
  • 2,763
  • 3
  • 34
  • 54
3

Here is my solution to this. I'm essentially just looping through document.styleSheets[].rules[].selectorText as @helen suggested.

/**
 * This function searches for the existence of a specified CSS selector in a given stylesheet.
 *
 * @param (string) styleSheetName - This is the name of the stylesheet you'd like to search
 * @param (string) selector - This is the name of the selector you'd like to find
 * @return (bool) - Returns true if the selector is found, false if it's not found
 * @example - console.log(selectorInStyleSheet ('myStyleSheet.css', '.myClass'));
 */    

function selectorInStyleSheet(styleSheetName, selector) {
    /*
     * Get the index of 'styleSheetName' from the document.styleSheets object
     */
    for (var i = 0; i < document.styleSheets.length; i++) {
        var thisStyleSheet = document.styleSheets[i].href ? document.styleSheets[i].href.replace(/^.*[\\\/]/, '') : '';
        if (thisStyleSheet == styleSheetName) { var idx = i; break; }
    }
    if (!idx) return false; // We can't find the specified stylesheet

    /*
     * Check the stylesheet for the specified selector
     */
    var styleSheet = document.styleSheets[idx];
    var cssRules = styleSheet.rules ? styleSheet.rules : styleSheet.cssRules;
    for (var i = 0; i < cssRules.length; ++i) {
        if(cssRules[i].selectorText == selector) return true;
    }
    return false;
}

This function offers a speed improvement over other solutions in that we are only searching the stylesheet passed to the function. The other solutions loop through all the stylesheets which is in many cases unnecessary.

circuitry
  • 1,169
  • 16
  • 16
  • 1
    Checking idx for an undefined value should be better done with if(typeof idx != 'undefined'), otherwise an 0 value of idx would be omitted. – SeDav Nov 27 '14 at 12:38
  • Put the value of document.styleSheets.length in a variable. – Codebeat Apr 03 '16 at 21:25
  • jQuery.Deferred exception: Cannot read property 'length' of null TypeError: Cannot read property 'length' of null –  Mar 17 '17 at 21:28
  • @Soaku this answer doesn't use jquery... not sure where your error is coming from. – circuitry Apr 06 '17 at 04:33
  • This is too verbose. Please remove and upvote one of the existing, minimal solutions – anthumchris May 25 '23 at 17:08
3
  1. Document contains Element with class my-class:
    const isExists = !!document.querySelector('.my-class') // boolean
    
  2. Existing Element has class my-class:
    const el = document.querySelector(...)
    const isExists = !!el?.classList.contains('my-class') // boolean
    

References: querySelector()classListcontains()?. chaining!! logical not

anthumchris
  • 8,245
  • 2
  • 28
  • 53
Ignatius Andrew
  • 8,012
  • 3
  • 54
  • 54
  • 1
    In your example you check if an element has the class. It doesn't tell you if the class is defined in a stylesheet. – Codebeat Apr 03 '16 at 21:28
  • 2
    Also, your edit doesn't make any sense because you are searching for an element with the classname 'className' in the DOM (the page). You are not searching the CSS, searching for a rule, to check if a rule exist. – Codebeat Apr 04 '16 at 19:26
  • @codebeat please remove or consolidate these outdated comments? Could you edit and add a third solution that meets your use cases? – anthumchris May 25 '23 at 17:13
  • @anthumchris It isn't outdated. With this you cannot see a CSS style/rule exists, if it is defined. You can only see the classnames applied to the element. That doesn't mean the style itself is defined. See also "The Element.classList is a read-only property that returns a live DOMTokenList collection of the class attributes OF THE ELEMENT." - https://developer.mozilla.org/en-US/docs/Web/API/Element/classList – Codebeat May 26 '23 at 13:25
  • To reduce and simplify, could you remove the comments and augment the answer so it can help users? – anthumchris May 26 '23 at 15:52
2

/* You can loop through every stylesheet currently loaded and return an array of all the defined rules for any selector text you specify, from tag names to class names or identifiers.

Don't include the '#' or '.' prefix for an id or class name.

Safari used to skip disabled stylesheets, and there may be other gotchas out there, but reading the rules generally works better across browsers than writing new ones. */

function getDefinedCss(s){
    if(!document.styleSheets) return '';
    if(typeof s== 'string') s= RegExp('\\b'+s+'\\b','i'); // IE capitalizes html selectors 

    var A, S, DS= document.styleSheets, n= DS.length, SA= [];
    while(n){
        S= DS[--n];
        A= (S.rules)? S.rules: S.cssRules;
        for(var i= 0, L= A.length; i<L; i++){
            tem= A[i].selectorText? [A[i].selectorText, A[i].style.cssText]: [A[i]+''];
            if(s.test(tem[0])) SA[SA.length]= tem;
        }
    }
    return SA.join('\n\n');
}

getDefinedCss('p')//substitute a classname or id if you like

the latest item in the cascade is listed first.

kennebec
  • 102,654
  • 32
  • 106
  • 127
  • RegEx introduces unnecessary complexity, please upvote one of the existing minimal/simple solutions, mostly achievable in one line. – anthumchris May 25 '23 at 17:10
0

Building on Helen's answer, I came up with this:

//**************************************************************************
//** hasStyleRule
//**************************************************************************
/** Returns true if there is a style rule defined for a given selector.
 *  @param selector CSS selector (e.g. ".deleteIcon", "h2", "#mid")
 */
  var hasStyleRule = function(selector) {

      var hasRule = function(selector, rules){
          if (!rules) return false;
          for (var i=0; i<rules.length; i++) {
              var rule = rules[i];
              if (rule.selectorText){ 
                  var arr = rule.selectorText.split(',');
                  for (var j=0; j<arr.length; j++){
                      if (arr[j].indexOf(selector) !== -1){
                          var txt = trim(arr[j]);
                          if (txt===selector){
                              return true;
                          }
                          else{
                              var colIdx = txt.indexOf(":");
                              if (colIdx !== -1){
                                  txt = trim(txt.substring(0, colIdx));
                                  if (txt===selector){
                                      return true;
                                  }
                              }
                          }
                      }
                  }
              }
          }
          return false;
      };

      var trim = function(str){
          return str.replace(/^\s*/, "").replace(/\s*$/, "");
      };

      for (var i=0; i<document.styleSheets.length; i++){
          var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules;
          if (hasRule(selector, rules)){
              return true;
          }

          var imports = document.styleSheets[i].imports;
          if (imports){
              for (var j=0; j<imports.length; j++){
                  rules = imports[j].rules || imports[j].cssRules;
                  if (hasRule(selector, rules)) return true;
              }
          }
      } 

      return false;
  };
Peter
  • 1,182
  • 2
  • 12
  • 23
  • This is too verbose and complicated to recommend to developers. Native Web APIs exist: [`querySelectorAll()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) – anthumchris May 25 '23 at 17:07
-1

You could check and see if an object of the style your are looking for already exists. If it does then the css class must exist because an object is using it. For example if you wanted to make sure that distinctly named svg objects each have their own style:

function getClassName(name) {
    //Are there any elements which use a style named 'name' ?
    if (document.getElementsByClassName(name).length === 0){
        //There are none yest, let's make a new style and add it
        var style = document.createElement('style');
        style.type = 'text/css';
        //Where you might provide your own hash function or rnd color
        style.innerHTML = '.'+name+' { fill: #' + getHashColor(name) + '; background: #F495A3; }';
        //Add the style to the document
        document.getElementsByTagName('head')[0].appendChild(style);
        }
        return name;
    }

Note that this is NOT a good approach if you are looking for a style which isn't necessarily used in your document.

Quinn Carver
  • 587
  • 7
  • 14
  • This is too verbose and complicated to recommend to developers. Native Web APIs exist: [`querySelectorAll()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) – anthumchris May 25 '23 at 17:07
-1
if ($(".class-name").length > 0) {

}

That is a nice way to check the class in HTML by using javascript

Md Nurullah
  • 472
  • 7
  • 21
  • qjuery is not javascript – B''H Bi'ezras -- Boruch Hashem Apr 27 '20 at 07:22
  • This is wrong. This gives you if the html element existing with the given class name. It is not giving you whether the css class exists in stylesheet of the page which is asked in the question. – doraemon May 09 '23 at 11:20
  • Please don't recommend third-party libraries to developers when native Web APIs exist: [`querySelectorAll()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) – anthumchris May 25 '23 at 17:06
-1

Oneliner:

[].slice.call(document.styleSheets)
.reduce( (prev, styleSheet) => [].slice.call(styleSheet.cssRules))
.reduce( (prev, cssRule) => prev + cssRule.cssText)
.includes(".someClass")
Pieter
  • 1,751
  • 3
  • 30
  • 65
  • `[].slice.call( document.styleSheets ) .reduce((last, currentStyleSheet) => [] .slice .call( currentStyleSheet.cssRules ) ) .reduce((last, currentCssRule) => last + currentCssRule.cssText ) .includes(".name")` in firefox gives error `SecurityError: The operation is insecure.` – B''H Bi'ezras -- Boruch Hashem Apr 27 '20 at 07:21
-1
function getAllSelectors() {
  var ret = {};
  for(var i=0;i<document.styleSheets.length;i++){
    try {
      var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules;
      for(var x in rules) {
        if(typeof rules[x].selectorText === 'string'){
          if(ret[rules[x].selectorText] === undefined){
            ret[rules[x].selectorText] = rules[x].style.cssText;
          }
          else {
            ret[rules[x].selectorText] = ret[rules[x].selectorText] + ' ' + rules[x].style.cssText;
          }
        }
      }    
    }
    catch(error){
      console.log(document.styleSheets[i]);
    }
  }
  return ret;
}
function selectorExists(selector) {
  var selectors = getAllSelectors();
  if(selectors[selector] !== undefined){
    return true;
  }
  return false;
}
// var allSelectors = getAllSelectors();
SYNAIKIDO
  • 69
  • 1
  • 4