자바스크립트 드롭다운 메뉴 목록 만들기

원본: 자바스크립트로 드롭다운 메뉴를 만드는 방법

웹 서핑을 하면서 드롭다운 메뉴를 사용해 본 적이 있을 것 입니다. 이는 주로 Form 양식에서 사용자 입력 수집하기, 웹 애플리케이션에서 탐색 메뉴 구현 등에 사용됩니다.

드롭다운은 애플리케이션의 레이아웃 흐름을 깨지 않고 여러 기능을 제공하는 가장 좋은 방법입니다. 웹 외에도 exe 프로그램, 운영체제 등에서 사용됩니다.

이 포스트에서는 HTML, CSS, 자바스크립트를 사용하여 드롭다운 탐색 메뉴를 만드는 방법을 알아보겠습니다. 다음은 빌드할 내용의 스크린샷입니다.

드롭다운 스크린샷

Step 1 – 드롭다운 마크업 추가

시각적 요소를 위해 이번 예제에서는 아이콘을 사용하겠습니다. 아이콘은 간단히 처리하기 위해 Boxicons라는 무료 라이브러리를 사용 하겠습니다. 원하는 다른 대안이 있으면 자유롭게 선택할 수 있습니다.

페이지에 Boxicons를 설정하는 방법은 여러가지가 있습니다. 가장 간단한 방법은 다음과 같이 HTML 파일의 <head>에 태그를 정의하는 것 입니다:

<head>
  <link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet" />
</head>

아이콘을 추가한 후 “container”라는 클래스 명을 가지는 div 요소를 추가합니다. 이 요소 안에 버튼과 드롭다운 메뉴를 넣을 것 입니다.

container 내부에 button 요소를 생성하고 클래스 명과 id를 “btn”으로 지정합니다. 버튼의 텍스트로 “Dropdown”과 화살표 아이콘을 지정합니다.

다음은 버튼에 대한 마크업입니다:

<button class="btn" id="btn">
  Dropdown
  <i class="bx bx-chevron-down" id="arrow"></i>
</button>

다음으로 드롭다운 메뉴 자체에 대한 마크업을 추가하겠습니다.

button 태그 다음에 div 요소를 추가하고 클래스 명과 id를 “dropdown”으로 지정합니다. 이 요소 내에는 각각의 메뉴 항목에 대해 a 태그를 추가하고 해당 텍스트와 아이콘을 지정합니다.

<div class="dropdown" id="dropdown">
  <a href="#create">
    <i class="bx bx-plus-circle"></i>
    Create New
  </a>
  <a href="#draft">
    <i class="bx bx-book"></i>
    All Drafts
  </a>
  <a href="#move">
    <i class="bx bx-folder"></i>
    Move To
  </a>
  <a href="#profile">
    <i class="bx bx-user"></i>
    Profile Settings
  </a>
  <a href="#notification">
    <i class="bx bx-bell"></i>
    Notification
  </a>
  <a href="#settings">
    <i class="bx bx-cog"></i>
    Settings
  </a>
</div>

위의 HTML 코드를 모두 index.html 파일에 작성하고 실행하면 다음과 같은 화면을 볼 수 있습니다:

드롭다운 HTML 예제

아직 좋게 보이진 않습니다. 이제 메뉴에 스타일링을 해보겠습니다.

Step 2 – 드롭다운 메뉴 스타일링

먼저 페이지 모든 요소의 기본 margin과 padding을 재설정하고 CSS 파일 전체에서 재사용할 수 있도록 변수를 설정합니다.

@import url(https://fonts.googleapis.com/css?family=Inter:100,200,300,regular,500,600,700,800,900);

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Inter", sans-serif;
  --shadow: rgba(0, 0, 0, 0.05) 0px 6px 10px 0px, rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
  --color: #166e67;
  --gap: 0.5rem;
  --radius: 5px;
}

body {
  margin: 2rem;
  background-color: #b3e6f4;
  font-size: 0.9rem;
  color: black;
}

다음 단계는 버튼과 드롭다운 컨테이너 자체의 스타일을 지정하는 것 입니다.

