淘先锋技术网

首页 1 2 3 4 5 6 7

一、了解HTML5 details, summary默认交互行为

<details>标签在Chrome,Firefox等浏览器下默认是有展开收起行为的,例如下面HTML:

<details>
    <summary>这是摘要1</summary>
    <p>这里具体描述,标签相对随意,例如这里使用的&lt;p&gt;标签。</p>
</details>

只显示summary内容,而p标签的内容是隐藏的

展开与收起是通过open属性控制的

通过在 <details> 标签上添加布尔类型的 open 属性,可以让我们的详情信息默认就是展开状态,如下HTML示意:
<details open>
    <summary>这是摘要2</summary>
    <content>这里&lt;details&gt;标签设置了HTML布尔属性open,因此,默认是展开状态。</content>
</details>

<summary>如果缺省

<summary>标签如果缺省,则<details>元素会在内部自动创建一个<summary>内容,默认的文案是“详细信息”。如下HTML代码:

<details open>
    <p>如果&lt;summary&gt;缺省,则会自动补上,文案是“详细信息”。</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>元素的语义,但是并不需要点击展开收起的行为,该怎么处理呢?

例如,某评论,或者某帖子有标题和正文,非常符合详情-概要-内容的语义,但是希望是纯展示的,点击时候不收起,可以这么处理:

  1. <summary>标签设置tabindex="-1"让键盘无法访问;
  2. 设置CSS:
    summary {
      outline: 0;
      pointer-events: none;
    }

    这样就不能点,也不会有outline轮廓。