Skip to content

Overlay element that overcomes the stacking context trap

Notifications You must be signed in to change notification settings

rslawik/iron-overlay

 
 

Repository files navigation

Build Status

The problem

Overlays should always render on the top layer. This is achieved using the css properties position: fixed and z-index. When an overlay is contained in a node that creates a new stacking context, it causes the overlay to be trapped within it (z-index and position will be relative to the new stacking context), resulting in problems like this one:

<style>
  .backdrop {
    position: fixed;
    top: 0; bottom: 0;
    left: 0; right: 0;
    z-index: 100;
    background-color: rgba(0, 0, 0, 0.5);
  }
  .overlay {
    position: fixed;
    z-index: 999;
  }
</style>
<div class="backdrop"></div>
<!-- this creates a new stacking context -->
<div style="transform: translateZ(0);">
  <div class="overlay">
    <button>click me!</button>
  </div>
</div>

iron-overlay works around this issue by "teleporting" its content to a stacking-context-safe node.

<!-- this creates a new stacking context -->
<div style="transform: translateZ(0);">
  <button onclick="this.nextElementSibling.opened = true">Open overlay</button>
  <iron-overlay>
    <template>
      <!-- overlay content -->
      This text will be stamped and appended to the document body.
    </template>
  </iron-overlay>
</div>

iron-overlay

It delegates rendering of the overlay content to a renderer (iron-overlay-renderer). It won't host the renderer, but request another element to host it through the events iron-overlay-attach and iron-overlay-detach, or append it to <body>. It requires overlay contents to be contained in a <template> (since they need to be hosted in the renderer).

iron-overlay-renderer

Takes care of the rendering (e.g. center overlay), and handles the switch from opened state to closed state & viceversa.

iron-overlay-container

Hosts the overlay renderers, keeps track of the opened overlays. This element should be placed in a stacking-context safe node (e.g. document.body).

<div style="transform: translateZ(0);">
  <button onclick="this.nextElementSibling.opened = true">Open overlay</button>
  <iron-overlay>
    <template>
      <!-- overlay content -->
      This text will be contained in iron-overlay-content
    </template>
  </iron-overlay>
</div>

<!-- it will contain all the overlay renderers -->
<iron-overlay-container></iron-overlay-container>

Styling

Styling must be done in the context of where iron-overlay will be hosted.

Styling the renderer

iron-overlay sets the renderer's data-overlay attribute to be its id, so that styling of the overlay can be done like this:

<custom-style><style is="custom-style">
  [data-overlay] {  
    --iron-overlay-background-color: yellow;
  }
  [data-overlay="overlay1"] {
    --iron-overlay-background-color: orange;
  }
</style></custom-style>

<div style="transform: translateZ(0);">
  <iron-overlay>
    <template>Overlay Content</template>
  </iron-overlay>
  <iron-overlay id="overlay1">
    <template>Overlay 1 Content</template>
  </iron-overlay>
</div>

Styling the content

Content can be styled by passing a <style> element into the template, but beware of possible conflicts with classes, as selectors will apply to all matching elements in the styling context where they're hosted:

<iron-overlay>
  <template>
    <style>
      .my-content {
        background-color: yellow;
      }
    </style>
    <div class="my-content">Content</div>
  </template>
</iron-overlay>

<iron-overlay>
  <template>
    <!-- Will have yellow background as well -->
    <div class="my-content">Other Content</div>
  </template>
</iron-overlay>

The best approach to ensure style encapsulation is to create a custom element for your content.

<iron-overlay>
  <template>
    <my-content>Content</my-content>
  </template>
</iron-overlay>

<iron-overlay>
  <template>
    <my-other-content>Other Content</my-other-content>
  </template>
</iron-overlay>

About

Overlay element that overcomes the stacking context trap

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • HTML 100.0%