0

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'));
qwertyuiop
  • 47
  • 6
  • Are you getting this problem in your JavaScript or in some preprocessor like LESS or SASS? – cjl750 Jun 25 '18 at 17:36
  • Just Javascript. – qwertyuiop Jun 25 '18 at 18:16
  • Can you update your question to show that bit of JavaScript then. I find your question a bit unclear as it is currently worded. – cjl750 Jun 25 '18 at 19:19
  • you need to parse the CSS file in order to do this – Temani Afif Jun 25 '18 at 20:00
  • What is the use case? If you know it is "*always 50%*" then isn't just hard-coding this value in your JS enough? (btw `calc(100% / 2)` makes very little sense, why not directly `50%`?). There might be better solutions depending on the use-case though, but as it stands this is a very important bit of your question which is missing. – Kaiido Jun 26 '18 at 00:45
  • Ps: if you keep your question as "How to get the authored value", then it is a dupe of https://stackoverflow.com/questions/9730612/get-element-css-property-width-height-value-as-it-was-set-in-percent-em-px-et/49144353#49144353 But I'm sure there is a way for your use case, if we could know it... – Kaiido Jun 26 '18 at 01:06

1 Answers1

1

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>
JstnPwll
  • 8,585
  • 2
  • 33
  • 56
  • CSS parsing is not as easy as that... Add a simple rule before your width one and your parser is broken. – Kaiido Jun 26 '18 at 00:42
  • As I said, "Here is a very naive solution..." I'm aware that parsing CSS will take more than one line of regex, but the goal is to get them headed in the right direction, not write them a CSS parsing library. – JstnPwll Jun 26 '18 at 01:49
  • Well arguably, giving them false hope is hardly getting them headed in the right direction. CSS parsing is a tough thing, not only your "naive implementation" will break in two seconds as I demonstrated, but you would even have to parse all StyleSheets, not only ` – Kaiido Jun 26 '18 at 01:56
  • To be able to guide them in the correct direction, we would need more info as to why they initially though they needed this. From there, we might be able to find other ways to accomplish the same end-result. – Kaiido Jun 26 '18 at 01:57
  • Hi, thanks for providing me a straight-forward solution! @Kaiido yup what you mentioned is correct, there might be better way to accomplish the same task. I need the width in formula form because I need to adjust the width based on percentage. Something like 50% + 16% etc. Of course there are many ways of doing this, in fact I already found some other way but this is one of the option I consider and I would like to find out whether this is workable – qwertyuiop Jun 26 '18 at 04:48
  • @qwertyuiop Please include all informations in an [edit to your question](https://stackoverflow.com/posts/51028821/edit) rather than in comments. – Kaiido Jun 26 '18 at 04:52
  • @qwertyuiop I've updated my answer to be more generic and comprehensive, albeit not perfect. – JstnPwll Jun 26 '18 at 15:12