JS+CSS特效:HTML+JS+CSS 实现精致的带二级菜单的头部菜单

本篇,我们来演示一个二级菜单是怎么做出来的。

案例效果图

因为本次内容主要目标是实现顶部的导航菜单,所以我们不关心其他内容。

第一步:清除浏览器默认样式 & 添加基本样式

css 复制代码
*{ margin: 0px; padding: 0px; box-sizing: border-box; }
ul { list-style: none; }
/* General Definitions  定义全局样式 */
body {
	background: #f3f3f3;
	font-family: "微软雅黑",Helvetica,weiruanyahei,Tahoma,Arial,Sans-serif;
	font-size: 14px;
	color: #333;
	box-sizing: border-box;
 transition: all .3s;
}
a{
	color: #414141;
	text-decoration: none;	
}
a:hover {
	color: #139ce4;
}

第二步:容器布局

通常情况下,我们可以用div来写,也可以ul来写,我个人习惯用ul。

一级菜单

html 复制代码
<header>
      <nav>
         <ul class="nav-ul"> 
          <li><a href="###">Home</a></li>
          <li><a href="###">HTML&CSS</a></li> 
          <li><a href="###">Js&JQuery</a></li> 
          <li><a href="###">WordPress</a></li> 
          <li><a href="###">Others</a></li>
         </ul>
      </nav>
</header>
布局样式表

header标签:头部的背景

css 复制代码
header {
   position: fixed; /* 固定顶部导航 */ 
   background: rgba(255,255,255,0.9);
   width: 100%;
   height: 96px;
   box-shadow: 0 2px 15px 0px rgba(0,0,0,0.1);  /* 盒子阴影 */
   z-index: 10;
   -webkit-backdrop-filter: blur(8px);
   backdrop-filter: blur(8px);
}

nav标签:定位导航菜单

css 复制代码
nav {
   padding-top: 26px;
   width: 90%;
   float: right;
   margin-right: 20px;
}

ul li 标签:菜单样式

css 复制代码
.nav-ul{ float: right; }

写到这里,我们实现了对菜单的定位,但这个时候的列表还是竖着的排列的。

接下来,我们写样式,要让它横过来。

css 复制代码
.nav-ul>li {
   position: relative;
   float: left;
   margin-right: 10px;
}
美化一级菜单样式

接下来,我要把它变成它该有的样子

css 复制代码
.nav-ul>li>a {
   float: left;
   margin-right: 0px;
   padding: 10px 30px;
   width: auto;   
   height: auto;  
   -moz-border-radius: 35px;
   -webkit-border-radius: 35px;
   border-radius: 35px;
   -khtml-border-radius: 35px;
   color: #777;
   font-weight: bold;
   font-size: 1.3rem;
   line-height: 30px;
   text-shadow: 2px 2px 0 #fff;
   overflow: hidden;
}
.nav-ul>li>a:hover {   
background: #efefef; 
color: #999;   
transition: all .7s;
text-shadow: 1px 2px 2x #fff;
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.029) inset,5px 5px 6px rgba(0, 0, 0, 0.027) inset,10px 9px 12px rgba(0, 0, 0, 0.07) inset;
}

好了,一级导航菜单这样就算写完了。我们看看效果。

二级菜单

接下来,准备写二级菜单。先修改一下菜单结构。二级菜单,因为是通过一级菜单触发的,但又不是鼠标点击一级菜单,因为点击一级菜单,就要跳转走了。所以,我把二级菜单写在了 一级菜单的 li标签中间,与a标签并列。为了省事,我就不给每个菜单都添加二级菜单了。

菜单布局
html 复制代码
<header>
      <nav>
         <ul class="nav-ul"> 
          <li><a href="###">Home</a></li>
          <li>
             <a href="###">HTML&CSS</a>
             <ul class="sub-menu"> 
               <li><a href="###">布局与定位</a></li> 
               <li><a href="###">CSS字体</a></li> 
               <li><a href="###">导航&amp;按钮&amp;链接</a></li> 
               <li><a href="###">表单&amp;控件</a></li> 
               <li><a href="###">列表&amp;表格</a></li> 
               <li><a href="###">背景&amp;边框</a></li> 
               <li><a href="###">图片</a></li> 
               <li><a href="###">图文排版</a></li> 
               <li><a href="###">CSS3动画 </a></li> 
               <li><a href="###">其他纯CSS </a></li> 
            </ul> 
          </li> 
          <li><a href="###">Js&JQuery</a></li> 
          <li><a href="###">WordPress</a></li> 
          <li><a href="###">Others</a></li>
         </ul>
      </nav>
   </header>

