Basically I can get Bootstrap Tour working with the most basic example, but when targeting an element in a jQuery dialog the highlight covers up the element.

var t = new Tour({
    backdrop: true
});

t.addStep({
    element: "#content",
    title: "Title",
    content: "Content"
});

t.start();

Here is a jsFiddle example of what I mean.

Bootstrap Tour with a jQuery Dialog

The highlight element should be behind the targeted element so that the text is still visible.

I think the issue is the z-index of the elements. It should be dialog -> highlight -> element, but instead it looks like it's dialog -> element -> highlight.

The z-index of the dialog is 100, the highlight is 1010 and the element is 1011, which I believe should be correct.

I can make it work by explicitly removing the z-index on the .ui-front jQuery UI class, but that doesn't seem like the best solution.

Any ideas why the default styling doesn't work if the z-index's are correct?

The problem rests in the fact that the jQuery-UI Dialog has created a new stacking context and so changes to the z-index of the #content element will only show up relative to it's current stacking context.

For proof, add the following css, and you'll still see the #content div display above the dialog, which has a z-index of 100. --> i.e. Z-indexes are not absolute! ... jsFiddle

<!-- language: lang-css -->
#content { z-index: 0 !important; }

From What No One Told You About Z-Index:

Every stacking context has a single HTML element as its root element. When a new stacking context is formed on an element, that stacking context confines all of its child elements to a particular place in the stacking order. That means that if an element is contained in a stacking context at the bottom of the stacking order, there is no way to get it to appear in front of another element in a different stacking context that is higher in the stacking order, even with a z-index of a billion!

New stacking contexts can be formed on an element in one of three ways:

  • When an element is the root element of a document (the <html> element)
  • When an element has a position value other than static and a z-index value other than auto
  • When an element has an opacity value less than 1

The problem is Bootstrap Tour doesn't really have a good way of identifying this. When they start a tour on an element, they apply:

  • A full screen black tour-backdrop with a z-index of 1009,
  • A white tour-step-background behind the object with a z-index of 1010
  • and apply a z-index to the current tour element of 1011

...but the last z-index has no effect since our object is already in a stacking context. It is just positioned higher than any of the other elements within that stack (which it already was). Incidentally, that's why removing the z-index from ui-front results in the proper appearance because it frees the element from its current stack.


Here's what Bootstrap Tours should be doing, and we'll do manually with DOM manipulation.

The problem is that they are trying to position the elements relative to one another with z-indexes, but anytime the tour object is in a stacking context different from the .tour-step-background and .tour-backdrop, this will fail.

Solution? Place the elements you're generating inside the same stacking context!

Here's a simplified markup tree

  • Body
    • Tour background (normally goes here)
    • New stacking context
      • Tour object
      • Tour background (should go here)

To override this, we'll plugin to the tours onShown method and move the backdrops ourselves:

In JavaScript, when creating a tour, we'll do the following:

var t = new Tour({
    backdrop: true,
    onShown: function(tour) {
        var stepElement = getTourElement(tour);
        $(stepElement).after($('.tour-step-background'));
        $(stepElement).after($('.tour-backdrop'));
    }
});
 
function getTourElement(tour){
    return tour._steps[tour._current].element
}

This uses jQuery's .after() DOM manipulation to move the backdrop to the same stacking context as our tour object.

Also, we'll need to position both our tour backdrop elements as fixed instead of absolute, so they don't try to squeeze inside of our dialog. We can do that with the following CSS:

<!-- language: lang-css -->
.tour-step-background, 
.tour-backdrop {
    position: fixed;
}

Working Demo in Fiddle

Which should look like this:

demo