4

I've got a website that has a fixed navbar, and I want to use Zurb Joyride to attach tips to elements in the navbar. The problem is that when the page scrolls, the navbar stays put but the tooltips don't.

I tried attaching the tooltips to elements within the navbar (instead of body), but I got strange rendering issues. Setting position: fixed on the div containing the tip seems to work, but I'm wondering if there's an easy way to programmatically detect if an element is non-scrolling, due to the fact that its contained within a fixed-position container, so that I can detect when to set the Joyride tips to be fixed as well. Any suggestions?

acjay
  • 34,571
  • 6
  • 57
  • 100

4 Answers4

5

Here is a pure JavaScript approach. It iterates over all offset parents until it finds a fixed one (or none at all).

function isFixed(elem){
    do{
      if(getComputedStyle(elem).position == 'fixed') return true;
    }while(elem = elem.offsetParent);
    return false;
}

If you're using jQuery, you'll need to extract the node object using elem[0] or elem.get(0).

Tunaki
  • 132,869
  • 46
  • 340
  • 423
Jameson the dog
  • 1,796
  • 1
  • 11
  • 12
2

You can use jQuery to do this. Lets say your ancestor element which is the fixed position container has a class of "ancestor" for simplicity. Lets also say your descendants (Joyride tips) have a class of "descendant". Both of these assumptions should be something you can easily add to your HTML, or alternatively use an existing class as a different jQuery selector. Then you can do something like this to do your detection.

if ($(".descendant").closest(".ancestor").css("position") == "fixed") {
    // set your Joyride tip to fixed
}

Updated

Since you have given a little more away of what you want to do, I think the question is something like "How can I check if an ancestor has a fixed position and there is no closer ancestor that scrolls?". Adding to that, there is a requirement that none of the ancestors have classes or ids specified. I am going to assume that your Joyride stops all have a class of "joyride-stop" purely for this example. So to determine whether to apply a fixed position to your Joyride stop or not, you would just need to do the following (using jQuery, since zurb joyride has it as a dependency):

var jStops = $(".joyride-stop");

for (var i=0; i<jStops.length; i++) {
    var pEls = jStops[i].parents();
    for (var j=0; j<pEls.length; j++) {
        if(pEls[j].css("position") == "fixed") {
            // closest ancestor is fixed.
            // insert code to fix your Joyride element here
            break;
        } else if (pEls[j].css("overflow") == "scroll") {
            // closest ancestor scrolls so just break and move on
            break;
        }
    }
}

Note that I have only checked for the overflow css property here. If you wanted to get fancy you could check for overflow-x, overflow-y and potentially any other attribute that may be influencing whether scrolling is present (such as some other custom JavaScript widget). The check depends on what you need to worry about on your page really,

Is this what you were after?

dcarson
  • 2,853
  • 1
  • 25
  • 34
  • The problem is that the tip could potentially be attached to any element. But any ancestor of that element might happen to be `position: fixed`. I think it would be poor SoC to add a style class to every element that happens to have a tip. I'd rather be able to make sure the tip stays fixed if its element stays fixed, without crapping up the markup. – acjay Jul 03 '13 at 11:01
  • I was just using the class approach as an example in lieu of the fact you provided no code example to support your question. If it was made clear how tips were applied, then I could give a more relevant answer. Given that the tips know which element they apply to, I am pretty sure that you could access that information too. Then you could apply the approach I described above. Lastly applying classes all through your mark up is a very common approach, it's hardly pollution as that's what the attribute is intended for – dcarson Jul 03 '13 at 11:09
  • Fair enough, but if I'm adding classes manually to make this work, I might as well just hardwire the `position: fixed` in the markup. Joyride is auxiliary to the content markup, and the advantage of my status quo solution is that its edits are at least restricted to the Joyride markup. I still have to manually maintain which elements are fixed instead of detecting them, but your solution has that drawback as well. – acjay Jul 03 '13 at 16:43
  • I modified the answer to suit what I think it is you needed. – dcarson Jul 07 '13 at 02:46
  • I had this problem so long ago, I don't remember whether this solves it or not. But reading the updated answer, it sounds pretty good. – acjay Nov 13 '15 at 21:50
1

Here's a way using jQuery:

var ancestorFixed = false;
$element.parents().each(function () {
    ancestorFixed = ancestorFixed || ($(this).css('position') == 'fixed');
});
Charlie
  • 8,530
  • 2
  • 55
  • 53
0

So far, the best solution I've got is to manually class the li's of the tips with a style that has position: fixed.

Note that it occurs to me that an element with a position: fixed ancestor might still scroll if a closer ancestor has scrolling content, so there's probably no general static method solve my problem by detecting a single position: fixed ancestor. I think an ideal solution would be to dynamically update the tip location upon scrolling to make sure it stays fixed relative to its target element.

acjay
  • 34,571
  • 6
  • 57
  • 100