7

CSS3 calc()を見ていましたが、jQuery (または RegEx) を使用して入力文字列から値を減算できるかどうか疑問に思いました。

例えば:

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

100%パーセント値 ( ) とピクセル値 ( )を取得したいのですが、その後ろに ( 、、、 )50pxが続くものを知る必要があります。pxempt%

だから基本的に:

  • calc(セパレータの前後の値を取得する( +, -, *, /)
  • 区切り記号の後と前の値を取得します)
  • 複数の値が存在する可能性があることに注意してください!calc(100% - 20px - 0.8em)

編集: Spudley は CSS スタイルシート全体を解析することについて話していますが、これはオーバーヘッドを引き起こす可能性があります。これは一体のプロジェクトであるため、オーバーヘッドが許可されているため、これを達成するためにやりたいことは何でもできます。

ありがとう。

4

3 に答える 3

5

実際のアプリケーションではこれを実際に行うべきではなく、必要とするべきでもありませんが、これは単なる楽しみであると言っているので。ここに楽しい部分があります:

はい、できます。AJAX呼び出しを介してCSSファイルをロードすることが唯一の方法ではありませんが、それを実際にクロスブラウザーにする唯一の(しかし非効率的な)方法である可能性があります。関数はすべてのブラウザーでサポートされているわけではなく、CSS3の機能であるため、以下の宣言でさえ、真のクロスブラウザーにはなりません。calc()

編集: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);
}

とそのルールから生のCSSコードを取得できます。ルールdocument.styleSheetsのプロパティはあなたに完全なステートメントを与えます。ただし、ブラウザが異なれば、関数cssTextを使用した値の解析も異なる場合があります。calc()

calc()より複雑な例を使用して、ブラウザーが関数をどのように処理するかを確認します。

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

Firefox(v.18)はこれを次のように扱います。

Firefoxのcalc()関数

そして、これはGoogle Chrome(v.24)がそれをどのように扱うかです:

Chromeのcalc()関数

示されているように; FFはプレフィックスなしのcalc値をそのまま取得し、Chromeは-webkitプレフィックス付きの値を取得して、ネストされた括弧で再解析します(必要な場合)。Chromeで-webkitと宣言しない場合。値を完全に無視します。したがって、calcステートメントを操作するときは、これらを考慮に入れる必要があります。

ここで、複雑な例を使用します。まず、calc()関数内のステートメントを取得します。

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

次に、ステートメントの要素を配列に分解します。

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

最後に、配列アイテムの値と単位を処理して、プログラムで使用できるようにします(必要に応じて)。

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

上記の最終結果には、値オブジェクトと演算子が(順番に)含まれています。

さらに読む前に; 以下のコードは、すべてのブラウザと状況で完全にテストされているわけではないことに注意してください。ネストされた括弧の解析(Chromeのように)や、複数または組み合わせたcalc()関数を持つ値は処理しません。これをテストしたい場合; Firefoxはネストされた括弧を解析しないため、またはコードを拡張してそれらのサポートを有効にすることができるため、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);
/** 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'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; }

それでおしまい。私が言ったように、私はこれをしませんが、何かが可能かどうかを知ることは常に良いことです。

:jQueryプラグインの作成について言及したので(楽しみのために)。このためにjQueryは実際には必要ありません。また、のような関数を呼び出すと$('div').css('width')、計算された値のみが提供され、生のcalcステートメントは提供されません。

于 2013-01-26T16:25:29.763 に答える
1

ここでの簡単な答えはノーです、あなたはそれをすることはできません。ブラウザAPIは生のCSSコードを提供しないため、要求していることを実行できません。

これを実現する唯一の方法は、スタイルシートファイルを手動で(つまり、Ajax呼び出しを介して)JavaScriptにロードし、それを解析することです。これはブラウザにとって大きなオーバーヘッドです

これは、特定のブラウザでは利用できないCSS機能を実装するために一部のポリフィルスクリプトで使用される手法です(たとえば、IEでのメディアクエリサポート用のこのスクリプトですが、実行中に値をチェックするだけの場合は、それよりも手間がかかりますこのような小さな質問の価値があります。

計算値を取得するためだけに、JSコードでCSSファイル全体を手動で解析する場合は、既存のポリフィルスクリプトの1つから解析コードを取得するのが最善の策です。しかし、私があなたの立場にあった場合、このアイデアを論理的な結論に強制しようとするのではなく、根本的な問題に対する代替の解決策を見つけるでしょう。

根本的な問題は、質問が本当に頭に浮かぶ必要があるということだと思います。固定値のCSSがあるのはなぜですか。calcコードでそれらの値がわからない場合はどうでしょうか。の要点は、既知の値の組み合わせを指定できるようにすることです。これは、ユーザーが入力した不明な値ではありません(または、少なくともそうすべきではありません)。それでは、なぜJavascriptが値をまだ認識していないのでしょうか。100%50pxcalc

JSとCSSコードの間に断絶がある場合は、ブラウザーよりもチェーンの上位でそれを処理する方法を検討する必要があります。calcこれは、Javascriptを使用して値を取得できたとしても、ブラウザーが意味するためです。毎回同じ値の場合、ページの読み込みごとに同じ一連の処理を繰り返し実行する必要があります。それは多くの無駄な努力です。

于 2013-01-20T11:36:51.070 に答える
0

ネストされた括弧が内部で使用されておらずcalc(...)、css全体に対して正規表現のマッチングを行うオーバーヘッドが許容できると仮定すると、次のコード

  1. jQuery.get()を使用してCSSをロードします。
  2. 何かを検索します : calc(...);(少し汚れていますが、おそらく十分です)、
  3. 中括弧の間のすべてを抽出し、
  4. 演算子と周囲の空白を削除し、
  5. 単位を含む各オペランドに警告します。

あなたは確かにあなたのニーズに応じていくつかの調整をしなければなりませんが、これは基本的にあなたが望んでいたことだと思います:

$(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]);
            }
        }
    });
});
于 2013-01-21T19:37:14.253 に答える