系列文章
- [ 基础系列 ] - CSS 小测 01
- [ 基础系列 ] - CSS 小测 02
- [ 基础系列 ] - CSS 小测 03
- [ 基础系列 ] - CSS 小测 04
- [ 基础系列 ] - CSS 小测 05
- [ 基础系列 ] - CSS 小测 06
- [ 基础系列 ] - CSS 小测 07
- [ 基础系列 ] - CSS 小测 08
说在前面
本篇是张鑫旭老师的 CSS 基础测试10 的阅后笔记。(MVP 依然是 XboxYan 同学,用张老师的话说,这位同学的回答,一开始就是大结局了)
题目
先来看看题目。
请实现如下图所示布局效果:

需求:
- HTML 选择合理
- 视觉还原良好
- 支持点击展开的交互效果(无JS)
- 代码友好
思路
不考虑兼容性的话(chrome 12+,Firefox 49+,Opera 15+,Safari 6+,不支持 IE 及 Edge),上述题目的最佳方案应该是 HTML 的 details + summary 标签。
可能有的同学对此比较陌生,这里就简单介绍一下。
<details>元素可创建一个挂件,仅在被切换成展开状态时,它才会显示内含的信息。<summary>元素可为该部件提供概要或者标签。
举个栗子:
<details>
<summary>summary 提供标签或概要</summary>
<p>这里是详细信息一</p>
<p>这里是详细信息二</p>
<p>这里是详细信息三</p>
</details>
效果如下:

看到这个效果,是不是离题目要求的只剩视觉还原了呢?
至于视觉还原,唯一的难题应该是右边的小三角,所以我们先将基础实现下来,然后再看这个小三角:
<aside class="menu-bar">
<!-- 布局 -->
<details class="menu-box" menu-type="layout">
<summary class="menu-title">布局</summary>
<menu class="menu-item-list">
<a href class="menu-item">Flex布局</a>
<a href class="menu-item">Grid布局</a>
<a href class="menu-item">Shapes布局</a>
<a href class="menu-item">Columns布局</a>
</menu>
</details>
<!-- 组件 -->
<details class="menu-box" menu-type="component">
<summary class="menu-title">组件</summary>
<menu class="menu-item-list">
<a href class="menu-item">按钮</a>
<a href class="menu-item">输入框</a>
<a href class="menu-item">下拉列表</a>
<a href class="menu-item">单复选框</a>
</menu>
</details menu-type="layout">
</aside>
/* reset style */
menu {
margin: 0;
padding: 0;
}
::-webkit-details-marker {
display: none;
}
::-moz-list-bullet {
font-size: 0;
float: left;
}
summary {
outline: none;
}
.menu-item-list a{
text-decoration: none;
}
/* set style */
.menu-bar {
width: 200px;
}
.menu-title {
padding: 0 10px;
line-height: 40px;
color:#333;
cursor: pointer;
}
.menu-title:hover,
.menu-title:focus{
background: #edf9ff;
}
.menu-item{
display: block;
padding: 0 26px;
line-height: 40px;
font-size: 14px;
color:#666;
cursor: pointer;
transition: 0.3s;
}
.menu-item:hover{
background: #edf9ff;
color: #33b2ee;
}
效果如下:

接下来我们来看看右边的小三角形。其实看过前面几期画三角形的同学应该已经有思路了:
- step1 - 用
border画一个正方形 - step2 - 消去其中相邻的两边
- step3 - 旋转 45°/135°
那么我们就按照步骤来完成绘制
.menu-title::after{
content:"";
border:2px solid;
}
效果如下:

.menu-title::after{
content:"";
border:2px solid;
border-top: 0;
border-left: 0;
}

接下来将其旋转 45° 即可:
.menu-title::after{
content:"";
border:2px solid;
border-top: 0;
border-left: 0;
transform: rotate(45deg);
}
效果如下:

至于小三角的旋转,可以结合 details 的 open 属性:
.menu-box[open] .menu-title::after{
transform: rotate(-135deg);
}
最终效果如下:

感兴趣的同学可以看看 在线 demo
兼容 IE
上面提到 details/summary 是不兼容 IE 任何版本的,如果想要兼容 IE 的话,大致有以下几种方案:
- checkbox
- target
- focus-within
checkbox
checkbox 是以前实现下拉菜单的常规套路,核心思路是在 checkbox 下藏一个菜单,当 checkbox 被选中的时候显示这个菜单。
核心代码如下:
<input id="menu-component" type="checkbox"></input>
<label for="menu-component" class="menu-title">组件</label>
.menu-box > [type="checkbox"]{
display: none;
}
.menu-box > [type="checkbox"]:checked + .menu-title::after {
transform: translateY(-8px) rotate(-135deg);
}
.menu-item-list{
display: none;
}
.menu-box > [type="checkbox"]:checked ~ .menu-item-list {
display: block;
}
效果如下:

感兴趣的同学可以看看 在线 demo
target
:target 伪类代表一个唯一的页面元素(目标元素),其 id 与当前 URL 片段匹配
通常 target 用于实现定位到页面中指定位置,此处通过 target 实现题中效果原理与 checkbox 相同,与之区别的一点是,由于 target 具有唯一性,所以此菜单仅支持手风琴效果。
核心代码如下:
<a id="menu-layout" class="menu-title" href="#menu-layout">布局</a>
.menu-title:target::after {
transform: translateY(-8px) rotate(-135deg);
}
.menu-item-list {
display: none;
}
.menu-title:target ~ .menu-item-list {
display: block;
}
效果如下:

感兴趣的同学可以看看 在线 demo
focus-within
focus-within 是一个 CSS 伪类 ,表示一个元素获得焦点,或,该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配 focus 伪类。
这个伪类比较常用的场景是:当用户在表单中某个 <input> 域上获得焦点,会高亮整个表单。
同 target,由于无法同时使两个元素获得者焦点,所以 focus-within 也仅支持手风琴模式,另外 focus-within 是比较新的特新,使用的时候需要注意兼容性。
核心代码如下:
<a class="menu-title" href="javascript:;" role="button">布局</a>
.menu-box:focus-within .menu-title::after {
transform: translateY(-8px) rotate(-135deg);
}
.menu-item-list {
display: none;
}
.menu-box:focus-within .menu-item-list {
display: block;
}
效果如下:

感兴趣的同学可以看看 在线 demo
结束语
下面是张老师总结的一些要点:
- 由于
details > summaryIE 和 Edge 都不支持,所以可以作为判读浏览器是否是 IE(Edge) 的依据:const isIE = !('open' in document.createElement('details')) - :focus-within 只要子元素有 focus,就能匹配。是目前最先支持的具有“父选择器”特性的伪类。最佳实践是下拉菜单。类似的选择器还有 :target-within。