Подтвердить что ты не робот

Проверьте, имеет ли свойство css важный атрибут

Если у меня такой стиль -

​div#testdiv {position:absolute;top:10px !important;}​

Я могу запросить значение top с помощью jQuery следующим образом:

$("#testdiv").css("top");

который вернет значение 10px. Можно ли использовать jQuery или JavaScript, чтобы проверить, имеет ли свойство top атрибут !important к нему?

4b9b3361

Ответ 1

Прежде всего, такое решение, похоже, не существует в jQuery.

Доступно множество доступных javascript-решений, используйте функцию getPropertyPriority(). Во-первых, эта функция не поддерживается IE6-IE8 (см. здесь и здесь). Во-вторых, эта функция не работает непосредственно над элементами, если их стиль не объявлен встроенным. Таким образом, мы могли бы получить важное свойство в следующем случае:

<div id="testdiv" style="top : 10px !important;">Some div</div>
<script type="text/javascript">
// should show 'important' in the console.
console.log(document.getElementById("testdiv").style.getPropertyPriority('top'));
</script>

Однако, если мы можем объявить стиль #testdiv в таблице стилей css, мы получим пустую строку. Кроме того, интерфейс CSSStyleDeclaration недоступен в IE6-8. Конечно, это бесполезно. Нам нужен другой подход.

Я применил этот подход в JSFiddle. Мы можем прочитать важное свойство непосредственно из таблиц стилей css, которые содержатся в массиве document.styleSheets[]. (Opera 8 и ниже не поддерживают этот массив). В Quirksmode вы можете увидеть методы, поддерживаемые для доступа к таблицам стилей. На основании этой информации мы можем сделать следующее:

  • Для IE6-8 мы используем styleSheets[].imports для доступа к импортированным таблицам стилей (и продолжаем делать это рекурсивно, пока мы больше не найдем никаких операторов импорта), а затем styleSheets[].rules в основном для каждой таблицы стилей добавьте правила css в массив.
  • Для других браузеров мы используем styleSheets[].cssRules для доступа как к импортированным, так и к CSS-правилам. Мы определяем правила импорта, проверяя, реализует ли он интерфейс CSSImportRule и используют их для рекурсивного доступа к правилам CSS в импортированных таблицах стилей.

