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'));
6
  • Are you getting this problem in your JavaScript or in some preprocessor like LESS or SASS? Commented Jun 25, 2018 at 17:36
  • Just Javascript. Commented Jun 25, 2018 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. Commented Jun 25, 2018 at 19:19
  • you need to parse the CSS file in order to do this Commented Jun 25, 2018 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. Commented Jun 26, 2018 at 0:45

1 Answer 1

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>

Sign up to request clarification or add additional context in comments.

7 Comments

CSS parsing is not as easy as that... Add a simple rule before your width one and your parser is broken.
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.
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 <style> elements (this includes the ones in <link> that you may not have access to from js, and also style attributes, from there, you'd have to build the whole CSSOM in order to know which rules are actually applied (taking into account various importance rules) etc. I never saw such a parser in js, while many have hoped for it.
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.
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
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.