首页 > web前端 > css教程 > 弹出气球

弹出气球

Joseph Gordon-Levitt
发布: 2025-03-08 10:12:10
原创
797 人浏览过

HTML和CSS的强大功能总是令人惊叹不已。Popover API 的全新交互特性再次证明了仅使用这两种语言就能实现的惊人效果。

您可能已经看过其他教程展示了Popover API 的功能,但这篇文章更侧重于将其“彻底征服”。我们将添加一些额外的“趣味”元素,例如气球……一些字面意义上的“爆破”效果。

我使用仅HTML和CSS(当然)创建了一个游戏,并依赖于Popover API。您的任务是在一分钟内尽可能多地戳破气球。但要小心!有些气球(正如咕噜所说)是“狡猾的”,会触发更多气球。

我巧妙地将其命名为Pop(over) the Balloons,我们将一步一步地一起制作它。完成后,它看起来会像(好吧,完全像)这样:

Pop(over) the Balloons

处理popover属性

只要我们使用popover属性对其进行设计,任何元素都可以作为弹出框:

<div popover="">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

我们甚至不需要为popover提供值。默认情况下,popover的初始值为auto,并使用规范中所谓的“轻量级关闭”。这意味着可以通过点击弹出框外部的任何位置来关闭弹出框。当弹出框打开时,除非它们嵌套在一起,否则页面上的任何其他弹出框都会关闭。auto弹出框就是这样相互依赖的。

另一个选项是将popover设置为manual值:

<div popover="manual">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

这意味着元素是手动打开和关闭的——我们必须点击一个特定的按钮才能打开和关闭它。换句话说,manual创建了一个顽固的弹出窗口,只有当您点击正确的按钮时才会关闭,并且完全独立于页面上的其他弹出窗口。

使用
元素作为起点

使用Popover API构建游戏的挑战之一是,您无法加载页面时弹出框已经打开……如果我们的目标是仅使用HTML和CSS构建游戏,则无法使用JavaScript解决这个问题。

这时就需要details元素。与弹出框不同,details元素可以默认打开:

&lt;details open=&quot;&quot;&gt;&lt;/details&gt;
登录后复制
登录后复制
登录后复制

如果我们采用这种方法,我们就可以显示一堆按钮(气球),并通过关闭<code><details></details>来“戳破”所有气球,直到最后一个气球。换句话说,我们可以将起始气球放在打开的<code><details></details>元素中,以便在加载页面时显示它们。

这就是我所说的基本结构:

<details open=""><summary>?</summary>???</details>
登录后复制
登录后复制

