13

So basically I have a page that has it's own CSS. On my server I have a folder of different CSS style files, so I want to have a "preview" window on my page for them. Can I somehow, maybe using javascript, apply an external CSS file only to a certain DIV, not to the entire page so I can get a "preview" of the custom CSS file? I'd rather not use iframes.

Martin Marinov
  • 1,167
  • 3
  • 15
  • 25

4 Answers4

11

Like Quentin said, you can use descendent selector to limit the scope. Something like less can help a lot. For example, I would like to have "bootstrap.css" applies only to #MyDiv, in "my.less":

#MyDiv {
  @import "bootstrap.less";
}

"bootstrap.css" should be renamed (or linked) to "bootstrap.less". Run:

lessc my.less my.css

would add #MyDiv to every selectors in the imported file.

Arthur Yip
  • 121
  • 1
  • 3
  • 3
    Can we do this using javascript? – Jayantha Lal Sirisena Jul 30 '13 at 09:26
  • @Jayanta you can use less.js to do this which means the render process is done in client side. It is not recommended on production usage though. See here for details http://lesscss.org/#client-side-usage. – SubRed Apr 29 '15 at 09:22
  • shouldn't the @import rule always precede all other types of rules? – Jascha Goltermann Aug 02 '15 at 15:52
  • this is exactly what I needed. I only wanted to apply the bootstrap classes to a specific div and this worked perfectly. – jtate Dec 16 '15 at 16:20
  • Is there a way to do this for selectors in the imported file that have commas? The CSS you have would only take `.classA, .classB` and turn it into `#MyDiv .classA, .classB` – Adam Konieska Jan 06 '16 at 22:51
8

For one of my projects, I needed exactly the same thing, but to be also supported in CSS version 2.
After a long search all over the web, I didn't found anything useful, so I decided to created this functionality using JavaScript that can actually able to apply a whole css to a specific Element in DOM.

Just call the function applyCSSFileToElement, as described below (depended on jQuery library):

function renderCSSForSelector(css, selector) {
    return ((css+"")||"").replace(/\n|\t/g, " ")
      .replace(/\s+/g, " ")
      .replace(/\s*\/\*.*?\*\/\s*/g, " ")
      .replace(/(^|\})(.*?)(\{)/g, function($0, $1, $2, $3) {
        var collector = [], parts = $2.split(",");
        for (var i in parts) {
            collector.push(selector + " " + parts[i].replace(/^\s*|\s*$/, ""));
        }
        return $1 + " " + collector.join(", ") + " " + $3;
    });
}

function applyCSSToElement(css, elementSelector) {
    $("head").append("<style type=\"text/css\">" + renderCSSForSelector(css, elementSelector) + "</style>");
}

function applyCSSFileToElement(cssUrl, elementSelector, callbackSuccess, callbackError) {
    callbackSuccess = callbackSuccess || function(){};
    callbackError = callbackError || function(){};
    $.ajax({
        url: cssUrl,
        dataType: "text/css",
        success: function(data) {
            applyCSSToElement(data, elementSelector);
            callbackSuccess();
        },
        error: function(jqXHR) {
            callbackError();
        }
    })
}

Functions explanations:

  • renderCSSForSelector - Actually prepends a selector for each style definition.
  • applyCSSToElement - Takes the CSS source data, applies renderCSSForSelector and injects it into the HEAD tag.
  • applyCSSFileToElement - Applies a CSS file (cssUrl) into a specific area (elementSelector) in DOM. The callbackSuccess is called when the file is loaded successfully and the CSS has been applied. The callbackError is called when there is an error loading the CSS file.

Good luck!

Slavik Meltser
  • 9,712
  • 3
  • 47
  • 48
8

CSS applies to entire documents.

If you want to limit the scope, then you need to make use of a descendent selector.

e.g. #id_of_div .the .rest .of .the .selector {}

You have to apply this to every selector, and take into account groups (so it isn't as simple as just prefixing the whole stylesheet and suffixing every })

You would also find the stylesheet for the main document applying to your preview.

A frame would probably be the best approach to solving this problem.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
2

You could use an iframe to load the preview page or dynamically load the CSS into the page. But, if you want the styles to only by applied to the div, you have to prefix your CSS selectors with the id of the div. #div-id #element-inside-div { }.

The script for loading it in might look something like this:

var cssFile = document.createElement( "link" );
cssFile.rel = "stylesheet";
cssFile.type = "text/css";
cssFIle.href = "file.css";
document.getElementsByTagName( "head" )[0].appendChild( cssFile );
Will
  • 19,661
  • 7
  • 47
  • 48