Closed
Bug 780822
Opened 13 years ago
Closed 13 years ago
floating blocks don't always float to where they should belong
Categories
(Core :: Layout: Floats, defect)
Tracking
()
RESOLVED
INVALID
People
(Reporter: v+mozbug, Unassigned)
Details
Attachments
(1 file)
|
9.45 KB,
text/html; charset=UTF-8
|
Details |
Load attached file into browser. Shrink browser window horizontally until blocks 1, 2, and 3 appear on the first row, but not block 4.
Note that block 5 should easily also fit on the second row, but it doesn't... this is the first example of the bug.
As you stretch the browser window horizontally, when block 4 pops to the first row, there would be room for block 6 on the second row... but it doesn't come up.
When block 5 gets to the first row, all looks pretty good. Blocks 6, 7, 8, on second row. But then when you stretch enough for block 9 to fit on row 2, the others should all fit on row 3, but are vertical instead.
Other instances of the problem occur with additional stretching of the browser window.
There is debug code in the javascript that makes me believe that the problem is in or is triggered by the getBoundingClientRect() call. The block of code be functions dynrowsdo from "ix = dynrowspos + 1" and the whole next "if" statement are totally unnecessary to the application, but I added them for debugging... if you take them out, and change the timeout to several seconds, you can watch as the bug appears, when getBoundingClientRect is called, and without the debug code, it shows the block correctly positioned for the length of the timeout, and then it jumps to the wrong position.
| Reporter | ||
Comment 1•13 years ago
|
||
Attachment #649546 -
Attachment mime type: text/plain → text/html; charset=UTF-8
| Reporter | ||
Comment 2•13 years ago
|
||
As a side note, I think it is cumbersome to have to write Javascript to achieve the goal here, which is to pack boxes left to right, until one doesn't fit on the right, and then return to the left margin for the next box. Without the javascript, when block 5 doesn't fit on the top row, it would position itself under block 3, because block 2 is longer than block 3.
Perhaps an appropriate solution would be a new type of float that, if it cannot be aligned at the top with its left neighbor, would return to the left margin... something like float: left-margin (and a corresponding float: right-margin would be appropriate for symmetry).
(In reply to Glenn Linderman from comment #0)
> Load attached file into browser. Shrink browser window horizontally until
> blocks 1, 2, and 3 appear on the first row, but not block 4.
>
> Note that block 5 should easily also fit on the second row, but it
> doesn't... this is the first example of the bug.
That's because the CSS specification requires floats to prefer a higher position, and block 4 can be higher if it stays to the right of block 2. See http://www.w3.org/TR/CSS21/visuren.html#float-position
(Assuming you've taken the script out, anyway. When the script is there I see different results than what you describe.)
> As you stretch the browser window horizontally, when block 4 pops to the
> first row, there would be room for block 6 on the second row... but it
> doesn't come up.
No, for the same reason. (Again, ssuming you've taken the script out.)
> When block 5 gets to the first row, all looks pretty good. Blocks 6, 7, 8,
> on second row. But then when you stretch enough for block 9 to fit on row
> 2, the others should all fit on row 3, but are vertical instead.
Why do you think this is a bug in the browser rather than a bug in the JavaScript code in the page?
(In reply to Glenn Linderman from comment #2)
> Perhaps an appropriate solution would be a new type of float that, if it
> cannot be aligned at the top with its left neighbor, would return to the
> left margin... something like float: left-margin (and a corresponding
> float: right-margin would be appropriate for symmetry).
It sounds like you want display:inline-block and vertical-align:top, rather than float.
You're really using floats for things they weren't designed for, and I don't see any reason to believe our behavior is incorrect, though I'd be open to a simpler testcase showing that we're not following the rules in the CSS spec (see above).
Status: UNCONFIRMED → RESOLVED
Closed: 13 years ago
Resolution: --- → INVALID
| Reporter | ||
Comment 5•13 years ago
|
||
David,
Thanks for the hint about display:inline-block and vertical-align:top... I'll experiment with that, perhaps it will do what I want. And if it does, I'll wonder why no one in stackoverflow land, and similar forums suggested that solution to a fair number of people that had similar goals as I... None of the suggestions were from you, I'll admit :)
On the other hand, if you don't see what I see, using Mozilla 14.0.1, then probably I didn't describe things well enough.
I understand what happens without the script: that a float that won't fit on one line gets bumped down enough to move to the left to fit. My goal was to make it go clear to the left margin, when it won't fit on the right. The technique is to check getBoundingClientRect().top for adjacent <div>s, and when they differ, add the "clear: left;" style to force them to the right. This actually works pretty well, most of the time. In the cases the fail, the call to getBoundingClientRect() actually causes the <div> to be repositioned. I cannot imagine _any_ reason why a "get" sort of operation should cause anything to be repositioned... so that is part of why I think there is a bug in Firefox. The other part is that I added enough console.log()ging, to determine that my program was doing what it should, but that the results from getBoundingClientRect() were surprising.
I'm sorry to switch the status back to unconfirmed, but I really don't think it is an INVALID bug report.
If you don't see what I describe, it is probably a matter of different interpretations of my description, or a different version of Firefox, or both. Can you describe what you do see, and maybe we can iterate on terminology until we are communicating better?
Status: RESOLVED → UNCONFIRMED
Resolution: INVALID → ---
| Reporter | ||
Comment 6•13 years ago
|
||
And the third part of the reason I think it is a bug, is that if I take out the dynrowsbeg class (using firebug) after the script puts them in, that the display can be made to be correct for all these cases, but running the script again, getBoundingClientRect() will cause the <div> to move again, returned the position after the move, instead of the position that was correct, when the appropriate number of dynrowsbeg class settings are inserted manually.
| Reporter | ||
Comment 7•13 years ago
|
||
So I removed the event handlers from the <body>, and added
display: inline-block;
vertical-align: top;
to the .stall div CSS rules, and the results seem to be exactly what I want. Thank you for the hint.
However, I still believe that this is a valid bug report, even though it is a more complex technique than necessary to achieve the goal.
Comment 8•13 years ago
|
||
Glenn, I believe this is in fact a bug in your script. The fact that the behavior is the same in other browsers should have been a red flag...
The bug is that the logic looks like this:
if( dynrowstop != divrect.top )
{ dynrowstop = divrect.top
div.className = 'dynrowsbeg'
and then on the next iteration, the top of the next div is compared to the dynrowstop that was set here. But in the attached testcase, block 2 is taller than block 3. So the position of block 4 when you first get to it is to the right of block 2, under block 3. You store this vertical position (the bottom edge of block 3) in dynrowstop. Then you set block 4 to "clear: left", which moves it down to the vertical position corresponding to the bottom edge of the taller block _2_. The browser lays out block number 5 next to it, since it fits.
So now we do the next iteration, and you compare the top of block 5 to the stored dynrowstop. They're different (in particular the top of block 5 is now lower than the top of block 4 used to be before you set it to clear:left), so your script sets clear:left on block 5.
Simply moving the assignment to dynrowstop down to where you have the correct position of block 4 with clear applied (e.g. setting it right before your "rect+1" console.log call), makes the script work as you seem to expect it to work.
Status: UNCONFIRMED → RESOLVED
Closed: 13 years ago → 13 years ago
Resolution: --- → INVALID
| Reporter | ||
Comment 9•13 years ago
|
||
Thanks for the analysis, Boris. With the change you suggest, the script does work much more consistently, but there are a few surprising glitches while stretching the size of the window... all fixed by rerunning the script again manually, or by resizing just a little wider or narrower, which are probably due to the number of resize events overlapping with the script which is not complete. Probably removing the setTimeout stuff (which was only added to try to understand what was going wrong step by step, but sadly I didn't quite make it to that understanding anyway) would resolve those glitches.
Of course, David's suggested alternative approach, with no javascript, is a much better solution, but I have to admit it was very non-obvious to me. CSS seems to me to be like a maze of twisty little passages, and the passage that seems like the obvious solution often isn't...
You need to log in
before you can comment on or make changes to this bug.
Description
•