Get CSS value written in stylesheet using jQuery or RegEx

I was looking at CSS3 calc () and I was wondering if it is possible to subtract the value from the input string using jQuery (or RegEx).

For instance:

div { width: calc(100% - 50px); } 

I want to get the percentage value ( 100% ) and the pixel value ( 50px ), and I need to know what it is followed by ( px , em , pt , % ).

So basically:

  • get the value after calc( and before the delimiter ( + , - , * , / )
  • get the value after the separator and before )
  • note that there may be more values ​​than one !, for example. calc(100% - 20px - 0.8em)

EDIT: Spudley talks about parsing the entire CSS stylesheet, but this can cause overhead. Since this project is for this, overhead is allowed , so you can go haywire and do whatever you want to achieve!

Thanks.

+6
source share
3 answers

You should not really do or even need it in a real application, but since you say it is just for fun; here is the interesting part:

Yes you can do it. Loading a CSS file using AJAX calls is not the only way, but it may be the only (but inefficient) way to make it truly cross-browser. Even the declaration below will not make it truly a cross browser, since the calc() function is not supported by everyone , and it is a CSS3 function.

 div { width: 300px; /* a fallback value for old browsers */ width: -webkit-calc(100% - 50px); width: -moz-calc(100% - 50px); width: calc(100% - 50px); } 

You can get CSS source code from document.styleSheets and their rules. The cssText property of the rule will give you a full report. But different browsers can analyze values ​​using the calc() function in different ways.

I'll go with a more complex example to see how the browser handles the calc() function:

 calc(100% - -50px*6 + 4em/2); 

Here's how it relates to Firefox (v.18):

calc () function in Firefox

And this is how Google Chrome (v.24) accesses it:

calc () function in Chrome

As shown; FF gets the value without the calc prefix as it is, and Chrome takes the -webkit prefix value and -webkit it with nested brackets (if necessary). If you do not declare it -webkit in Chrome; he completely ignores the meaning. Therefore, we must take this into account when manipulating the calc statement.

Now, using a complex example; we first get the statement inside the calc () function:

 "100% - -50px*6 + 4em/2" 

Then disconnect the elements of the instruction into an array:

 ["100%", "-", "-50px", "*", "6", "+", "4em", "/", "2"] 

Finally, process the values ​​and units of the array elements to make them programmatically useful (as you wanted):

 [{ value:100, unit:"%" }, "-", { value:-50, unit:"px" }, "*", { value:6, unit:undefined }, "+", { value:4, unit:"em" }, "/", { value:2, unit:undefined }] 

The end result above includes value objects and operators (in order).

