Is it possible to get css class object?

Today I have found interesting problem.

I am trying to get list of attributes and values of css class. All references found on internet lead me to node styles (html element styles) so I cannot get the object of the css class.

Is there a way how to access this in browser? I need to check if there is some attribute of specified value in a class (which is used by element) and then either to remove the class from element or keep it there.

Seems like imposible task in standard javascript, huh?

This is propably quite slow for sites that include bigger CSS libs, but it should give you most CSS rules that are related to a .class:

const hasClass = new RegExp(String.raw`\.${ className }(?:[^\w-]|$)`);
const rules = [ ];
Array.prototype.forEach.call(document.styleSheets,
    ({ rules, }) => rules && Array.prototype.forEach.call(rules,
        rule => hasClass.test(rule.selectorText) && rules.push(rule)
    )
);

To get all related rules, you’d have to scan ate child rules of stuff like media query rules too.

I cannot make it working. You should explain some bits of the code. What is this:

new RegExp(String.raw\.${ className }(?:[^\w-]|$));

I guess this produces error in my code. (Of sure I don’t see any error in Toolbox, I just cannot open the Content Script when there is error).

This should explain the RegExp (and show that it works):

https://regex101.com/r/nU2hY3/2

Array.forEach only exists in FF and you need to define a variable className to be substituted in the template string.

****, the manual is so confusing:

Syntax

arr.forEach(callback[, thisArg])
WTF, WTF…

You use it like an array but they have callback in syntax.

What I was using with Array.forEach is an <a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Array_generic_methods">Array generic method, since document.styleSheets is not an Array and has no own .forEach method.
It is the same as using Array.prototype.forEach.call(...) which will work in all browsers, but is longer to write.

It is depricated.

Is it this?

(function (global, infinity, undefined) {
    /*jshint bitwise:false, maxlen:95, plusplus:false, validthis:true*/
    "use strict";

    /**
     * Local references to constructors at global scope.
     * This may speed up access and slightly reduce file size of minified version.
     */
    var Array = global.Array;
    var Object = global.Object;
    var Math = global.Math;
var Number = global.Number;

function forEach(callback, scope) {
    /*jshint newcap:false*/
    var elements, length, index;

    // convert elements to object
    elements = Object(this);

    // make sure callback is a function
    requireFunction(callback);

    // convert length to unsigned 32 bit integer
    length = elements.length >>> 0;

    // iterate over elements
    for (index = 0; index < length; ++index) {

        // current index exists
        if (index in elements) {

            // execute callback
            callback.call(scope, elements[index], index, elements);
        }
    }
}
}

But if this is non-cross browser solution than it has no sense to integrate it in my addon.

Yeah, just read that too. Shame though, I really liked them (but the Chrome people didn’t, thus the deprecation).

But you don’t need to use a polyfill, that’s somewhat overkill. I will update the code above to work in Chrome. (done)

The function code is too hard for me to understand. I don’t know which parts are non-cross browser. Maybe the global.Array . If it would be possible to write such forEach function but cross-browser, then I would integrate it.

As I said, I’ve updated the code above

Can you yet explain this?

hasClass.test(rule.selectorText)

I see RegExp.prototype.test() but it is still not clear to me from where you got the selectorText value.

first call
Array.prototype.forEach.call(document.styleSheets
you go through styleSheets.

What is this:
({ rules, })
unknown syntax for me. Callback with one argument? Why the dash is there? No, I guess some type of assignment…

So what is the final result - one dimentional array?

Quite strange code. Is the updated version still non-cross browser?

Why the dash is there?

Which dash? After String.raw inside the template string? (Note: you lost two characters in your quote) That one is escaping the ‘.’ for the RegExp

So what is the final result - one dimentional array?

Yes

Quite strange code. Is the updated version still non-cross browser?

The code worked in Firefox before the “update”, so yes, the whole point of changing it was to make it cross-browser compatible.

I speak about this dash “,”:

({ rules, })
I see only one parameter inside the {} and so I am confused why the dash is not followed by some variable or property…

That’s a comma :D. This is a dash: “-”

Tailing commas in (modern) JavaScript are optional. So you don’t have to set them but you can

Why the rules array is declared as const? I think you save object to it so it should be variable.

(I’m not entirely sure what you mean, but:)

The const doesn’t effect the referenced value, but the reference to it:
declaring an identifier const means you can’t assign to it (const a = { }; a = [ ]; doesn’t work),
but you can still manipulate the values properties (const a = { }; a.b = 42; works).

I tried your code but the rules array is empty when function finishes. Maybe I could send you my addon so you could check how it works?

I would explain you what I am working on and maybe you can improve the code. If it would work it would be great because the code is quite sort. I tried to create complicated solution but I failed here and here.


I wonder that such function like yours is not standard part of browsers. We use functions to remove css classes but we cannot analyse it’s content… Which is neccessary if you need to remove a class dynamically/automatically.

What exactly is it you want to achieve?
Do you want to forcefully apply (user) styles to elements with a certain class?
If so, do you really need anything more than rules that are declared as !important?

I am working on addon which can swap columns (divs). This is archieved by 1) analysing divs positions and 2) analysing styles. Before I can apply new (absolute) position of the divs, I must to remove the classes which give the position:absolute, left: …, right: …, top: … or bottom: … positions and float: being set to “non-none”. So I need to analyse the classes or even div’s id.

The code looks like this:

var selectors = "div.fauxcolumn-right-outer;div.fauxcolumn-center-outer"
var selectors = selectors.split(";");
var searches = [];
var targets = [];
for ( var k in selectors )
  {
  if ( (k % 2) == 0 )
    searches.push(selectors[k]);
  else
    targets.push(selectors[k]);      
  }

for ( var k in searches )
  {
  var search, target; 
  search = $(searches[k]);
  if ( search.length )
   target = $(targets[k]);
  if ( !search.length || !target.length )
    continue;
    
  var s_css_arr = search.prop("className").split(" ");
  var t_css_arr = target.prop("className").split(" ");
  
  var className = s_css_arr[0];
  const hasClass = new RegExp(String.raw`\.${ className }(?:[^\w-]|$)`);
  const rules = [ ];
  
  Array.prototype.forEach.call(document.styleSheets,
      ({ rules, }) => rules && Array.prototype.forEach.call(rules,
          rule => hasClass.test(rule.selectorText) && rules.push(rule)
      )
  );

I see the problem. There is div.classname so I will need to modify it