天天看点

Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

在Web前端开发中,树形级联菜单,是一种常见且实用的界面交互组件。它不仅可以提供清晰的导航和大量信息分类展示,还能让用户更方便地进行操作和查询。然而,除了其直观的功能外,树形级联菜单,还可以被用于学习和应用CSS选择器以及CSS技巧。本文将通过代码和实例,分步骤地讲解如何通过树形级联菜单,来理解和运用CSS选择器与CSS技巧。

Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

基本示例

接下来,我们通过上一篇文章的例子,来了解本文的信息点。

HTML

<ul id="tree-menu">
    <li><label>Device 1</label>
        <ul>
            <li><label>Subdevice 1-1</label></li>
            <li><label>Subdevice 1-2</label>
                <ul>
                    <li><label>Subdevice 1-2-1</label></li>
                    <li><label>Subdevice 1-2-2</label></li>
                    <li><label>Subdevice 1-2-3</label></li>
                    <li><label>Subdevice 1-2-4</label></li>
                    <li><label>Subdevice 1-2-5</label></li>
                    <li><label>Subdevice 1-2-6</label></li>
                    <li><label>Subdevice 1-2-7</label></li>
                    <li><label>Subdevice 1-2-8</label></li>
                    <li><label>Subdevice 1-2-9</label></li>
                </ul>
            </li>
        </ul>
    </li>
    <li><label>Device 2</label></li>
</ul>           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

基础样式

CSS

<style type="text/css">
ul,
li {
    margin: 0;
    padding: 0;
    list-style: none;
}
/* 默认隐藏子项 */
#tree-menu ul {
    display: none;
}
/* 点击节点展开子项 */
#tree-menu li.collapsed>ul {
    display: block;
}
</style>           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

层级样式

CSS

<style type="text/css">
#tree-menu li ul {
    padding: 0.5rem 1rem;
} 
</style>           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

边框及选中样式

CSS

<style type="text/css">
#tree-menu li ul {
    padding: 0.5rem 1rem;
}

#tree-menu li {
    border: 1px solid #ddd;
}

#tree-menu li+li {
    border-top: 0;
}

#tree-menu label {
    display: block;
    padding: 0.5rem 1rem;
}

#tree-menu label:hover {
    background-color: aliceblue;
}
</style>           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

圆角样式1

CSS

<style type="text/css">
#tree-menu li ul {
    padding: 0.5rem 1rem;
} 
#tree-menu li {
    border: 1px solid #ddd;
    border-radius: 10px;
    margin-bottom:0.5rem;
}
/* #tree-menu li+li {
    border-top: 0;
}  */
#tree-menu label {
    display: block;
    padding: 0.5rem 1rem;
}

#tree-menu label:hover {
    background-color: aliceblue;
    border-radius: 10px;
}
</style>           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

圆角样式2

li label{ }

这个示例表示:li元素下面所有层级的label

li>label{ }

这个示例表示:li元素孩子级层级的label

CSS

#tree-menu li ul {
    padding: 0.5rem 1rem;
} 
#tree-menu li {
    border: 1px solid #ddd;
    /* border-radius: 10px;
    margin-bottom:0.5rem; */
}
/* 第一个子节点之后的所有兄弟节点 */
#tree-menu li+li {
    border-top: 0;
}
/* 第一个子节点 设置顶部圆角 */
#tree-menu li:first-child,
#tree-menu li:first-child>label {
    border-radius: 10px 10px 0 0;
}

/* 最后一个子节点 设置底部圆角  */
#tree-menu li:last-child,
#tree-menu li:last-child>label {
    border-radius: 0 0 10px 10px ;
}

/* 只有唯一 一个子节点时,顶部底部都设置圆角 */
#tree-menu li:only-child,
#tree-menu li:only-child>label {
    border-radius: 10px ;
}

/* 
    展开时背景圆角修复 
    :first-child 第一个子节点

    :not(:only-child)非唯一子节点
    这里表示这个子节点有子项

*/
#tree-menu li.collapsed:first-child:not(:only-child)>label {
    border-radius: 10px 10px 0 0;
}
#tree-menu li.collapsed:not(:only-child)>label {
    border-radius: 0;
}

