๊ด€๋ฆฌ ๋ฉ”๋‰ด

UI Code Lab

JavaScript๋กœ ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ ํŠธ๋ฆฌ UI ๋งŒ๋“ค๊ธฐ (3Depth ์ง€์› + ํด๋”/ํŒŒ์ผ ์•„์ด์ฝ˜) ๋ณธ๋ฌธ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธUI

JavaScript๋กœ ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ ํŠธ๋ฆฌ UI ๋งŒ๋“ค๊ธฐ (3Depth ์ง€์› + ํด๋”/ํŒŒ์ผ ์•„์ด์ฝ˜)

๐Ÿฏ๊ฟ€์ƒ์ด๐Ÿ 2025. 7. 8. 14:37

JavaScript ํŒŒ์ผํƒ์ƒ‰๊ธฐ ํŠธ๋ฆฌ UI ๋งŒ๋“ค๊ธฐ

 

 

 

์˜ค๋Š˜์€ ์›น์—์„œ ์ž์ฃผ ์“ฐ์ด๋Š”

ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ ํ˜•ํƒœ์˜ ํŠธ๋ฆฌ ๊ตฌ์กฐ 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 ๋Š˜๋ฆฌ๊ธฐ)
  • ํ™•๋Œ€ ์‹œ ๋ ˆ์ด์•„์›ƒ์ด ๊นจ์ง€์ง€ ์•Š๋„๋ก ๋ฐ˜์‘ํ˜• ๊ตฌ์„ฑ

 

โœ… ๋งˆ๋ฌด๋ฆฌ

์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋งŒ์œผ๋กœ๋„

์ง๊ด€์ ์ธ ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ ์Šคํƒ€์ผ์˜ ํŠธ๋ฆฌ ๋ฉ”๋‰ด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”.

 

์ •์  ์‚ฌ์ดํŠธ, ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€,

๋˜๋Š” ๊ฐœ์ธ ํฌํŠธํด๋ฆฌ์˜ค์— ํ™œ์šฉํ•ด๋ณด์„ธ์š”!