.btn {
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  column-gap: var(--gap);
  padding: 0.6rem;
  cursor: pointer;
  border-radius: var(--radius);
  border: none;
  box-shadow: var(--shadow);
  position: relative;
}

.bx {
  font-size: 1.1rem;
}

.dropdown {
  position: absolute;
  width: 250px;
  box-shadow: var(--shadow);
  border-radius: var(--radius);
  margin-top: 0.3rem;
  background: white;
}

.dropdown a {
  display: flex;
  align-items: center;
  column-gap: var(--gap);
  padding: 0.8rem 1rem;
  text-decoration: none;
  color: black;
}

.dropdown a:hover {
  background-color: var(--color);
  color: white;
}

드롭다운 요소는 버튼 위에 배치되므로 버튼의 positionrelative이고 드롭다운의 positionabsolute가 됩니다.

이렇게 하면 페이지 레이아웃 흐름에 영향을 주지 않으면서 두 요소를 가깝게 또는 겹치게 배치할 수 있습니다.

다음은 결과물입니다:

css 스타일 적용

이제 스타일을 지정했으므로 처음 부터 메뉴가 표시되지 않고 버튼을 눌렀을 때만 표시되도록 하겠습니다. 이러한 작업을 위해 CSS에 메뉴 숨기기 속성을 추가하겠습니다.

CSS의 숨기기는 display: none을 사용하면 되는데 MDN Docs에 의하면 이는 애니메이션 가능하지 않습니다.

여기서는 애니메이션이 가능하면서 메뉴를 숨기기위해 visibilityopacity를 사용해 보겠습니다. 앞서 정의했던 dropdown 클래스에 visibility: hiddenopacity: 0을 추가해 페이지에서 메뉴를 숨깁니다.

메뉴가 보이는 상황을 처리하기 위해 show 클래스를 추가하고 visibility: visibleopacity: 1을 설정합니다. 이 클래스는 자바스크립트를 사용하여 요소에 삽입할 수 있습니다.

.dropdown {
  position: absolute;
  width: 250px;
  box-shadow: var(--shadow);
  border-radius: var(--radius);
  margin-top: 0.3rem;
  background: white;
  transition: all 0.1s cubic-bezier(0.16, 1, 0.5, 1);
    
  transform: translateY(0.5rem);
  visibility: hidden;
  opacity: 0;
}

.show {
  transform: translateY(0rem);
  visibility: visible;
  opacity: 1;
}

.arrow {
  transform: rotate(180deg);
  transition: 0.2s ease;
}

메뉴를 숨기고 보이는 스타일과 함께 버튼을 누르면 화살표 아이콘을 회전하는 arrow 클래스도 추가했습니다.

Step 3 – 드롭다운 기능 추가

우선 재사용이 가능하도록 getElementById() 메소드를 사용하여 조작할 요소들을 변수에 저장하겠습니다.

const dropdownBtn = document.getElementById("btn");
const dropdownMenu = document.getElementById("dropdown");
const toggleArrow = document.getElementById("arrow");

다음으로 show와 arrow 클래스를 토글하는 toggleDropdown() 함수를 만들겠습니다.

const toggleDropdown = function () {
  dropdownMenu.classList.toggle("show");
  toggleArrow.classList.toggle("arrow");
};

그런 다음 addEventListener 메소드를 사용하여 버튼을 클릭하면 위의 함수를 호출하게 합니다. 이렇게 하면 버튼을 클릭할 때마다 메뉴 표시 및 숨기기 기능이 실행됩니다.

dropdownBtn.addEventListener("click", function (e) {
  e.stopPropagation();
  toggleDropdown();
});

이벤트 핸들러 내에 stopPropagation() 메소드를 호출한 것을 확인할 수 있습니다. 이렇게 하면 클릭 이벤트가 부모 요소로 전달되는 것을 방지하여 기능이 두 번 실행되는 것을 방지합니다.

다른 DOM 요소 클릭 시 드롭다운 메뉴 닫기

