Determine if an element has a fixed or percentage width using JavaScript

Using Mootools Element.Dimensions I can get the calculated pixel size of any element. However, I cannot find a way to determine if the element was the size of pixel or percentage values ​​(except for the special case of its inline style).

Is there any reasonable way to do this? The only solution I can come up with (so terrible that it hardly deserves a name) is to go through the document stylesheets, looking for selectors that match the target element, and then look at the declared styles for the target projection.

Background

I am trying to replace all text fields of a specific CKEditor class with instances. Ideally, text fields with 100% width will be replaced by instances of instances with the same style - so they will scale when the window is resized - while text fields of a fixed size will be replaced by editors with a fixed size.

Yes, I could just give them another class (which I will do if there is no good solution), but ideally I would like to leave my CKEditor script and everything just works without the need to configure HTML.

+4
source share
5 answers

It can be done. Looking at this question ( Why does getComputedStyle return β€œauto” for pixel values ​​right after creating an element? ) Gives us a hint.

If you set the style of the element to display = none, and then call getComputedStyle, you will get the calculated value (percentage width or "auto" or whatever style is applied to the element) instead of the pixel width.

Jsfiddle working code https://jsfiddle.net/wtxayrnm/1/

function getComputedCSSValue(ele, prop) { var resolvedVal = window.getComputedStyle(ele)[prop]; //does this return a pixel based value? if (/px/.test(resolvedVal)) { var origDisplay = ele.style.display; ele.style.display = 'none'; var computedVal = window.getComputedStyle(ele)[prop]; //restore original display ele.style.display = origDisplay; return computedVal; } else { return resolvedVal; } } 

It should be noted that this will lead to re-rendering of the layout, but, depending on your situation, this is probably a simpler solution than moving all the rules of the stylesheet or cloning an element (which may lead to some cascading rules not being applied )

+4
source

Not that familiar with Motools, but in jQuery you can do it.

Check out the live demo here http://jsbin.com/ewuqa

Or check this out, it also handles a few matching CSS rules, but returns only the correct value (the only thing I didn't bother with was setting !important ).

JS enabled

 http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js http://github.com/hafriedlander/jquery.concrete/raw/master/vendor/jquery.selector/jquery.class.js http://github.com/hafriedlander/jquery.concrete/raw/master/vendor/jquery.selector/jquery.selector.js http://github.com/hafriedlander/jquery.concrete/raw/master/vendor/jquery.selector/jquery.selector.specifity.js 

Native functions

 function compare(as,bs) { return (as[0] - bs[0]) || (as[1] - bs[1]) || (as[2] - bs[2]); } //selector should only match a single element //property is a css style-name //returns the set css value (if set) for matched element, not the computed value //also handles multiple matching rules and only returns most specific match //doesn't handle !important function whatIsSet(selector, property) { var se = $(selector); var regex = new RegExp("(.*)-(.)(.*)","g"); var p = property; if (/-/.test(p)) { p = regex.exec(property); p = p[1] + p[2].toUpperCase() + p[3]; } if (se.get(0).style[p] != undefined && se.get(0).style[p] != '') return se.get(0).style[p]; var matchers = new Object(); var mostSpecific = undefined; for(var i = 0; i < document.styleSheets.length; i++) { //IE support var rules = document.styleSheets[i].cssRules ? document.styleSheets[i].cssRules : document.styleSheets[i].rules; for (var j=0; j < rules.length; j++) if (rules[j].style[p]) if (jQuery.inArray(se, $(rules[j].selectorText))) matchers[rules[j].selectorText] = rules[j].style[p]; } for(var i in matchers) { if(mostSpecific != undefined) { var ms = $.selector(mostSpecific).specifity(); var is = $.selector(i).specifity(); mostSpecific = compare(ms, is) > 0 ? mostSpecific : i; } else mostSpecific = i; } return matchers[mostSpecific]; } 

CSS

 body { background-color: #000; font: 16px Helvetica, Arial; color: #fff; } #myElement {background-color: yellow; width:10%} div {background-color: green; width:200px} div#myElement {background-color: blue; width:30%} div.asd#myElement {background-color: red; width:50%;} 

HTML

  <div id="myElement" class="asd" style="width:91%">asd</div> <input type="button" onclick="javascript:alert('width originally set to: '+ whatIsSet('#myElement', 'width'));" value="Tell me original width!"><br> <input type="button" onclick="javascript:alert('height originally set to: '+ whatIsSet('#myElement', 'height'));" value="Tell me original height!"><br> <input type="button" onclick="javascript:alert('background-color originally set to: '+ whatIsSet('#myElement', 'background-color'));" value="Tell me original background-color!"><br> 
+3
source

In IE, element.currentStyle.width . In many other browsers, getComputedStyle(element, null).getPropertyValue('width') .

+1
source

I migrated and updated my answer from a closed duplicate:

How to determine if an element has a fluid width

Not wanting to follow the path of scanning style decals, I found that this works ... but, unfortunately, only for firefox :( I would be wise that if an element has nothing to calculate its width (i.e. part document flow), it should return to its original value - this is what FireFox does:

 function isElementFluid(elm){ var clone = elm.cloneNode(false); if( window.getComputedStyle ) { value = window.getComputedStyle(clone,null).width; } else if( clone.currentStyle ) { value = clone.currentStyle.width; } return (value && String(value).indexOf('%') != -1 ); } 

(not tested for IE)

Webkit and Opera, however, return a null value, but again another example of where I agree with the implementation of FireFox and are unhappy with others.

update 2

Well, not a fan of being defeated by computers;) so we came up with this feature - completely on top, but it seems to work. Again, I have yet to test this on IE, because at the moment I don't have a Windows machine. This is annoying when the original FireFox-only version is pretty brief, but the logic here is that it returns to what a normal person will do when testing if something stretches.

 function isElementFluid(elm){ var wrapper, clone = elm.cloneNode(false), ow, p1, p2; if( window.getComputedStyle ) { value = window.getComputedStyle(clone,null).width; } else if( clone.currentStyle ) { value = clone.currentStyle.width; } /// the browsers that fail to work as Firefox does /// return an empty width value, so here we fall back. if ( !value ) { /// remove styles that can get in the way clone.style.margin = '0'; clone.style.padding = '0'; clone.style.maxWidth = 'none'; clone.style.minWidth = 'none'; /// create a wrapper that we can control, my reason for /// using an unknown element is that it stands less chance /// of being affected by stylesheets - this could be improved /// to avoid possible erroneous results by overriding more css /// attributes with inline styles. wrapper = document.createElement('wrapper'); wrapper.style.display = 'block'; wrapper.style.width = '500px'; wrapper.style.padding = '0'; wrapper.style.margin = '0'; wrapper.appendChild(clone); /// insert the element in the same location as our target elm.parentNode.insertBefore(wrapper,elm); /// store the clone calculated width ow = clone.offsetWidth; /// change the wrapper size once more wrapper.style.width = '600px'; /// if the new width is the same as before, most likely a fixed width if( clone.offsetWidth == ow ){ /// tidy up elm.parentNode.removeChild(wrapper); return false; } /// otherwise, calculate the percentages each time - if they /// match then it likely this is a fluid element else { p1 = Math.floor(100/500*ow); p2 = Math.floor(100/600*clone.offsetWidth); /// tidy up elm.parentNode.removeChild(wrapper); return (p1 == p2) ? Math.round(p1)+'%' : false; } } else { p1 = (value && String(value).indexOf('%') != -1); return p1 ? value : false; } } 
+1
source

I doubt it can be done. You have accurately described the reason: we have access to this information only if it is in the element's style attribute. The only way I can think of is to slightly increase the parent container and see if the size of the text area is proportional, but this is probably not always possible, and it is probably difficult to make cross-browser functionality.

I would be very interested in more positive answers.

0
source

All Articles