์๋ฐ์คํฌ๋ฆฝํธUI
JavaScript๋ก ํ์ผ ํ์๊ธฐ ํธ๋ฆฌ UI ๋ง๋ค๊ธฐ (3Depth ์ง์ + ํด๋/ํ์ผ ์์ด์ฝ)
๐ฏ๊ฟ์์ด๐
2025. 7. 8. 14:37
์ค๋์ ์น์์ ์์ฃผ ์ฐ์ด๋
ํ์ผ ํ์๊ธฐ ํํ์ ํธ๋ฆฌ ๊ตฌ์กฐ UI๋ฅผ
์ง์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ํฌํจํ ๊ฑฐ์์:
- 3๋จ๊ณ(3 Depth) ํธ๋ฆฌ ๊ตฌ์กฐ
- ํด๋/ํ์ผ ์ ๋์ฝ๋ ์์ด์ฝ ์ ์ฉ
- ํด๋ฆญ ์ ํผ์น๊ธฐ/์ ๊ธฐ ๊ธฐ๋ฅ
- ๊ฐ๊ฒฐํ๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ฝ๋
๐ ๏ธ ํธ๋ฆฌ UI ๊ตฌํ ์ฝ๋
โ HTML
<ul id="tree">
<li>
<span class="toggle">โธ</span> ๐ ๋ฃจํธ
<ul>
<li>
<span class="toggle">โธ</span> ๐ ์์1
<ul>
<li>๐ ์์1-1.txt</li>
<li>
<span class="toggle">โธ</span> ๐ ์์1-2
<ul>
<li>๐ ์์1-2-1.png</li>
<li>๐ ์์1-2-2.pdf</li>
</ul>
</li>
</ul>
</li>
<li>๐ ์์2.txt</li>
</ul>
</li>
</ul>
โ CSS
ul {
list-style: none;
padding-left: 1em;
font-family: sans-serif;
}
li {
margin: 0.25em 0;
}
.toggle {
cursor: pointer;
margin-right: 5px;
color: #555;
}
ul ul {
display: none;
padding-left: 1.5em;
}
.toggle.open + ul {
display: block;
}
โ JavaScript
document.querySelectorAll('.toggle').forEach(toggle => {
toggle.addEventListener('click', function () {
const nextUl = this.nextElementSibling;
if (nextUl && nextUl.tagName === 'UL') {
const isOpen = nextUl.style.display === 'block';
nextUl.style.display = isOpen ? 'none' : 'block';
this.textContent = isOpen ? 'โธ' : 'โพ';
}
});
});
๐ผ๏ธ ์คํ ๊ฒฐ๊ณผ
- ํด๋ ์์ด์ฝ ๐์ ํผ์น ์ ์๊ณ ,
- ํ์ผ ์์ด์ฝ ๐์ ํด๋ฆญํด๋ ๋ฐ์ ์์ด ๋จ์ํ ๋ ธ์ถ๋จ
- ๋ฃจํธ → ์์1 → ์์1-2 ๊ฐ์ 3๋จ๊ณ ๊ตฌ์กฐ๋ ์ง์
๐ ํ์ฉ ํ
- ์์ด์ฝ์ Font Awesome ๋ฑ์ผ๋ก ์ปค์คํฐ๋ง์ด์ฆ ๊ฐ๋ฅ
- JSON ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํ๋ฉด ๋์ ํธ๋ฆฌ ๊ตฌ์ฑ๋ ์ฝ๊ฒ ๊ฐ๋ฅ
- React, Vue ๋ฑ์ ํ๋ ์์ํฌ๋ก๋ ํ์ฅ ๊ฐ๋ฅ
โฟ ์ ๊ทผ์ฑ๋ ์ฑ๊ฒจ๋ณด์ – ํธ๋ฆฌ UI์ ํฌํจํด์ผ ํ ์์๋ค
ํ์ผ ํ์๊ธฐ ํธ๋ฆฌ UI๋ ์๊ฐ์ ์ผ๋ก ์ง๊ด์ ์ด์ง๋ง,
๋ชจ๋ ์ฌ์ฉ์๊ฐ ํธ๋ฆฌํ๊ฒ ์ธ ์ ์๋๋ก ์ ๊ทผ์ฑ์ ๊ณ ๋ คํ๋ ๊ฒ๋ ์ค์ํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ ์์๋ฅผ ์ถ๊ฐํ๋ฉด
์คํฌ๋ฆฐ๋ฆฌ๋ ์ฌ์ฉ์, ํค๋ณด๋ ์ฌ์ฉ์ ๋ฑ
๋ค์ํ ํ๊ฒฝ์์๋ UX๋ฅผ ๊ฐ์ ํ ์ ์์ด์.
โ ARIA ์์ฑ์ผ๋ก ์๋ฏธ ๋ถ์ฌํ๊ธฐ
<ul role="tree">
<li role="treeitem" aria-expanded="true">๐ ๋ฃจํธ</li>
</ul>
- role="tree" / role="treeitem"์ผ๋ก ๊ตฌ์กฐ ๋ช ์
- aria-expanded, aria-selected ์์ฑ์ผ๋ก ํผ์นจ ์ํ ์ ๋ฌ
- ์๊ฐ์ ์์์ aria-label์ ์ถ๊ฐํ์ฌ ์๋ฏธ ์ ๋ฌ
โ ํค๋ณด๋ ํ์ ์ง์
- Tab, Arrow Up/Down์ผ๋ก ๋ ธ๋ ๊ฐ ์ด๋
- Enter๋ก ํผ์น๊ธฐ/์ ๊ธฐ ์คํ
- tabindex="0"์ผ๋ก ํฌ์ปค์ค ์ค์ + ์คํ์ผ๋ก ์๊ฐ์ ํผ๋๋ฐฑ ์ ๊ณต
document.querySelectorAll('.toggle').forEach(toggle => {
toggle.setAttribute('tabindex', '0');
toggle.addEventListener('keydown', e => {
if (e.key === 'Enter' || e.key === ' ') toggle.click();
});
});
โ ์์ ๋๋น์ ํ ์คํธ ๋ณด์
- ํ ์คํธ ๋๋น์จ ์ต์ 4.5:1 ์ด์์ผ๋ก ์ค์ (WCAG ๊ธฐ์ค)
- ์์ด์ฝ ์ธ์๋ ํ ์คํธ, ํจํด, ๊ตต๊ธฐ ๋ฑ์ ํ์ฉํ์ฌ ์๋ฏธ ์ ๋ฌ
โ ๋ชจ๋ฐ์ผ ์ ๊ทผ์ฑ๋ ๊ณ ๋ ค
- ํฐ์น ์์ญ ๋๊ฒ ์ค์ (ex. padding ๋๋ฆฌ๊ธฐ)
- ํ๋ ์ ๋ ์ด์์์ด ๊นจ์ง์ง ์๋๋ก ๋ฐ์ํ ๊ตฌ์ฑ
โ ๋ง๋ฌด๋ฆฌ
์ด๋ ๊ฒ ๊ฐ๋จํ ์ฝ๋๋ง์ผ๋ก๋
์ง๊ด์ ์ธ ํ์ผ ํ์๊ธฐ ์คํ์ผ์ ํธ๋ฆฌ ๋ฉ๋ด๋ฅผ ๋ง๋ค ์ ์์ด์.
์ ์ ์ฌ์ดํธ, ๊ด๋ฆฌ์ ํ์ด์ง,
๋๋ ๊ฐ์ธ ํฌํธํด๋ฆฌ์ค์ ํ์ฉํด๋ณด์ธ์!