这样,我们可以点击<summary></summary>中的气球来关闭<code><details></details>并“戳破”所有按钮气球,留下一个气球(最后的<summary></summary>(稍后我们将解决如何移除它)。

您可能会认为<dialog></dialog>对于我们的游戏来说是一个更有语义的方向,您是对的。但是使用<dialog></dialog>有两个缺点,我们在这里无法使用它:

  1. 唯一能够关闭页面加载时打开的<dialog></dialog>的方法是使用JavaScript。据我所知,没有我们可以添加到游戏中来关闭页面加载时打开的<dialog></dialog>的关闭方法。
  2. <dialog></dialog>是模态的,并在打开时阻止点击其他内容。我们需要允许玩家戳破<dialog></dialog>之外的气球才能击败计时器。

因此,我们将使用&lt;details open=&quot;&quot;&gt;&lt;/details&gt;元素作为游戏的顶级容器,并使用普通的<div>作为弹出窗口本身,即<code><div popover="">。目前,我们只需要确保所有这些弹出框和按钮都连接在一起,以便点击按钮打开弹出框。您可能已经从其他教程中学到了这一点,但是我们需要告诉弹出框元素它需要响应哪个按钮,然后告诉按钮它需要打开哪个弹出窗口。为此,我们为弹出框元素提供一个唯一的ID(所有ID都应该是),然后在按钮上使用<code>popovertarget属性引用它:

<div popover="">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

当所有内容都连接在一起时,这就是想法:

打开和关闭弹出框

在最后一个演示中,还需要做一些工作。到目前为止,游戏的一个缺点是,点击弹出窗口的按钮会打开更多弹出窗口;再次点击同一个按钮,它们就会消失。这使得游戏过于简单。

我们可以通过在按钮上设置popovertargetaction属性(不,HTML规范作者并不关心简洁性)来分离打开和关闭行为。如果我们将属性值设置为showhide,则按钮将仅对该特定弹出框执行一项操作。

<div popover="manual">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

请注意,我在<div>内添加了一个新的按钮,该按钮设置为目标另一个<code><div>,通过故意<em>不</em>在上面设置<code>popovertargetaction属性来打开或关闭。看看“戳破”元素是多么具有挑战性(以一种好的方式):

样式气球

现在我们需要为<summary></summary>和按钮元素设置相同的样式,以便玩家无法区分它们。请注意我说的是<summary></summary>而不是<code><details></details>。这是因为<summary></summary>是我们点击打开和关闭<code><details></details>容器的实际元素。

大部分工作都是标准的CSS工作:设置背景、填充、边距、大小、边框等。但是有一些重要的事情,并非一定直观,需要包含在内。

  • 首先,在<summary></summary>元素上将list-style-type属性设置为none,以去除指示<code><details></details>是否打开或关闭的三角形标记。该标记非常有用,并且默认情况下非常好,但是对于这样的游戏,最好删除该提示以获得更好的挑战。
  • Safari不喜欢同样的方法。要在此处删除<code><details></details>标记,我们需要设置一个特殊的供应商前缀伪元素,summary::-webkit-details-marker设置为display: none;
  • 如果鼠标光标指示气球是可点击的,那就太好了,因此我们也可以在<summary></summary>元素上设置cursor: pointer
  • 最后一个细节是在<summary></summary>上设置user-select属性为none,以防止气球(只是表情符号文本)被选中。这使它们更像页面上的对象。
  • 是的,现在是2024年,我们仍然需要该前缀-webkit-user-select属性来考虑Safari支持。谢谢,苹果。

将所有这些代码放在我们将用于按钮和<summary></summary>元素的.balloon类中:

<div popover="">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

气球的一个问题是,其中一些气球是故意什么也不做的。这是因为它们关闭的弹出框没有打开。玩家可能会认为他们没有点击/点击特定气球或游戏坏了,因此让我们在气球处于点击的:active状态时添加一些缩放:

<div popover="manual">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

奖励:因为光标是一只指向其食指的手,所以点击气球有点像手用手指戳气球。???

我们在屏幕上分配气球的方式是另一个需要考虑的重要因素。如果没有JavaScript,我们就无法随机放置它们,所以这是不可能的。我尝试了很多方法,例如创建我自己的“随机”数字,定义为可作为乘数使用的自定义属性,但我无法在不重叠气球或建立某种视觉模式的情况下获得整体“随机”效果。

我最终使用一个类来在不同的行和列中定位气球的方法——不像CSS网格或多列,而是基于物理内插的虚构行和列。它看起来有点像网格,而且不像我想要的那样“随机”,但是只要没有气球具有相同的两个类,它们就不会相互重叠。

我决定使用一个8×8的网格,但留空了第一“行”和“列”,这样气球就不会遮挡浏览器的左边缘和上边缘。

&lt;details open=&quot;&quot;&gt;&lt;/details&gt;
登录后复制
登录后复制
登录后复制

祝贺玩家(或不祝贺)

我们已经准备好大部分游戏组件,但是最好有一个胜利的弹出框来祝贺玩家在规定时间内成功戳破所有气球。

一切都回到了&lt;details open=&quot;&quot;&gt;&lt;/details&gt;元素。一旦该元素打开,游戏就应该结束,最后一步是戳破最后一个气球。因此,如果我们给该元素一个ID,例如#root,我们可以创建一个条件,当它处于未打开状态时使用display: none;将其隐藏:

<div popover="">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

在这里,拥有:has()伪选择器非常棒,因为我们可以使用它来选择#root元素的父元素,以便当#root关闭时,我们可以选择该父元素的子元素——一个具有#congrats ID的新元素——来显示一个伪弹出框,向玩家显示祝贺消息。(是的,我知道这很讽刺。)

<div popover="manual">...</div>
登录后复制
登录后复制
登录后复制
登录后复制

如果我们在此时玩游戏,我们可以在没有戳破所有气球的情况下收到胜利信息。同样,手动弹出框不会关闭,除非点击正确的按钮——即使我们关闭其祖先<code><details></details>元素。

有没有办法在CSS中知道弹出框是否仍然打开?是的,输入:popover-open伪类。

:popover-open伪类选择一个打开的弹出框。我们可以将其与之前的:has()结合使用,以防止在页面上仍然打开弹出框时显示消息。以下是将这些内容链接在一起以像and条件语句一样工作的方法。

&lt;details open=&quot;&quot;&gt;&lt;/details&gt;
登录后复制
登录后复制
登录后复制

现在,只有当玩家真正获胜时,才会收到祝贺。

相反,如果玩家无法在一分钟计时器到期前戳破所有气球,我们应该通知玩家游戏结束。由于我们在CSS中没有if()条件语句(至少现在还没有),我们将运行一分钟的动画,以便此消息淡入以结束游戏。

<details open=""><summary>?</summary>???</details>
登录后复制
登录后复制

但是我们不希望失败消息在胜利屏幕显示时触发,因此我们可以编写一个选择器来防止#fail消息与#congrats消息同时显示。

<details open=""><summary>?</summary>?</details><div popover="manual">
  <h2>Level 1 Popup</h2>
</div>
登录后复制

我们需要一个游戏计时器

玩家应该知道他们有多少时间戳破所有气球。我们可以使用一个元素创建一个相当“简单”的计时器,该元素占据屏幕的全部宽度(100vw),在水平方向上缩放它,然后将其与上面的动画匹配,该动画允许#fail消息淡入。

<details open=""><summary>?</summary>??</details><div popover="manual">
  <h2>Level 1 Popup</h2>?
</div>
登录后复制

只有一个失败点可能会使游戏过于简单,因此让我们尝试添加第二个<code><details></details>元素,并使用第二个“root”ID,#root2。同样,我们可以使用:has检查#root#root2元素是否都没有打开,然后再显示#congrats消息。

.balloon {
  background-color: transparent;
  border: none;
  cursor: pointer;
  display: block;
  font-size: 4em;
  height: 1em;
  list-style-type: none;
  margin: 0;
  padding: 0;
  text-align: center;
  -webkit-user-select: none; /* Safari fallback */
  user-select: none;
  width: 1em;
}
登录后复制

总结

剩下的唯一事情就是玩游戏!

有趣,对吧?我确定我们可以在没有自我强加的无JavaScript方法限制的情况下构建更强大的东西,而且我们并没有认真对待可访问性,但是将API推向极限既有趣具有教育意义,对吧?

我很感兴趣:您还能想到哪些古怪的想法来使用弹出框?也许您想到了另一个游戏、一些漂亮的UI效果,或者一些巧妙的方法将弹出框与其他新兴的CSS功能(如锚点定位)结合起来。无论是什么,请分享!

以上是弹出气球的详细内容。更多信息请关注PHP中文网其他相关文章!

上一篇:速度与接近的交集 下一篇:上次CSSWG会议之后,CSS的东西I&#039;
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
最新问题
关于CSS思维导图的课件在哪? 课件
来自于 2024-04-16 10:10:18
0
0
2520
相关专题
更多>
热门推荐
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板