1

I've read up on inserting css rules using Javascript and have managed to get it working (after some trial & error). So I have 2 questions:

Q.1 Why is an index < 1 not working - see Mozilla example (and many others) below:

// push a new rule onto the top of my stylesheet - doesn't work...
myStyle.insertRule("#blanc { color: white }", 0); // returns Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to insert the rule.

// change the index and it works!
myStyle.insertRule("#blanc { color: white }", 1); 

This article by David Walsh (very helpful), explains that the default for index is -1. He uses 1 in his example, which is what worked for me. Anything less than 1, ie 0 or -1 (as per the default) threw the following errors:

Index -1 error: Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': The index provided (4294967295) is larger than the maximum index (2071).

Index 0 error: Uncaught DOMException: Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to insert the rule.

It's not a huge problem, but it does mean I can't control specificity. I can use !important or rework the css/inserted rule so that it overrides any existing styles, but as I'm just learning JavaScript, I'd really like to know why it's not working as expected. Does anyone have any ideas?

Q.2 Having got it to work using index 1, I now want to pull in values dynamically. I have the item names in an array, which is used to create multiple objects, inside which are the property values I want to use for the individual style rules for that object.

Basically what I'm trying to output is this (which works):

styleSheet.insertRule("#item { border-top-color: #000000; border-right-color: #ffffff; }", 1);  

But using variables, something like this:

styleSheet.insertRule("[itemName] { border-top-color: [itemName.value1]; border-right-color: [itemName.value2]; }", 1); // itemName.valueX being the object's array item

I've tried heaps of things, but I can't get the array item bit to work, ie colour and colour4 should actually be itemName.value1/2 or a var that equals the same. This is the closest I've got so far...

styleSheet.insertRule("#" + name + " { border-top-color: " + colour + "; border-right-color: " + colour4 + " !important; }", 1); // 1st rule works, 2nd doesn't show anything 

It all works lovely if I write it manually (as per the 1st example), but how to do it dynamically? I've found info on insertRule, but not using dynamic values - can anyone help/point me in the right direction?

Many thanks in advance!

Expanded WIP for more clarity:

