zoukankan      html  css  js  c++  java
  • css做一个可以变成关闭图标的菜单按钮

    不记得什么是时候在某个网站上看到一个菜单按钮, 初始状态是三条横线, 点击打开菜单后可以变成关闭按钮, 这个过程有一个过度动画, 效果像下面这样(因为想不起来是哪个网站了, 所以下面的的gif是我根据印象实现后的效果)

    这个东西实现起来挺简单, 但是这个过度动画挺有意思的;

    首先是html, 外层一个div.menu元素, 里面放三个span用作三条杠

    <div class="menu">
        <span></span>
        <span></span>
        <span></span>
    </div>
    

    然后写点css, 设置下menu的宽高和三条横杠, 同时也设置下过度相关的属性; 我这里用了less作为css的预处理器:

    @menu-size: 50px;
    @menu-stroke: 4px;
    @menu-stroke-color: #fff;
    @menu-animation-duration: .3s;
    
    .menu {
      display: inline-flex;
      flex-direction: column;
      justify-content: space-around;
      height: @menu-size;
      span {
         @menu-size;
        height: @menu-stroke;
        display: block;
        transition-property: opacity transform top;
        transition-duration: @menu-animation-duration;
        background-color: @menu-stroke-color;
      }
      span:nth-child(2){
        transition-duration: .1s;
      }
    }
    

    基本的样式写完后写开始写过度之后的样式, 给这个样式取一个名字叫menu-closeable

    .menu-closeable {
      position: relative;
      span:nth-child(1) {
        position: absolute;
        transform: rotateZ(45deg);
        top: @menu-size/2;
      }
      span:nth-child(2) {
        opacity: 0;
      }
      span:nth-child(3) {
        position: absolute;
        transform: rotateZ(-45deg);
        
        top: @menu-size/2;
      }
    }
    

    这些样式写完后需要通过js来触发, 点击后在让菜单关闭状态和普通状态间进行切换

    const el = document.querySelector('.menu');
    let clicked = false;
    el.addEventListener('click', () => {
      clicked = !clicked;
      if (clicked) {
      el.classList.add('menu-closeable');
      } else {
        el.classList.remove('menu-closeable');
      }
    })
    

    这样就完成了, 每次点击菜单, 菜单都会在三条横杠和一个叉叉的状态的间切换, 并且还有过度动画, 就像开头的git里面那样.

    完整的演示可以参见Codepen.

    Angular中的实现这个动画

    模板html

    <div class="menu"
         [@menuCloseIcon]="{ value: isCloseIcon ? 'close' : 'menu', params: { size: size + 'px' } }"
         [ngStyle]="{ height: size + 'px' }">
      <span [ngStyle]="spanStyle"
            [@span1Trigger]="{ value: isCloseIcon ? 'close': 'menu', params: { size: size + 'px' } }"></span>
      <span [ngStyle]="spanStyle"
            [@span2Trigger]="{ value: isCloseIcon ? 'close': 'menu', params: { size: size + 'px' } }"></span>
      <span [ngStyle]="spanStyle"
            [@span3Trigger]="{ value: isCloseIcon ? 'close': 'menu', params: { size: size + 'px' } }"></span>
    </div>
    

    ts代码

    import {
      animate,
      animateChild,
      group,
      query,
      state,
      style,
      transition,
      trigger,
    } from '@angular/animations';
    import { Component, Input, OnInit } from '@angular/core';
    
    const childrenOption = {
      params: { size: '' },
    };
    
    @Component({
      selector: 'cnb-moving-menu',
      templateUrl: './moving-menu.component.html',
      styleUrls: ['./moving-menu.component.less'],
      animations: [
        trigger('menuCloseIcon', [
          transition('* <=> *', [
            group([
              query('@span1Trigger', animateChild()),
              query('@span2Trigger', animateChild()),
              query('@span3Trigger', animateChild()),
            ]),
          ]),
        ]),
        trigger('span1Trigger', [
          state(
            'close',
            style({
              position: 'absolute',
              transform: 'rotateZ(45deg)',
              top: '{{size}}/2',
            }),
            childrenOption
          ),
          state('menu', style({ transform: 'rotateZ(0)' })),
          transition('* => *', [animate('.2s ease-in')]),
        ]),
        trigger('span2Trigger', [
          state(
            'close',
            style({
              opacity: 0,
            }),
            childrenOption
          ),
          state('menu', style({ opacity: 1 })),
          transition('* => *', [animate('.2s ease-in')]),
        ]),
        trigger('span3Trigger', [
          state(
            'close',
            style({
              position: 'absolute',
              transform: 'rotateZ(-45deg)',
              top: '{{size}}/2',
            }),
            childrenOption
          ),
          state('menu', style({ transform: 'rotateZ(0)' })),
          transition('menu <=> close', [animate('.2s ease-in')]),
        ]),
      ],
    })
    export class MovingMenuComponent implements OnInit {
      @Input() size = 24;
      @Input() stroke = 3;
      @Input() transitionDuration = '.3s';
      @Input() isCloseIcon = false;
      @Input() strokeColor = '#fff';
      spanStyle = {
        height: this.stroke + 'px',
         this.size + 'px',
        'background-color': this.strokeColor,
      };
    
      constructor() {}
    
      ngOnInit(): void {}
    }
    

    样式文件

    :host {
      display: inline-flex;
      align-items: center;
    }
    
    .menu {
      display: inline-flex;
      flex-direction: column;
      justify-content: space-around;
    
      span {
         @menu-size;
        height: @menu-stroke;
        display: block;
      }
    }
    

    作者:Laggage

    出处:https://www.cnblogs.com/laggage/p/14815512.html

    说明:转载请注明来源

  • 相关阅读:
    Bootstrap历练实例:带有下拉菜单的标签和胶囊导航
    python学习网址
    /mnt/sdcard 是什么东西
    tornado中文教程
    ssh免密码登录远程服务器(不采用securecrt登录)
    接口测试博客
    [python学习篇] [os模块] [2]删除文件夹
    解压文件夹python
    adb pull 文件夹的时候注意
    [uiautomator篇][python调用java][1]应用下载的插件需要很长时间问题解决
  • 原文地址:https://www.cnblogs.com/laggage/p/14815512.html
Copyright © 2011-2022 走看看