响应式导航栏实现

前言

最近想实现定制化的响应式顶部导航栏,即支持主流设备的正常访问(Phone、Pad、PC),并根据屏幕比例实现对应的显示效果。

曾尝试使用以下方式

  • Element UI提供的导航栏(样式单调,没有响应式效果)
  • BootStrap 提供的导航栏(有响应式效果,需额外引入依赖包,且定制效果修改较繁琐)

由此,产生自己动手实现响应式顶部导航栏的想法,并应当拥有以下特点:

  • 实现方式较为简单,无需引入额外依赖库(或较少)
  • 可以实现动态添加功能菜单,个性化定制较为简便
  • 实现对多种设备的兼容性,保证显示效果较为美观
效果展示
最终效果
  • Tips:若 gif 图片未加载出,请尝试刷新。
提前准备
  • 掌握H5、CSS布局技巧
  • 理解掌握CSS媒体查询
  • 掌握一种渐进式框架(这里结合Vue进行实现)
  • 对所要实现导航栏有一定的设计规划
实现

思路:将导航栏分为左右两部分,当窗口宽度减少时,使用css媒体查询实现样式修改,当宽度减小至最小时,隐藏当前导航显示,替换为下拉列表展示。

  • 主要通过css媒体查询实现样式改变
  • 为方便扩展,导航选项设置为对象数组

Header.vue

  • template 部分
<template>
  <!--xs: phone, sm: pad, md: pc, lg: 2k-pc, xl: 4k-pc-->
  <nav class="header">
    <!-- 顶部导航 -->
    <div class="container">
      <ul class="container-left-ul">
        <li>
          <img id="icon" src="@assets/image/icon.png"/>
        </li>
        <li :class="$store.state.activeName === item.activeName ? 'menu-item-active' : 'container-left-li'" @click="toActiveMenuItem(item)"
          v-for="(item, index) in leftMenuList" :key="index">
          {{ item.titleName }}
        </li>
      </ul>
      <ul class="container-right-ul">
        <li :class="$store.state.activeName === item.activeName ? 'menu-item-active' : 'container-right-li'" @click="toActiveMenuItem(item)"
          v-for="(item, index) in rightMenuList" :key="index">
          {{ item.titleName }}
        </li>
        <li id="bars" @click="dropDownShow = !dropDownShow">
          <i class="fa fa-bars fa-lg"/>
        </li>
      </ul>
    </div>

    <!-- 下拉菜单 -->
    <transition name="dropdown-fade-show">
      <div v-show="dropDownShow" class="dropdown">
        <ul class="dropdown-top-ul">
          <li class="dropdown-top-li" v-for="(item, index) in leftMenuList" :key="index" @click="toActiveMenuItem(item)">{{ item.titleName }}</li>
        </ul>
        <ul class="dropdown-bottom-ul">
          <li class="dropdown-bottom-li" v-for="(item, index) in rightMenuList" :key="index" @click="toActiveMenuItem(item)">{{ item.titleName }}</li>
        </ul>
      </div>
    </transition>

  </nav>
</template>
  • script 部分
export default {
  name: 'Header',
  data () {
    return {
      dropDownShow: false, // 控制下拉菜单显示
      leftMenuList: [ // 左侧菜单内容
        { activeName: 'Home', titleName: '主页', activeUrl: '/index' },
        { activeName: 'Infinity', titleName: 'Infinity', activeUrl: '/infinity' },
        { activeName: 'About', titleName: '关于', activeUrl: '/about' }
      ],
      rightMenuList: [ // 右侧菜单内容
        { activeName: 'Support', titleName: '赞助', activeUrl: '/support' }
      ],
      activeName: '' // 导航栏激活名称
    }
  },
  methods: {
    toActiveMenuItem (item) { // 激活导航菜单
      this.activeName = item.titleName
      this.$router.push(item.activeUrl)
      this.dropDownShow = false
    }
  }
}
  • css 部分(这里使用stylus)