function itemColours() {

for (i = 3; i < itemsArray.length; i++) {

let name = itemsArray[i];
let colour = #000000;

console.log(item1.value); // returns the hex value I want to use in the rule

styleSheet.insertRule("#" + name + " { border-top-color: " + colour + "; border-right-color: " + name + ".value !important; }", 1);
// rule 1 works, rule 2 doesn't...
}
Meanderling
  • 53
  • 1
  • 8
  • What sort of syntax is this?: `styleSheet.insertRule("[itemName] { border-top-color: [itemName.value1]; border-right-color: [itemName.value2]; }"` – zer00ne Oct 28 '17 at 01:50
  • The reason for the weird index default is because it's assumed that you want to add a new style at the end of the stylesheet thereby overriding earlier styles. Anything at the end of an index is -1. Having said that, index 0 should work, but really in your case it would seem that using default would be in your best interest seeing that you are using `!important`. – zer00ne Oct 28 '17 at 01:56
  • Sorry, thought I replied yesterday! Wrote it out, made edits to the original Q. thought I'd try again & forgot to post...doh! The sq brackets in ex#2 were just indicating what/where - the edit showing WIP should make more sense. Re indexing - the default behaviour is exactly what I want. I only used !important to ensure specificity, as I get errors using an index <1 (see edit for errors). I've sort of figured out the dynamic values, but it's still wrong (would be good to know the right way) as now the rule won't execute, despite the code looking fine in the error message. Maybe it's connected? – Meanderling Oct 29 '17 at 12:12
  • Wow! I got it working using an Object Prototype, which I couldn't get to work before - probably to do with whatever function I'd written or how I was trying to call it? Anyway, with all the workarounds and random key smashing, it seems I may have learnt some stuff, as it's working lovely now. All except the indexing -1 issue... If you have any thoughts, I'd love to figure it out. Thanks for getting back to me, I meant to say that in the last message, but ran out of room. Much appreciated! – Meanderling Oct 29 '17 at 15:08
  • Just to make sure I'm getting the whole picture: When using `.insertRule` you are attempting to add CSSRule to an external CSS file such as ``. If so, how many externals `` does your page have? – zer00ne Oct 30 '17 at 00:59
  • There are a few sheets; 1 main and a few for plugins. I followed the article mentioned to find the correct sheet, so 'stylesheet' in the above code does select the correct sheet. The rule is inserted 6x corresponding to the 6 ids on the page (with a view to that increasing in the future). Everything works now, except for the indexing issue. Incidentally, if I amend the same style sheet in the browser, the rule disappears. I assume because it only gets written once when the page is loaded. Is that correct? – Meanderling Oct 30 '17 at 12:52
  • Yes that is correct. Is there any advantage to this? If you manipulated styles in a ` – zer00ne Oct 30 '17 at 17:35
  • No advantage, I just wanted to check I was understanding it correctly (I am, so that's good). With the indexing, it fails to execute if the index is 0 (see error msg added to original question). If the index is 1, both rules execute perfectly. The code I'm using is: `styleSheet.insertRule("#" + this.itemNm + " { border-top-color: " + this.value1 + " !important; border-right-color: " + this.value2 + " !important; }", 1);` – Meanderling Oct 30 '17 at 20:28
  • Ok, I got it working dynamically on a `for` loop and using index 0 and 1, see answer. – zer00ne Oct 31 '17 at 02:12
  • **Caution**: the David Walsh article linked to in the question is wrong (or outdated). Specifically, `-1` is not a valid `index` argument for `insertRule` (throws an exception), and it defaults to `0`, not `-1` if omitted. The correct `index` value for inserting a rule at end of sheet is `styleSheet.cssRules.length` @Meanderling – typeracer May 25 '23 at 15:45

1 Answers1

0

Update 2

This demo:

  • can accept user data to use insertRule() and deleteRule().

  • has an Add Set button which will create and append a clone of the <form> part of the document

  • has 3 styleSheets Bootstrap [0], CSSOM, and the <style> tag.

Demo 4

// Just for demo
.as-console-wrapper {
  width: 170px;
  max-height: 40px;
  transform: translateX(340px)
}
<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8'>
  <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' title='Bootstrap-3.3.7'>
  <link href='https://glpjt.s3-us-west-1.amazonaws.com/ir/cssom.css' rel="stylesheet" title='CSSOM'>
  <style title='Tag'>
    body {
      max-width: 96%;
      visibility: hidden;
      font: 400 16px/1.2 Verdana
    }
    
    ul.x-list.x-list {
      margin-left: 0;
      padding-left: 1em;
      text-indent: -1em;
      list-style-type: none;
    }
    
    li.x-item.x-item {
      list-style: none;
      line-height: 1.5;
    }
    
    .x-flex.x-flex {
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    .x-col {
      display: flex;
      flex-direction: column
    }
    
    option::before {
      content: attr(name)
    }
    
    #idx {
      max-width: 6ch;
    }
    
    label {
      margin: 10px auto 10px -15px
    }
    
    #add {
      position: fixed;
      z-index: 1;
      top: 50px;
      left: 20px
    }
  </style>
</head>

<body>
  <main class='container' style='padding:50px 0 20px 20px'>


    <form id='cssom' class='row x-col'>
      <div class='btn-group col-sm-12'>
        <input id='add' class='btn-lg btn-success' type='button' value='Add Set'>
      </div>
      <section class='row'>
        <!--=================================[0]-->
        <fieldset class='set0 col-sm-12'>
          <hr>
          <div class='row x-flex'>
            <!--=================================[1]-->
            <label class='form-control-label col-sm-2'>CSS Rule</label>
            <textarea id='rul0' class='form-control col-sm-10' rows='2'>li.x-item.x-item::before {content: '\1f539\00a0';list-style:none;font-size:small;position:relative;bottom:2px}</textarea>
          </div>
          <div class='form-inline row'>
            <label class='form-control-label col-sm-2'>Stylesheet</label>
            <select id='sht0' class='form-control col-sm-4'>
                 <optgroup label="LINK">
                  <!--================================[3]-->
                  <option value='0' selected name='Bootstrap-3.3.7'> [0]</option>
                  <option value='1' name='CSSOM'> [1]</option>
                </optgroup>
                <optgroup label="STYLE">
                  <option value='2' name='Tag'> [2]</option>
                </optgroup>
               </select>
            <label class='form-control-label col-sm-1'>Rule Index</label>
            <input id='idx0' class='form-control col-sm-1' type='number' min='-1' value='0'>
            <!--==========[4]-->

            <div class="btn-group col-sm-4">

              <!--=====[5]-->
              <input id='ins0' class='btn btn-primary' type='button' value='Insert Rule' onclick='modRule(this)'>
              <!--======[6]-->
              <input id='del0' class='btn btn-danger' type='button' value='Delete Rule' onclick='modRule(this)'>
            </div>
          </div>
        </fieldset>
      </section>
      <hr><br>

    </form>


    <hgroup class='x-inline'>
      <!--====================================[hgroup.x-inline]-->
      <h1 class='h1'>CSSStyleSheet</h1>
      <h2 class='h2'>.insertRule()</h2>
    </hgroup>
    <article class='text-primary'>
      <blockquote class='blockquote'>
        <h3 id="Restrictions" class='h3'>Restrictions</h3>
        <p>CSS stylesheet rule-lists have a number of intuitive and not-so-intuitive <a class="external" href="https://drafts.csswg.org/cssom/#insert-a-css-rule">restrictions</a> affecting how and where rules can be inserted. Violating these will likely
          cause an error raised as a <a title="The DOMException interface represents an abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API." href="https://developer.mozilla.org/en-US/docs/Web/API/DOMException"><code>DOMException</code></a>          </p>

        <!--==========================[ul.x-list | li.x-fade]-->
        <ul id='list' class='list-group-flush x-list'>
          <li class='list-group-item-text fade x-fade x-item'>If index &gt; number of rules in the stylesheet (the <a title="A CSSRuleList is an (indirect-modify only) array-like object containing an ordered collection of CSSRule objects." href="https://developer.mozilla.org/en-US/docs/Web/API/CSSRuleList"><code>CSSRuleList</code></a>.length),
            then aborts with IndexSizeError.</li>
          <li class='list-group-item-warning x-item'>If rule cannot be inserted at index 0 due to some CSS constraint, then aborts with HierarchyRequestError.</li>
          <li class='list-group-item-danger x-item'>If more than one rule is given in the rule parameter, then aborts with SyntaxError</li>
          <li class='list-group-item-text x-fade x-item'>If trying to insert an @import at-rule after a style rule, then aborts with HierarchyRequestError.</li>
          <li class='list-group-item-text x-fade x-item'>If rule is @namespace at-rule and list has more than just @import at-rules and/or @namespace at-rules, then aborts with InvalidStateError.</li>
        </ul>
      </blockquote>
      <footer class='blockquote-footer'>

        <!--===============================[[cite.x-cite]-->
        <cite class='x-cite'><a href='https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule#Restrictions'>CSSStyleSheet.insertRule() - Wed APIs #Restrictions | MDN</a></cite> </footer>
    </article>
  </main>
  <script>
    var cnt = 0;
    var form = document.forms[0];
    var add = document.getElementById('add');

    function modRule(ID) {
      var e = window.event;
      var i = ID.id.split('').pop();
      console.log('ruleIndex: ' + i);

      var sheets = document.styleSheets;
      var sheet = document.getElementById('sht' + i);
      var rulez = document.getElementById('rul' + i);
      var index = document.getElementById('idx' + i);
      var vSht = parseInt(sheet.value, 10);
      var vIdx = parseInt(index.value, 10);
      var vRul = rulez.value;

      if (e.target.value === 'Delete Rule') {
        switch (vSht) {
          case 0:
            sheets[0].deleteRule(vIdx);
            break;
          case 1:
            sheets[1].deleteRule(vIdx);
            break;
          case 2:
            sheets[2].deleteRule(vIdx);
            break;
          default:
            sheets[0].deleteRule(vIdx);
            break;
        }

      } else if (e.target.value === 'Insert Rule') {
        switch (vSht) {
          case 0:
            sheets[0].insertRule(vRul, vIdx);
            break;
          case 1:
            sheets[1].insertRule(vRul, vIdx);
            break;
          case 2:
            sheets[2].insertRule(vRul, vIdx);
            break;
          default:
            sheets[0].insertRule(vRul, vIdx);
            break;
        }
      } else {
        return;
      }
    }

    add.addEventListener('click', addSet, false);

    function addSet(e) {
      cnt++;
      var set = document.querySelector('.set0');
      var opt = document.options
      var dupe = set.cloneNode(true);
      dupe.className = 'set' + cnt;
      var fields = Array.from(dupe.querySelectorAll('[id]'));
      var ids = fields.map(function(ID, idx) {
        var zero = ID.id.lastIndexOf("0");
        ID.id = ID.id.slice(0, zero);
        ID.id = ID.id + cnt;
        if (ID.id === 'rul' + cnt) {
          ID.textContent = 'p {color:red}';
        }
        console.log('id: ' + ID.id + ' val: ' + ID.value);
        return ID.value;
      });
      form.appendChild(dupe);
    }
  </script>
</body>

</html>


Update

If the stylesheet is big, wouldn't it be more efficient to dynamically create a new stylesheet for them?

Yes, but not an external <link> it's far more efficient and a ton more easier to dynamically manipulate a <style> block at the bottom of the </head>.

  • Not only is it simple, it's powerful since it's at the bottom of the cascade it'll override anything from an external <link>.
  • Also another thing to consider is that a HTTP request isn't needed unlike an external file which requires it and that' adds to your website's latency.

Demo 3 features 3 functions:

  1. injectCSS() will be called mere microseconds before it's counterpart injectJS() at window.onload. It will create a <style> block within the </head> along with whatever styles we want initially.
  2. injectJS() loads after injectCSS() because as a general rule style should always load before script. It will create a <script> tag and append it as the last child of the <body> tag specifically right before the closing </body> tag. Just like injectCSS() it may have anything within its tags that's script.
  3. inject() calls both injectCSS() and injectJS() asynchronously to ensure that the former will always load before the latter.

As far as this demo relates to the OP, injectCSS() is the function that we should concern ourselves with as was already explained previously.

Details are commented in the demo

For faster loading time, please review the PLUNKER instead.

Demo 3

<!DOCTYPE html>
<html>

<head>
  <style>
    html {
      font: 400 100%/1 Consolas;
    }
    
    html,
    body {
      height: 100%;
      width: 100%;
    }
    
    main {
      height: auto;
      width: 100%;
      padding: 10px;
    }
    
    section {
      height: auto;
      width: 100%;
      padding: 10px
    }
    
    fieldset {
      min-width: 70%;
      margin: 20px 0;
      padding: 10px;
    }
    
    var {
      background: rgba(0, 0, 0, .7);
      color: lime;
    }
  </style>
</head>

<body>


  <h1></h1>

  <main>
    <p><var>injectCSS =</var> All paragraphs will be red</p>
    <section>
      <form id='test0'>
        <fieldset>
          <legend>Test Log</legend>
          <label for='msg0'>injectCSS()...:&nbsp;
 <output id='msg0'></output></label>
          <br>
          <label for='msg1'>injectJS()....:&nbsp;
 <output id='msg1'></output></label>
        </fieldset>
      </form>
    </section>
    <section>

    </section>

  </main>
  <footer>
    <p>Review this page with Firebug/DevTools and we'll see an extra &lt;style&gt; tag in the &lt;head&gt; and we'll see an extra &lt;script&gt; tag right before the closing &lt;\body&gt; tag.</p>
  </footer>


  <script>
    // HTMLFormControlsCollection★
    var x0 = document.forms[0].elements;
    var m0 = x0.msg0;
    var m1 = x0.msg1;

    // Input strings of styles and scripts that are to be injected
    var css = "p {color:red}";
    var js = "document.querySelector('h1').innerHTML = '<var>injectJS =</var> H1 HTML'";

    /* This function manages injectCSS() and injectJS() functions by using
    || the async/await★ keywords. Times are provided by 
    || performance.now()★ method.
    */ //* ✎  Delete/add the first * to disable/enable this version of inject().
    // The proceeding edit ✎  must be done as well.
    var inject = async function() {
      var wait0 = injectCSS.call(this, css);
      var wait1 = injectJS.call(this, js);
      m0.value = performance.now();
      var init1 = await wait1;
      m1.value = performance.now()
      return false;
    };
    /*/// ✎ Delete/add the first / to enable/disable this version of inject().
  // The previous edit ✎  must be done as well.
  
  var inject = function() {
    injectCSS.call(this, css);
     m0.value = performance.now();
    injectJS.call(this, js); 
    m1.value = performance.now()
    return false;
  };
  
  /* These 2 functions do the same thing but with different content.
  || They could be refactored into one function but I made them
  || separately to show injectCSS() sepatately for QA SO46985099. 
  || Both creates a tag, then writes the code in it, and then appends
  || it to DOM.
  */
    function injectCSS(style) {
      var sty = document.createElement("style");
      sty.innerHTML = style;
      document.querySelector('head').appendChild(sty);
    }

    function injectJS(script) {
      var scr = document.createElement("script");
      scr.innerHTML = script;
      document.body.appendChild(scr);
    }

    /* The main function inject() is called at window.load. This is the last
    || loading event possible in which we are able call our function. This
    || ensures that specific CSS is loaded before specific JS is called. 
    || This is the last step in the loading process, therefore there should be
    || no more styles to render or script that blocks.
    */
    window.onload = inject;
  </script>
</body>

</html>


Demo Outline

  • Collects all <link> and <style> into a styleSheetList using document.stylesheets
  • Converts it into an array called sheetArray with Array.from()
  • The target is the 3rd <link> which is sheetArray[2]
  • Then there are 2 rules inserted at index 0 and index 1 successfully.
  • This is done through a for loop and arrays as the dynamic parameters and interpolation of Template Literals.

This demo does not function on SO, go to PLUNKER for a functioning demo.

Note: In the demo content is an excerpt from MDN that defines the restrictions of insertRule(). The highlighted items may apply to your specific errors.

Demo 1 - index.html [Review PLUNKER for a working demo]

<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8'>
  <link href='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css' rel='stylesheet'>
  <link href="style.css" rel="stylesheet">
  <link href='cssom.css' rel="stylesheet">
</head>

<body>
  <main class='container'>
    <hgroup class='x-inline'>
      <!--====================================[hgroup.x-inline]-->
      <h1 class='h1'>CSSStyleSheet</h1>
      <h2 class='h2'>.insertRule()</h2>
    </hgroup>
    <article class='text-primary'>
      <blockquote class='blockquote'>
        <h3 id="Restrictions" class='h3'>Restrictions</h3>
        <p>CSS stylesheet rule-lists have a number of intuitive and not-so-intuitive <a class="external" href="https://drafts.csswg.org/cssom/#insert-a-css-rule">restrictions</a> affecting how and where rules can be inserted. Violating these will likely
          cause an error raised as a <a title="The DOMException interface represents an abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API." href="https://developer.mozilla.org/en-US/docs/Web/API/DOMException"><code>DOMException</code></a>          </p>

        <!--==========================[ul.x-list | li.x-fade]-->
        <ul class='list-group-flush x-list'>
          <li class='list-group-item-text x-fade'>If index &gt; number of rules in the stylesheet (the <a title="A CSSRuleList is an (indirect-modify only) array-like object containing an ordered collection of CSSRule objects." href="https://developer.mozilla.org/en-US/docs/Web/API/CSSRuleList"><code>CSSRuleList</code></a>.length),
            then aborts with IndexSizeError.</li>
          <li class='list-group-item-warning'>If rule cannot be inserted at index 0 due to some CSS constraint, then aborts with HierarchyRequestError.</li>
          <li class='list-group-item-danger'>If more than one rule is given in the rule parameter, then aborts with SyntaxError</li>
          <li class='list-group-item-text x-fade'>If trying to insert an @import at-rule after a style rule, then aborts with HierarchyRequestError.</li>
          <li class='list-group-item-text x-fade'>If rule is @namespace at-rule and list has more than just @import at-rules and/or @namespace at-rules, then aborts with InvalidStateError.</li>
        </ul>
      </blockquote>
      <footer class='blockquote-footer'>

        <!--===============================[[cite.x-cite]-->
        <cite class='x-cite'><a href='https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule#Restrictions'>CSSStyleSheet.insertRule() - Wed APIs #Restrictions | MDN</a></cite> </footer>
    </article>
  </main>
  <script>
    var sheets = document.styleSheets;
    var sheetArray = Array.from(sheets);
    var sel = ['ul.x-list', 'li::before'];
    var dec = [`margin-left: 0; padding-left: 1em; text-indent: -1em;`, `content: '';`];
    var idx = [0, 1];
    var qty = idx.length;
    
    for (let r = 0; r < qty; r++) {
      sheetArray[2].insertRule(`${sel[r]} {${dec[r]}}`, idx[r]);
    }
  </script>
</body>

</html>

Deno 2 - cssom.css

/*0*/
hgroup.x-inline {display:flex; justify-content:center; align-items: center;}
/*1*/
ul.x-list.x-list {list-style: none;}
/*2*/
li.x-fade.x-fade {color:rgba(0,0,0,.3);}
/*3*/
cite.x-cite.x-cite {position:relative; left:60%}
/*4*/
cite.x-cite.x-cite::before {content:"\2014 \00A0"}
/*5*/
.blockquote-footer::before {content: '';}
/*6*/
li.list-group-item {line-height:1.5}
/*7*/
a {text-shadow: 2px 5px 3px rgba(192,192,192,.8)}
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • I may miss something, but how does this solves the issue? Iterating through styleSheets as an array makes the magic? Can you repro OP's issue? – Kaiido Oct 31 '17 at 08:32
  • Nice demo, thanks! However, I need the selector & declaration property values to be dynamic. I see from the linked article, it's possible, but I would still have to get them somehow. Also, if I've understood it correctly, you've created an array from an existing stylesheet, in order to add new items to it. If the stylesheet is big, wouldn't it be more efficient to dynamically create a new stylesheet for them? Given the spec (good call btw!), wouldn't it be easier to just split my 1 insertion into 2? It does work, but again, not with an index of < 1. Or have I misunderstood the spec? – Meanderling Oct 31 '17 at 16:16
  • The most efficient and fastest IMO is to dynamically embed a ` – zer00ne Oct 31 '17 at 17:11
  • [Cont.]...your files locally? Not sure why you can't get index 0. I'm pretty sure you've noticed during your research that 90% of the solutions involve iteration because something about modification is only indirect (cssRules is an object that can be used with `CSSStyleSheets` but not `CSSRuleList` which would be a much more intuitive choice. Anyways, I got my index accessible by using an array of `[0,1]` to iterate through. I got mixed results using more common direct ways like a simple variable or interpolation, or regex replacement. I'll update my answer with a ` – zer00ne Oct 31 '17 at 17:24
  • I tried the form, but it didn't do anything & I didn't see any new js, so couldn't see what it was supposed to do. By style injection, do you mean like [this](https://stackoverflow.com/a/524721/3160443)? Is there a reason not to split the rule? It's going to an existing sheet, so no additional request (unless it requests when inserting) & it seems to work (locally anyway). Or getElementById & add them inline? Sorry for all the questions, I've only been learning js a week, so it's all new to me & I'd rather learn good habits than bad. I'm using Chrome (latest), files are local/using WAMP. – Meanderling Oct 31 '17 at 22:15
  • Great demo! That pretty much covers inserting style rules and I can see it being really helpful to a lot of people - thank you! I would still need to figure out how to iterate the itemsArray to get the IDs, declarations and values formatted correctly, so that they make up 'var css' or a series of vars. Are there any restrictions, ie 1 rule per variable, can it be an object array separated by commas, etc? There's a lot to get my head around, so I will dissect & play tomorrow. In the meantime, thank you so much for your help, it's all good learning & much appreciated. – Meanderling Nov 01 '17 at 00:17
  • OK, Update 2 is ready to review, this is a form the `insertRule()` and `deleteRule()` index 0 is accessible on the `rulesList`. – zer00ne Nov 02 '17 at 12:55
  • Hi @Kaiido, initially, I was treating `document.styleSheets` as an array-like object but it was an object that even when converted to a real array, references were always lost inexplicably. Any attempts to iterate a counter variable through the bracket notation would fail as well. I managed to cover 3 stylesheets by placing each iteration in a switch instead. – zer00ne Nov 02 '17 at 13:16