views:

119

answers:

3

I have something vaguely like the following:

<div id="body">
  surrounding text 
  <div id="pane" style="overflow: auto; height: 500px; width: 500px;">
    lots and lots of text here
    <span id="some_bit">tooltip appears below-right of here</span>
  </div>
  more surrounding text (should be overlapped by tooltip)
</div>

and:

<div id="tooltip" style="width: 100px; height: 100px;">Whee</div>

What I want to do is insert the tooltip such that it is positioned above the pane it's in. If it's attached to an element that's next to the pane boundary (like above), then it should be visible above the pane, and above the text surrounding the pane.

It should NOT a) extend the pane, such that you have to scroll down to see the tooltip (like in http://saizai.com/css_overlap.png), or b) be cut off, so you can't see all of the tooltip.

I'm inserting this with JS, so I can add a wrapper position:relative div or the like if needed, calculate offsets and make it position:absolute, etc. I would prefer to not assume anything about the pane's position property - the tooltip should be insertable with minimal assumptions of possible page layout. (This is just one example case.)

It's for a prototype tooltip library I'm writing that will be open source.

ETA: http://jsfiddle.net/vCb2y/5/ behaves visually like I want (if you keep re-hovering the trigger text), but would require me to update the position of the tooltip on all DOM changes and scrolling behavior. I would rather the tooltip be positioned with pure CSS/HTML so that it has the same visual behavior (i.e. it overlaps all other elements) but stays in its position relative to the target under DOM changes, scrolling, etc.

ETA 2: http://tjkdesign.com/articles/z-index/teach_yourself_how_elements_stack.asp (keep defaults except set cyan div 'a' to position:relative; imagine 'A' is the pane and 'a' the tooltip) seems to more closely behave as I want, but I've not been able to get it to work elsewhere. Note that if you make 'A' overflow: auto, it breaks the overlapping behavior of 'a'.

+1  A: 

Edit: CSS used

#tooltip {
    z-index: 9999;
    display: none;
    position: absolute;
}

JS used

Note: in jQuery, but it should be easy to change it to Prototype syntax.

$('#some_bit').hover(function() {
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    // hovered element
    var offset = $(this).offset();
    var top = offset.top + docViewTop;
    var left = offset.left;
    var width = $(this).width();
    var height = $(this).height();
    var right = left + width;
    var bottom = top + height;

    // pane
    var poffset = $('#pane').offset();
    var ptop = poffset.top + docViewTop;
    var pleft = poffset.left;
    var pwidth = $('#pane').width();
    var pheight = $('#pane').height();
    var pright = pleft + pwidth;
    var pbottom = ptop + pheight;

    // tooltip
    var ttop = bottom;
    var tleft = right;
    var twidth = $('#tooltip').width();
    var theight = $('#tooltip').height();
    var tright = tleft + twidth;
    var tbottom = ttop + theight;

    if (tright > pright)
        tleft = pright - twidth;
    if (tbottom > pbottom)
        ttop = pbottom - theight;
    if (tbottom > docViewBottom)
        ttop = docViewBottom - theight;
    $('#tooltip').offset({top: ttop, left: tleft});
    $('#tooltip').css('display', 'block');
}, function() {
    $('#tooltip').hide();    
});

Edit: See it here.

