admin管理员组

文章数量:1391995

In a pure HTML/CSS website (no JS) with a traditional body structure (header, main and footer), the header contains some buttons for navigation or locale selection using the Popover API. The resulting popover is displayed on the top layer, positioned over the main or footer, below the header (i.e. in viewport plane terms, not the layer stack).

Using CSS ::backdrop allows to style the area "around" the popover, which can be handy. However, it will impact the whole viewport (i.e. all body elements beneath the top layer).

So, what are the alternatives so that the header containing the buttons from which the popovers are activated is still visible and intact (i.e. the backdrop effect would only apply to the main and footer)?

See below the current code, that is affecting the whole viewport (sets a color with transparency over everything), so not exactly what I'm after (i.e. do not set this color for the header):

[popover]::backdrop {
  background: var(--backdrop);
}

:root {
  --backdrop: rgba(255, 255, 255, 0.8);
}
<header>
  <nav>
    <button popovertarget="target">My button</button>
    <ul id="target" popover>
      <!--Some nav stuff that get displayed when My button is clicked-->
    </ul>
  </nav>
</header>
<main>
  <!--Some main stuff that is partially covered when popover-->
</main>
<footer>
  <!--Some footer stuff-->
</footer>

In a pure HTML/CSS website (no JS) with a traditional body structure (header, main and footer), the header contains some buttons for navigation or locale selection using the Popover API. The resulting popover is displayed on the top layer, positioned over the main or footer, below the header (i.e. in viewport plane terms, not the layer stack).

Using CSS ::backdrop allows to style the area "around" the popover, which can be handy. However, it will impact the whole viewport (i.e. all body elements beneath the top layer).

So, what are the alternatives so that the header containing the buttons from which the popovers are activated is still visible and intact (i.e. the backdrop effect would only apply to the main and footer)?

See below the current code, that is affecting the whole viewport (sets a color with transparency over everything), so not exactly what I'm after (i.e. do not set this color for the header):

[popover]::backdrop {
  background: var(--backdrop);
}

:root {
  --backdrop: rgba(255, 255, 255, 0.8);
}
<header>
  <nav>
    <button popovertarget="target">My button</button>
    <ul id="target" popover>
      <!--Some nav stuff that get displayed when My button is clicked-->
    </ul>
  </nav>
</header>
<main>
  <!--Some main stuff that is partially covered when popover-->
</main>
<footer>
  <!--Some footer stuff-->
</footer>

Using backdrop-filter could maybe be an option, how so? What other alternatives do you think of? Thanks in advance!

Share Improve this question edited Mar 12 at 11:11 Ori Drori 194k32 gold badges238 silver badges229 bronze badges asked Mar 12 at 10:38 marcpmarcp 212 bronze badges 3
  • 1 Don't try to do this because you are defeating the purpose of popover that was defined to work exactly like that with the new "top layer" feature. And that feature was defined to avoid having to deal with a z-index war in order to make the popup above everything. Maybe your use case is not suitable for a popover – Temani Afif Commented Mar 12 at 13:40
  • I have to agree with Temani Afif. Always try to use things only for their intended purpose. Not doing so might have strange consequences in the future. In this case there might be browser in which a solution with [popover]::backdrop will work for you, and other browser in which it doesn't. – KIKO Software Commented Mar 12 at 14:14
  • Hi! Thank you all for the input. In the end, I chose a simple tweak to the backdrop style: background: linear-gradient(transparent, transparent var(--header-height), var(--backdrop) var(--header-height), var(--backdrop));. It does the trick in this case. – marcp Commented Mar 13 at 8:34
Add a comment  | 

2 Answers 2

Reset to default 0

<dialog>s are the big brothers of popovers. There's two types of <dialog>s:

  1. Modal: Like popover, it has a ::backdrop, but the modal ::backdrop cannot be dismissed by just clicking it (that can be changed, let me know if you want that posted as well).

  2. Dialog: This type has no ::backdrop.

The JavaScript is very minimal, to open a modal:

document.querySelector("dialog").showModal();

To open a dialog:

document.querySelector("dialog").show();

To close either type:

document.querySelector("dialog").close();

In the example below is a modal, a dialog, and an extra modal I added because I just wanted to see it with a cool ::backdrop.

const openM = document.getElementById("modal-btn");

const openD = document.getElementById("dialog-btn");

const modal = document.getElementById("modal");

const dialog = document.getElementById("dialog");

openM.onclick = e => modal.showModal();

openD.onclick = e => dialog.show();

const closeM = document.querySelector("#modal .close");

const closeD = document.querySelector("#dialog .close");

closeM.onclick = e => modal.close();

closeD.onclick = e => dialog.close();


const modal2 = document.getElementById("modal2");
document.getElementById("modal-btn2").onclick = e => modal2.showModal();