接下来我们看一下现在的菜单是什么样子的:

显然,我们需要给它进行样式美化,然后还要把这个菜单隐藏起来。只有当鼠标移动到一级菜单上时,才能显示二级菜单。

现在,就让我们分析一下这个二级菜单有那些特点。为了看得仔细,我们在浏览器界面按住ctrl键然后向上滚动鼠标中间的滚轮,让浏览器视窗比例变大。然后截图,细节就清晰可见了。

目标样式
  1. 蓝色的圆角边框;
  2. 它有个比白色稍稍深一点点的背景色和圆角内框;
  3. 一行两列的菜单项布局;
  4. 菜单框的最外面的上边框中间位置,还有个蓝色的小三角,指向它的上级菜单,
  5. 菜单项的顶部有1像素的白边,下面有像素的灰色边,另外就是两列菜单项中间有一条灰色的线,右侧菜单项的左边有一条白色的边框线,这形成了一种立体的感觉。
  6. 当鼠标移动到菜单项上时:它的背景色变成了浅蓝色,菜单链接颜色变成了蓝色,且有1个像素的白色阴影,产生了按钮文字凹陷的效果。

接下来,让我们一行行去实现这些样式。

首先是蓝色外边框和内部的浅白色圆形内框。

css 复制代码
.sub-menu{
   position: absolute;
   top:50px;
   border-radius: 10px;
   background: #fcfcfc;
   border:5px solid #139ce4;
   width: auto;
   height:auto;
   }

先做个边框看看哈:

接下来,布局菜单项:

css 复制代码
.sub-menu li a {
   display: block;
   position: relative;
   float: left;
   background: #fcfcfc;
   line-height: 2.5rem;
   width: 50%;
   color: #999;
   font-size: 0.9rem;
   text-shadow: 1px 1px 0 #fff;
   transition: all .3s;
   border-top:1px solid #fff;
   border-bottom: 1px solid #f1f1f1;   
   border-left:1px solid #fff;
   border-right:1px solid #f1f1f1;
   box-sizing: border-box;
}

看看效果:

(⊙o⊙)... 跟我想的不一样呢。 没有解决的问题:

  1. 文字没有撑开宽度。

2.文字没有居中

3.貌似内框的圆角消失了。

我们一个个来解决:

  1. 试试文字禁止换行的效果。
  2. 文字居中,这个要使用 text-align:center属性
  3. 把a标签的背景色去掉试试。
css 复制代码
.sub-menu li a {
   display: block;
   position: relative;
   float: left;  
   line-height: 2.5rem;
   width: 50%;
   color: #999;
   font-size: 0.9rem;
   text-shadow: 1px 1px 0 #fff;
   transition: all .3s;
   border-top:1px solid #fff;
   border-bottom: 1px solid #f1f1f1;   
   border-left:1px solid #fff;
   border-right:1px solid #f1f1f1;
   box-sizing: border-box;
   white-space: nowrap; /* 禁止文字换行 */
   text-align: center;
}

刷新一下浏览器:

(⊙o⊙)... 虽然文字没有换行,可这宽度依然很。。。

看来要换个思路解决问题。我在二级菜单里写了一个宽度50%,当然是为了实现一行两列。那么如果我给菜单设定宽度呢?试试。

css 复制代码
width: 120px;

这???一行两列果断消失了。

好吧,那我去把父元素 sub-menu的宽度设置成它的两倍。。

css 复制代码
.sub-menu{
   position: absolute;
   top:50px;
   border-radius: 10px;
   background: #fcfcfc;
   border:5px solid #139ce4;
   overflow: visible;
   width: 240px;
   height: auto;
   
}
.sub-menu li a {
   display: block;
   position: relative;
   float: left;  
   line-height: 2.5rem;
   width: 120px;
   color: #999;
   font-size: 0.9rem;
   text-shadow: 1px 1px 0 #fff;
   transition: all .3s;
   border-top:1px solid #fff;
   border-bottom: 1px solid #f1f1f1;   
   border-left:1px solid #fff;
   border-right:1px solid #f1f1f1;
   box-sizing: border-box;
   white-space: nowrap; /* 禁止文字换行 */
   text-align: center;
}

