0

Considering getPropertyValue() only return units in px, as far as I know, I wonder if there is a way, to get a CSS value, given by any way (inline CSS, external stylesheet…) in its original unit (em, vw, %).

let el = document.querySelector('div')
let cs = window.getComputedStyle(el)
let height = cs.getPropertyValue('height')
el.innerText = height + " \n(I need to get 20vh)"
div{
  width:200px;
  height:20vh;
  background:LawnGreen;
}
<div></div>

[edit] Not a duplicate of Get element CSS property (width/height) value as it was set (in percent/em/px/etc) as it seems to focus on em and % and as it is almost 10 years old, it ignores vh, and vw, and so are the answers.

1213
  • 706
  • 2
  • 8
  • 25
  • `v(h/w)` is relative to viewport. Is extra calculation such as `100 / (window.innerHeight / height)` not a viable solution for you? – choz Apr 01 '21 at 22:25
  • Maybe you'll find a solution in this thread: https://stackoverflow.com/questions/9730612/get-element-css-property-width-height-value-as-it-was-set-in-percent-em-px-et – Hans Spieß Apr 01 '21 at 22:29
  • @HansSpieß I edited my question regarding this link – 1213 Apr 02 '21 at 08:54
  • 1
    Did you try the answers and found they did not work with `vh` or `vw`? Because the accepted answer talks about using the `CSSUnitValue` API, which doesn't care about `em`, `%`, `vw` or any specific unit. The age of the question is irrelevant; the technologies used in your accepted answer are as old or older than the technologies used in the accepted answer in the duplicate. – Heretic Monkey Apr 02 '21 at 17:23
  • Yes I did try the answer https://jsfiddle.net/168jbwp4/12/ (chrome / chromium only) – 1213 Apr 03 '21 at 08:09

1 Answers1

2

Just for fun - this is wildly inefficient, but you could parse each stylesheet, check if each rule matches the element, if it does, add the rule to a list of matches. Then, for each match, check if setting the inline style of that element to that rule changes the computed value, if it doesn't, assume that is the rule in use:

const getCssActualValue = (el, property) => {
  const matches = new Set();
  const allCSS = [...document.styleSheets]
    .map(styleSheet => {
      try {
        return [...styleSheet.cssRules]
          .map(rule => rule.cssText)
          .join('');
      } catch (e) {
        console.log('Access to stylesheet %s is denied. Ignoring...', styleSheet.href);
      }
    })
    .filter(Boolean)
    .map(rule => rule.split('}'))
    .forEach((styleSheet) => {
        styleSheet.forEach((rule) => {
            const [selector, styles] = rule.split(' {');
            try {
                if (selector && el.matches(selector)) {
                    styles.split(';').map(el => el.trim()).forEach((rule) => {
                        const [prop, val] = rule.split(': ')
                        if (prop === property) {
                            matches.add(val);
                        }
                    });
                }
            } catch {}
        });
    });
    return Array.from(matches);
  }
  

  const getCurrentCssValue = (el, property) => {
    const matches = getCssActualValue(el, property);
    const current = getComputedStyle(el)[property];
    const currentInline = el.style[property];
    for (const match of matches) {
        el.style[property] = match;
        if (getComputedStyle(el)[property] === current) {
            el.style[property] = currentInline;
            console.log({match});
            return match;
        }
    }
    el.style[property] = currentInline;
    return currentInline;
  }
  
  const property = 'height';
  const el = document.getElementById('test');
  el.innerText = getCurrentCssValue(el, property);
#test{
  width:200px;
  height:20vh;
  background:LawnGreen;
}
<div id="test"></div>
dave
  • 62,300
  • 5
  • 72
  • 93