melhosseiny
This example does not work. See http://jsfiddle.net/DTBBt/1/ where I actually added lots of text where it said.Yours has the "insert tooltip into the scrollable area" problem just like my image.
Sai Emrys
What's the reasoning behind using span to enclose the tooltip? It's basically being used as a block-level element, right?
Lèse majesté
Using span makes the HTML valid.
melhosseiny
DIVs can be nested AFAIK. The only thing you're not allowed to do in a valid HTML document is nest block level elements inside inline elements.
Lèse majesté
Yes, but i don't think he wants to enclose the tooltip in a div.
melhosseiny
But that's what I'm getting at. If you're going to render the SPAN as a block element, then why the preference for SPAN over DIV? Is it a semantic issue?
Lèse majesté
But i'm only changing its display property using CSS, the HTML document is still valid. If you use a div element, it will not validate. By the way, I'm sorry Sai. I didn't understand your problem right away. Most likely you'll have to calculate its position using JS as Lèse mentioned.
melhosseiny
Ah, my mistake. I hadn't noticed that `#some_bit` was also a SPAN.
Lèse majesté
For my usage, #some_bit is totally arbitrary. It might actually be a span, img, div - anything really. The tooltip has to support being attached to any arbitrary element.
Sai Emrys
mel: Your code still doesn't behave the way I need. See http://jsfiddle.net/vCb2y/2/The tooltips I'm using aren't only triggered by mouseover, and they aren't necessarily bound to the pane. So I've commented out that. The other issue is that if the pane is scrolled, the tooltip fails to scroll along with it. You could trap the scroll and reposition in JS, but that's a kludge; I'd rather that it behave naturally as part of the DOM.
Sai Emrys
How about http://jsfiddle.net/vCb2y/4/? Is this the behavior you want?
melhosseiny
mel: that one doesn't have the tooltip even vaguely attached to its target; it's just fixed at the bottom. (Making it position:absolute doesn't work either.)
Sai Emrys
Why does it work here: http://tjkdesign.com/articles/z-index/teach_yourself_how_elements_stack.asp ? Just make the cyan one relative and it is on top of the green - basically what I want. But when I try to replicate that it doesn't seem to work.
Sai Emrys
Ah yes. Check http://jsfiddle.net/vCb2y/5/.
melhosseiny
Do you mean you actually want the tooltip to overlap the browser window? Because if the tooltip is attached to the bottom-right of the element and you scroll, it should either scroll out of view or just stick to the browser edge it hits.
melhosseiny
mel: That doesn't quite work either - try scrolling either the red or white window (intentionally both are long enough to trigger the scroll bars). The popup stays in place rather than tracking its target.
Sai Emrys
Behavior wise: I want the tooltip to be above EVERYTHING. Always.I will optionally have it be constrained to be within certain boundary (eg the viewport, or a pane) but that's optional. Default case is that it overlaps.
Sai Emrys
You can never have an element overlap the browser. And for the scrolling behavior, what exactly do you want to happen to the tooltip when you scroll the pane? And also what should happen when you scroll the viewport?
melhosseiny
... so basically your current version is the same as LM's above. Both fail to handle scrolling or other contextual change.If it were a mouse-bound tooltip that'd be okay - I'd just update it on mousemove anyway. But for an element-bound tooltip I want it to always follow the element - preferably with CSS rather than having to track all DOM changes and reposition it myself.
Sai Emrys
If it's not viewport-bound (that's separate logic), then it should stay "element-relative". That is, if it's told to be 5px down-right of the target element, then that should still be true after scrolling. If that location isn't in the viewport, then an element-bound tooltip isn't visible either.
Sai Emrys
Basically, I want the visual behavior it has now (ignoring the viewport boundary bit), but without having to update its position with JS whenever the DOM changes, the viewport or pane is scrolled, etc.
Sai Emrys
The problem is that if you put the tooltip inside the overflowed pane (so that it can be positioned relative to the element), you'll never be able to make it overlap the pane. And if you take it outside and position it absolutely, you'll never be able to keep track of the pane scrolling without JS.
melhosseiny
mel: That is indeed exactly the problem. ;-) Surely there's some way around this constraint?
Sai Emrys
I'm afraid not. That's as far as CSS positioning goes.
melhosseiny
+1  A: 

I would just put the tooltip outside of the #pane div and position it absolutely using JavaScript since you're using JS anyway.

I don't use Prototype so I don't know how it's done in Prototype, but in jQuery, you'd use $(element).position() to get the element position. If you have to do it manually, it's a little more complicated.

And you'll probably want to add a little extra logic to prevent the tooltip from extending outside of the document.

Lèse majesté
AFAICT, the problem with this is that if that if `#pane` is scrolled, the position of the attachment point will change (with respect to the viewport and the document), and I'll have to reposition it. This means monitoring the scroll - which introduces significant complexity I'd prefer to avoid if possible.
Sai Emrys
That's a good point. And I'd be interested in some kind of pure-CSS/HTML solution, but I'm not sure there is one.
Lèse majesté
+2  A: 

Hi Sai,

I can't think of a pure HTML/CSS solution for this.

The overflow declaration is the issue here. If the tooltip is in #pane:

  1. you establish a positioning context within #pane, then the tooltip shows next to #some_bit (regardless of scrolling, etc.) but it gets cut-off.

  2. you do not establish a positioning context, then the tooltip is not clipped but it has no clue where #some_bit is on the page.

I'm afraid you'll need JS to monitor where #some_bit is on the page and position the tooltip accordingly. You'd also need to kill that tooltip as soon as #some_bit is outside of the viewing area (not an issue if the trigger is mouseover).

Actually, if the trigger is mouseover then you may want to use the cursor coordinates to position the tooltip (versus calculating the position of #some_bit).

Thierry Koblentz
Thanks for the answer.I was kinda hoping that there'd be a way to attach something to it so that it wouldn't share the context but would still track its position. Sigh.
Sai Emrys