《HTML并不简单:Web前端开发精进秘籍》张鑫旭 笔记

自带交互的details元素

可以实现几乎任意的通过点击行为触发的展开和收起效果。

<details>元素通常和<summary>元素同时使用。

<details open>
	<summary>这是摘要</summary>
	<p>这里具体描述</p>
</details>

在这里插入图片描述
点击summary标签可以展开或收起下面的内容。

对于这段代码:

  • <details>元素是整个交互的核心,即使没有设置<summary>元素,也可以通过切换open属性决定里面内容的显示与隐藏
  • <summary>元素表示摘要,是点击行为的触发源,也就是在默认情况下,我们通过点击<summary>元素来影响交互行为的发生
  • 若设置open属性,则默认展开;未设置默认隐藏
  • 如果没有设置summary,浏览器会自动补上:Chrome自动生成“详情”,Edge自动生成“详细信息”
  • 自动创建的<summary>元素是写在Shadow DOM中的,外部CSS无法改变样式
  • 在实际开发中,若不想出现summary,可以手动写一个隐藏的
<summary hidden></summary>

作者示例:https://www.htmlapi.cn/3/1-1.html

自定义样式

改变颜色:

summary::marker {
    color: pink;
}

改变位置,比如小三角改到右边:

summary {
    width: fit-content;
    direction: rtl;
}

自定义小三角图标:隐藏浏览器原生的标记符,再使用::before或::after伪元素模拟

在这里插入图片描述

案例

details/summary元素实际使用案例 (htmlapi.cn)

  • 悬浮菜单,自定义下拉框
  • 多项菜单折叠
  • 多级嵌套的树形菜单

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

全新name属性

目前仅Chrome和Safari浏览器支持。

如果多个<details>元素设置了相同的name属性值,则这些<details>元素之间会形成互斥关系,即同一时间只有一个<details>元素可以展开,其他的元素会自动收起。

在这里插入图片描述

dialog元素

对话框元素 - HTML(超文本标记语言) | MDN (mozilla.org)

只要没有兼容性方面的顾虑,对话框效果,使用dialog元素实现一定是最佳解决方案

<dialog>对话框的主体内容可以是任何HTML元素。

<dialog open>
	<p>aaaaa</p>
</dialog>

在这里插入图片描述
如果我们使用open属性或者使用dialog.open()方法打开对话框,则对话框默认并不是在屏幕的垂直中心位置,而是在<dialog>元素所在的DOM树位置附近

dialog还有一些无可替代的使用特性。

form元素与对话框自动关闭

对话框元素中往往都会有一两个按钮不参与任何业务逻辑处理,其作用仅仅是关闭对话框,例如Alert类型对话框的确认按钮,或者是对话框右上角的图标字样的关闭按钮。

可以直接使用HTML实现这种功能,不需要借助JS。

dialog元素表单提交自动关闭 (htmlapi.cn)

 <dialog open>
     <p>hello world</p>
     <form method="dialog">
         <button>我知道了</button>
     </form>
 </dialog>

点击【我知道了】,对话框会关闭。

关键:在form元素上设置了method='dialog',一个表单新特性。声明此属性后,提交表单元素时,不会刷新页面或打开新窗口,而是关闭当前dialog对话框元素。

表单提交的按钮只能是submit性质的按钮。因此,【我知道了】按钮不能设置为type="button"或者type="reset"

button的type只有submit、button和reset。
只有type='submit'会关闭对话框。

type="submit"上的button设置属性formmethod="dialog",也可以实现关闭对话框功能。

<dialog open>
	<p>hello world</p>
	<form>
		<button formmethod="dialog">我知道了</button>
	</form>
</dialog>

关闭来源的判断

<dialog>元素的DOM对象上支持一个名为returnValue的属性,可以自动或手动设置对话框关闭行为的来源

https://www.htmlapi.cn/3/2-2.html

自动聚焦特性

原生HTML元素:无障碍访问天然支持,无需额外的自定义。

所谓“自动聚焦”​,指的是对话框显示后,浏览器的焦点会自动聚焦到对话框内。

showModal()方法与真正的对话框

真正的对话框应该是足够聚焦的(用户只能专注于当前的任务)​,而不是像一个普通的绝对定位浮层。

https://www.htmlapi.cn/3/2-3.html

showshowModal方法显示对话框的区别:

show

  • 水平居中
  • 绝对定位
  • 没有背景层

showModal

  • 水平垂直居中
  • 固定定位
  • 有背景层

