Article
0 comment

Inconvenient page setup on modern pages or broken z-index behaviour

Consider the following simple scenario. You like to write a new SPFx web part, and you have the requirement to show a popup or a flyout container opened from a web part. This flyout menu should overlay whatever comes after your web part.

See the Pen SPFx flyout container – Base Setup by Stefan Bauer (@stfbauer-the-sans) on CodePen.0

The red containers could be web part one. The yellow box is the flyout/callout that should be only visible on hover. The teal box, on the other hand, is the following web part. Fully working as intended, it looks like this.

See the Pen SPFx flyout container – Hover by Stefan Bauer (@stfbauer-the-sans) on CodePen.0

So when you hover the red box, you should see the flyout element over the teal box again.

The CSS is pretty much straight forward. The red container is position relative, which is only an attribute but does not change its position on the page. The flyout inside the red box is positioned absolute and relative to the parent container. In other words, positioned absolutely to the red box.

Move this sample over to SharePoint should be theoretically an easy task. Everything in this sample stays in the web part. No DOM manipulated or what so ever required, not even JavaScript or ReactJS.

The SPFx behaviour of this sample

The sample seems to work in the local workbench.

Local workbench in edit view

Local workbench in edit view

At least the flyout overlays the second web part perfectly at least in the edit mode of the local workbench.

Local workbench in preview mode

Local workbench in preview mode

The same works in the preview page of the local workbench. Seems to be a legit solution. To make sure everything is working in its last real habitat, in SharePoint.

page edit mode in SharePoint

Page Edit mode in SharePoint

It seems to work in SharePoint on Office 365 in edit mode too, but once the page was published the web part flyout element of the first web part slides below the second web part and therefore get overplayed by the next sibling content.

Page View Mode in SharePoint

Page View Mode in SharePoint

This malicious behaviour becomes more evident when the flyout height is even higher, then it is entirely under the other web part.

Where is the problem? The Z-Index of the overall page setup

While researching this issue, I executed a lot of tests and research on this. The only conclusion is that someone in the background of the overall page layout messes around with positioning and therefore the z-index even if there is non-explicit applied.

The overall page setup follows the following relevant properties.

ClasszIndexpositiondisplayoverflow
.CanvasComponentautorelativeblockvisible
.Canvasautorelativeblockvisible
.CanvasZoneContainerautorelativeblockvisible
.CanvasZoneautostaticblock visible
 .CanvasSection auto relative block visible
 .ControlZone auto staticblockvisible
.ControlZoneEmphasisBackgroundautostatic blockvisible
 .ControlZone-controlauto staticblock visible
 .Canvas-slideUpInauto static block visible

Overall nothing seems suspicious, but still, the z-index property at some point gets broken. Sadly increasing the z-index of the flyout does not have any effect at all on the web part.

Solution: Fix the z-Index yourself on the page for now

The only fix, for now, involves bad DOM or CSS manipulation and it is no long term correct solution. Sadly yet the only solution for now.

To re-stack the page properly again the z-Index of the ‘.CanvasZoneContainer’ and ‘.ControlZone’ needs an adjustment. Also, the position of the ‘.ControlZone’ needs to have position: relative. The following script accomplishes that.

private fixAllZIndex = () => {

  // Adjust z-index for web part zones
  let zIndexContainer = document.querySelectorAll(".CanvasZoneContainer");

  let zIndex = zIndexContainer.length;

  zIndexContainer.forEach((elem, index) => {

    (<HTMLElement>elem).style.zIndex = (zIndex - index).toString();

  });

  // Adjust z-index for web parts
  let zIndexControlZone = document.querySelectorAll(".ControlZone");

  zIndex = zIndexControlZone.length*5;

  zIndexControlZone.forEach((elem, index) => {

    (<HTMLElement>elem).style.zIndex = (zIndex - index).toString();
    (<HTMLElement>elem).style.position = "relative";

  });

}


public render(): void {
  const element: React.ReactElement<IFlyoutContainerProps > = React.createElement(
    FlyoutContainer,
    {
      description: this.properties.description
    }
  );

  ReactDom.render(element, this.domElement);

  // fix z-index after web part is rendered
  this.fixAllZIndex();
}

First is a query for all ‘.CanvasZoneContainer’ DIV-elements and decrease the z-index by one. So it reorders the web part zones and inverts the stack order.

The ‘.ControlZone’ z-index gets increased by 5 for every web part on the page. Position relative on the web part itself has then its stack order exclusively for the flyout. The z-index of this element is 10 directly in the CSS.

The result is that in every case, the flyout hovers over the other web part parts.

Fixed flyouts through z-index adjustments

Fixed flyouts through z-index adjustments

The problem is now solved at least until the overall causing issue is solved.

Alternatively Callouts from Office UI Fabric for the rescue?

If you think all your code should stay in the web part and DOM manipulations are evil, then Callout out of the Office UI Fabric is not an alternative in any web part.

Office UI Fabric Callouts

Office UI Fabric Callouts

The way this callout works is that the content of the callout gets hidden attached right before the body tag of the page. When the callout then gets activated, it gets positioned in an absolute way on the page next to the calling UI Element.

Resizing the browser without repositioning the callout is no option anymore. Instead, the callout gets removed from the page. On the callout test page this behaviour can easily be tested. After the resize, the user needs to open the callout element again. They are not responsive in any way.

Finally

I really hope this issue will be fixed soon on modern pages because it does not make sense to hack the DOM of a SharePoint Page like shown here. If you really need to apply this fix it should be a temporary rather than permanently solution.

It makes me also somewhat sad the see that in case of web part development Office UI Fabric doesn’t have a better solution to offer than this heavy DOM manipulation.

To give my solution a try you will find the source code on GitHub.