qwertyuiop
qwertyuiop

Reputation: 47

Return CSS width as formula instead of computed value

My css is coded in such a way that the point class would always be 50% of the div. Whenever I use css.('width'), it returns me the computed value. Any way to return width as "calc(100%/2)"?

css

.point{width:calc(100%/2)}

Javascript

var myPoint = document.getElementsByClassName('point');
console.log($(myPoint).css('width'));

Upvotes: 0

Views: 244

Answers (1)

JstnPwll
JstnPwll

Reputation: 8685

As others have mentioned in comments, it requires some complicated CSS parsing to figure out which rule(s) apply the element in question. This solution isn't perfect, but it parses the CSS styles for an element and determines which rule is the most specific, then returns the value for it. Note that it doesn't necessarily preserve the original format of the style...colors are converted from hex to rgb. But it does preserve units and computed value definitions.

Also, performance is most likely atrocious, I have not optimized this in any way.

HTMLElement.prototype.getCSSPropertyAsAuthored = (function(){
  var extractRule = function(cssText){
    return cssText.split('{').shift();
  }
  var extractStyle = function(cssText){
    var match = cssText.match(/[^{]+\{([^}]*)\}/)
    if(match){
      return match[1];
    }
    return '';
  }
  var shouldKeepRule = function(selector, styles, property){
    if(selector.substr(0,1) == '@')
      return false;
    if(styles.indexOf(property+':') == -1)
      return false;
    return true;
  }
  var getAllPotentialRules = function(property){
    var css = [];
    for (var i=0; i<document.styleSheets.length; i++){
        var sheet = document.styleSheets[i];
        var rules = ('cssRules' in sheet)? sheet.cssRules : sheet.rules;
        if (rules){
            for (var j=0; j<rules.length; j++){
                var rule = rules[j];
                var cssText = !!('cssText' in rule)
                var selectors = (cssText ? extractRule(rule.cssText) : rule.selectorText).split(',');
                var styles = cssText ? extractStyle(rule.cssText) : rule.style.cssText;
                for(var selector of selectors){
                  if(shouldKeepRule(selector, styles, property)){
                    var nodes = document.querySelectorAll(selector);
                    if(Array.prototype.indexOf.apply(nodes, [this]) > -1){
                      css.push({selector: selector, style: styles})
                    }
                  }
                }
            }
        }
     }
     return css;
  }
  
  var extractMostSpecificStyle = function(styles, property){
    if(!styles.length) return null;
    var match, re = new RegExp('(^|;)\\s*'+property+':([^;]+);?'), count = 0;
    for(var style of styles){
      style.value = '';
      style.count = count++;
      style.ownStyle = style.selector===''?1:0;
      style.tagCount = (match=style.selector.match(/(^|[\s>]|:not\()[a-zA-z-]+/gi))?match.length:0;
      style.classCount = (match=style.selector.match(/\./gi))?match.length:0;
      style.idCount = (match=style.selector.match(/#/gi))?match.length:0;
      if(match=style.style.match(re)){
        style.value = match[2].trim();
      }
      style.important = style.value.indexOf('!important') > -1 ? 1 : 0;
    }
    styles.sort(function(a,b){
      if(a.important != b.important) return b.important - a.important;
      if(a.ownStyle != b.ownStyle) return b.ownStyle - a.ownStyle;
      if(a.idCount != b.idCount) return b.idCount - a.idCount;
      if(a.classCount != b.classCount) return b.classCount - a.classCount;
      if(a.tagCount != b.tagCount) return b.tagCount - a.tagCount;
      return b.count - a.count;
    });
    return styles[0].value;
  }  
  
  return function(property){
    if(!property) return null;
    property = property.toLowerCase();
    
    var styles = getAllPotentialRules.apply(this, [property]);
    var styleValue = this.getAttribute('style');
    if(shouldKeepRule('', styleValue||'', property)){
      styles.push({selector: '', style: styleValue})
    }
    return extractMostSpecificStyle(styles, property);
  }
})();

var test = document.getElementById('test');
console.log(test.getCSSPropertyAsAuthored('width'));
console.log(test.getCSSPropertyAsAuthored('background-color'));
console.log(test.getCSSPropertyAsAuthored('border'));
<style>
.point {
  border: 1px solid red;
  width: 100%;
  background-color: #ccc;
}
#test {
  background-color: #eee;
}
div > div {
  border: 1px solid blue !important;
}
</style>

<div>
  <div id="test" class="point" style="width:calc(100%/2);">Point</div>
</div>

Upvotes: 1

Related Questions