#tree-menu label {
    display: block;
    padding: 0.5rem 1rem;
}
/* 
 :hover 鼠标在元素上面时
*/
#tree-menu label:hover {
    background-color: aliceblue;
    /* border-radius: 10px; */
}           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

节点标记样式

CSS

#tree-menu li label {
    position: relative;
    padding: 0.5rem 1rem 0.5rem 1.5rem;
}

/**
  如果有子项,添加展开或折叠的标记符号。
  默认折叠标记 
*/
#tree-menu li label::before {
    position: absolute;
    content: '-';
    left: 0;
    width: 1.6rem;
    height: 1.2rem;
    text-align: center;
    line-height: 1.2rem;
    color: #333;
}

/** 
  :only-child表示没有兄弟元素 
  不显示标记
*/
#tree-menu li label:only-child::before {
    content: ' ';
}

/* 显示展开标记 */
#tree-menu li.collapsed>label::before {
    content: '+';
}           

到此,一个还比较美观的树形菜单,基本完成了。

Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

但是,有朋友说,我要实现以下需求呢?

1、不要边框;

2、保留缩进;

3、保留展开折叠标记;

3、横向拉通选择;

横向拉通选择样式

CSS

#tree-menu label {
    position: relative;
    display: block;
    padding: 0.5rem 1rem;
}

#tree-menu label:hover {
    background-color: aliceblue;
}

/** 缩进拉通选择*/
#tree-menu li label {
    padding-left: 0;
}
#tree-menu li li label {
    padding-left: 0.5rem;
}
#tree-menu li li li label {
    padding-left: 1rem;
}
#tree-menu li li li li label {
    padding-left: 1.5rem;
}
#tree-menu li li li li li label {
    padding-left: 2rem;
}
#tree-menu li li li li li li label {
    padding-left: 2.5rem;
}


/**
  如果有子项,添加展开或折叠的标记符号。
  默认折叠标记 
*/
#tree-menu li label::before {
    float: left;
    content: '-';
    width: 1.6rem;
    height: 1.2rem;
    text-align: center;
    line-height: 1.2rem;
    color: #333;
}

/** 
  :only-child表示没有兄弟元素 
  不显示标记
*/
#tree-menu li label:only-child::before {
    content: ' ';
}

/* 显示展开标记 */
#tree-menu li.collapsed>label::before {
    content: '+';
}           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

如果层级很深,我不是得写很多个li才能实现多级缩进?

比如:tree-menu li li li li li li li li li li li label{}

JavaScript方式

查找所有 label 元素,然后看 label 元素上面有多少个 li 元素,以此判断所属层级。

CSS

<script>
  function parents(element, selector) {
  var parentsArray = [];
  var parent = element.parentNode;
  
  while (parent && parent !== document) {
    if (parent.matches(selector)) {
      parentsArray.push(parent);
    }
    parent = parent.parentNode;
  }
  return parentsArray;
}

  const items = document.querySelectorAll('#tree-menu label');
  items.forEach((item) => {
    const level = parents(item.parentElement, 'li').length
    const padding = 10  * level;
    item.style.paddingLeft = `${padding}px`;
  });
</script>           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

1、我不想写JavaScript;

2、我不想写多个li li li li li li li;

3、我不想写多个.level1{} .level2{} .level3{};

4、我想写少量CSS代码,来解决这个问题,一劳永逸;

5、我想它支持无限层级的缩进;

有这样CSS代码吗?我怎么不知道?

你别说,还真有这样得CSS代码。

当然,这也是本文得重点,算一个CSS得小技巧吧。

counters() 简介

CSS 函数 counters() 是一个嵌套计数器,返回表示指定计数器当前值的连接字符串。counters() 函数有两种形式: counters(name, string) 或 counters(name, string, style) 。它通常和伪元素搭配使用,但是理论上可以在支持<string>值的任何地方使用。生成的文本是具有给定名称的所有计数器的值,从最外层到最内层,之间由指定字符串分隔。计数器以指示的样式呈现,如果未指定样式,则默认为十进制。

