Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add prefix to css rules with javascript

I have a string with the following css that I need to process with javascript

h1
{
    color: red;
}

.info
{
    border: 1px dotted blue;
    padding: 10px;
}

#rect
{
    background: pink;
}

h2,
h3,
h4
{
    font-weight: bold;
}

table td:last td
{
    background: gainsboro;
}

How can I add the prefix .page to each rule so the css doesn't break?

I want this result

.page h1
{
    color: red;
}

.page .info
{
    border: 1px dotted blue;
    padding: 10px;
}

...

Right now, I solve it with looking for the indentation, but the code fails on this case

h1
{
color: red;
}

Which then ends up with

.page h1
{
.page color: red;
}

I could also look for rows that only has brackets, but then this case would fail

h1 { color: red; }

I don't want to build my own css parser and the ones I found mostly handles css applied to elements in the DOM and not strings with css. Is there a good parser or can this be achieved otherwise?

like image 774
Adrian Rosca Avatar asked Oct 20 '15 11:10

Adrian Rosca


People also ask

What is prefix in CSS?

The prefix descriptor of the @counter-style rule specifies content that will be prepended to the marker representation. If not specified, the default value will be "" (an empty string).

What is WebKit prefix in CSS?

CSS prefixes -webkit- (Chrome, Safari, newer versions of Opera and Edge, almost all iOS browsers including Firefox for iOS; basically, any WebKit or Chromium-based browser) -moz- (Firefox) -o- (old pre-WebKit versions of Opera) -ms- (Internet Explorer and Microsoft Edge, before Chromium)

How do you target a class in CSS?

To select elements with a specific class, write a period (.) character, followed by the name of the class. You can also specify that only specific HTML elements should be affected by a class. To do this, start with the element name, then write the period (.)

What is automatic vendor prefixing?

CSS vendor prefixes allow the makers of web browsers to add support for the latest CSS features, for experimentation or a testing period. So they allow you to run all your CSS rules across all browsers.


1 Answers

Here is a function to prefix all selectors with a class name. This function properly handle the @ rules:

var prefixCssSelectors = function(rules, className) {
  var classLen = className.length,
    char, nextChar, isAt, isIn;

  // makes sure the className will not concatenate the selector
  className += ' ';

  // removes comments
  rules = rules.replace( /\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g, '' );

  // makes sure nextChar will not target a space
  rules = rules.replace( /}(\s*)@/g, '}@' );
  rules = rules.replace( /}(\s*)}/g, '}}' );

  for (var i = 0; i < rules.length-2; i++) {
    char = rules[i];
    nextChar = rules[i+1];

    if (char === '@' && nextChar !== 'f') isAt = true;
    if (!isAt && char === '{') isIn = true;
    if (isIn && char === '}') isIn = false;

    if (
      !isIn &&
      nextChar !== '@' &&
      nextChar !== '}' &&
      (
        char === '}' ||
        char === ',' ||
        ((char === '{' || char === ';') && isAt)
      )
    ) {
      rules = rules.slice(0, i+1) + className + rules.slice(i+1);
      i += classLen;
      isAt = false;
    }
  };

  // prefix the first select if it is not `@media` and if it is not yet prefixed
  if (rules.indexOf(className) !== 0 && rules.indexOf('@') !== 0) rules = className+rules;

  return rules;
}


// Some examples:
console.log(prefixCssSelectors('div { width: 100%; }', '.page'));

console.log(prefixCssSelectors('@charset "utf-8"; div { width: 100%; }', '.page'));

console.log(prefixCssSelectors('@media only screen { div { width: 100%; } p { size: 1.2rem; } } @media only print { p { size: 1.2rem; } } div { height: 100%; font-family: "Arial", Times; }', '.page'));

console.log(prefixCssSelectors('@font-face { font-family: "Open Sans"; src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"); } div { width: 100%; }', '.page'));

If you only want to have the class name for the html and body selectors, add this:

rules = rules.replace(/( html| body)/g, '');
like image 53
Nicolas BADIA Avatar answered Sep 25 '22 01:09

Nicolas BADIA