Before reading further; note that the code below is not fully tested in all browsers and situations. It does not handle the expansion of nested brackets (e.g. Chrome) or values ​​with multiple or combined calc () functions. If you want to check it out; I recommend Firefox because it does not parse nested parentheses, or you can extend the code to include support for them.

 // Get the sheet you want to process. (assume we want to process the third sheet): var sheet = document.styleSheets[2]; //you could also iterate all the sheets in a for loop processRules(sheet); 
 /** Iterates through the rules of the specified style sheet; * then dissolves and logs values including a calc() function. */ function processRules(sheet) { var rules = sheet.cssRules // Mozilla, Safari, Chrome, Opera || sheet.rules; // IE, Safari for (var i = 0; i < rules.length; i++) { var rule = rules[i]; // Check if we have a calc() function in this rule if (hasCalc(rule.cssText)) { // Get the calculation statement inside the calc() function. var statement = getCalcStatement(rule.cssText); // Dissolve the statement into its elements and log. console.log(dissolveCalcElements(statement)); } } } 
 /** Checks whether the CSS value includes a calc() function, * (This is also for avoiding unnecessary regex.) */ function hasCalc(value) { return value.toLowerCase().indexOf('calc(') >= 0; } /** Gets the full statement (string) inside a calc() function. */ function getCalcStatement(rule) { if (!rule) return ''; var pattern = /calc\(([^\)]+)\).*/; var match = pattern.exec(rule); return match && match.length > 1 ? match[1] : ''; } /** Splits the calc operation elements (values and operators) and * dissolves the values into objects with value and unit properties. */ function dissolveCalcElements(statement) { // The CSS calc() function supports 4 basic math operations only: // Addition (+), Subtraction (-), Multiplication (*), Division (/) // White-spaces are very important in a calc statement. // From Mozilla: "The + and - operators must always be surrounded by whitespace. // The * and / operators do not require whitespace, but adding it for consistency is allowed, and recommended." // We could use: statement.split(/(\s+[\+\-]\s+|\s*[\*\/]\s*)/); // to include the operators inside the output array, but not all browsers // support splicing the capturing parentheses into the array like that. So: statement = statement.replace('*', ' * ').replace('/', ' / '); var arr = statement.split(/\s+/); console.log("arr", arr); var calcElems = []; for (var i = 0; i < arr.length; i++) { var d = dissolveElement(arr[i]); calcElems.push(d); } return calcElems; } /** Dissolves the value and unit of the element and * returns either the operator or an object with "value" and "unit" properties. */ function dissolveElement(val) { // Check if the value is an operator. var ops = '+-*/'; if (ops.indexOf(val) >= 0) return val; var o = {}; // CSS units in a calc statement can have all the regular units. // According to W3C; they can also, can include a "vw" unit (stands for viewport). var pattern = /([\+\-]?[0-9\.]+)(%|px|pt|em|in|cm|mm|ex|pc|vw)?/; // Exec the value/unit pattern on the property value. var match = pattern.exec(val); // So we reset to the original value if there is no unit. if (match) { var v = match.length >= 2 ? match[1] : match[0]; o.value = toFloat(v); //parse value as float o.unit = match.length >= 3 ? match[2] : ''; } else { o = { value:val, unit:''}; } console.log("dissolve", match, val, o); return o; } // Helper Functions function toFloat(value) { return parseFloat(value) || 0.0; } 

What is it. As I said, I wouldn’t do this, but it’s always good to know if anything is possible.

Note Since you mentioned creating the jQuery plugin (for fun); you don't need jQuery for this. And calling functions like $('div').css('width') will only give the computed value, not the raw calc expression.

+4
source

The short simple answer is no, you cannot do this. The browser API will not give you raw CSS, so you cannot do what you ask.

How you will achieve this is to load the stylesheet manually into your javascript (i.e. via an Ajax call) and analyze it. This is a lot of overhead for the browser.

This is the method used by some polyfill scripts to implement CSS functions that are not available in some browsers (for example, this script for media processes in IE , but to just check the values ​​as you do, I would say that this is more effort than this stands for a smaller question like this.

If you want to splash and parse the entire CSS file manually in your JS code just for the sake of extracting calc values, then the best option would be to add parsing code from one of the existing polyfill scripts. But if I were in your place, I would find an alternative solution to the main problem, rather than trying to bring this idea to its logical conclusion.

I assume that the main problem is that the question should actually be asked: why do you have CSS calc with fixed values ​​of 100% and 50px if you do not know in the code what these values ​​will be? The whole point of calc is that you can specify a combination of known values. This is not some unknown value entered by the user (or at least it should not be), since your Javascript no longer knows the value?

If there is a gap between your JS and your CSS code, you should consider how to work with it higher than in the browser, because even if you manage to get the values ​​from calc using Javascript, this means that the browser will have to do the same set of processing over and over each time the page is loaded, for values ​​that will be the same every time. This is a lot of effort.

+1
source

Assuming no parentheses are used in calc(...) and it is assumed that the overhead of doing some regular expression matching throughout css is acceptable, the following code

  • loads your css using jQuery.get () ,
  • looking for any : calc(...); (a little dirty, but probably enough)
  • extracts something between braces,
  • removes any operators and surrounding spaces,
  • warns each operand, including its block.

You should probably make a few tweaks to suit your needs, but I think this is basically what you wanted:

 $(document).ready(function() { $.get("your.css", function(data) { var re1 = /: calc\((.*)\);/g; var re2 = /\s*[\-\+\/\*]\s*/; while (match = re1.exec(data)) { var arr = match[1].split(re2); for (i in arr) { alert(arr[i]); } } }); }); 
0
source

All Articles