先看一个例子:

HTML

<ol>
  <li>
     <ol>
        <li></li>
        <li></li>
        <li></li>
      </ol>
  </li>
  <li></li>
  <li></li>
  <li>
     <ol>
        <li></li>
        <li>
           <ol>
              <li></li>
              <li></li>
              <li></li>
           </ol>
        </li>
      </ol>
  </li>
</ol>
           

CSS

ol {
  counter-reset: listCounter;
}
li {
  counter-increment: listCounter;
}
li::marker {
   content:  counters(listCounter, '.', upper-roman) ') ';
}
li::before {
  content:  counters(listCounter, ".") " == " counters(listCounter, ".", lower-roman) ;
}
           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

counters() 示例

通过上面的例子,我们看到了类似word的多级列表。此时很多朋友可能已经有思路了,那么我们将利用CSS这个特性,来实现上面的要求。

修改了部分样式

#tree-menu label {
    position: relative;
    display: block;
    /* padding: 0.5rem 1rem; */
    padding: 0.5rem 1rem 0.5rem 0;
}
/* #tree-menu li label::before {} */
#tree-menu li label::after {}
  
/* #tree-menu li label:only-child::before {} */
#tree-menu li label:only-child::after {}
  
/* #tree-menu li.collapsed>label::before {} */
#tree-menu li.collapsed>label::after {}           

counters属性样式

/** 缩进拉通选择 修改前*/
/* #tree-menu li label {
    padding-left: 0;
}
#tree-menu li li label {
    padding-left: 0.5rem;
}
#tree-menu li li li label {
    padding-left: 1rem;
}
#tree-menu li li li li label {
    padding-left: 1.5rem;
}
#tree-menu li li li li li label {
    padding-left: 2rem;
}
#tree-menu li li li li li li label {
    padding-left: 2.5rem;
} */

/* 修改后 */
#tree-menu,
#tree-menu ul {
    counter-reset: listCounter;
}

#tree-menu label {
    counter-increment: listCounter;
}

#tree-menu label::before {
    float: left;
    /* 把标记设置成透明 */
    color:transparent;
    /* 默认数字*/
    content: counters(listCounter, "");
}           
Web前端通过【树形级联菜单】了解【CSS选择器】与【CSS技巧】

完整的CSS

ul,
li {
    margin: 0;
    padding: 0;
    list-style: none;
}

/** 
折叠状态与展开状态样的样式
 */
#tree-menu ul {
    display: none;
}

#tree-menu li.collapsed>ul {
    display: block;
}

#tree-menu label {
    position: relative;
    display: block;
    padding: 0.5rem 1rem 0.5rem 0;
}

#tree-menu label:hover {
    background-color: aliceblue;
}

/** 缩进拉通选择*/
/* 修改后 */
#tree-menu,
#tree-menu ul {
    counter-reset: listCounter;
}

#tree-menu label {
    counter-increment: listCounter;
}

#tree-menu label::before {
    float: left;
    /* 将序号设置为透明 */
    color:transparent;
    /***/
    content: counters(listCounter, "");
}



/**
  如果有子项,添加展开或折叠的标记符号。
  默认折叠标记 
*/
#tree-menu li label::after {
    float: left;
    content: '-';
    width: 1.6rem;
    height: 1.2rem;
    text-align: center;
    line-height: 1.2rem;
    color: #333;
}

/** 
  :only-child表示没有兄弟元素 
  不显示标记
*/
#tree-menu li label:only-child::after {
    content: ' ';
}

/* 显示展开标记 */
#tree-menu li.collapsed>label::after {
    content: '+';
}           

通过树形级联菜单,学习CSS选择器与CSS技巧,是一种非常有效的学习方法。我们不仅可以学会如何使用各种选择器,来控制页面元素,还能掌握一些实用的CSS技巧和概念。希望本文对您了解树形级联菜单、CSS选择器和CSS技巧有所帮助,并能为您在Web前端开发中的工作提供一些启发。

希望本文能够对您有所帮助,感谢您的阅读!

人人为我,我为人人,谢谢您的浏览,我们一起加油吧。