document.querySelector("#modal2 .close").onclick = e => modal2.close();
*,
*::before,
*::after {
  box-sizing: border-box;
}

:root {
  font: 2ch/1.5 "Segoe UI"
}

dialog {
  width: 70vw;
  max-width: 600px;
  border: 0;
  border-radius: 8px;
  box-shadow: rgba(0, 0, 0, 0.25) 0px 54px 55px, rgba(0, 0, 0, 0.12) 0px -12px 30px, rgba(0, 0, 0, 0.12) 0px 4px 6px, rgba(0, 0, 0, 0.17) 0px 12px 13px, rgba(0, 0, 0, 0.09) 0px -3px 5px;
}

dialog header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

h3 {
  margin: 0
}

menu {
  display: flex;
  justify-content: center;
  gap: 0.25rem;
  list-style: none;
  padding: 0
}

button,
input {
  font: inherit;
  cursor: pointer;
  box-shadow: rgba(6, 24, 44, 0.4) 0px 0px 0px 2px, rgba(6, 24, 44, 0.65) 0px 4px 6px -1px, rgba(255, 255, 255, 0.08) 0px 1px 0px inset;
}

dialog button {
  width: 2rem;
  padding-inline: 0.25rem;
}

.close {
  width: 1.5rem;
  height: 1.5rem;
  padding-inline: 0.25rem;
}

#modal::backdrop {
  background: rgba(0, 0, 0, 0.3);
}

#modal2::backdrop {
  --s: 5rem;
  --c1: #3eb3d0;
  --c2: #7d3636;

  --G:
    var(--c2) 6% 14%, var(--c1) 16% 24%, var(--c2) 26% 34%, var(--c1) 36% 44%,
    var(--c2) 46% 54%, var(--c1) 56% 64%, var(--c2) 66% 74%, var(--c1) 76% 84%, var(--c2) 86% 94%;
  background:
    radial-gradient(100% 100% at 100% 0, var(--c1) 4%, var(--G), #0008 96%, #0000),
    radial-gradient(100% 100% at 0 100%, #0000, #0008 4%, var(--G), var(--c1) 96%) var(--c1);
  background-size: var(--s) var(--s);
}
<header>
  <nav>
    <button id="modal-btn">Open Modal</button>
    <button id="dialog-btn">Open Dialog</button>
    <button id="modal-btn2">Open Modal</button>
  </nav>
  <dialog id="dialog">
    <header>
      <h3>Dialog</h3> <input class="close" type="button" value="&#128940;">
    </header>
    <menu>
      <li><button>VI</button></li>
      <li><button>VII</button></li>
      <li><button>VIII</button></li>
      <li><button>IX</button></li>
      <li><button>X</button></li>
    </menu>
  </dialog>
</header>
<main>
  <p>The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children. And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers. And you will know My name is the Lord when I lay My vengeance upon thee. </p>
</main>
<footer>
  Some footer stuff
</footer>

<dialog id="modal">
  <header>
    <h3>Modal</h3> <input class="close" type="button" value="&#128940;">
  </header>
  <menu>
    <li><button>I</button></li>
    <li><button>II</button></li>
    <li><button>III</button></li>
    <li><button>IV</button></li>
    <li><button>V</button></li>
  </menu>
</dialog>

<dialog id="modal2">
  <header>
    <h3>Modal</h3> <input class="close" type="button" value="&#128940;">
  </header>
  <menu>
    <li><button>XI</button></li>
    <li><button>XII</button></li>
    <li><button>XIII</button></li>
    <li><button>XIV</button></li>
    <li><button>XV</button></li>
  </menu>
</dialog>

If anchor positioning is supported, you can set the header as anchor, and anchor the top of the backdrop to it, so the backdrop would appear under the header:

header {
  anchor-name: --headerAnchor;
}

[popover]::backdrop {
  top: anchor(--headerAnchor bottom);
  background: var(--backdrop);
}

:root {
  --backdrop: red;
}
<header>
  <nav>
    <button popovertarget="target-1">Show 1</button>
    <button popovertarget="target-2">Show 2</button>
    <div id="target-1" popover>popover 1</div>
    <div id="target-2" popover>popover 2</div>
  </nav>
</header>

If you can't use anchor positioning you'll have to set a static value:

[popover]::backdrop {
  top: 2lh;
  background: var(--backdrop);
}

:root {
  --backdrop: red;
}
<header>
  <nav>
    <button popovertarget="target-1">Show 1</button>
    <button popovertarget="target-2">Show 2</button>
    <div id="target-1" popover>popover 1</div>
    <div id="target-2" popover>popover 2</div>
  </nav>
</header>

本文标签: htmlBackdrop alternative letting specific selectors intactStack Overflow