Determine whether element has fixed or percentage width using JavaScript

前端 未结 5 425
情话喂你
情话喂你 2020-12-18 08:24

Using Mootools Element.Dimensions I can get the computed size, in pixels, of any element. However, I can find no way of telling whether an element has been sized using pixel

相关标签:
5条回答
  • 2020-12-18 08:37

    I've migrated and updated my answer from a closed duplicate:

    How to tell if an element has a fluid width

    Not wanting to go down the route of scanning style declerations I found that this works... but unfortunately only for firefox :( To me it would make sense that if the element has nothing to compute it's width against (i.e. it's not part of the document flow) it should return it's original value - which 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 );
    }
    

    (have not tested for IE)

    Webkit and Opera however return a blank value - yet again another instance of where I agree with FireFox's implementation and frown at the others.

    update 2

    Ok, not a fan of being defeated by computers ;) so have come up with this function -- totally over the top, but it does seem to work. Again I have yet to test this on IE as I don't have a Windows machine to hand at the moment. It's annoying when the original FireFox-only version is quite succinct, but the logic here is sound - it falls back to what a normal human would do in testing if something is stretchy.

    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's 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's 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;
      }
    }
    
    0 讨论(0)
  • 2020-12-18 08:38

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

    Check here for a live demo http://jsbin.com/ewuqa

    Or check this it handles also multiple matching CSS rules but only returns the correct value (the only thing I didn't bother to handle is if !important is set).

    Included JS

    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
    

    Own 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> 
    
    0 讨论(0)
  • 2020-12-18 08:38

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

    0 讨论(0)
  • 2020-12-18 08:39

    I doubt it can be done. You described the reason quite accurately: We have access to this kind of information only if it is in the element's style attribute. The only way I can think of is enlarge the parent container a bit and see if the textarea grows proportionately in size, but this is probably not always feasible, and probably hard to make cross-browser functional.

    I'd be highly interested in more positive answers, though.

    0 讨论(0)
  • 2020-12-18 08:44

    It can be done. Looking at this question (Why does getComputedStyle return 'auto' for pixels values right after element creation?) gives us the hint.

    If you set the element's style to display = none and then call getComputedStyle you will get the calculated value (percentage width or 'auto' or whatever the stylesheets apply to the element) instead of the pixel width.

    Working code jsfiddle 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 cause the layout to be re-rendered but, depending on your situation, it's probably a simpler solution than traversing all the stylesheet rules or cloning the element (which can cause some cascading rules to not be applied).

    0 讨论(0)
提交回复
热议问题