面试官:你可以用纯CSS实现折叠式菜单吗?

面试题

面试官:你别用JavaScript,就用css实现一个可以点击折叠的菜单。

我:啊?好家伙,把JavaScript给我ban了,这不是相当于绑了我的双手嘛。

面试官:能不能行?

我:能行,不行也得行。

效果展示:

面试官:恭喜你拿下一道简单题。

我:啊?头发都掉了几根了就解开了一道简单题。

纯css折叠菜单

好戏开场。

要点一:怎么实现触发点击事件?

要点二:怎么实现折叠效果?

不用JavaScript让我实现点击事件,一瞬间让我小脑萎缩。如果可以使用JavaScript,那我会设置一个点击事件,触发的处理函数就把选中时应有的样式添加上去实现折叠操作。

但是在不能使用JavaScript时则需要通过复选框实现点击事件的触发。当复选框被点击后它的checked属性就会发生变化,按照复选框的这个特性,我们就可以通过高级css选择器选择复选框选中情况下的一些元素并且为其编辑一些样式,这样就实现了点击触发的折叠效果。

要点一

既然要用复选框实现就开整。但是用上复选框时觉得它太丑了,并且选中复选框的范围太小了,不太友好。那就需要进一步操作,把复选框给隐藏掉(在input标签里添加hidden属性),然后将label标签的for属性和复选框的id属性设置为用一个属性值进行绑定,这样一顿操作下来既可以选中复选框,又可以让选中的范围增加到label标签元素的大小。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>纯css菜单</title>
    <link rel="stylesheet" href="./demo.css">
</head>
<body>
    <div class="accordion">
        <input type="checkbox" id="collapse1" hidden>
        <input type="checkbox" id="collapse2" hidden>
        <input type="checkbox" id="collapse3" hidden>
        <article>
            <label for="collapse1">点我一下</label>
            <p>A</p>
        </article>
        <article>
            <label for="collapse2">叫你点我一下</label>
            <p>B</p>
            <p>C</p>
        </article>
        <article>
            <label for="collapse3">你点不点</label>
            <p>D</p>
            <p>E</p>
            <p>F</p>
        </article>
    </div>
</body>
</html>

当点击这三个label中的任何一个就可以展示所有的兄弟p标签。

要点二

接下来就是重头戏了,精彩的CSS表演。

如果直接编写CSS代码,我觉得太麻烦了,并且也不能增加面试官的印象分,于是便使用Stylus(css预处理器)编写CSS代码。

Stylus 拥有简洁而富有表现力的语法,能省略花括号和分号,让代码更简洁清晰,还支持变量、混合、嵌套规则等,大幅减少重复代码。

使用Stylus编写CSS的准备工作:

  1. 全局安装Stylus。

    less 复制代码
    npm i -g stylus //全局安装stylus
  2. 创建一个.styl文件。

  3. 将创建的.styl文件编译为 CSS 文件,并将结果输出为 .css文件 。

    markdown 复制代码
    eg:
    	stylus demo.styl -o demo.css(修改后不会自动编译为css)
    	stylus -w demo.styl -o demo.css(修改后会自动编译为css)   
  4. 通过<link>元素引入CSS样式。

    html 复制代码
    <link rel="stylesheet" href="./demo.css">

准备阶段结束了。

开始.styl文件的编写。

