likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 25

面试题

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

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

面试官:能不能行?

我:能行,不行也得行。

效果展示:

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

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

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

纯css折叠菜单

好戏开场。

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

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

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

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

要点一

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

<!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。

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

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

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

    <link rel="stylesheet" href="./demo.css">
    

准备阶段结束了。

开始.styl文件的编写。

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

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

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

    .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元素设置样式。

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

    .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标签设置高度。

    .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

* {
  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选择器就可以快速解决类似的问题。

转载自:https://juejin.cn/post/7387348384493830196
评论
请登录