oddbird / popover-polyfill

Polyfills the HTML popover attribute and showPopover/hidePopover/togglePopover methods onto HTMLElement, as well as the popovertarget and popovertargetaction attributes on <button> elements.
BSD 3-Clause "New" or "Revised" License
240 stars 14 forks source link

Recommended example for :backdrop #75

Open jh3y opened 1 year ago

jh3y commented 1 year ago

Hey 👋

Might be cool to have some kind of support for :backdrop behavior or a heads-up on how you might implement that yourself.

Could be in something like:

[popover].:open:before { ...backdropStyles }
@supports ([popover]:backdrop) { ...backdropStyles }

Although using the pseudoelement runs into the issue of getting the :backdrop beneath the content. Might be nice to give some kind of guided snippet for those wanting that behavior 👍

@jh3y

joshnuss commented 7 months ago

One solution to keep the backdrop beneath everything, is to use :has():

::backdrop, body:has(.\:popover-open)::before { 
  z-index: 1;
  content: '';
  width: 100%;
  height: 100%;
  position: fixed;
  left: 0;
  top: 0;

  background: #0004;
  backdrop-filter: blur(2px); 
}

.\:popover-open {
  z-index: 2;
}

[popup]:popover-open {
  z-index: 2;
}
jgerigmeyer commented 6 months ago

@mirisuzanne @keithamus What do you think about this? Seems related to #130

mirisuzanne commented 6 months ago

I agree these are the same issue - so we could close the newer one as a duplicate. Overall, I think it's a good idea to provide a solution here. I'd have to play around with the different options to know what solution I like best. It seems to me like providing an additional wrapping element might be the most robust solution?

jgerigmeyer commented 6 months ago

I closed the newer issue. @mirisuzanne Is this something you'd have time to look at? Or maybe @stacyk?

mirisuzanne commented 6 months ago

Looking again, I think the body:has() trick from @joshnuss is pretty promising. Could simplify a bit, maybe:

/* This could be built into the polyfill */
body:has(.\:popover-open)::before { 
  content: '';
  position: fixed;
  inset: 0;
}

/* This is the snippet for authors to use */
::backdrop,
body:has(.\:popover-open)::before {
  /* backdrop styles */
}

I don't think we need the z-index stuff, since both parts will be positioned, and body::before should default to the bottom of the stack. I also replaced the combo top + left + width + height with just inset: 0.

But someone should probably test that.

mirisuzanne commented 6 months ago

If we don't want to require :has() support, we could probably just inject an element at the start of the body - and do something similar with it?

joshnuss commented 6 months ago

Another solution for avoiding :has could be to add a class to the <body> element when the popover is open.

onelonemonkey commented 4 months ago

One solution to keep the backdrop beneath everything, is to use :has():

::backdrop, body:has(.\:popover-open)::before { 
  z-index: 1;
  content: '';
  width: 100%;
  height: 100%;
  position: fixed;
  left: 0;
  top: 0;

  background: #0004;
  backdrop-filter: blur(2px); 
}

.\:popover-open {
  z-index: 2;
}

[popup]:popover-open {
  z-index: 2;
}

I've tried implementing this on a large application and ran into all sorts of issues with z-index, positioning and overflow, it works perfectly in isolation but the TopLayer breaks free of constraints natively however even though the backdrop works, the popover is still bound by surrounding elements and their styles in the DOM.