8.6 Snippet - Menu

1. Accordion

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Accordion Menu</title>
  <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
  <link href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" rel="stylesheet">

  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    html, body {
      height: 100%;
    }

    body {
      background-image: linear-gradient(20deg, #08aeea 0%, #2af598 100%);
      font-family: 'Open Sans', Arial, Helvetica, Sans-serif, Verdana, Tahoma;
    }

    ul {
      list-style-type: none;
    }

    h1 {
      color: #fff;
      font-size: 2.5rem;
      font-weight: bold;
      text-align: center;
      padding: 40px;
    }

    .accordion {
      width: 100%;
      max-width: 360px;
      margin: auto;
      background: #fff;
      border-radius: 4px;
    }

    .accordion .menu {
      position: relative;
      padding: 15px 15px 15px 45px;
      color: #4d4d4d;
      font-weight: bold;
      border-bottom: 1px solid #ccc;
      cursor: pointer;
      transition: all 0.4s ease;
    }

    .accordion li:last-child .menu {
      border-bottom: 0;
    }

    .accordion li i {
      position: absolute;
      top: 1.2rem;
      left: 1rem;
      color: #595959;
      transition: all 0.4s ease;
    }

    .accordion li i.fa-chevron-down {
      right: 1rem;
      left: auto;
    }

    .accordion li.show i.fa-chevron-down {
      transform: rotate(180deg);
    }

    .accordion li.show .menu {
      color: #b63b4d;
    }

    .accordion li.show i {
      color: #b63b4d;
    }

    /* Show submenu */
    .accordion li.show .submenu {
      /* height: auto;를 지정하면 transition이 동작하지 않는다 */
      max-height: 500px;
    }

    .submenu {
      /* height: auto;를 지정하면 transition이 동작하지 않는다 */
      max-height: 0;
      overflow: hidden;
      background: #444359;
      font-size: 14px;
      transition: max-height 0.4s ease;
    }

    .submenu li {
      border-bottom: 1px solid #4b4a5e;
    }

    .accordion li:last-child .submenu {
      border-radius: 0 0 4px 4px;
    }

    .accordion li:last-child .submenu li:last-child {
      border-bottom: 0;
    }

    .submenu a {
      display: block;
      text-decoration: none;
      color: #d9d9d9;
      padding: 12px;
      padding-left: 42px;
      transition: all 0.25s ease-in-out;
    }

    .submenu a:hover {
      background: #b63b4d;
      color: #fff;
    }
  </style>
</head>

<body>
  <h1>Accordion Menu</h1>

  <ul id="accordion" class="accordion">
    <li class="show">
      <div class="menu"><i class="fa fa-code"></i>Front-end<i class="fa fa-chevron-down"></i></div>
      <ul class="submenu">
        <li><a href="#">HTML</a></li>
        <li><a href="#">CSS</a></li>
        <li><a href="#">Javascript</a></li>
      </ul>
    </li>
    <li>
      <div class="menu"><i class="fa fa-mobile"></i>Responsive web<i class="fa fa-chevron-down"></i></div>
      <ul class="submenu">
        <li><a href="#">Tablets</a></li>
        <li><a href="#">Mobiles</a></li>
        <li><a href="#">Desktop</a></li>
      </ul>
    </li>
    <li>
      <div class="menu"><i class="fa fa-globe"></i>Web Browser<i class="fa fa-chevron-down"></i></div>
      <ul class="submenu">
        <li><a href="#">Chrome</a></li>
        <li><a href="#">Firfox</a></li>
        <li><a href="#">Safari</a></li>
      </ul>
    </li>
  </ul>
</body>
<script>
  class Accordion {
    constructor(options) {
      // 기본 옵션과 사용자 지정 옵션을 병합
      this.config = Accordion.mergeConfig(options);
      this.accordion = document.querySelector(this.config.selector);
      // 이벤트 핸들러 내부의 this는 currentTartget
      this.accordion.addEventListener('click', this.toogle.bind(this));
    }

    static mergeConfig(options) {
      // 기본 옵션
      const config = {
        selector: '#accordion',
        multi: true
      };

      return { ...config, ...options };
    }

    toogle(event) {
      if (!event.target.classList.contains('menu')) return;
      // click 이벤트를 발생시킨 <div class="menu"> 요소의 부모 요소인 li 요소
      const targetLi = event.target.parentNode;

      // 멀티 오픈을 허용하지 않으면 타깃 이외의 모든 서브메뉴를 클로즈한다.
      if (!this.config.multi) {
        [].filter.call(
          this.accordion.childNodes,
          li => li.nodeType === Node.ELEMENT_NODE && li !== targetLi
        ).forEach(li => li.classList.remove('show'));
      }

      // li 요소의 class에 "show"가 있으면 제거하고 없으면 추가한다.
      targetLi.classList.toggle('show');
    }
  }

  window.onload = function () {
    const accordion = new Accordion({ multi: false });
    // const accordion = new Accordion();
  };
</script>
</html>
Back to top
Close