9

So, I have a DIV #Wrapper which has a fixed width. Inside that DIV, I have another DIV #Panel which also has a fixed width:

<div id="Wrapper">
    <p>...</p>
    <div id="Panel">Panel</div>
    <p>...</p>
</div>  

Sometimes, the width of the Panel is larger than the with of the Wrapper, and in those cases I would like to widen the Wrapper via JavaScript, so that it wraps the Panel perfectly.

Live demo: http://jsfiddle.net/H6rML/

I intended to use .scrollWidth on the Wrapper to determine the width of the Panel. However, the problem is that the Wrapper has horizontal padding, and the .scrollWidth for some reason only includes the left-padding of the wrapper. So:

Wrapper.scrollWidth === Wrapper.LeftPadding + Panel.Width

So, given:

#Wrapper {
    width: 200px;
    padding: 10px;        
}

#Panel {
    width: 300px;
}

Wrapper.scrollWidth returns 310px, which is not very useful. If .scrollWidth didn't include any padding and only returned the width of the Panel, I could work with that (I would add the padding manually to that value). If both paddings were included, I could work with that too. But why is only the left padding included? (Btw this behavior appears to be cross-browser.)

A few additional notes:

  1. I cannot set the width on the Wrapper directly. In my actual code, I set the width on an ancestor element that is several levels above the Wrapper, and I use a custom API to set the width. This is why I need to retrieve the full 320px value.

  2. I would like a solution that does not depend on the content of the Wrapper. In my demo it's a Panel, but in other scenarios there could be a different element that overflows, or even multiple elements. That is why I went with .scrollWidth on the Wrapper.

Is there a way to get the value 320px without having to manually add the right padding to the .scrollWidth value?


Btw, according to the standard, the right padding should be included:

The scrollWidth attribute must return the result of running these steps:

  1. If the element does not have any associated CSS layout box return zero and terminate these steps.

  2. If the element is the root element and the Document is not in quirks mode return max(document content width, value of innerWidth).

  3. If the element is the HTML body element and the Document is in quirks mode return max(document content width, value of innerWidth).

  4. Return the computed value of the 'padding-left' property, plus the computed value of the 'padding-right', plus the content width of the element.

Source: http://www.w3.org/TR/cssom-view/

Why don't the browsers behave accordingly?


To further improve the clarity of my post, let me sum up the two main questions:

(1) If the standard states that the right padding should be included in the .scrollWidth value, then why don't the browsers behave accordingly?

(2) Is it possible to retrieve the correct value (320px in my case), without having to manually add the right padding?


This question has been answered in another thread

The answer to this question is located here: When a child element overflows horizontally, why is the right padding of the parent ignored?

Community
  • 1
  • 1
Šime Vidas
  • 163,768
  • 59
  • 261
  • 366
  • @RokoC.Buljan I cannot set the width on the Wrapper directly. Please read the comments below Elliot's answer. I will update my question in order to clarify that. – Šime Vidas Apr 06 '12 at 18:58
  • Why you need to recalculate the `#Wrapper` width? After `#Panel` is perfectly wrapped, I would not bother more :) – Roko C. Buljan Apr 06 '12 at 19:00
  • P.S: you really cannot use jQ for that purpose? http://jsfiddle.net/ytByf/1/ using `.outerWidth(true)` it returns '320' ! Hope that helps! (Hello to Zagreb.) – Roko C. Buljan Apr 06 '12 at 19:08
  • @RokoC.Buljan As I said, I do *not* set the width on the Wrapper, but on an outer element (an ancestor that is further up the DOM tree). I have a custom function which sets the width on that ancestor, and in order for it to correctly set the width, I have to pass the value `320` to it. `Wrapper.scrollWidth` (incorrectly?) returns the value `310` (it doesn't include the right padding), so I have to figure out how to deal with this issue. (Pozdrav `:)`) – Šime Vidas Apr 06 '12 at 19:10
  • Kind of interesting, looks like there's no easy way to calculate BOTH paddings. Even with jQuery we have to use strictly 'padding-left' (or other) to get the computed padding (native) value. http://jsbin.com/onufey/edit#javascript,html,live But here it's achieved: http://jsbin.com/onufey/2/edit – Roko C. Buljan Apr 06 '12 at 19:19
  • @RokoC.Buljan I could add the right padding to the `.scrollWidth` value; that would work. The question is, why isn't the right padding included in `.scrollWidth`. The standard states that it should be. – Šime Vidas Apr 06 '12 at 19:22
  • Ah, I see now in the docs. And you bolded it. I'll look further to that issue. – Roko C. Buljan Apr 06 '12 at 19:45

4 Answers4

1

I'm not sure if I understand correctly, but from what I read, I assume you want to change width of #Wrapper based on #Panel. In that case, maybe you could try the following:

#Wrapper {
    display: inline-block;
    make sure to remove width from #Wrapper
}
Dygestor
  • 1,260
  • 1
  • 10
  • 20
