usablica / intro.js

Lightweight, user-friendly onboarding tour library
http://introjs.com
Other
22.8k stars 2.59k forks source link

Doesn't work on children of absolute/relative positioned elements #50

Closed m-mitchell closed 10 years ago

m-mitchell commented 11 years ago

introjs_stackingcontextbug

Source for test here: http://pastebin.com/ztyuYjK7 More info about stacking contexts here: http://tinyurl.com/cnxomh5

I think the problem is that the introjs elements are added to the global stacking context, regardless of the stacking context of the target. This causes the overlay and helper layers to be stacked on top of the desired target, instead of underneath.

afshinm commented 11 years ago

Thanks for reporting this problem. Marked as bug.

sayhiben commented 11 years ago

I've actually been spending my morning trying to fix this one. The closest I've come is to rewrite the overlay completely by dividing it into top/left/bottom/right elements and surrounding the highlight area. It mostly works, though animation is a pain and you lose the rounded corners.

Another approach may be to remove the target element and insert it into the highlight temporarily, though this would probably lead to style issues.

pattle commented 11 years ago

I might be overlooking something but why don't you just append the overlay and the help layer to the body rather than the target element. This would be fine because you will only have one intro sequence open at any one time and it would also fix the positioning issue.

afshinm commented 11 years ago

This problem solved on v0.2.1. Isn't it?

sayhiben commented 11 years ago

@pattle Can you clarify? At the moment, the overlay, helperLayer and it's contents are added to the body element, but the highlight is done by adding a class with a high z-index to the targetElement. This method works until the targetElement is a child of another element with a set z-index. The pull request I submitted (and need to clean up) solves this by duplicating the targetElement and making the clone a child of the helperLayer.

pattle commented 11 years ago

I had a problem where I had 2 intro sequences on the same page. I was calling them like introJs(',div1').start() and introJs('.div2').start() etc. intro.js appends the overlay and help layers as childs of the target element and positions them absolutely. This is a problem if any of the parents have position relative because the it means the position is relative to them when they need to be relative to the body, is this correct?

m-mitchell commented 11 years ago

Hey @pattle, sorry, I should have been more clear but I thought the image was self-explanatory. This bug report is about a problem with the layering (z-axis), not positioning (x/y axes). As @casiotone says, the overlay is already added to the body. If the overlay was a child or sibling of the target element, it would layer fine (although as you mention, this would destroy the positioning).

pattle commented 11 years ago

@m-mitchell Yeah sorry I think I posted this in the wrong place. Although I still think there is a problem with the position of the .introjs-helperLayer when its place inside elements that have relative positioning.

minicstudio commented 11 years ago

@m-mitchell , i have to agree with @pattle . Currently the plugin appends the overlay after the target element, and if the parent of that element has position: relative than the positioning is wrong. I think this can be resolved if the overlay is inserted in every case into the body. In my case as i saw the overlay position are calculated based on the top offest (how far is the element from the top of the body) and inserted into a child div of the body which has position: relative in my case, so the positioning is totally wrong. This only happen if i init the plugin for a div

introJs('.minic-content').start();
afshinm commented 11 years ago

@minicstudio Do you any idea about how we can fix that? Or any implementation?

minicstudio commented 11 years ago

@afshinm i think there is two ways. If the overlay will be inserted into the body (than the current position calculation is ok) or if the insertion remains than the position calculation has to be calculated based on the parent element. I think both method should work well (first one seems easier).

afshinm commented 11 years ago

@minicstudio Yeah, fine. And can you help to implement or fix this bug? Then I will merge the bug fix with upstream.

minicstudio commented 11 years ago

@afshinm just append the overlay and overlayHelper into the body all the time. As i tested quickly, its working in any case!!

Of course overlay need

position: fixed;
width: 100%;
heigth: 100%;
top: 0;
left: 0;
Dahs81 commented 10 years ago

I'm not sure if this helps, but it worked for me. I add this after introjs().start(): $('.introjs-fixParent').css('position', 'absolute');

This assume you are using introjs().setOptions() in your js file.

My use case is I have multiple steps in the navbar (NOTE: navbar is outside of body).

bigforcegun commented 10 years ago

I have a same bug in the last version. If intro element have at least one relative parent, the following happens screenshot_18 or screenshot_19

I change function _getOffset(element) with monkey patch for filter relative parents - It incorrectly identifies the position of the overlay and helperLayer.

If necessary, I can recreate the bug on jsfiddle.

stephendeo commented 10 years ago

Ahh i'm having this same issue, i just opened an issue with it.. I've tried some of the stuff on here but nothing...

andyravensable commented 10 years ago

We've also found this bug, only occurring on iOS devices.

We found that it was caused because we had scrolling areas, which were absolutely positioned, and we'd put "-webkit-overflow-scrolling: touch", to ensure smooth scrolling on iOS devices.

To get round it, we went into the introjs.css file (line 22), and added the following line:

.introjs-fixParent {
  z-index: auto !important;
  opacity: 1.0 !important;
  transform: none !important;
  -ms-transform: none !important;
  -webkit-transform: none !important;
  -webkit-overflow-scrolling: auto !important; /* this is the line we added */
}

This assumes that, if you're showing a tour, you're not allowing scrolling whilst the tour is active. It temporarily converts the element with "-webkit-overflow-scrolling: touch" to "-webkit-overflow-scrolling: auto", rendering it temporarily immobile, but allowing it to follow the z-index rules properly, and then returning it back to normal after the tour has ended.

We've tested this on iOS, and can confirm it works.

yPhil-gh commented 6 years ago

It does it (hiding the highlighted elt) for position: fixed parent too ; switching from fixed to absolute solves the problem indeed. Problem is I need fixed :(