然而:

等下,我想到一个可能的办法:

因为要解决这个菜单的定位,所以,前面我把这个菜单的定位写成了 绝对定位。所以,当它的宽度设为100%时,它等于父元素的宽度。那么我们发现,它的菜单项的宽度有时候文字会很多,所以,我可以设定它的菜单项宽度等于父元素的宽度。为了容纳一行两列的布局,我可以把它的宽度设置成200%;

然后,子菜单的宽度设为50%。

Q:为什么是50%?父元素的宽度是200%,子菜单项的宽度不应该是100%吗?

A:请仔细思考一下,子菜单的父元素的宽度是多少?50%是哪个宽度的50%?

试一下:

.

css 复制代码
.sub-menu{
     width:200%;
     }
.sub-menu li a{
    width:50%;
}

刷新看看:

OYE~ 宽度有了,但是位置貌似还不太对,要让它基于父元素水平居中对齐。还得给它增加一个属性。

css 复制代码
.sub-menu{ width:200%; left:-50%; }

刷新再看看:

这下居中的没问题了。剩下就是小三角和内圆角。。

小三角利用before的来写一个border的就行,这个容易。

先来写这个小三角

css 复制代码
.sub-menu::before {
   display: block;
   content: "";
   height: 0;
   width: 0;
   position: absolute;
   border: 12px solid;
   border-color: transparent transparent #139ce4 transparent;
}

刷新一下,看看定位在哪里:

高度不太对,大概需要向上移动24-36像素左右。

css 复制代码
.sub-menu::before {
   left: 50%;
   transform: translateX(-50%);
   top: -30px;
}

水平的话,写个居中。。。高度就得微调了,试试看看效果:

额,高了一点。把之前的top:-30px,改一下:

css 复制代码
top: -28px;

剩下的就是内框的圆角了。

既然a标签把它填满导致了原来的内圆角没有了,而去掉了a标签的背景色依然没有出现圆角。那么我不妨把第一行的两个菜单项和最后一行的两个菜单项写个圆角。这里利用子选择器实现。为了避免菜单项数量改变而导致样式的变化,需要把样式写在最后两个子列表项上,而不是第7和第8上面。所以,在最后两个列表项上,我们使用的 nth-last-child 而不是 nth-child。

css 复制代码
.sub-menu li:nth-child(1) a{
	border-radius: 5px 0 0 0;
	overflow: hidden;
}
.sub-menu li:nth-child(2) a{
	border-radius: 0 5px 0 0;
	overflow: hidden;
}

/* 
.sub-menu li:nth-child(7) a{
	border-radius: 0 0 5px 0;
	overflow: hidden;
}
.sub-menu li:nth-child(8) a{
	border-radius: 0 0 0 5px;
	overflow: hidden;
}
*/

.sub-menu li:nth-last-child(1) a{
	border-radius: 0 0 5px 0;
	overflow: hidden;
}
.sub-menu li:nth-last-child(2) a{
	border-radius: 0 0 0 5px;
	overflow: hidden;
}

顺便,把右侧菜单项的右边框去掉:

css 复制代码
.sub-menu li:nth-child(2n) a{
   border-right:0px;
}

刷新页面,放大一倍,截图看看

基本样式就是这样了,接下来我们把鼠标hover效果写一下:

css 复制代码
.sub-menu li a:hover {
	color: #139ce4;	
	background: #e7f6fd;
}

嗯,先看就完美了。接下来,就剩下最后一步了。把它的常态设置为不可见,当鼠标到一级菜单时,再将它改为可见。

大功告成

我们截图看效果:

相关推荐
cs_dn_Jie19 分钟前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic1 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿1 小时前
webWorker基本用法
前端·javascript·vue.js
清灵xmf2 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据2 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161772 小时前
防抖函数--应用场景及示例
前端·javascript
334554323 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test3 小时前
js下载excel示例demo
前端·javascript·excel
PleaSure乐事3 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶3 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json