Intro.js: Selected Element doesn't show on top of overlay... Problem with z index

Created on 28 Apr 2013  Â·  67Comments  Â·  Source: usablica/intro.js

I tried to use introjs, then everything looks fin, except, when an element is selected then element is placed under the selector box, and because of its background transparency, I can see it but not clear, it looks despite having higher z-index to the selected element by adding two classes "introjs-showElement introjs-relativePosition", but still my element get some other CSS side-effects from another one, I wanted to see have been faced by something like this...

bug

Most helpful comment

If somebody wants a quick fix until the issue is resolved, this is how I did it.
I took an inspiration in this CodePen https://codepen.io/iGadget/pen/gpNqWm
and the resulting CSS is:

    .introjs-helperLayer {
        background: transparent;
    }

    .introjs-overlay {
        display: none;
    }

    .introjs-helperLayer:before {
        opacity: 0;
        content: '';
        position: fixed;
        width: inherit;
        height: inherit;
        border-radius: 0.5em;
        border: .2em solid rgba(255, 217, 68, 0.8);
        box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
        opacity: 1;
    }

    .introjs-helperLayer:after {
        content: '';
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        position: fixed;
        z-index: 1000;
    }

It will disable introJs' overlay and instead use box-shadow and create a hole in it, which will result in similar behavior.

Note: the last CSS selector:after is probably unnecessary, but I did not have time to test it, so I'm leaving it there, just to be sure. Let me know what you will find out.

All 67 comments

Thanks for report.
Could you please provide an online example of your problem? Like jsFiddle.

Yes, I can also confirm this is happening. Looks like the intro-js layers are being appended to the DOM in the body, not as siblings of the target's parent. I believe that the z-index won't work unless the intro-js layers are adjacent in the DOM to the target.

Yes, Actually, if the selected element is nested through some DIVs (or any
other block elements) with position RELATIVE, this bug will be raised!
Basically when B is nested within A and A is relative, then turn B to an ABSOLUTE
div, just make it absolute in relative to the A region, not to the whole "window", so
that's why, doesn't matter how much is its "z-index", still B is sucked within
A and there is no way to get out!! Moreover if A is nested in another relative element then this story would be more complicated. But there is a solution....I hv to try...

On Mon, Apr 29, 2013 at 6:09 AM, tvpmb [email protected] wrote:

Yes, I can also confirm this is happening. Looks like the intro-js layers
are being appended to the DOM in the body, not as siblings of the target's
parent. I believe that the z-index won't work unless the intro-js layers
are adjacent in the DOM to the target.

—
Reply to this email directly or view it on GitHubhttps://github.com/usablica/intro.js/issues/109#issuecomment-17143782
.

I confirm this happening. Any solutions so far?

I've created a fiddle to demonstrate the problem: http://jsfiddle.net/Zwr7s/

Looks to be when the parent has both absolute positioning and a z-index.

UPDATE - actually, it happens whether the parent has absolute or relative positioning. Doesn't occur when no position is set (static)

Thanks @Dozyatom.
I'll work on the patch for next version, marked as bug.

Also let me know if you have ideas about how to fix it.

I fixed that. Could someone check that the problem is solved or not? I need a confirm.

Thanks for the quick update, but I've got two problems:
1) it doesn't work for a parent with position: fixed
2) it looks like you're removing the z-index of the parent - this is a little heavy handed! I need my existing z-index attributes to remain as they are, otherwise it breaks existing layout.

I've spent a bit of time fiddling with this now, and I'm not sure it can be solved. My basic fiddle is http://jsfiddle.net/7MPpe/ - you can see I'm trying to cater for any type of nesting. No combination of z-index's seems to be able to elevate the target element above the mask.

And reading https://developer.mozilla.org/en-US/docs/CSS/Understanding_z-index/The_stacking_context seems to indicate that it's impossible to do. It appears the z-index property is relative only to the parent container, so an external div cannot be manipulated to sit in-between.

I confirm the same issue with parents with fixed position. Any updates?

@Dozyatom Really we can't fix this problem in another way, that's the only way! I want your feedback, what you think about the current patch? I believe this patch at least could solve some problems.

@drgomesp I'll fix the problem for fixed element positioned today.