드롭다운 메뉴는 일반적으로 다음 네 가지 방법으로 닫힙니다:

  • 메뉴를 열었던 버튼을 다시 누를 때
  • 메뉴의 항목을 눌렀을 때
  • body 요소 같은 메뉴의 바깥을 눌렀을 때
  • esc 키를 눌렀을 때

여기서는 세 번째 경우 까지만 다루겠습니다.

루트 요소인 <html>을 참조하기 위해 document.documentElement를 사용합니다. 여기에 클릭 이벤트를 추가해 toggleDropdown() 함수를 실행합니다.

주의할 점은 메뉴 요소에 show 클래스가 존재하는지 확인을 하고 toggleDropdown() 함수를 실행해야 한다는 점 입니다.

document.documentElement.addEventListener("click", function () {
  if (dropdownMenu.classList.contains("show")) {
    toggleDropdown();
  }
});

See the Pen Untitled by shinyks (@shinyks) on CodePen.

전체 코드

index.html

<html>

<head>
  <link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet" />
  <link href="style.css" rel="stylesheet" />
</head>

<body>
  <div class="container">
    <button class="btn" id="btn">
      Dropdown
      <i class="bx bx-chevron-down" id="arrow"></i>
    </button>

    <div class="dropdown" id="dropdown">
      <a href="#create">
        <i class="bx bx-plus-circle"></i>
        Create New
      </a>
      <a href="#draft">
        <i class="bx bx-book"></i>
        All Drafts
      </a>
      <a href="#move">
        <i class="bx bx-folder"></i>
        Move To
      </a>
      <a href="#profile">
        <i class="bx bx-user"></i>
        Profile Settings
      </a>
      <a href="#notification">
        <i class="bx bx-bell"></i>
        Notification
      </a>
      <a href="#settings">
        <i class="bx bx-cog"></i>
        Settings
      </a>
    </div>
  </div>

  <script src="script.js"></script>
</body>

</html>

style.css

@import url(https://fonts.googleapis.com/css?family=Inter:100,200,300,regular,500,600,700,800,900);

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Inter", sans-serif;
  --shadow: rgba(0, 0, 0, 0.05) 0px 6px 10px 0px,
    rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
  --color: #166e67;
  --gap: 0.5rem;
  --radius: 5px;
}

body {
  margin: 2rem;
  background-color: #b3e6f4;
  font-size: 0.9rem;
  color: black;
}

.btn {
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  column-gap: var(--gap);
  padding: 0.6rem;
  cursor: pointer;
  border-radius: var(--radius);
  border: none;
  box-shadow: var(--shadow);
  position: relative;
}

.bx {
  font-size: 1.1rem;
}

.dropdown {
  position: absolute;
  width: 250px;
  box-shadow: var(--shadow);
  border-radius: var(--radius);
  margin-top: 0.3rem;
  background: white;

  visibility: hidden;
  opacity: 0;
  transform: translateY(0.5rem);
  transition: all 0.1s cubic-bezier(0.16, 1, 0.5, 1);
}

.dropdown a {
  display: flex;
  align-items: center;
  column-gap: var(--gap);
  padding: 0.8rem 1rem;
  text-decoration: none;
  color: black;
}

.dropdown a:hover {
  background-color: var(--color);
  color: white;
}

.show {
  visibility: visible;
  opacity: 1;
  transform: translateY(0rem);
}

.arrow {
  transform: rotate(180deg);
  transition: 0.2s ease;
}

script.js

const dropdownBtn = document.getElementById("btn");
const dropdownMenu = document.getElementById("dropdown");
const toggleArrow = document.getElementById("arrow");

// Toggle dropdown function
const toggleDropdown = function () {
  dropdownMenu.classList.toggle("show");
  toggleArrow.classList.toggle("arrow");
};

// Toggle dropdown open/close when dropdown button is clicked
dropdownBtn.addEventListener("click", function (e) {
  e.stopPropagation();
  toggleDropdown();
});

// Close dropdown when dom element is clicked
document.documentElement.addEventListener("click", function () {
  if (dropdownMenu.classList.contains("show")) {
    toggleDropdown();
  }
});

관련 글

자바스크립트 튜토리얼