这是一个来自 Moritz Gießmann 的 简单演示,它展示了如何为<details>元素的三角形添加动画,这个三角形是 提示,它告诉人们这个东西可以打开。为它添加动画,也是一种提示,告诉人们这个东西正在打开。
技巧?
- 关闭默认的三角形:
details summary::-webkit-details-marker { display:none; }
。你不能为它添加动画。 - 使用 CSS 边框技巧 和 伪元素 创建一个替代的三角形。
- 在打开状态时为新三角形添加动画:
details[open] > summary::before { transform: rotate(90deg); }
。
这只会为三角形添加动画。里面的内容仍然“突然”打开。想让它更平滑吗?Louis Hoebregts 的 “如何使用 WAAPI 为<details>元素添加动画” 涵盖了这一点。
这里有一个我将它们结合在一起的分支,因为
我看到 Moritz 也在<summary>上添加了 cursor: pointer;
,就像 Greg Gibson 建议的那样.
你也可以只用 CSS 为<details>元素添加动画。
不如 JS 解决方案平滑。
但也是一个不错的纯 CSS 解决方案。
互联网的妙处在于,你分享了令人惊叹的东西,其他人也会分享令人惊叹的东西。❤
这是一个纯 CSS 版本,它与你最终使用 CSS 和 JS 的版本一样工作。
太酷了。我还不知道。感谢你和 Moritz 的付出。保持创造力!
有没有办法只用 CSS 为关闭添加动画?
是的,可以使用类似于使用复选框的技巧。
将内容移动到元素**之后**,并使用你喜欢的隐藏方式,使用兄弟选择器
details:not([open]) + .content
。原因
该元素以编程方式隐藏其内容。CSS 无法延迟它,因此关闭动画在内容隐藏后发生。
进一步的障碍
为<height>添加动画需要预先计算的值,<auto> 不会添加动画。如果内容的高度不固定,则需要 JS 来测量内容并将高度存储在 CSS 变量中。
纯 CSS 解决方案仍然可以通过为其他属性添加动画来实现。
如果内容是绝对定位的,则为<opacity>添加动画是显示/隐藏的好方法。
如果内容在文档流中,则需要其他技巧。为内容的子元素的<margin-top>添加动画使其变为足够大的负值可以是一个解决方案,尽管效率低下且很 hacky。但它有效。适合无 JS 备用方案,如果启用了 JS,它可以进行适当的<heigth>动画。但这会增加更多维护和测试时间。
示例
codepen[yLMmmVb][350]
我也尝试创建了一个纯 CSS 解决方案。关闭不平滑,但打开比较优雅:https://codepen.io/dada1smo/pen/LYydWBg
嗨!首先,内容很棒。关于代码本身,我有两个问题。
我使用 TypeScript 和 Angular 来实现它,你编写的这些函数都会在另一个函数内部调用,而这个函数会在点击<details>元素时调用一次。
它们在 forEach 内部被调用,像这样
…
isOpen = () => {
let allDetails = document.querySelectorAll(“details”);
allDetails.forEach(details => {
let summaryContent = details.querySelector(‘summary’) as HTMLElement;
let subContent = details.querySelector(‘.nav_sub_link’) as HTMLElement;
summaryContent.addEventListener(‘click’, (e) => onClick(e));
…
动画正在工作,只需要一些调整。但 onClick() 函数只会在第一次点击<details>元素时被调用,因此“else if”部分会在那时被调用。
我仍然是 TypeScript 和 JavaScript 的新手,所以我很难找到罪魁祸首。
有什么建议吗?
谢谢。
为什么评论中的所有纯 CSS 解决方案只在第一次点击时有效?
第一次点击是平滑的,但在关闭并重新打开后,你只会在第一次尝试时获得效果?
@David
我在不同的浏览器中也遇到了同样的问题。
Firefox:在打开时过渡<opacity>每次都有效
Chrome:在打开时过渡<opacity>第一次有效
Safari:在打开时过渡<opacity>永远无效
我真的很困惑,还没找到这个问题的解决方案。我尝试使用动画而不是过渡,但我在所有浏览器中都没有得到好的结果。
三角形的动画在运行在 macOS Monterey 上的 Safari 版本 16 中不起作用 :(((
<details> 标签主要是出于可访问性原因创建的。如果你使用点击事件,你基本上会破坏所有功能(例如屏幕阅读器)。你应该始终使用在任何情况下都会触发的切换事件,并且绝不使用点击事件,除非你只想针对桌面用户。
我发现两种只用 CSS 为<details>元素的打开和关闭添加动画的方法,不需要 JavaScript。一种方法使用相邻兄弟选择器 (+),另一种使用 :has() 伪类。两者都非常有效,并能提供平滑的动画。
以下是使用我的两种方法的文章示例:https://codepen.io/jgustavoas/pen/zYLNKbN
主要的关键是让页面以其打开状态(<details open>)开始,然后通过切换复选框更改其<max-height>值,并使用过渡效果为该更改添加动画。
为了控制元素的<max-height>值的更改,你需要一个复选框,并将其与<details>元素关联起来。你可以选择两种方法来做到这一点,两者都非常有效
1) 使用 + 相邻兄弟选择器
2) 使用 :has() 伪类
两种方法之间的区别在于,在第一种方法中,复选框输入必须紧挨在<details>元素之前,而在第二种方法中,复选框必须是<details>元素的后代。
在<details>元素的<summary>标签中,放置一个<label>,它会切换复选框
使用 :has() 方法时需要注意的一点是,在 Firefox 中,用户必须显式启用此功能(参见 caniuse.com 和 MDN Web Docs)。