Stylus 使用缩进来表示嵌套,因此保持一致的缩进非常重要,通常推荐使用 Tab进行缩进。

  1. 清除所有所有元素的内外边距。

    stylus 复制代码
    *
        margin 0
        padding 0
  2. .accordion 类设置宽度为 300 像素;给.accordion 类中article 元素的鼠标指针样式设置为指针;通过&+的CSS选择器组合进行元素的选择。

    stylus 复制代码
    .accordion
        width 300px
        article
            cursor pointer
            & + article 
                margin-top 5px

    & + article

    • &表示当前选择器的父元素,也就是.accordion article选择器。
    • +是相邻兄弟元素选择器,用于选择紧接在另一个元素后的元素,并且它们具有相同的父元素。
    • & + article 编译为CSS是.accordion article + article选择器,用于选择紧接在 .accordion 类下的 article 元素之后的下一个 article 元素。

    最终实现有兄长的article,则加上5像素的上边距。

  3. label元素设置样式。

    stylus 复制代码
    .accordion
        label
            display block
            height 40px
            padding 0 20px
            background-color #6495ED
            cursor pointer
            line-height 40px
            font-size: 16px
            color:#fff
  4. p元素设置样式。

    stylus 复制代码
    .accordion
        p
            overflow: hidden
            padding 0 20px
            bottom 1px solid #f66
            border-top none
            border-bottom-width 0
            max-height 0
            line-height 30px
            transition all 300ms

    当菜单没有被点击时,p标签的最大高度设置为0;当被菜单被点击则将p标签的最大高度修改为不是0,并且加上transition all 300ms动画过渡属性。

  5. 给被选中的菜单所属的p标签设置高度。

    stylus 复制代码
    .accordion 
        input
            &:nth-child(1):checked ~ article:nth-of-type(1) p,
            &:nth-child(2):checked ~ article:nth-of-type(2) p,
            &:nth-child(3):checked ~ article:nth-of-type(3) p
                max-height 600px

    &:nth-child(1):checked ~ article:nth-of-type(1) p

    • :是伪类选择器。:checked表示input被选中的状态,这是这个不用js实现仅靠css实现的项目的关键。
    • :nth-child(x)表示选择第n个孩子。
    • :nth-of-type(n) 表示选择第n个同类型的元素。
    • &:nth-child(1):checked ~ article:nth-of-type(1) p编译为CSS是.accordion input:nth-child(1):checked ~ article:nth-of-type(1) p选择器,用于选择第一个被选中的input时,其后面同类型的article的第一个中的所有p元素。

    实现了被点击的菜单可以展开子菜单。

最终编译成的CSS

css 复制代码
* {
  margin: 0;
  padding: 0;
}
.accordion {
  width: 300px;
}
.accordion article {
  cursor: pointer;
}
.accordion article + article {
  margin-top: 5px;
}
.accordion input:nth-child(1):checked ~ article:nth-of-type(1) p,
.accordion input:nth-child(2):checked ~ article:nth-of-type(2) p,
.accordion input:nth-child(3):checked ~ article:nth-of-type(3) p {
  max-height: 600px;
}
.accordion label {
  display: block;
  height: 40px;
  padding: 0 20px;
  background-color: #6495ed;
  cursor: pointer;
  line-height: 40px;
  font-size: 16px;
  color: #fff;
}
.accordion p {
  overflow: hidden;
  padding: 0 20px;
  bottom: 1px solid #6495ed;
  border-top: none;
  border-bottom-width: 0;
  max-height: 0;
  line-height: 30px;
  transition: all 300ms;
}

总结

大体思路其实是很简单的,就是借用复选框被选中的特性然后结合CSS样式,但是这需要对CSS选择器足够熟悉。只要掌握了这种思想,并且熟悉一些常用的CSS选择器就可以快速解决类似的问题。

相关推荐
华农第一蒟蒻16 分钟前
Java中JWT(JSON Web Token)的运用
java·前端·spring boot·json·token
积水成江17 分钟前
关于Generator,async 和 await的介绍
前端·javascript·vue.js
___Dream19 分钟前
【黑马软件测试三】web功能测试、抓包
前端·功能测试
金灰19 分钟前
CSS3练习--电商web
前端·css·css3
人生の三重奏22 分钟前
前端——js补充
开发语言·前端·javascript
Tandy12356_34 分钟前
js逆向——webpack实战案例(一)
前端·javascript·安全·webpack
TonyH200236 分钟前
webpack 4 的 30 个步骤构建 react 开发环境
前端·css·react.js·webpack·postcss·打包
你会发光哎u40 分钟前
Webpack模式-Resolve-本地服务器
服务器·前端·webpack
王小二(海阔天空)41 分钟前
个人文章合集 - 前端相关
前端·css·vue·jquery
老华带你飞1 小时前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计