一、了解HTML5 details, summary默认交互行为
<details>
标签在Chrome,Firefox等浏览器下默认是有展开收起行为的,例如下面HTML:
<details> <summary>这是摘要1</summary> <p>这里具体描述,标签相对随意,例如这里使用的<p>标签。</p> </details>
只显示summary内容,而p标签的内容是隐藏的
展开与收起是通过open属性控制的
通过在<details>
标签上添加布尔类型的 open
属性,可以让我们的详情信息默认就是展开状态,如下HTML示意: <details open>
<summary>这是摘要2</summary>
<content>这里<details>标签设置了HTML布尔属性open,因此,默认是展开状态。</content>
</details>
<summary>如果缺省
<summary>
标签如果缺省,则<details>
元素会在内部自动创建一个<summary>
内容,默认的文案是“详细信息”。如下HTML代码:
<details open> <p>如果<summary>缺省,则会自动补上,文案是“详细信息”。</p> </details>
二、details浏览器内置UI可以自定义
<details>
标签默认的小三角样式有些简陋,在实际应用的时候,往往不是我们希望的样子,不要担心,我们是可以对其进行自定义的。在Chrome等浏览器下使用::-webkit-details-marker
,在Firefox浏览器下使用::-moz-list-bullet
可以对小三角进行UI控制,例如改变颜色,改变大小,使用自定义的图形代替,或者直接隐藏等,我们来看几个简单的案例。
案例1:小三角右侧显示同时颜色变淡
HTML代码如下:
<details class="details-1" open> <summary>这是示例1</summary> <content>本案例展示对小三角UI重定义:包括显示在右侧,颜色减淡等。</content> </details>
CSS如下:
.details-1 summary { width: -moz-fit-content; width: fit-content; direction: rtl; } .details-1 ::-webkit-details-marker { direction: ltr; color: gray; margin-left: .5ch; } .details-1 ::-moz-list-bullet { direction: ltr; color: gray; margin-left: .5ch; }
案例2:隐藏浏览器原生的小三角并使用自定义三角替换
html:
<details class="details-2" open> <summary>这是示例2</summary> <content>本案例隐藏原生小三角,使用自定义小三角。</content> </details>
/* 隐藏默认三角 */
.details-2 ::-webkit-details-marker {
display: none;
}
.details-2 ::-moz-list-bullet {
font-size: 0;
}
可以看到Chrome浏览器和Firefox浏览器的小三角隐藏采用的是不同的策略。在Chrome浏览器下,我们可以直接设置display:none
进行隐藏,但是这一招在Firefox浏览器下确实没有效果的,即使设置display:none!important
也是如此,根据我的测试,只有font-size:0
能够比较完美的隐藏。类似position:absolute;visibility:hidden
这种常见的隐藏也是不行的,因为position:absolute
无法生效。
然后是自定义小三角显示的CSS,这里采用的是::after
伪元素模拟的:
/* 自定义的三角 */
.details-2 summary::after {
content: '';
position: absolute;
width: 1em; height: 1em;
margin: .2em 0 0 .5ch;
background: url(./arrow-on.svg) no-repeat;
background-size: 100% 100%;
transition: transform .2s;
}
.details-2:not([open]) summary::after {
margin-top: .25em;
transform: rotate(90deg);
}
最后有一点需要注意一下,就是如果 <details>
标签内并没有 <summary>
元素,则我们的对三角的自定义代码都是无效的,可以使用一个空的 <summary>
元素占位,类似这样: <details> <summary></summary> <content>内容。</content> </details>
三、Chrome浏览器下点击时候outline轮廓等体验处理
1. 利用<a>标签的outline交互体验
浏览器对<a>
标签元素的outline
轮廓进行了专门的体验优化处理,鼠标点击的时候不显示轮廓,键盘访问时候显示轮廓。于是我们可采用李代桃僵策略,让<summary>
元素的outline
交给<a>
元素,方法就是在<summary>
中再内嵌一个<a>
,同时通过tabindex
属性remove掉<summary>
原本的可访问性。HTML代码示意如下:
<details open> <summary tabindex="-1"><a href="javascript:" target="_blank" rel="external nofollow" >这是示例</a></summary> <content>点击无外框,键盘focus有。</content> </details>
css:
summary {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
outline: 0;
}
summary a {
color: inherit;
pointer-events: none;
}
2. JS捕获键盘行为手动设置outline
这个方法不需要对HTML进行任何的改动,是通过CSS和JS配合对全局的<summary>
元素进行outline
优化。
summary { user-select: none; outline: 0; } summary[focus] { outline: 1px dotted; outline: 5px auto -webkit-focus-ring-color; }
JS如下:
window.addEventListener('keydown', function () { window.isKeyEvent = true; setTimeout(function () { window.isKeyEvent = false; }, 100); }); document.addEventListener('focusin', function (event) { var target = event.target; if (target && target.tagName.toLowerCase() == 'summary' && window.isKeyEvent == true) { target.setAttribute('focus', ''); } }); document.addEventListener('focusout', function (event) { var eleFocusAll = document.querySelectorAll('summary[focus]'); [].slice.call(eleFocusAll).forEach(function (summary) { summary.removeAttribute('focus'); }); });
要把上面的CSS和JS复制到页面中,视觉体验和交互体验完美支持的<summary>
元素outline
效果就有了。
表现为,点击<summary>
没有任何outline
,键盘focus
时候出现,且和浏览器原生outline
效果一模一样,Space键和Enter键展开与收起访问完全保留。
关键是全局监听
keydown
事件,如果有发生,则认为此100毫秒内的页面 focus
行为均是键盘产生,从而有效区分是点击触发的 focus
行为还是键盘触发的 focus
行为,如果是键盘触发,给 <summary>
元素手动增加 outline
效果。 四、基于details元素行为的各种交互效果案例
了解了<details>
元素的点击交互行为;解决了UI定制难题;解决了outline
的体验问题,下面我们就可以付诸实践,不借助任何JS来实现各种我们平常见到的交互效果。
案例1:“更多”展开与收起效果
<details> <summary> <p>据台媒报道,大...青睐。</p> <div class="more"> <p>其他几首歌曲...</p> </div> <a>更多</a> //单纯a标签 </summary> </details>
css:
::-webkit-details-marker {
display: none;
}
::-moz-list-bullet {
font-size: 0;
float: left;
}
summary {
user-select: none;
outline: 0;
}
.more {
display: none;
}
[open] .more {
display: block;
}
[open] summary a {
font-size: 0;
}
[open] summary a::before {
content: '收起';
font-size: 14px;
}
案例3:accordion多项折叠效果
此效果常见于条目比较多的垂直导航栏,新闻条目等。
例如下面实现的效果:
css:
/* 隐藏默认三角 */
::-webkit-details-marker {
display: none;
}
::-moz-list-bullet {
font-size: 0;
float: left;
}
summary {
user-select: none;
outline: 0;
}
dt::after {
content: '';
position: absolute;
width: 12px; height: 12px;
margin: 4px 0 0 .5ch;
background: url(http://www.zhangxinxu.com/study/201801/arrow-on.svg) no-repeat;
background-size: 100% 100%;
transition: transform .2s;
}
[open] dt::after {
transform: rotate(90deg);
}
<details open>
<summary><dt>订单中心</dt></summary>
<dd><a href>我的订单</a></dd>
<dd><a href>我的活动</a></dd>
<dd><a href>评价晒单</a></dd>
<dd><a href>购物助手</a></dd>
</details>
<details open>
<summary><dt>关注中心</dt></summary>
<dd><a href>关注的商品</a></dd>
<dd><a href>关注的店铺</a></dd>
<dd><a href>关注的专辑</a></dd>
<dd><a href>收藏的内容</a></dd>
</details>
<details open>
<summary><dt>资产中心</dt></summary>
<dd><a href>余额</a></dd>
<dd><a href>优惠券</a></dd>
<dd><a href>礼品卡</a></dd>
</details>
案例5:多级嵌套的树形菜单交互效果
这里的树形菜单效果实现也很简单,多个<details>
元素相互嵌套就可以,效果Gif如下:
CSS代码:
/* 隐藏默认三角 */
::-webkit-details-marker {
display: none;
}
::-moz-list-bullet {
font-size: 0;
float: left;
}
details {
padding-left: 20px;
}
summary::before {
content: '';
display: inline-block;
width: 12px; height: 12px;
border: 1px solid #999;
background: linear-gradient(to right, #999, #999) no-repeat center, linear-gradient(to top, #999, #999) no-repeat center;
background-size: 2px 10px, 10px 2px;
vertical-align: -2px;
margin-right: 6px;
margin-left: -20px;
}
[open] > summary::before {
background: linear-gradient(to right, #999, #999) no-repeat center;
background-size: 10px 2px;
}
HTML代码:
<details>
<summary>我的视频</summary>
<details>
<summary>爆肝工程师的异世界狂想曲</summary>
<div>tv1-720p.mp4</div>
<div>tv2-720p.mp4</div>
...
<div>tv10-720p.mp4</div>
</details>
<details>
<summary>七大罪</summary>
<div>七大罪B站00合集.mp4</div>
</details>
<div>珍藏动漫网盘地址.txt</div>
<div>我们的小美好.mp4</div>
</details>
五、如果只想要details/summary的语义不要行为
如果只想要<details>
元素,<summary>
元素的语义,但是并不需要点击展开收起的行为,该怎么处理呢?
例如,某评论,或者某帖子有标题和正文,非常符合详情-概要-内容的语义,但是希望是纯展示的,点击时候不收起,可以这么处理:
<summary>
标签设置tabindex="-1"
让键盘无法访问;- 设置CSS:
summary { outline: 0; pointer-events: none; }
这样就不能点,也不会有
outline
轮廓。