Blog

Rewriting CSS using Javascript

I've been working on an HTML5 webapp project and the directory structure is set up like this:

/app
  webapp.html
  /img
  /js
  /css
/design
  test.html

The app has a build process that lints, compresses, and inlines the Javascript and CSS (compiled scss files) into webapp.html, which means that all of the background-image:url() attributes need to use URLs that are relative to the app directory. I can't use full URLs because the domain can be either dev.domain.com, test.domain.com, or www.domain.com depending on the which server it's deployed to.

To speed up development I create static HTML files in the /design directory that link to the CSS and Javascript files in the /app directory. This makes it much faster to code and test since all it takes is a page refresh on my local MAMP server to run the new code.

The design page includes the css file:

<link type="text/css" media="screen" rel="stylesheet" href="../app/css/appstyle.css">

…which include rules like this:

background-image: url(img/graphic.svg);

The problem being that the url is relative to the css file. Since the css is inlined in the webapp, the relative link to the img directory works fine. When using the source CSS file it's looking for /app/css/img/graphic.svg

My solution was to write some Javascript for the test files that located and rewrote the offending rules. Changing url(img/ to url(../img/ did the trick.

$(document).ready(function () {
  var sheets = document.styleSheets;
  const regexSheet = /appstyle.css/;  // Locate the stylesheet to modify
  const regexUrl = /url\("img\//;     // Match relative url links
  for (let i = 0; i < sheets.length; i++) {
  if (regexSheet.test(sheets[i].href)) {
    // We've got our target stylesheet, now loop through the rules
    for (let j = 0; j < sheets[i].rules.length; j++) {
      if (typeof sheets[i].rules[j].style !== 'undefined') {
        // This rule has styles
        let rule = sheets[i].rules[j].style;
        if (typeof rule.backgroundImage !== 'undefined' 
            && regexUrl.test(rule.backgroundImage)) {
          let newUrl = rule.backgroundImage.replace(/"img\//, '"../img/');
          sheets[i].rules[j].style.backgroundImage = newUrl;
        }
      }
    }
  }
}

Other than some error messages in console for the images that were not found before the code executed, it works perfectly and I can add image links at will now.

RSS Feed