使用JavaScript确定元素是否具有固定宽度或百分比宽度

时间:2009-11-23 11:29:32

标签: javascript css mootools

使用Mootools Element.Dimensions我可以获得任何元素的计算大小(以像素为单位)。但是,我无法确定元素是否已使用像素值或百分比值进行调整(除了具有内联样式的特殊情况)。

这样做有明智的方法吗?我能想到的唯一解决方案(它太可靠了,几乎不值得这个名字)是遍历文档样式表,寻找与目标元素匹配的选择器,然后查看目标属性的声明样式。

背景

我正在尝试用CKEditor个实例替换某个类的所有textareas。理想情况下,100%宽度的textareas将被类似样式的编辑器实例替换 - 因此它们可以在窗口调整大小上缩放 - 而固定大小的textareas将被固定大小的编辑器替换。

是的,我可以给他们一个不同的类(如果没有很好的解决方案,我会这样做),但理想情况下我希望能够放入我的CKEditor脚本并让一切正常工作而无需调整HTML。

5 个答案:

答案 0 :(得分:4)

可以做到。看看这个问题(Why does getComputedStyle return 'auto' for pixels values right after element creation?)给了我们一些提示。

如果您将元素的样式设置为display = none,然后调用getComputedStyle,您将获得计算值(百分比宽度或' auto'或任何样式表应用于元素)而不是像素宽度。

工作代码 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;
  }
}

应该注意的是,这将导致布局重新呈现,但是,根据您的情况,它可能比遍历所有样式表规则或克隆元素(这可能导致一些级联)更简单的解决方案规则不适用。)

答案 1 :(得分:3)

不熟悉Motools,但在jQuery中你可以做到。

点击此处观看直播演示http://jsbin.com/ewuqa

或者检查一下它还会处理多个匹配的CSS规则,但只返回正确的值(我唯一不愿意处理的是设置!important)。

包含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

自己的职能

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> 

答案 2 :(得分:1)

在IE中,element.currentStyle.width。在许多其他浏览器中,getComputedStyle(element, null).getPropertyValue('width')

答案 3 :(得分:1)

我已从一个已关闭的副本中迁移并更新了我的答案:

How to tell if an element has a fluid width

不想走下扫描风格的路线我发现这有效...但不幸的是只有firefox :(对我而言,如果元素没有任何东西可以计算它的宽度(即它不是它应该返回原始值 - 这就是FireFox的作用:

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 );
}

(尚未测试IE)

然而,Webkit和Opera会返回一个空白值 - 这又是我同意FireFox实现的另一个例子,并且对其他人不满意。

更新2

好吧,不是被计算机击败的粉丝;)所以提出了这个功能 - 完全超过顶部,但它似乎确实有效。我还没有在IE上测试这个,因为我现在还没有Windows机器。当原始的FireFox版本非常简洁时,它很烦人,但这里的逻辑是合理的 - 它可以回归到普通人在测试时是否有弹性。

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;
  }
}

答案 4 :(得分:0)

我怀疑它可以做到。您非常准确地描述了原因:只有在元素的样式属性中才能访问此类信息。我能想到的唯一方法是稍微扩大父容器,看看textarea的大小是否成比例增长,但这可能并不总是可行,并且可能很难使跨浏览器功能化。

但是,我对更积极的答案非常感兴趣。