酷酷的SVG动画菜单

Author image Cloud on 前端 , UI , SVG
SVG动画,结合了CSS3的transition, 先看下效果图 动画效果: 直接参见本页面的导航菜单鼠标一上去,会有border变长,通过border的dashoffset的变化,包围住整个菜单矩形。用到了css3的animation,详细用法大家可以看下: http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html 讲的比较好注意,Firefox中跟webkit计算dash-offset方法有不同,需要fix一下:/** * FIX Firefox bugs: an

SVG动画,结合了CSS3的transition, 先看下效果图 屏幕快照 2015-10-27 下午8.25.00.png

动画效果: 直接参见本页面的导航菜单laughing


鼠标一上去,会有border变长,通过border的dashoffset的变化,包围住整个菜单矩形。

用到了css3的animation,详细用法大家可以看下: http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html 讲的比较好


注意,Firefox中跟webkit计算dash-offset方法有不同,需要fix一下:

/**
 * FIX Firefox bugs: anti-direcion,
 * and dashoffset is different with Chrome
 */
@keyframes moz_draw {
  0% {
    stroke-dasharray: $dash_len $dash_space_len;
    stroke-dashoffset: $dash_offset;
    stroke-width: $stroke_max_width;
  }
  100% {
    stroke-dasharray: $dash_full_len+$dash_space_len;
    stroke-dashoffset: -$dash_offset;
    stroke-width: $stroke_min_width;
  }
}


然后单独对Firefox进行CSS Hack:

&:hover .shape {
          -webkit-animation: 0.5s linear 0s normal forwards 1 draw;
          animation: 0.5s linear 0s normal forwards 1 draw;

          //fix Firefox :stroke-dashoffset not 0 ??
          @-moz-document url-prefix() {
            animation: 0.5s linear 0s normal forwards 1 moz_draw;
          }
}


Firefox的差异,稍后有时间我再研究下。这种东西比较坑爹~



其他不多说,上代码,算法代码总有注释:

1.  先上html结构参考:


<header>
    <nav>
        <div class="menu active">
            <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="180px" height="48px">
                <rect width="180px" height="48px" class="shape"></rect>
            </svg>
            <a href="/" class="text">HOME</a>
        </div>
        <div class="menu">
            <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="180px" height="48px">
                <rect width="180px" height="48px" class="shape"></rect>
            </svg>
            <a href="/toxic" class="text">TOXIC</a> 
        </div>
        <div class="menu">
            <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="180px" height="48px">
                <rect width="180px" height="48px" class="shape"></rect>
            </svg>
            
            <a href="/gallery" class="text">GALLERY</a>
        </div>
    </nav>
</header>



2. 这块是定义变量和动画, 注意下stroke和dash、dash offset的值的定义:

@import 'define';
@import 'util';

/**
 * Stroke Calculator =====================
 * @type {[type]}
 * @description: stroke-dashoffset ,
 * 是起点偏移量,在svg的rect中,从左上角开始,
 * 如果offset为负值,那么线段向右偏移移动。
 * dasharray第一个是线段长度,
 * 第二个是空白间隔长度,
 * 当空白间隔小于 offset的时候,
 * 起点处会进入一部分线段(起点之前的线段)。
 * 线段是无穷循环的,
 * 但是都会没入结点中,超过结点后,被覆盖。
 */
$stroke_color: #19f6e8;
$menu_w: 180px;
$menu_h: 48px;
$stroke_max_width: 6px;
$stroke_min_width: 2px;
$dash_len: 120px;
$dash_space_len: $menu_w + $menu_h + ($menu_w - $dash_len)/2;
$dash_offset: - $dash_space_len;
 
$dash_full_len: 2*($menu_w + $menu_h);
//======================================
/**
 * A text center size
 */
$text_size: 18px;
$text_bottom: $text_size + ($menu_h - $text_size)/2 + $stroke_min_width;
@keyframes draw {
  0% {
    stroke-dasharray: $dash_len $dash_space_len;
    stroke-dashoffset: $dash_offset;
    stroke-width: $stroke_max_width;
  }
  100% {
    stroke-dasharray: $dash_full_len;
    stroke-dashoffset: 0;
    stroke-width: $stroke_min_width;
  }
}
/**
 * FIX Firefox bugs: anti-direcion,
 * and dashoffset is different with Chrome
 */
@keyframes moz_draw {
  0% {
    stroke-dasharray: $dash_len $dash_space_len;
    stroke-dashoffset: $dash_offset;
    stroke-width: $stroke_max_width;
  }
  100% {
    stroke-dasharray: $dash_full_len+$dash_space_len;
    stroke-dashoffset: -$dash_offset;
    stroke-width: $stroke_min_width;
  }
}



3. 这块是CSS样式



      .menu {  
        width: $menu_w;
        height: $menu_h;
        display: inline-block;
        margin: 2px;
        // margin: 0 auto;
        text-align: center;
        position: relative;

        /**
         * @debug Firefox和一些safair版本中,不识别CSS中的width和height
         * 必须将width写在svg代码中
         */
        svg{
          width: $menu_w;
          height: $menu_h;
          .shape {
            
            // @extend .hardware;

            width: $menu_w;
            height: $menu_h;

            fill: transparent;
            stroke-dasharray: $dash_len $dash_space_len;
            stroke-dashoffset: $dash_offset;
            stroke-width: 0;
            stroke: $stroke_color;
  
            // 选中状态的
            @at-root nav .menu.active svg .shape {
              stroke-width: $stroke_max_width;
            }

          }
        }

        &:hover .shape {
          -webkit-animation: 0.5s linear 0s normal forwards 1 draw;
          animation: 0.5s linear 0s normal forwards 1 draw;

          //fix Firefox :stroke-dashoffset not 0 ??
          @-moz-document url-prefix() {
            animation: 0.5s linear 0s normal forwards 1 moz_draw;
          }
        }

        .text {
          // 具有子菜单的一级菜单,具有交互模糊效果
          @at-root .menu.on .text{
            @include blur(2px);
          }
          @include trans-all(); 
          
          color: $nav_a_color;
          font-size: $text_size;
          letter-spacing: 3px;
          line-height: $text_size;
          position: relative;
          bottom: $text_bottom;
          // font-family: 'roboto';
          text-decoration: none;          
          
          &:hover {
            color: $nav_a_color;
            letter-spacing: 4px;
          }
        }
      }