В обоих случаях мы добавляем правила css в массив только в том случае, если правила соответствуют элементу HTMLElement (в вашем случае #testdiv). Это приводит к массиву правил CSS, которые соответствуют HTMLElement. Это в основном то, что делает функция getMatchedCSSRules() в браузерах webkit. Однако мы пишем его здесь.

На основе этой информации мы пишем нашу функцию hasImportant(htmlNode, property), где htmlNode - это HTMLElement (ваш testdiv) и свойство css ( "верхний" в вашем случае). Во-первых, мы проверяем, имеет ли встроенный стиль верхнего свойства важный атрибут. Это экономит нас, просматривая таблицы стилей, если он содержит этот атрибут.

Напишем новую функцию isImportant(node, property), которая использует нашу добрую старую функцию node.style.getPropertyPriority(property). Однако, как я уже упоминал ранее в этом ответе: эта функция не поддерживается в IE6-IE8. Мы можем сами написать эту функцию: в IE свойство node.style.cssText содержит текст блока объявления. Мы ищем свойство ('top') в этом блоке текста и проверяем, содержит ли его значение '! Important'. Мы можем повторно использовать эту функцию для каждого правила css, полученного с помощью функции getMatchedCSSRules, путем прокрутки всех правил css, которые соответствуют htmlNode и вызова функции isImportant.

Все вышеперечисленное можно найти в коде ниже. Это базовый подход и, вероятно, должен быть дополнительно отрегулирован:

  • некоторый код может быть заменен на jQuery
  • некоторый код может быть упрощен
  • css правила, реализующие интерфейс CSSMediaRule, и другие интерфейсы могут вызвать некоторые проблемы для этого кода и выполнить проверку ошибок
  • может быть более простой подход, но я не знаю другого способа получить этот рабочий кросс-браузер.

    var debug = true;
    
    /**
     * Get the css rules of a stylesheet which apply to the htmlNode. Meaning its class
     * its id and its tag.
     * @param CSSStyleSheet styleSheet
     * @param HTMLElement htmlNode
     */
    function getCssRules(styleSheet, htmlNode) {
        if ( !styleSheet )
            return null;
    
        var cssRules = new Array();
        if (styleSheet.cssRules) {
            var currentCssRules = styleSheet.cssRules;
            // Import statement are always at the top of the css file.
            for ( var i = 0; i < currentCssRules.length; i++ ) {
                // cssRules all contains the import statements.
                // check if the rule is an import rule.
                if ( isImportRule(currentCssRules[i]) ) {
                    // import the rules from the imported css file.
                    var importCssRules = getCssRules(currentCssRules[i].styleSheet, htmlNode);
                    if ( importCssRules != null ) {
                        // Add the rules from the import css file to the list of css rules.
                        cssRules = addToArray(cssRules, importCssRules, htmlNode);
                    }
                    // Remove the import css rule from the css rules.
                    styleSheet.deleteRule(i);
                }
                else {
                    // We found a rule that is not an CSSImportRule
                    break;
                }
            }
            // After adding the import rules (lower priority than those in the current stylesheet),
            // add the rules in the current stylesheet.
            cssRules = addToArray(cssRules, currentCssRules, htmlNode);
        }
        else if (styleSheet.rules) {
            // IE6-8
            // rules do not contain the import statements.
            var currentCssRules = styleSheet.rules;
    
            // Handle the imports in a styleSheet file.
            if ( styleSheet.imports ) {
                // IE6-8 use a seperate array which contains the imported css files.
                var imports = styleSheet.imports;
                for ( var i = 0; i < imports.length; i++ ) {
                    var importCssRules = getCssRules(imports[i], htmlNode);
                    if ( importCssRules != null ) {
                        // Add the rules from the import css file to the list of css rules.
                        cssRules = addToArray(cssRules, importCssRules, htmlNode);
                    }
                }
            }
            // After adding the import rules (lower priority than those in the current stylesheet),
            // add the rules in the current stylesheet.
            cssRules = addToArray(cssRules, currentCssRules, htmlNode);
        }
    
        return cssRules;
    }
    
    /**
     * Since a list of rules is returned, we cannot use concat. 
     * Just use old good push....
     * @param CSSRuleList cssRules
     * @param CSSRuleList cssRules
     * @param HTMLElement htmlNode
     */
    function addToArray(cssRules, newRules, htmlNode) {
        for ( var i = 0; i < newRules.length; i++ ) {
            if ( htmlNode != undefined && htmlNode != null && isMatchCssRule(htmlNode, newRules[i]) )
                cssRules.push(newRules[i]);
        }
        return cssRules;
    }
    
    /**
     * Matches a htmlNode to a cssRule. If it matches, return true.
     * @param HTMLElement htmlNode
     * @param CSSRule cssRule
     */
    function isMatchCssRule(htmlNode, cssRule) {
        // Simply use jQuery here to see if there cssRule matches the htmlNode...
        return $(htmlNode).is(cssRule.selectorText);
    }
    
    /**
     * Verifies if the cssRule implements the interface of type CSSImportRule.
     * @param CSSRule cssRule
     */
    function isImportRule(cssRule) {
        return cssRule.constructor.toString().search("CSSImportRule") != -1;
    }
    
    /**
     * Webkit browsers contain this function, but other browsers do not (yet).
     * Implement it ourselves...
     *
     * Finds all matching CSS rules for the htmlNode.
     * @param HTMLElement htmlNode
     */
    function getMatchedCSSRules(htmlNode) {
        var cssRules = new Array();
    
        // Opera 8- don't support styleSheets[] array.
        if ( !document.styleSheets )
            return null;
    
        // Loop through the stylesheets in the html document.
        for ( var i = 0; i < document.styleSheets.length; i++ ) {
            var currentCssRules = getCssRules(document.styleSheets[i], htmlNode)
            if ( currentCssRules != null )
                cssRules.push.apply(cssRules, currentCssRules);
        }
    
        return cssRules;
    }
    
    /**
     * Checks if the CSSStyleRule has the property with 'important' attribute.
     * @param CSSStyleRule node
     * @param String property
     */
    function isImportant(node, property) {
        if ( node.style.getPropertyPriority && node.style.getPropertyPriority(property) == 'important' )
            return true;
        else if ( node.style.cssText && getPropertyPriority(node.style.cssText, property) == 'important' ) {
            // IE6-8
            // IE thinks that cssText is part of rule.style
            return true;
        }
    }
    
    /**
     * getPropertyPriority function for IE6-8
     * @param String cssText
     * @param String property
     */
    function getPropertyPriority(cssText, property) {
        var props = cssText.split(";");
        for ( var i = 0; i < props.length; i++ ) {
            if ( props[i].toLowerCase().indexOf(property.toLowerCase()) != -1 ) {
                // Found the correct property
                if ( props[i].toLowerCase().indexOf("!important") != -1 || props[i].toLowerCase().indexOf("! important") != -1) {
                    // IE automaticaly adds a space between ! and important...
                    return 'important'; // We found the important property for the property, return 'important'.
                }
            }
        }
        return ''; // We did not found the css property with important attribute.
    }
    
    /**
     * Outputs a debug message if debugging is enabled.
     * @param String msg
     */
    function debugMsg(msg) {
        if ( debug ) {
            // For debugging purposes.
            if ( window.console )
                console.log(msg);
            else
                alert(msg);
        }
    }
    
    /**
     * The main functionality required, to check whether a certain property of 
     * some html element has the important attribute.
     * 
     * @param HTMLElement htmlNode
     * @param String property
     */
    function hasImportant(htmlNode, property) {
    
        // First check inline style for important.
        if ( isImportant(htmlNode, property) ) {
            // For debugging purposes.
            debugMsg("Inline contains important!");
            return true;
        }
    
        var rules = getMatchedCSSRules(htmlNode);
    
        if ( rules == null ) {
            debugMsg("This browser does not support styleSheets...");
            return false;
        }
    
        /**
         * Iterate through the rules backwards, since rules are
         * ordered by priority where the highest priority is last.
         */
        for ( var i = rules.length; i-- > 0; ) {
            var rule = rules[i];
    
            if ( isImportant(rule, property) ) {
                // For debugging purposes.
                debugMsg("Css contains important!");
                return true;
            }
    
        }
        return false;
    }
    
    $(document).ready(function() {
        hasImportant($('#testdiv')[0], 'top');
    });