1

I have no idea why leading browsers share this bug up until today, but here is a demo of the problem and inline-block workaround.

document.body.innerHTML += 'one.scrollWidth = '+ document.querySelector('.one').scrollWidth 
                          +'<br>two.scrollWidth = '+ document.querySelector('.two').scrollWidth
                          +'<br>three.scrollWidth = '+ document.querySelector('.three').scrollWidth
                          +'&nbsp;&nbsp;&nbsp;(fix applied to grand children)<br>four.scrollWidth = '+ document.querySelector('.four').scrollWidth +'&nbsp;&nbsp;&nbsp;(fix applied to direct child)';
.parent{
  border:1px solid rgba(50,150,220,1);
}
.child{
  background:rgba(100,200,255,0.3);
  padding:10px 20px;
  white-space:nowrap;
}
.scroll-container{
  border:1px solid red;
  display:inline-block;
  overflow:hidden;
}
.two, .three, .four{
  width:60px;
}
.three .child{
  display:inline-block;
}
.four .parent{
  display:inline-block;
}
<div class="scroll-container one">
  <div class="parent">
    <div class="child">Lorem ipsum dolor</div>
    <div class="child">Lorem ipsum dolor sit amet</div>
  </div>
</div>
<br>
<div class="scroll-container two">
  <div class="parent">
    <div class="child">Lorem ipsum dolor</div>
    <div class="child">Lorem ipsum dolor sit amet</div>
  </div>
</div>
<br>
<div class="scroll-container three">
  <div class="parent">
    <div class="child">Lorem ipsum dolor</div>
    <div class="child">Lorem ipsum dolor sit amet</div>
  </div>
</div>
<br>
<div class="scroll-container four">
  <div class="parent">
    <div class="child">Lorem ipsum dolor</div>
    <div class="child">Lorem ipsum dolor sit amet</div>
  </div>
</div>
<br>
Slava
  • 2,447
  • 1
  • 28
  • 34
0

Try this:

#Wrapper {
    min-width: 200px;
    padding: 10px;
    float: left; 
}

or use jQuery

$(document).ready(function() {
    var width = jQuery("#Panel").width();
    $("#Wrapper").width(width);
});
chadpeppers
  • 1,938
  • 1
  • 17
  • 27
  • Switching the element to a float is a relatively big change, that may introduce issues with the existing CSS/JavaScript code, so I see it only as an eventual last resort... – Šime Vidas Apr 06 '12 at 15:44
  • Can you use jquery method above? Why is floating it left such a drastic change? – chadpeppers Apr 06 '12 at 16:31
  • Are you able to use jquery like the solution above? – chadpeppers Apr 06 '12 at 16:33
  • When an element is floated, it is removed from the page flow. There are various differences between in-flow and out-of-flow elements: they are laid out differently, different CSS properties apply differently (different algorithms are used to determine the computed value) or don't apply at all. – Šime Vidas Apr 06 '12 at 17:32
0

You can use jQuery to do this:

$(function() {
    $("#Wrapper").width($("#Panel").outerWidth());
});

This takes into account #Panel's padding, margins, etc.

Elliot Bonneville
  • 46,945
  • 19
  • 86
  • 120
  • Unfortunately, I'm not setting the width on the Wrapper itself. The code in my answer is a simplified version of my actual code. In my code I have several layers of wrappers (one of them being an iframe), and the width is set via a third-party API (not jQuery). Therefore, I need to determine the correct value (`320px` in my example above). – Šime Vidas Apr 06 '12 at 17:27
  • Replace 'Wrapper' with the ID of the element you are setting the width of, then, right? – Elliot Bonneville Apr 06 '12 at 17:35
  • That wouldn't work because your code doesn't take into account the padding of the Wrapper. The value of `$("#Panel").outerWidth()` is `300`, but the value that I need is `320`. In the special case when you set the width on the Wrapper itself, you can use the value `300`, but if you set the width on an outer element (you need to take into account the horizontal padding of the Wrapper). – Šime Vidas Apr 06 '12 at 18:00
  • Maybe you want to set `$("#Wrapper").innerWidth()` instead. – Elliot Bonneville Apr 06 '12 at 18:01
  • `.innerWidth()` cannot be set; it is a read-only method. As I said, I don't set the width on the Wrapper, but on an outer element. This cannot be changed. – Šime Vidas Apr 06 '12 at 18:09
  • Mm. Well, sorry I couldn't help you. Good luck. – Elliot Bonneville Apr 06 '12 at 18:32