@afshinm any updates?

Sorry guys but this problem still exists. I need more time to solve this problem.

We can help, after all this is an open source project.

Tell us more about what do you think its happening.

I think this problem is not solvable using traditional HTML/CSS -- Its just
the way that z-index + html nesting child/parent relationships work.
However, a somewhat hacky solution that would work is to do something like
the Image Area Select jquery plugin.

Take a look at the way this plugin masks off the selected area.

https://github.com/odyniec/imgareaselect

Matt Babineau
VP, Product Marketing
TVPage, Inc.
6827 Nancy Ridge Drive
San Diego, CA 92121
t: 858 427-4909
f: 858 427-4951
e: [email protected]
www.tvpage.com

On Mon, May 13, 2013 at 6:16 AM, Daniel Ribeiro [email protected]:

We can help, after all this is an open source project.

Tell us more about what do you think its happening.

—
Reply to this email directly or view it on GitHubhttps://github.com/usablica/intro.js/issues/109#issuecomment-17810603
.

@drgomesp Sure, why not?
Actually currently I'm pretty busy for releasing the v0.4.0 and manage other pull request and feature requests, it's really hard to keep the mind focused on the problems like this. But you can take a look at this problem, it's a little bit confusing but I don't think it's an impossible to solve.

Was there ever a solution to this problem with fixed elements?

I think I have solved this with the alternative approach suggested by @tvpmb - take a look at https://github.com/Dozyatom/guide.js

Basically, I surround the element, rather than try raise it above a mask. It's working for me so hopefully useful to others as well...

@Dozyatom I have this issue. guide.js solves the problem. but I like the introjs interface items. Did you by any chance make a version using your "surround" method but with intro.js. I'd really like that.

Have this problem as well.

Is there any update on this issue in Intro.js...? I have used it at many places, and currently short of time to switch to Guide.js at all places. Suggest.

@afshinm Any chance there is a fix in place for this? Check out a possible solution here: https://github.com/heelhook/chardin.js/issues/26

@afshinm Just confirming that this is still an issue. I'm using the angular-intro port, but the issue resides with the positioning/z-indexing. Any ideas on this?

@afshinm In my particular situation, changed the parent z-index to match that of the highlighted element (99999...) worked perfectly. But I agree that in the other scenarios above, there is still error

@Dozyatom I think using your surround method could be promising in an intro.js context. I would be interested in seeing that.

https://github.com/Dozyatom/guide.js - still some outstanding issues, but does demonstrate the principle

@Dozyatom Have you tried integrating the surround method into intro.js though? I am looking into your code right now and seeing how difficult it would be to replace Intro.js's overlay with the surround method.

@Dozyatom So, I just submitted a pull request to guide.js with some tiny things, and also just created "angular-guide" which is a port of the angular-intro wrapper but for guide.js I've also registered both with bower, assuming you merge the pull. PM me for more info [email protected], so we don't pollute this thread.