<style lang="stylus" scoped>
@import "../../assets/stylus/init.stylus" // 初始化导航栏参数
@import "../../assets/stylus/fade.stylus" // 实现导航栏下拉展示动画效果
.header
  color $headerTextColor
  background $headerBg
  height $header-height
  width 100%
  position fixed
  top 0
  padding 0 10%
  .container
    width 100%
    height 100%
    .container-left-ul
      float left
      li
        height 100%
        line-height $header-height
        width $header-li-width
        display inline-block
      #icon
        height 30px
        vertical-align middle
        transition transform 0.5s
      #icon:hover
        transform scale(1.5, 1.5) rotate(180deg)
      .container-left-li:hover
        color $menu-active-color
        box-shadow 0px -4px 0px $menu-active-color inset
    .container-right-ul
      float right
      li
        height 100%
        line-height $header-height
        width $header-li-width
        display inline-block
      .container-right-li:hover
        color $menu-active-color
        box-shadow:0px -4px 0px $menu-active-color inset
      #bars > i
        padding 8px 14px
        border 1px $headerTextColor solid
        border-radius 5px
  .dropdown
    border 1px red solid
    width 100%
    background $headerBg
    li
      height 40px
      line-height 40px
    li:hover
      background black

.menu-item-active
  color $menu-active-color
  box-shadow 0px -4px 0px $menu-active-color inset

@media screen and (max-width: 992px) {
  .header {
    padding 0
  }
}
@media screen and (max-width: 768px) {
  .container-left-li {
    display none !important
  }
  .container-right-li {
    display none !important
  }
}
@media screen and (min-width: 768px) {
  #bars {
    display none
  }
  .dropdown {
    display none
  }
}
</style>
  • init.stylus
    • params.stylus (参数配置)
    • color.stylus (颜色配置)
/* params.stylus (参数配置)*/
// 配置页头的相关参数
$header-height = 60px
$header-li-width = 70px
// 导航栏菜单激活颜色
$menu-active-color = $googleYellow
$headerBg = #282C34
$headerTextColor = #ffffff

/* color.stylus (颜色配置) */
$googleRed = #f4433c
$googleBlue = #2d85f0
$googleGreen = #0aa858
$googleYellow = #ffbc32

Tips:

  • css变量的引入可以更好的解决主题等相关配置问题

导航栏实现后,屏幕尺寸缩小后,显示出下拉菜单,此时应给菜单显示和消失添加动画效果,实现el-zoom-in-top类似效果(借助vue的<transition>实现效果)。

  • fade.stylus
// 下拉菜单出现效果
.dropdown-fade-show-enter-active
  animation fadeShow .25s
.dropdown-fade-show-leave-to
  animation fadeShow .25s reverse
@keyframes fadeShow {
  0% {
    transform-origin 0 top
    transform scaleY(0)
    opacity 0
  }
  100% {
    transform-origin 0 top
    transform scaleY(1)
    opacity 1
  }
}
结语

这里只是提供响应式导航布局的设计思路,细节部分仍可优化。

待优化点:

  • 可以通过设计及css优化相关样式
  • 结合Vuex、浏览器本地缓存解决页面刷新后导航栏状态恢复的问题

优化代码后续更新,也欢迎大家积极讨论,共同进步!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容

  • 笔记参考自《响应式Web设计:HTML5和CSS3实践》,2013年出版内容说不上最新。如下是全书的章的目录:第 ...
    于晓鱼阅读 864评论 0 1
  • 独倚栏栅等马龙, 轻望杨絮染城白。 伸手拂晓前世尘, 抬步骤行心何归?
    南风喃o北秋悲阅读 142评论 0 1
  • 一个有钱的富人,正在家院的花园时赏梅花。 那是冬日寒冷的清晨,艳红的梅花正以最美丽的姿容吐露,富人颇为自己的花园里...
    共书君阅读 373评论 0 0
  • 这两天吴昕一直上热搜,然后就有很多关于她的新闻跳出来被我了解。在我的印象里,她在节目里就是安安静静的人,最近拍的时...
    哇是京京呀阅读 348评论 0 0
  • 简诗歌\原创 傍晚时分,我在江边漫步。 扭头看向夕阳的方向,我被那一幕惊呆了。 无边的璀璨的云霞,变幻着色彩将我整...
    简诗歌阅读 306评论 0 2