์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- ํ ๋ง์๋์ ํ
- UIUX
- ์น๊ฐ๋ฐ
- ui์ปดํฌ๋ํธ
- ์น๋์์ธ
- JavaScript
- ์นUI
- ๋คํฌ๋ชจ๋
- ํ๋ก ํธ์๋
- ๋คํฌ๋ชจ๋ํ ๊ธ
- ์คํฌ๋ฆฐ๋ฆฌ๋์ง์
- ์ธํฐ๋ ํฐ๋ธui
- ์๋ฐ์คํฌ๋ฆฝํธ์ปดํฌ๋ํธ
- ์ฝ๋ฉ์์
- ๋ฐ๋๋ผjs
- ๋ก์ปฌ์คํ ๋ฆฌ์ง
- uiux๋์์ธ
- ์๋ฐ์คํฌ๋ฆฝํธui
- ์๋ฐ์คํฌ๋ฆฝํธ
- js์คํฌ๋กค์ด๋ฒคํธ
- css์ ๋๋ฉ์ด์
- css๋ณ์
- ์คํฌ๋กค์ ๋๋ฉ์ด์
- ๋ฐ์ํ์น
- ์นui๋์์ธ
- preferscolorscheme
- ๋ฐ๋๋ผ์คํฌ๋ฆฝํธ
- ์ ๊ทผ์ฑ
- ์น์ ๊ทผ์ฑ
- UX๋์์ธ
- Today
- Total
UI Code Lab
์๋ฐ์คํฌ๋ฆฝํธ๋ก ๋๋กญ๋ค์ด ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ (Dropdown) ๋ณธ๋ฌธ
์๋ฐ์คํฌ๋ฆฝํธ๋ก ๋๋กญ๋ค์ด ๊ธฐ๋ฅ ๋ง๋ค๊ธฐ (Dropdown)
๐ฏ๊ฟ์์ด๐ 2025. 6. 19. 09:00
์น ํ์ด์ง๋ฅผ ๋ง๋ค๋ค ๋ณด๋ฉด ๋ฉ๋ด๋ ํํฐ, ์ค์ ์ฐฝ ๋ฑ ๋๋กญ๋ค์ด(dropdown) ๊ธฐ๋ฅ์ด ๊ผญ ํ์ํ ๋๊ฐ ์์ต๋๋ค. ์ด๋ฒ ๊ธ์์๋ jQuery ์์ด๋ ๊ตฌํ ๊ฐ๋ฅํ ์์ ์๋ฐ์คํฌ๋ฆฝํธ(dropdown)๋ฅผ ํ์ฉํด ์ฌ์ฉ์๊ฐ ํด๋ฆญํ๋ฉด ์ด๋ฆฌ๊ณ , ๋ค์ ํด๋ฆญํ๋ฉด ๋ซํ๋ ๊ธฐ๋ณธ ๋๋กญ๋ค์ด UI๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์๊ฐํฉ๋๋ค.
โ ๋๋กญ๋ค์ด์ด๋?
๋๋กญ๋ค์ด(dropdown)์ ์ฌ์ฉ์์ ํด๋ฆญ์ ๋ฐ๋ผ ์ ํ์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ UI ์์์ ๋๋ค. ๋ํ์ ์ธ ์๋ก ๋ด๋น๊ฒ์ด์ ๋ฉ๋ด, ์ธ์ด ์ ํ ์ฐฝ, ์๋ฆผ ๋ชฉ๋ก ๋ฑ์์ ์์ฃผ ํ์ฉ๋ฉ๋๋ค.
๐ ๏ธ HTML ๊ตฌ์กฐ
๋จผ์ dropdown์ ๊ตฌ์ฑํ ๊ธฐ๋ณธ HTML์ ์์ฑํฉ๋๋ค:
<div class="dropdown">
<button id="dropdownButton">๋ฉ๋ด ์ด๊ธฐ โพ</button>
<ul id="dropdownMenu" class="dropdown-menu">
<li><a href="#">ํ</a></li>
<li><a href="#">์๊ฐ</a></li>
<li><a href="#">๋ฌธ์</a></li>
</ul>
</div>
๐จ CSS ์คํ์ผ
๊ธฐ๋ณธ์ ์ผ๋ก ๋๋กญ๋ค์ด ๋ฉ๋ด๋ ์จ๊ธฐ๊ณ , ๋ฒํผ ํด๋ฆญ ์ ๋ณด์ด๋๋ก ์ฒ๋ฆฌํฉ๋๋ค.
.dropdown-menu {
display: none;
position: absolute;
background-color: #fff;
border: 1px solid #ddd;
list-style: none;
padding: 0;
margin-top: 8px;
width: 160px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
.dropdown-menu li {
padding: 10px;
}
.dropdown-menu li:hover {
background-color: #f4f4f4;
}
โ๏ธ JavaScript๋ก ํ ๊ธ ๊ธฐ๋ฅ ๊ตฌํ
๋ฒํผ์ ํด๋ฆญํ๋ฉด ul.dropdown-menu์ display ์์ฑ์ ํ ๊ธ ํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํฉ๋๋ค.
document.addEventListener("DOMContentLoaded", function () {
const button = document.getElementById("dropdownButton");
const menu = document.getElementById("dropdownMenu");
button.addEventListener("click", function () {
const isVisible = menu.style.display === "block";
menu.style.display = isVisible ? "none" : "block";
});
// ์ธ๋ถ ํด๋ฆญ ์ ๋๋กญ๋ค์ด ๋ซ๊ธฐ
document.addEventListener("click", function (event) {
if (!button.contains(event.target) && !menu.contains(event.target)) {
menu.style.display = "none";
}
});
});
์ด ์คํฌ๋ฆฝํธ๋:
- ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋ฉ๋ด๋ฅผ ์ด๊ณ ,
- ๋ค์ ํด๋ฆญํ๋ฉด ๋ซ์ผ๋ฉฐ,
- ๋ฉ๋ด ์ธ๋ถ๋ฅผ ํด๋ฆญํ๋ฉด ์๋์ผ๋ก ๋ฉ๋ด๊ฐ ์ฌ๋ผ์ง๋๋ค.
์๋๋ ๋๋กญ๋ค์ด ๋ฉ๋ด ํญ๋ชฉ์ ์ ํํ๋ฉด ๋ฒํผ ํ ์คํธ๊ฐ ํด๋น ํญ๋ชฉ์ผ๋ก ๋ณ๊ฒฝ๋๋ ๊ธฐ๋ฅ๊น์ง ํฌํจํ ์๋ฐ์คํฌ๋ฆฝํธ ์์ ์ ๋๋ค. ๋๋กญ๋ค์ด ๊ธฐ๋ฅ์ ์์ด UX์ ์ผ๋ก๋ ๋งค์ฐ ์ ์ฉํ ๊ฐ์ ์ด์์. ๐
โ๏ธ ๋ณด์๋ JavaScript
document.addEventListener("DOMContentLoaded", function () {
const button = document.getElementById("dropdownButton");
const menu = document.getElementById("dropdownMenu");
// ๋ฉ๋ด ํ ๊ธ
button.addEventListener("click", function (e) {
e.stopPropagation(); // ๋ฉ๋ด ์ธ๋ถ ํด๋ฆญ ์ ๋ซํ ๋ฐฉ์ง
menu.style.display = menu.style.display === "block" ? "none" : "block";
});
// ๋ฉ๋ด ํญ๋ชฉ ํด๋ฆญ ์ ๋ฒํผ ํ
์คํธ ๋ณ๊ฒฝ
menu.querySelectorAll("li a").forEach(item => {
item.addEventListener("click", function (e) {
e.preventDefault(); // ๊ธฐ๋ณธ ๋งํฌ ๋์ ๋ฐฉ์ง
button.textContent = this.textContent + " โพ"; // ๋ฒํผ ํ
์คํธ ๋ณ๊ฒฝ
menu.style.display = "none"; // ๋ฉ๋ด ๋ซ๊ธฐ
});
});
// ์ธ๋ถ ํด๋ฆญ ์ ๋ฉ๋ด ๋ซ๊ธฐ
document.addEventListener("click", function (e) {
if (!menu.contains(e.target) && !button.contains(e.target)) {
menu.style.display = "none";
}
});
});
์ด ์ฝ๋๋ ๋ค์์ ๊ตฌํํฉ๋๋ค:
- ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋๋กญ๋ค์ด ๋ฉ๋ด๊ฐ ์ด๋ฆฌ๊ณ ,
- ๋ฉ๋ด ํญ๋ชฉ์ ํด๋ฆญํ๋ฉด ํด๋น ํ ์คํธ๋ก ๋ฒํผ์ด ๋ณ๊ฒฝ๋๋ฉฐ,
- ์ธ๋ถ๋ฅผ ํด๋ฆญํ๋ฉด ๋๋กญ๋ค์ด์ด ๋ซํ๋๋ค.
๋๋กญ๋ค์ด UI๋ ์๊ฐ์ ํจ๊ณผ๋ฟ ์๋๋ผ ๋ชจ๋ ์ฌ์ฉ์๊ฐ ์ ๊ทผ ๊ฐ๋ฅํด์ผ ํด์. ์ด์ ์ ๊ทผ์ฑ(Accessibility, A11y)์ ๊ณ ๋ คํ ๊ตฌ์กฐ๋ก ์ ๊ทธ๋ ์ด๋ํด๋ณผ๊ฒ์.
โ ์ ๊ทผ์ฑ์ ๊ฐํํ HTML ๊ตฌ์กฐ
<div class="dropdown">
<button
id="dropdownButton"
aria-haspopup="true"
aria-expanded="false"
aria-controls="dropdownMenu"
>
๋ฉ๋ด ์ด๊ธฐ โพ
</button>
<ul
id="dropdownMenu"
class="dropdown-menu"
role="menu"
aria-labelledby="dropdownButton"
>
<li role="menuitem"><a href="#">ํ</a></li>
<li role="menuitem"><a href="#">์๊ฐ</a></li>
<li role="menuitem"><a href="#">๋ฌธ์</a></li>
</ul>
</div>
๐ ์ ๊ทผ์ฑ ํฌ์ธํธ ์์ฝ:
- aria-haspopup="true": ์ด ๋ฒํผ์ด ํ์ ๋ฉ๋ด๋ฅผ ์ฐ๋ค๋ ์๋ฏธ
- aria-expanded: ์ด๋ฆผ ์ํ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ฐ์
- aria-controls + aria-labelledby: ๋ฒํผ๊ณผ ๋ฉ๋ด๋ฅผ ๋ช ํํ๊ฒ ์ฐ๊ฒฐ
- role="menu" + role="menuitem": ํ๋ฉด๋ญ๋ ๊ธฐ์์ ๋๋กญ๋ค์ด์ด๋ผ๋ ์๋ฏธ๋ฅผ ์ ๋ฌ
โ๏ธ ์ ๊ทผ์ฑ ๊ฐํ + ํค๋ณด๋ ์ง์ JavaScript
document.addEventListener("DOMContentLoaded", () => {
const button = document.getElementById("dropdownButton");
const menu = document.getElementById("dropdownMenu");
// ๋ฉ๋ด ์ด๊ธฐ/๋ซ๊ธฐ
function toggleMenu(show) {
menu.style.display = show ? "block" : "none";
button.setAttribute("aria-expanded", show ? "true" : "false");
}
button.addEventListener("click", (e) => {
e.stopPropagation();
const isOpen = button.getAttribute("aria-expanded") === "true";
toggleMenu(!isOpen);
});
// ๋ฉ๋ด ์์ดํ
ํด๋ฆญ → ๋ฒํผ ํ
์คํธ ๋ณ๊ฒฝ
menu.querySelectorAll("a").forEach(item => {
item.addEventListener("click", (e) => {
e.preventDefault();
button.textContent = item.textContent + " โพ";
toggleMenu(false);
});
});
// ์ธ๋ถ ํด๋ฆญ ์ ๋ฉ๋ด ๋ซ๊ธฐ
document.addEventListener("click", (e) => {
if (!menu.contains(e.target) && !button.contains(e.target)) {
toggleMenu(false);
}
});
// ESC ๋๋ ์ ๋ ๋ซ๊ธฐ
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
toggleMenu(false);
button.focus();
}
});
// ์๋ ๋ฐฉํฅํค๋ก ํฌ์ปค์ค ์ด๋
button.addEventListener("keydown", (e) => {
if (e.key === "ArrowDown") {
e.preventDefault();
const firstItem = menu.querySelector("a");
if (firstItem) firstItem.focus();
}
});
// ๋ฉ๋ด ํญ๋ชฉ ๊ฐ ๋ฐฉํฅํค ์ด๋
menu.addEventListener("keydown", (e) => {
const items = Array.from(menu.querySelectorAll("a"));
const currentIndex = items.indexOf(document.activeElement);
if (e.key === "ArrowDown") {
e.preventDefault();
const next = items[(currentIndex + 1) % items.length];
next.focus();
} else if (e.key === "ArrowUp") {
e.preventDefault();
const prev = items[(currentIndex - 1 + items.length) % items.length];
prev.focus();
}
});
});
๐ ์ด ์ฝ๋์ ์ ๊ทผ์ฑ ์์ฝ
- โ ๋ฒํผ ์ญํ ๋ช ํํ (aria-* ์์ฑ)
- โ ํค๋ณด๋ ํ์ ๊ฐ๋ฅ (๋ฐฉํฅํค, ESC ์ง์)
- โ ํฌ์ปค์ค ์ด๋ ์ฒ๋ฆฌ
- โ ํ๋ฉด ๋ญ๋ ๊ธฐ์์ ๋ฉ๋ด ์ธ์ ์ง์
์ด์ ์๊ฐ์ ์ฌ์ฉ์๋ฟ ์๋๋ผ ํค๋ณด๋ ์ฌ์ฉ์, ์คํฌ๋ฆฐ๋ฆฌ๋ ์ฌ์ฉ์ ๋ชจ๋์๊ฒ ์น์ ํ ๋๋กญ๋ค์ด UI๊ฐ ์์ฑ๋์ด์!
๐ต ๋ง๋ฌด๋ฆฌํ๋ฉฐ
๋๋กญ๋ค์ด UI๋ ๋จ์ํ ๊ธฐ๋ฅ์ฒ๋ผ ๋ณด์ผ ์ ์์ง๋ง,
์ฌ์ฉ์ ๊ฒฝํ์ ๋ํ ์ผ์ ์ข์ฐํ๋ ์ค์ํ ์์์ ๋๋ค.
์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ง์ผ๋ก๋ ํด๋ฆญ, ํค๋ณด๋ ํ์, ์ธ๋ถ ํด๋ฆญ ์ฒ๋ฆฌ ๋ฑ ๋ค์ํ ์ํธ์์ฉ์ ๊ตฌํํ ์ ์์ผ๋ฉฐ,
์ ๊ทผ์ฑ์ ๊ฐํํ๋ฉด ๋์ฑ ๋ง์ ์ฌ์ฉ์์๊ฒ ์ด๋ฆฐ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ ์ ์์ด์.
์์ ๋๋กญ๋ค์ด ํ๋๋ฅผ ๋ง๋ค๋ฉด์๋
HTML ๊ตฌ์กฐ, ์คํ์ผ๋ง, ์ด๋ฒคํธ ์ฒ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ์น ์ ๊ทผ์ฑ๊น์ง
๋ชจ๋ ๊ณ ๋ฏผํ ์ ์๋ค๋ ์ ์์ ํ๋ฐํธ์๋ ๊ฐ๋ฐ์ ์ ๋ง ๋งค๋ ฅ์ ์ธ ๋ถ์ผ์ฃ .
์์ผ๋ก๋ ์ด๋ฐ UI ์ปดํฌ๋ํธ ํ๋ํ๋๋ฅผ ์ธ์ฌํ๊ฒ ๋ง๋ค์ด๊ฐ๋ฉฐ,
๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ๋์์ธํด๋ณด์ธ์!
๋ค์ ํฌ์คํธ์์๋ ๋ ๋ค์ํ ์ธํฐ๋์ ์ด๋ ์ ๋๋ฉ์ด์ ํ์ฉ ๋ฐฉ๋ฒ๋ ์๊ฐํ ์์ ์ ๋๋ค.
๊ธฐ๋ํด์ฃผ์ธ์. ๐