showModal方法显示对话框的背景层是用CSS伪元素::backdrop自定义实现的:

dialog::backdrop {
	background://可以修改背景
}

可以使用:modal伪类区分是普通对话框或模态对话框:

dialog:modal {
	// 模态对话框的样式
}

除此之外,showModal()方法还有现有对话框组件无法模拟的稀缺特性:焦点隔离特性自动顶层特性

焦点隔离特性

一旦模态对话框显示,Web页面的焦点只能出现在当前的对话框元素中,对话框之外的元素是不可能获取焦点的,哪怕使用JavaScript代码强制聚焦也不行。也就是说整个网页中只有所示三个元素可以获得焦点。

在这里插入图片描述
此特性极为稀缺 。如果想用JS模拟,仅存在理论上的可能性,如使用HTML inert属性让dialog外的所有元素全部禁用。这不优雅简洁。

顶层特性

使用show()方法让对话框显示,对话框元素的层级是由CSS样式决定的,如果我们希望对话框元素的层级是最高的,则往往需要设置一个数值较大的z-index属性值。

使用showModal()方法让对话框显示,对话框元素的层级自动最高,无需任何CSS样式设置,此特性被称为顶层特性,有个专门的名词描述此特性,叫作top-layer。它是脱离z-index的。

在这里插入图片描述
top-layer顶层特性实现的原理比较简单:直接在<html>窗体之外创建一个绘制图层​,自然可以覆盖页面主体中的所有元素,尽管页面元素z-index为无穷大。

在这里插入图片描述
但是,一个页面可能有多个dialog元素。若多个dialog元素同时显示,层级规则该如何呢?

自动层级特性

如果一个页面中有多个对话框通过showModal()方法显示,那么后显示的对话框层级一定最高

传统的固定定位元素,如果不专门设置层级,则一定是位于DOM树后面的元素的层级最高,而模态对话框的层级高低与DOM位置无关,与呈现的时机有关。

若是用show方法,后弹出的dialog可能被覆盖在下面。
是用showModal方法,后弹出的dialog会在上面。

https://www.htmlapi.cn/3/2-4.html

综上所述,dialog元素不是普通的div元素可以比的。它有非常好用稀缺的特性,可以优雅简洁的实现一些功能。

原生弹层与popover属性

dialog在一些场景也不适用。如:点击预览图片时。

目标:点击图片可以预览图片,点击其他空白地方收起。

若用dialog实现,则需要给按钮绑定点击事件,将图片元素放在dialog中,然后写一个弹窗关闭的方法。麻烦。

在移动端开发中,许多交互效果都是是用弹层 实现的,即点击空白区域隐藏弹层 ,而dialog的模态层(上述为背景层)是没有隐藏行为的。因此这种类似场景不适合是用dialog。

可以使用popover,一个新HTML属性,已经被各大现代浏览器支持。是一个全局HTML属性,即:所有元素都可以设置的属性,如id、class、elementtiming属性(性能监控相关)。

基本使用:

<button popovertarget="imgPopover">点击我</button>
<div popover id="imgPopover">
	<img src="/stone-art.jpg" alt="" />
</div>

https://www.htmlapi.cn/3/2-5.html

popover弹层元素是顶层元素,且它模态背景是透明可穿透的,可以使用::backdrop自定义:

[popover]::backdrop {
 background-color: #000;
}

popover弹层内容之外的区域点击后会自动关闭当前弹层,无须额外的DOM事件支持,此行为可以自定义。

popover - HTML(超文本标记语言) | MDN (mozilla.org)

常用移动端弹出层实践:https://www.htmlapi.cn/3/2-6.html

<div class="ui-select">
    <button is="ui-select" popovertarget="selectPopover">点击我</button>
    <select is="ui-select" popup>
        <option>请选择</option>
        <option>选项1</option>
        <option>选项2</option>
    </select>
</div>

<ui-popup-container id="selectPopover" popover>
    <form id="form">
        <ui-list-item><input type="radio" name="n1" value="请选择" checked data-index="0">请选择</ui-list-item>
        <ui-list-item><input type="radio" name="n1" value="选项1" data-index="1">选项1</ui-list-item>
        <ui-list-item><input type="radio" name="n1" value="选项2" data-index="2">选项2</ui-list-item>
    </form>
</ui-popup-container>
form.onchange = function () {
    const input = form.querySelector('input:checked');
    const select = document.querySelector('select');
    select.selectedIndex = input.dataset.index;
    select.dispatchEvent(new Event('change'));
    // 关闭弹层
    selectPopover.hidePopover();
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