I experienced this problem only on Webkit browsers (in Firefox, it works). Turns out I had -webkit-transform: translateZ(0) on my parent element. When I commented it out, it works fine. (That's also why it runs OK on Firefox)

Help layer doesn't work with the absolute positioned element. In my case the helplayer prepends the absolute positioned element instead of surrounding it. My header is a fixed element, on using intro.js on header it forms a helplayer div of equal width and height and puts it before the actual header.
bug of intro

@anupamapanchal try onboard.js

@tannerlinsley : Hey can you please share the link of demo of onboard.js, i can't find it on their repository.

I don't think they have an online demo yet. Just clone it down and run the example/index . hymn for now. I'll see if I can work up a better online version here soon

Confirming that this is still an issue. Trying to use this lib on a Bootstrap 3 fixed navigation and the items being highlighted are be masked by the overlay. Its extremely frustrating that this has been marked as "trivial" and no patch has been made for it yet.

I have same problem you can use $(".introjs-fixParent").removeClass("introjs-fixParent");
after introJs().start();

@anupamapanchal, onboard.js is now an angular module called nzTour. If you're in to angular, enjoy!

Any update on this? I see this _only on Safari_ now, but I see it on iOS and on Mac.

This is an issue which is _only reproducible_ in Mobile Safari for me. The desktop version of Safari works fine for me, but it might be that this is just a slightly different setup?

For anyone else having this problem, you can use this 'hack'.

I forked this repo and made needed change to make it work. Feel free to include danishin/intro.js in package.json and use the following snippet.

 var introGuide = introJs();
 introGuide.onchange(function(targetElement) {

            // Find the parent having the introjs-fixParent class
            $parentElement = $(targetElement).parents(".introjs-fixParent");

            // Check if the parent has the position fixed
            if ($parentElement.css("position") === "fixed") {

                // Change the position to absolute
                $parentElement.css("position", "absolute");
            }
 });
introGuide.start();

in place of,

introJs().start();

For future reference, if you are using WOW.js, it may be conflicting too.

So, I got rid of the "wow fadeIn" and it worked.

I'm using intro.js (2.7.0) with angularjs and angular-material. I have the same z-index problem with a FAB element (Floating Action Button).

fab

I didn't get this to work. Does anybody still have the same issue?
This problem exists in several browsers (chrome, firefox, edge)

yes we do @ccvp

Still experiencing this issue with multiple elements in my application, intro.js v 2.4 . Any type of fix I try to do is breaking my layout, this is a major issue that degrades the usefulness of the library substantially.

I came across the same issue with an old version of Bootstrap Tour I am using in my Web app Clibu. It revolves around stacking order, z-index etc.

In the end the only solution that worked in all cases for me was to clone the elements you want highlighted and then absolutely position the clone over the original element.

guide.js and I think the current Bootstrap tour use 4 rectangular overlays which surround the element you want highlighted. Clearly this works, however if you wanted to highlight multiple elements, this would quickly get complex.

Here are some good articles:
https://philipwalton.com/articles/what-no-one-told-you-about-z-index/
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_without_z-index

If somebody wants a quick fix until the issue is resolved, this is how I did it.
I took an inspiration in this CodePen https://codepen.io/iGadget/pen/gpNqWm
and the resulting CSS is:

    .introjs-helperLayer {
        background: transparent;
    }

    .introjs-overlay {
        display: none;
    }

    .introjs-helperLayer:before {
        opacity: 0;
        content: '';
        position: fixed;
        width: inherit;
        height: inherit;
        border-radius: 0.5em;
        border: .2em solid rgba(255, 217, 68, 0.8);
        box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
        opacity: 1;
    }

    .introjs-helperLayer:after {
        content: '';
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        position: fixed;
        z-index: 1000;
    }

It will disable introJs' overlay and instead use box-shadow and create a hole in it, which will result in similar behavior.

Note: the last CSS selector:after is probably unnecessary, but I did not have time to test it, so I'm leaving it there, just to be sure. Let me know what you will find out.

If it can help anyone...
I read this conversation as I was experiencing the same issue. Thanks to nevf, I realized the problem was stacking context. I installed the Chrome extension z-context, which tells you if an element creates or is part of a stacking context. This helped me to figure out which elements created the context. And then, highlighting these elements, I saw that introjs already had partly fixed the issue using a class called "introjs-fixParent". This class is dynamically added to the parents elements that create stacking context, and sets several css attributes, for instance z-index to "auto", in order to remove temporarily the stacking context. But it missed the attribute "position" (probably because in some cases, it can lead to problems in the page layout).

So just to give it a try, I added the following rule :
.introjs-fixParent{position: absolute !important;}
to my css and it immediately worked like a charm !

As I expected, I found that originally introjs had included

position: absolute !important;

in the fixParent class, but it generated issues with the general layout in some (and maybe the majority) of cases. So it was removed, as we can see in #583

But in my case, this doesn't break my layout and totally solves the present issue, so it's worth giving it a try

+1

+1 to above by @rdacn to add .introjs-fixParent{position: absolute !important;}

Still a problem and what appears to be a pretty big and easily encountered one, wish it was more openly declared as a "restriction" in the introduction so users would know what they're getting into using this..

I do think it's a tough problem with opinionated solutions. Check out #826 for a proposed solution, with possible downsides.

If somebody wants a quick fix until the issue is resolved, this is how I did it.
I took an inspiration in this CodePen https://codepen.io/iGadget/pen/gpNqWm
and the resulting CSS is:

    .introjs-helperLayer {
        background: transparent;
    }

    .introjs-overlay {
        display: none;
    }

    .introjs-helperLayer:before {
        opacity: 0;
        content: '';
        position: fixed;
        width: inherit;
        height: inherit;
        border-radius: 0.5em;
        border: .2em solid rgba(255, 217, 68, 0.8);
        box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
        opacity: 1;
    }

    .introjs-helperLayer:after {
        content: '';
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        position: fixed;
        z-index: 1000;
    }

It will disable introJs' overlay and instead use box-shadow and create a hole in it, which will result in similar behavior.

Note: the last CSS selector:after is probably unnecessary, but I did not have time to test it, so I'm leaving it there, just to be sure. Let me know what you will find out.

This workaround works for me. I only need to change position to absolute.

If somebody wants a quick fix until the issue is resolved, this is how I did it.
I took an inspiration in this CodePen https://codepen.io/iGadget/pen/gpNqWm
and the resulting CSS is:

    .introjs-helperLayer {
        background: transparent;
    }

    .introjs-overlay {
        display: none;
    }

    .introjs-helperLayer:before {
        opacity: 0;
        content: '';
        position: fixed;
        width: inherit;
        height: inherit;
        border-radius: 0.5em;
        border: .2em solid rgba(255, 217, 68, 0.8);
        box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
        opacity: 1;
    }

    .introjs-helperLayer:after {
        content: '';
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        position: fixed;
        z-index: 1000;
    }

It will disable introJs' overlay and instead use box-shadow and create a hole in it, which will result in similar behavior.
Note: the last CSS selector:after is probably unnecessary, but I did not have time to test it, so I'm leaving it there, just to be sure. Let me know what you will find out.

This workaround works for me. I only need to change position to absolute.

+1, worked for me too, thanks a lot!

If somebody wants a quick fix until the issue is resolved, this is how I did it.
I took an inspiration in this CodePen https://codepen.io/iGadget/pen/gpNqWm
and the resulting CSS is:

    .introjs-helperLayer {
        background: transparent;
    }

    .introjs-overlay {
        display: none;
    }

    .introjs-helperLayer:before {
        opacity: 0;
        content: '';
        position: fixed;
        width: inherit;
        height: inherit;
        border-radius: 0.5em;
        border: .2em solid rgba(255, 217, 68, 0.8);
        box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
        opacity: 1;
    }

    .introjs-helperLayer:after {
        content: '';
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        position: fixed;
        z-index: 1000;
    }

It will disable introJs' overlay and instead use box-shadow and create a hole in it, which will result in similar behavior.
Note: the last CSS selector:after is probably unnecessary, but I did not have time to test it, so I'm leaving it there, just to be sure. Let me know what you will find out.

This workaround works for me. I only need to change position to absolute.

+1, worked for me too, thanks a lot!

Also remember to change,

.introjs-overlay {
display: none;
}

to,

.introjs-overlay {
opacity: 0 !important;
}

Otherwise you will be able to click the element below the overlay.

This fix helped me, thank you

If somebody wants a quick fix until the issue is resolved, this is how I did it.
I took an inspiration in this CodePen https://codepen.io/iGadget/pen/gpNqWm
and the resulting CSS is:

    .introjs-helperLayer {
        background: transparent;
    }

    .introjs-overlay {
        display: none;
    }

    .introjs-helperLayer:before {
        opacity: 0;
        content: '';
        position: fixed;
        width: inherit;
        height: inherit;
        border-radius: 0.5em;
        border: .2em solid rgba(255, 217, 68, 0.8);
        box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
        opacity: 1;
    }

    .introjs-helperLayer:after {
        content: '';
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        position: fixed;
        z-index: 1000;
    }

It will disable introJs' overlay and instead use box-shadow and create a hole in it, which will result in similar behavior.
Note: the last CSS selector:after is probably unnecessary, but I did not have time to test it, so I'm leaving it there, just to be sure. Let me know what you will find out.

This workaround works for me. I only need to change position to absolute.

+1, worked for me too, thanks a lot!

Also remember to change,

.introjs-overlay {
display: none;
}

to,

.introjs-overlay {
opacity: 0 !important;
}

Otherwise you will be able to click the element below the overlay.

I am still unable to click element below the overlay

Also remember to change,

.introjs-overlay {
display: none;
}

to,

.introjs-overlay {
opacity: 0 !important;
}

Otherwise you will be able to click the element below the overlay.

I had to add also

.introjs-overlay {
  opacity: 0 !important;
  z-index: 99999999!important; // <--- this!
}

So, final working code for me is:

/* Based on https://github.com/usablica/intro.js/issues/109 */

.introjs-helperLayer {
  background: transparent;
}

.introjs-overlay {
  opacity: 0 !important;
  z-index: 99999999!important;
}

.introjs-helperLayer:before {
  opacity: 0;
  content: '';
  position: absolute;
  width: inherit;
  height: inherit;
  border-radius: 0.5em;
  border: .2em solid rgba(255, 217, 68, 0.8);
  box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
  opacity: 1;
}

.introjs-helperLayer:after {
  content: '';
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  position: absolute;
  z-index: 1000;
}

Thanks!

We used the svg mask approach with Shepherd. If this issue is giving you problems, perhaps give Shepherd a try! https://github.com/shipshapecode/shepherd

.introjs-helperLayer {
mix-blend-mode: overlay !important;
}

This managed to work beautifully for me

In my case,
I just meet this issue on Safari.

So I just put this line to the global CSS:

.introjs-fixParent {
    -webkit-overflow-scrolling: initial !important;
}

Also remember to change,
.introjs-overlay {
display: none;
}
to,
.introjs-overlay {
opacity: 0 !important;
}
Otherwise you will be able to click the element below the overlay.

I had to add also

.introjs-overlay {
  opacity: 0 !important;
  z-index: 99999999!important; // <--- this!
}

So, final working code for me is:

/* Based on https://github.com/usablica/intro.js/issues/109 */

.introjs-helperLayer {
  background: transparent;
}

.introjs-overlay {
  opacity: 0 !important;
  z-index: 99999999!important;
}

.introjs-helperLayer:before {
  opacity: 0;
  content: '';
  position: absolute;
  width: inherit;
  height: inherit;
  border-radius: 0.5em;
  border: .2em solid rgba(255, 217, 68, 0.8);
  box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
  opacity: 1;
}

.introjs-helperLayer:after {
  content: '';
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  position: absolute;
  z-index: 1000;
}

Thanks!

I just found this and it seems to work. Would be nice if that got moved to the docs in FAQ / troubleshooting to save some googles

Yes, I can also confirm this is happening. Looks like the intro-js layers are being appended to the DOM in the body, not as siblings of the target's parent. I believe that the z-index won't work unless the intro-js layers are adjacent in the DOM to the target.

Same issue

If somebody wants a quick fix until the issue is resolved, this is how I did it.
I took an inspiration in this CodePen https://codepen.io/iGadget/pen/gpNqWm
and the resulting CSS is:

    .introjs-helperLayer {
        background: transparent;
    }

    .introjs-overlay {
        display: none;
    }

    .introjs-helperLayer:before {
        opacity: 0;
        content: '';
        position: fixed;
        width: inherit;
        height: inherit;
        border-radius: 0.5em;
        border: .2em solid rgba(255, 217, 68, 0.8);
        box-shadow: 0 0 0 1000em rgba(0,0,0, .7);
        opacity: 1;
    }

    .introjs-helperLayer:after {
        content: '';
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        position: fixed;
        z-index: 1000;
    }

It will disable introJs' overlay and instead use box-shadow and create a hole in it, which will result in similar behavior.

Note: the last CSS selector:after is probably unnecessary, but I did not have time to test it, so I'm leaving it there, just to be sure. Let me know what you will find out.

This help me a lot !!!! Thanks

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

I believe the correct solution was proposed here by @bozdoz https://github.com/usablica/intro.js/pull/826

Working on a fix here: https://github.com/usablica/intro.js/pull/1075

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexandernst picture alexandernst  Â·  5Comments

jaesung2061 picture jaesung2061  Â·  9Comments

Themandunord picture Themandunord  Â·  3Comments

danielgolden picture danielgolden  Â·  7Comments

cssagogo picture cssagogo  Â·  4Comments