javascriptcss-selectorsstring-comparisoncss-specificity

Use javascript to write CSS specificity function


I need to write a javascript function, which compares two arguments passed in. They will be strings. And represent CSS classes.

The aim of the function, is to weight CSS specificity. So if an argument passed in, is a CSS ID, it should be returned rather than the second argument. (EG if a = '#id', it will beat b = '.red').

Kinda getting lost on the best approach for my javascript function. Not sure whether to use if/else statements or switch/case. Either way, it's getting messy and need some pointers.

Here's what I'm trying to do:


Solution

  • I ran into this exact question recently during a job interview and I was able to figure it out like so:

    function compare(a, b) {
      let aItems = a.split([" "]);
      let aRating = [0, 0, 0];
    
      aItems.forEach((i) => {
        if (i.split("#").length > 1) {
          aRating[0] = aRating[0] + (i.split("#").length - 1);
        }
    
        if (i.split(".").length > 1) {
          aRating[1] = aRating[1] + (i.split(".").length - 1);
        }
    
        if (!i.startsWith("#") && !i.startsWith(".")) {
          aRating[2] = aRating[2] + 1;
        }
      });
    
      let bItems = b.split([" "]);
      let bRating = [0, 0, 0];
    
      bItems.forEach((i) => {
        if (i.split("#").length > 1) {
          bRating[0] = bRating[0] + (i.split("#").length - 1);
        }
    
        if (i.split(".").length > 1) {
          bRating[1] = bRating[1] + (i.split(".").length - 1);
        }
    
        if (!i.startsWith("#") && !i.startsWith(".")) {
          bRating[2] = bRating[2] + 1;
        }
      });
    
      if (aRating[0] > bRating[0]) {
        return a;
      } else if (bRating[0] > aRating[0]) {
        return b;
      }
    
      if (aRating[1] > bRating[1]) {
        return a;
      } else if (bRating[1] > aRating[1]) {
        return b;
      } else if (
        bRating[0] === aRating[0] &&
        bRating[2] === 0 &&
        aRating[2] === 0
      ) {
        return b;
      }
    
      if (aRating[2] > bRating[2]) {
        return a;
      } else if (bRating[2] > aRating[2]) {
        return b;
      }
    }
    
    

    There is one issue though, say you are comparing tagnames (ie, html, body where the more specific, the higher the specificity), then you might have some difficulty. I was able to hack my way through it string of if else tests.