使用jQuery或RegEx获取样式表中编写的CSS值

Bra*_*roy 7 css regex jquery css3

我在看CSS3 calc(),我想知道是否可以使用jQuery(或RegEx)从输入字符串中减去一个值.

例如:

div {
  width: calc(100% - 50px);
}
Run Code Online (Sandbox Code Playgroud)

我想要得到的百分比值(100%)和像素值(50px),我需要知道它是什么,然后(px,em,pt,%).

所以基本上:

  • 后得到的值calc(和前一个分隔符(+,-,*,/)
  • 在分离器之后和之前得到一个值 )
  • 请注意,可能会有比一个更多的值! calc(100% - 20px - 0.8em)

编辑: Spudley谈论解析整个CSS样式表,但这可能会导致开销.因为这个项目为它赫克,开销允许的,所以你可以去失控,做任何你想做到这一点!

谢谢.

Onu*_*rım 5

你不应该在真实的应用程序中真正做到甚至需要它,但是因为你说这只是为了好玩; 这是有趣的部分:

是的,你可以做到.通过AJAX调用加载CSS文件不是唯一的方法,但它可能是使其真正跨浏览器的唯一(但效率低下)方式.即便是下面的声明不会使它真正的跨浏览器的,因为calc()功能并非所有人都支持的浏览器,这是一个CSS3功能.

编辑:截至2018年,calc所有现代浏览器都支持.

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

可以从中获取原始CSS代码document.styleSheets及其规则.cssText规则的属性将为您提供完整的声明.但是不同的浏览器可能会以不同的方式解析值calc().

我将使用更复杂的示例来了解浏览器如何处理该calc()函数:

calc(100% - -50px*6 + 4em/2);
Run Code Online (Sandbox Code Playgroud)

这就是Firefox(第18版)对待它的方式:

Firefox中的calc()函数

这就是谷歌Chrome(第24集)对待它的方式:

chrome中的calc()函数

如图所示; FF calc按原样获取非前缀值,Chrome获取-webkit前缀值,并使用嵌套括号(如果需要)重新解析它.如果你没有在Chrome中声明它-webkit; 它会完全忽略这个价值.因此,我们应该在操作calc语句时考虑这些因素.

现在,使用复杂的例子; 我们将首先在calc()函数中获取语句:

"100% - -50px*6 + 4em/2"
Run Code Online (Sandbox Code Playgroud)

然后将语句元素解析为数组:

["100%", "-", "-50px", "*", "6", "+", "4em", "/", "2"]
Run Code Online (Sandbox Code Playgroud)

最后,处理数组项的值和单位,使它们以编程方式可用(如您所愿):

[{ value:100, unit:"%" }, "-", { value:-50, unit:"px" }, "*", { value:6, unit:undefined }, "+", { value:4, unit:"em" }, "/", { value:2, unit:undefined }]
Run Code Online (Sandbox Code Playgroud)

上面的最终结果包括值对象和运算符(按顺序).

在进一步阅读之前 请注意,以下代码未在所有浏览器和情境中完全测试.它不处理嵌套的括号解析(如Chrome所做的)或具有多个或组合calc()函数的值.如果你想测试这个; 我推荐Firefox,因为它不解析嵌套的括号,或者你可以扩展代码以支持它们.

// 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);
Run Code Online (Sandbox Code Playgroud)
/** 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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
/** 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's 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; }
Run Code Online (Sandbox Code Playgroud)

而已.正如我所提到的,我不会这样做,但是如果有可能的话,总是很好.

注意:既然你提到制作一个jQuery插件(为了好玩); 你真的不需要jQuery.调用函数$('div').css('width')只会给你计算值,而不是原始calc语句.