Dialog 弹窗也有“花活”?针不戳~

6,253 阅读3分钟

冲浪,看到一个 API HTMLDialogElement.showModal() - Web APIs | MDN

想想一直以来用 UI 框架的组件用惯了,即使自己写 Dialog,也只会老一套,用 JS + CSS display 属性来控制弹窗的显示和隐藏。

现在竟然直接有 API 方法了,纯 JS 实现。

🎉HTMLDialogElement.showModal()

赶紧码上掘金试一试,

code.juejin.cn/pen/7169464…

掘了,一点 CSS 不带:

当然,有一点 CSS 不带的 Dialog 弹窗,相应的,也就有一点 JS 不带的纯 CSS 实现了~

🎉用 :target - CSS: Cascading Style Sheets | MDN 也能实现窗口的打开和关闭:

code.juejin.cn/pen/7169477…

到这,还不足以说明:Dialog 弹窗也有“花活”

称得上花活的是 CSS :modal 伪类属性。

它用来检测当前的弹框,这样避免了在 JS 中管理 CSS

用法:

dialog:modal {
 scale: 2;
}

当出现弹框时,scale 赋值为 2

下面带来一个实战案例:

  • HTML
<div class="warning-message">
  :modal isn't supported in this browser :(
</div>
<dialog>
  <p>I'm a Dialog</p>
  <button>Close</button>
</dialog>
<div class="actions">
  <button data-modal="true">Open Modal</button>
  <button data-modal="false">Open Non-modal</button>
</div>
  • CSS
layer demo {
  dialog[open]:not(:modal) {
    z-index: 2;
    transform-style: preserve-3d;
  }

  dialog[open]:not(:modal):before {
    content: "";
    position: fixed;
    height: 100vh;
    width: 100vw;
    top: 50%;
    left: 50%;
    background: hsl(0 0% 10% / 0.25);
    transform: translate3d(-50%, -50%, -1px);
  }
}

@layer base {
  *,
  *:after,
  *:before {
    box-sizing: border-box;
  }

  body {
    display: grid;
    place-items: center;
    min-height: 100vh;
    background: var(--gradient-3);
    font-family: "Google Sans", sans-serif, system-ui;
  }

  .actions {
    display: flex;
    gap: var(--size-4);
  }

  dialog {
    padding: var(--size-4);
    gap: var(--size-2);
    background: var(--surface-1);
  }

  dialog::backdrop {
    background: hsl(0 0% 10% / 0.5);
  }

  dialog[open] {
    display: grid;
  }

  .warning-message {
    border: var(--size-1) solid var(--yellow-4);
    padding: var(--size-4);
    background: var(--gray-0);
    position: fixed;
    top: var(--size-4);
    left: var(--size-4);
  }
  @supports (selector(:modal)) {
    .warning-message {
      display: none;
    }
  }
}
  • JS
const BUTTONS = document.querySelectorAll("button");
const DIALOG = document.querySelector("dialog");

BUTTONS.forEach((BUTTON) => {
  BUTTON.addEventListener("click", (e) => {
    let modalStyle;
    switch (BUTTON.getAttribute("data-modal")) {
      case "true":
        modalStyle = "showModal";
        break;
      case "false":
        modalStyle = "show";
        break;
      default:
        modalStyle = "close";
    }
    DIALOG[modalStyle]();
  });
});

我们可以检测出非 :modal 的 dialog,为了以示区别,再加一个伪类 :before,做点不一样的样式出来。

image.png

你可以在这里测试:Is it :modal?

需要特别强调的是,它是一个比较新的属性,浏览器兼容目前还比较差,不过我们可以给予适当关注。

image.png

其实,这种思想是非常好的:即避免在 JS 中操作更多的样式。你可以去取值,去共享 CSS 的能力,但是不要去改值,不然样式问题就一团糟了~

细看以上代码还有很多有趣的用法,比如:

@layer ...
@supports (selector(:modal)) {
    .warning-message {
      display: none;
    }
}

你知道它们都是干什么用的吗?

@layer - CSS: Cascading Style Sheets | MDN

@supports - CSS: Cascading Style Sheets | MDN

把代码 clone 在线运行试试,进一寸有一寸的欢喜~


OK,以上便是本篇分享,希望各位工友喜欢~ 欢迎点赞、收藏、评论 🤟

我是掘金安东尼 🤠 100 万人气前端技术博主 💥 INFP 写作人格坚持 1000 日更文 ✍ 关注我,安东尼陪你一起度过漫长编程岁月 🌏

😹 加我微信 ATAR53,拉你入群,定期抽奖、粉丝福利多多。只学习交友、不推文卖课~

😸 我的公众号:掘金安东尼,在上面,不止编程,更多还有生活感悟~

😺 我的 GithubPage: tuaran.github.io,它已经被维护 4 年+ 啦~


本文正在参加「金石计划 . 瓜分6万现金大奖」