# HTML Lists(목록)

> Clean Markdown view of GeekNews topic #29588. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=29588](https://news.hada.io/topic?id=29588)
- GeekNews Markdown: [https://news.hada.io/topic/29588.md](https://news.hada.io/topic/29588.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-05-17T19:42:09+09:00
- Updated: 2026-05-17T19:42:09+09:00
- Original source: [blog.frankmtaylor.com](https://blog.frankmtaylor.com/2026/05/13/you-dont-know-html-lists/)
- Points: 1
- Comments: 1

## Topic Body

- HTML 목록은 시각적 모양보다 **의미와 상호작용 방식**으로 골라야 하며, 컨트롤·순서·설명·메뉴·비순서 목록으로 나뉨
- 고정 선택지는 **`&lt;select&gt;`/`&lt;option&gt;`**, 제안 입력은 `&lt;datalist&gt;`가 맞고, `multiple`, `optgroup`, `size`, `value` 동작을 구분해야 함
- **`&lt;ol&gt;`** 은 순서를 바꾸면 의미가 달라지는 절차·사건·연속체에 쓰며, `reversed`는 번호만 뒤집고 실제 항목 순서는 바꾸지 않음
- **`&lt;dl&gt;`** 은 HTML5에서 정의 목록을 넘어 설명 목록으로 확장됐고, 용어-값, 메타데이터, JSON 디버깅 같은 키-값 쌍에 맞음
- **`&lt;menu&gt;`** 는 도구 버튼 같은 명령 목록에 쓰며 `nav`와 의미·허용 콘텐츠가 다르고, 나머지 일반 목록은 `&lt;ul&gt;`이 담당함

---

### 컨트롤 목록: `&lt;select&gt;`/`&lt;option&gt;`과 `&lt;datalist&gt;`
- 폼에서도 사용자가 상호작용하는 **목록**을 구성할 수 있음
- ## 고정된 선택지는 `&lt;select&gt;`와 `&lt;option&gt;`
  - 사용자가 목록 안의 항목만 고를 수 있어야 하면 `&lt;select&gt;`와 `&lt;option&gt;`을 사용함
  - 언어 목록 예시는 `Select a Language`, `English`, `French`, `Spanish`, `Portuguese` 같은 `&lt;option&gt;`을 `&lt;select name="languages"&gt;` 안에 배치함
  - 기본 `&lt;select&gt;`는 정확히 하나의 선택지만 고르게 함
  - 여러 항목을 고르게 하려면 **`multiple` 속성**을 추가함
    - `multiple`을 사용하면 목록 표시가 달라지고 모든 옵션이 보이며, 사용자는 Shift 또는 Cmd + 클릭으로 여러 항목을 고를 수 있음
    - 실제 `select`와 `option`을 쓰면 `role="listbox"`가 붙은 목록 요소에 `aria-multiselectable`을 직접 붙일 필요 없이 브라우저 기본 시맨틱이 처리함
- ## 관련 옵션은 `&lt;optgroup&gt;`으로 묶기
  - 언어를 어족별로 묶고 싶으면 `&lt;optgroup&gt;`으로 옵션 목록을 그룹화함
  - 예시는 `Germanic`, `Romance`, `Celtic`이라는 `label`을 가진 `&lt;optgroup&gt;`을 만들고, 각 그룹에 `English`, `French`, `Spanish`, `Portuguese`, `Irish`, `Welsh`를 배치함
  - 특정 하위 묶음을 선택하지 못하게 하려면 해당 `&lt;optgroup&gt;`에 **`disabled` 속성**을 추가함
  - 예시에서는 `Celtic` 그룹에 `disabled`를 붙여 `Irish`, `Welsh`가 포함된 묶음을 비활성화함
- ## 기본 HTML 기능으로 개선하기
  - 그룹 사이에 시각적 구분이 필요하면 `&lt;select&gt;` 안에서 허용되는 **`&lt;hr&gt;`** 을 사용할 수 있음
  - `size` 속성은 한 번에 표시할 항목 수를 제어하므로 긴 목록에 유용함
  - `size`와 `optgroup`을 함께 쓰면 그룹 라벨도 표시 공간을 차지함
  - 예시는 `&lt;select name="languages" size="4" multiple&gt;`에 `Germanic`, `Romance`, `Celtic`, `Afroasiatic` 그룹과 그룹 사이 `&lt;hr /&gt;`를 넣고, `Hebrew`, `Arabic`까지 포함함

### 제안 목록: `&lt;datalist&gt;`
- 사용자가 반드시 목록에서만 고르는 것이 아니라 목록을 **제안**하려면 `&lt;datalist&gt;`를 사용함
- `&lt;datalist&gt;`는 두 단계로 연결함
  - `&lt;datalist&gt;`를 만들고 `id`를 부여함
  - 대응하는 `&lt;input&gt;`의 `list` 속성에 그 `id` 값을 넣음
- 언어 제안 예시는 `&lt;datalist id="languages"&gt;` 안에 `English`, `French`, `Spanish`, `Portuguese`, `Irish`, `Welsh`, `Hebrew`, `Arabic` 옵션을 두고, `&lt;input name="language" list="languages"&gt;`로 입력 필드와 연결함
- ## `&lt;option value&gt;`의 동작
  - `&lt;option&gt;`의 기본값은 감싼 텍스트이고, **`value` 속성**이 있으면 그 값이 기본값을 덮어쓰며 텍스트는 라벨처럼 동작함
  - `&lt;select&gt;`에서는 사용자가 텍스트만 보므로 큰 문제가 아니지만, `&lt;datalist&gt;`에서는 사용자가 라벨을 보고 선택한 뒤 입력창에는 `value`가 들어가 혼란스러울 수 있음
  - 예시에서 `&lt;option value="cy"&gt;Welsh&lt;/option&gt;`를 선택하면 사용자는 `Welsh`를 보지만 입력에는 `cy`가 들어감
  - `&lt;datalist&gt;`를 쓸 때는 삽입되는 값이 라벨이 아니라 **`value`** 라는 점을 전제로 해야 함
- ## 여러 입력 타입과 결합
  - `&lt;datalist&gt;`는 텍스트 옵션에만 쓰이지 않고 다른 `input` 타입과도 함께 쓸 수 있음
  - 주 단위 선택 예시는 `&lt;input type="week" name="week" id="camp-week" min="2026-W2" max="2026-W51" list="preferred-weeks" /&gt;`에 `&lt;datalist id="preferred-weeks"&gt;`를 연결함
  - 제안 주차는 `2026-W22`, `2026-W23`, `2026-W24`, `2026-W25`임
- ## `&lt;input type="range"&gt;`와 결합
  - `&lt;datalist&gt;`는 문자열 값에만 제한되지 않고 숫자와도 동작하므로, **range 입력**과 결합해 범위 위에 라벨이 붙은 지점을 만들 수 있음
  - 팁 비율 입력 예시는 `&lt;input type="range" name="tips" id="tips" min="0" max="50" step="1" list="recommended-tips" /&gt;`에 `&lt;datalist id="recommended-tips"&gt;`를 연결하고 `10%`, `18%`, `30%`, `45%` 라벨을 둠
  - Chrome 계열에서는 `@supports (x: attr(x type(percentage)))`로 `attr()`의 `label` 값을 읽고, `type()`으로 값을 퍼센트로 선언한 뒤 옵션을 `position: absolute`로 배치함
  - Firefox용 접근은 `@supports not (x: attr(x type(percentage)))`를 사용하며, 값은 `::before`로 표시됨
  - 이 방식은 모든 브라우저가 같은 방식으로 동작하거나 화면에 동일하게 표시된다고 보장하지 않음

### 순서 목록: `&lt;ol&gt;`
- 특정 순서로 읽어야 하는 항목 모음은 **`&lt;ol&gt;`** 을 사용함
- 항목 옆에 숫자가 보여야 하는지가 아니라, 항목의 순서를 바꾸면 **목록의 의미**가 달라지는지가 기준임
- `&lt;ol&gt;`에 적합한 컬렉션은 알고리듬, 사건의 연속, 증가 또는 감소하는 연속체 위의 항목, 레시피, 알파벳순 목록임
- 바나나 빵 레시피 예시는 오븐 예열과 팬 기름칠, 재료 섞기, 반죽 붓기, 60분 굽기 또는 이쑤시개가 깨끗하게 나올 때까지 굽기, 와이어 랙에서 식히기 순서를 `&lt;ol&gt;`로 표현함
- 알파벳순 재료 목록도 알파벳이라는 연속체를 따르므로 `&lt;ol&gt;`에 해당하며, `baking soda`, `bananas`, `brown sugar`, `butter`, `eggs`, `flour`, `salt` 순서로 배치됨
- ## 순서 목록과 비순서 목록의 중첩
  - 잘 구조화된 순서 목록은 브라우저 렌더링을 보지 않아도 어떤 일이 어떤 순서로 일어나야 하는지 읽을 수 있음
  - 레시피 예시는 상위 단계에 `&lt;ol&gt;`을 쓰고, 단계 안에서 순서가 중요하지 않은 항목은 `&lt;ul&gt;`, 다시 순서가 중요한 하위 단계는 `&lt;ol&gt;`로 중첩함
  - 구조는 `Prepare`, `Mix`, `Pour`, `Bake`, `Cool`의 상위 순서를 유지하면서, `Prepare`와 `Bake` 안의 병렬 항목은 `&lt;ul&gt;`로, `Mix`와 `Cool` 안의 절차는 `&lt;ol&gt;`로 표현함
- ## `reversed`
  - **`reversed` 속성**은 번호 매김 순서를 오름차순에서 내림차순으로 바꿈
  - 실제 목록 항목의 순서는 바꾸지 않음
  - `most to least`처럼 많은 것에서 적은 것으로 보여주는 재료와 수량 목록에 사용할 수 있음
  - 예시는 `&lt;ol reversed&gt;`에 `eggs (2)`, `flour (2 cups)`, `bananas (2) (mashed)`, `brown sugar (¾ cup)`, `butter (½ cup)`, `baking soda (1 teaspoon)`, `salt (¼ teaspoon)`을 넣음
- ## JavaScript로 실제 항목 순서 뒤집기
  - 목록을 실제로 뒤집으려면 JavaScript로 `li` 자식들을 역순으로 재배치하고 `reversed` 속성을 토글할 수 있음
  - 예시 함수는 `list.querySelectorAll('li')` 결과를 배열로 만들고 `.reverse()`한 뒤, `list.innerHTML = ''`로 비우고 `list.append(...children)`으로 다시 붙임
  - 마지막에 `list.toggleAttribute('reversed')`를 호출함
  - 예시 이벤트는 `orderedList.addEventListener('dblclick', (evt) => { reverseList(orderedList) })`로 더블클릭 시 뒤집기를 실행함
- ## `start`
  - **`start` 속성**은 하나의 거대한 목록 대신 여러 개의 순서 있는 목록으로 나눌 때 번호의 연속성을 유지하는 데 쓰임
  - 바나나 브레드 레시피 예시에서 `Prepare`는 `ul`로 두고, `Mix`는 `&lt;ol start=2&gt;`, `Pour`는 `&lt;ol start=5&gt;`, `Cool`은 `&lt;ol start=7&gt;`처럼 이어지는 단계 번호를 각 목록에 지정함
  - 중간에 `6: Bake`처럼 순서 없는 목록으로 표현된 섹션이 있어도, 이후 `Cool`의 `ol`을 `start=7`로 시작해 전체 절차의 번호 흐름을 유지할 수 있음

### 설명 목록: `&lt;dl&gt;`, `&lt;dt&gt;`, `&lt;dd&gt;`
- **설명 목록(description list)** 은 모든 내용을 `ol`이나 `ul`에 억지로 넣지 않아도 되게 해주는 목록 유형임
- ## HTML 4의 정의 목록
  - HTML 4에서는 `description list`가 아니라 **정의 목록(definition list)** 으로 불렸고, 정의를 제공하는 좁은 용도에 맞춰져 있었음
  - 구조는 정의할 용어인 `&lt;dt&gt;`와 정의 내용인 `&lt;dd&gt;`로 구성됐으며, 의미적으로 정확하게 쓰려면 정의되는 용어를 `&lt;dfn&gt;`으로 감쌈
  - 예시는 `throw`, `yeet`을 같은 정의에 연결하고, `no cap`, `bet`에 각각 정의를 붙임
  ```html
    &lt;dl&gt;
      &lt;dt&gt;&lt;dfn&gt;throw&lt;/dfn&gt;&lt;/dt&gt;
      &lt;dt&gt;&lt;dfn&gt;yeet&lt;/dfn&gt;&lt;/dt&gt;
      &lt;dd&gt;Verb. To discard at a high velocity&lt;/dd&gt;
      &lt;dt&gt;&lt;dfn&gt;no cap&lt;/dfn&gt;&lt;/dt&gt;
      &lt;dd&gt;Interjection. Expresses authenticity and truthfulness, sometimes surprise.&lt;/dd&gt;
      &lt;dt&gt;&lt;dfn&gt;bet&lt;/dfn&gt;&lt;/dt&gt;
      &lt;dd&gt;Interjection. Expresses agreement and affirmation.&lt;/dd&gt;
    &lt;/dl&gt;
  ```
- ## HTML5에서 넓어진 의미
  - HTML5에서는 정의에만 국한되지 않는 **설명 목록**이 됐고, “용어와 값의 집합”이 있을 때 쓸 수 있음
  - HTML5에서는 관련된 `&lt;dt&gt;`와 `&lt;dd&gt;`를 묶기 위해 비의미적 래퍼인 `&lt;div&gt;`를 허용함
  - 브라우저 엔진 예시에서는 `Chrome`, `Opera`, `Brave`, `Edge`를 `Blink-based browsers`에 묶고, `Firefox`, `Tor`, `Librewolf`를 `Gecko-based browsers`에 묶음
  ```html
    &lt;dl&gt;
      &lt;div class="dl-item"&gt;
        &lt;dt&gt;Chrome&lt;/dt&gt;
        &lt;dt&gt;Opera&lt;/dt&gt;
        &lt;dt&gt;Brave&lt;/dt&gt;
        &lt;dt&gt;Edge&lt;/dt&gt;
        &lt;dd&gt;Blink-based browsers&lt;/dd&gt;
      &lt;/div&gt;
      &lt;div class="dl-item"&gt;
        &lt;dt&gt;Firefox&lt;/dt&gt;
        &lt;dt&gt;Tor&lt;/dt&gt;
        &lt;dt&gt;Librewolf&lt;/dt&gt;
        &lt;dd&gt;Gecko-based browsers&lt;/dd&gt;
      &lt;/div&gt;
    &lt;/dl&gt;
  ```
- ## 메타데이터와 JSON 디버깅
  - 사실과 레이블의 연속이라면 **메타데이터** 표시에 설명 목록을 쓰는 것이 적합함
  - 사용자 프로필도 `&lt;dl&gt;`에 들어갈 수 있으며, 예시는 `First Frank`, `Last Taylor`, `Age 44`, `Job Writer`, `Handle Paceaux`를 `&lt;dt&gt;`와 `&lt;dd&gt;` 쌍으로 표현함
  - 단일 페이지 애플리케이션에서 **JSON 디버깅**용으로도 설명 목록을 사용할 수 있음
  - `DebugJson` 예시는 객체의 각 `key, value`를 `Object.entries(obj)`로 순회해 키는 `&lt;dt&gt;&lt;var&gt;...&lt;/var&gt;&lt;/dt&gt;`, 값은 `&lt;dd&gt;&lt;code&gt;...&lt;/code&gt;&lt;/dd&gt;`로 렌더링함
  - 값이 객체이고 배열이 아니면 `DebugJson.createDl(value)`를 다시 호출해 중첩된 `&lt;dl&gt;`을 만들고, 그 외 값은 `value.toString()`을 `&lt;code&gt;` 안에 넣음
  ```js
    const debugJson = new DebugJson({foo: 'bar', arr: ['a', 'b'], car: 1}, '.container')
    debugJson.render();
  ```
  - 설명 목록은 **키-값 쌍** 요구에 폭넓게 맞음

### 메뉴: `&lt;menu&gt;`
- **`menu` 요소**는 명령의 목록을 나타내며, 콘텐츠 렌더링보다 상호작용적인 웹에 더 가까움
- `menu`는 리치 텍스트 편집기의 텍스트 수정 컨트롤처럼 “도구”에 해당하는 버튼 목록에 맞음
- 리치 텍스트 편집기 예시는 `Strong`, `Emphasize`, `Strike` 버튼을 `menu` 안의 `li`로 배치함
```html
  &lt;menu&gt;
    &lt;li&gt;&lt;button onclick="strong()"&gt;Strong&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button onclick="emphasize()"&gt;Emphasize&lt;/button&gt;&lt;/li&gt;
    &lt;li&gt;&lt;button onclick="strike()"&gt;Strike&lt;/button&gt;&lt;/li&gt;
  &lt;/menu&gt;
```
- HTML 명세상 이는 **툴바(toolbar)** 용도이며, 상호작용 페이지에서 도구 버튼이 있는 곳은 `menu`에 들어갈 가능성이 큼
- 비디오 컨트롤 예시도 `menu`에 들어가며, `button`에 `commandfor="vid-123"`과 `command="--play"`, `--mute`, `--fullscreen`을 둠
```html
  &lt;div class="player player--video"&gt;
    &lt;video source="whatever.mp4" id="vid-123"&gt;&lt;/video&gt;
    &lt;menu&gt;
      &lt;li&gt;&lt;button commandfor="vid-123" command="--play"&gt;Play&lt;/button&gt;&lt;/li&gt;
      &lt;li&gt;&lt;button commandfor="vid-123" command="--mute"&gt;Mute&lt;/button&gt;&lt;/li&gt;
      &lt;li&gt;&lt;button commandfor="vid-123" command="--fullscreen"&gt;Fullscreen&lt;/button&gt;&lt;/li&gt;
    &lt;/menu&gt;
  &lt;/div&gt;
```
- `menu`를 쓰면 순서 없는 목록에 `aria-role="menu"`를 추가할 필요가 없음
- ## `li`가 두 컨테이너에만 들어간다고 가정하지 않기
  - 내비게이션의 목록 항목을 일반 목록처럼 보이게 하고 싶지 않다면, **`menu li`** 에도 같은 처리가 필요함
  - 스타일시트 상단에 `nav li`뿐 아니라 `menu li`까지 포함해 `list-style-type`, `text-indent`, `margin`을 초기화함
  ```css
    nav li,
    menu li {
        list-style-type: none;
        text-indent: 0;
        margin: 0;
    }
  ```
- ## `&lt;nav&gt;`와 `&lt;menu&gt;`는 다름
  - `nav`는 단순히 링크가 들어간 `menu`가 아니며, **의미와 허용 콘텐츠**가 다름
  - `nav`는 사용자에게 “어딘가로 가는 것에 관한 여러 항목”을 제공한다는 의미를 가진 섹션 요소임
  - `nav`는 `&lt;p&gt;`, `&lt;h1-6&gt;` 같은 문단과 제목, 그리고 `&lt;ul&gt;`, `&lt;ol&gt;`, `&lt;menu&gt;` 같은 목록을 포함할 수 있음
  - `menu`는 사용자에게 “할 수 있는 것들의 목록”을 제공한다는 의미를 가진 목록 요소이며, 목록 항목인 `&lt;li&gt;`만 허용함
  - **`menu`와 `nav`는 상호 배타적 선택지가 아니며**, `menu`는 `nav` 안에 들어갈 수 있지만 `nav`는 `menu` 안에 들어갈 수 없음

### 비순서 목록: `&lt;ul&gt;`
- `ul`은 다른 목록 유형과 `nav`로 해결되지 않는 나머지 목록 요구를 담는 **캐치올 목록**임
- 예전 HTML에서는 순서 있는 목록과 순서 없는 목록의 차이가 숫자인지 불릿인지 같은 시각적 차이에 가까웠음
- 현재는 접근성, 스크린 리더, 검색 엔진 최적화를 고려하므로 시각적 표시보다 **순서가 의미를 갖는지**에 집중해야 함
- 밴드 멤버 목록은 순서가 중요하지 않으므로 `ul`에 해당함
```html
  &lt;h3&gt;Beatles&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;John Lennon&lt;/li&gt;
    &lt;li&gt;Paul McCartney&lt;/li&gt;
    &lt;li&gt;Ringo Star&lt;/li&gt;
    &lt;li&gt;George Harrison&lt;/li&gt;
  &lt;/ul&gt;
```
- 밴드 이름 목록도 순서 없는 목록으로 표현할 수 있음
```html
  &lt;ul&gt;
    &lt;li&gt;Beatles&lt;/li&gt;
    &lt;li&gt;Rolling Stones&lt;/li&gt;
    &lt;li&gt;Van Halen&lt;/li&gt;
    &lt;li&gt;Foo Fighters&lt;/li&gt;
  &lt;/ul&gt;
```

## Comments



### Comment 57639

- Author: neo
- Created: 2026-05-17T19:42:09+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=48161861) 
- 예제만 테스트해 봐도 **datalist**가 Mobile Safari에서 잘 동작하지 않는 것 같음  
  이 정도로 큰 시장에서 호환성 문제가 있다면, 사실상 사용할 가치가 있는 시나리오가 거의 없다고 볼 수도 있음
  - 원하진 않았지만 꼭 필요했던 **현실의 찬물** 같은 정보임
    
    10년도 더 전에 UI에서 꽤 공격적인 입력 제안 위젯을 쓰는 프로젝트를 했고, 그때는 jQuery 플러그인을 사용했음  
    프런트엔드에서 가장 복잡한 부분이었고, 사실상 그 프로젝트에서 jQuery를 쓰는 주된 이유였음
    
    글을 읽으면서 그 프런트엔드를 가벼운 JS 최소화 버전으로 다시 구현하는 건 식은 죽 먹기겠다고 생각했지만, 사용자의 기기에 내 환경을 그대로 배송하지 않는 이상 현실은 그렇지 않음  
    그래도 요즘 **HTML 명세**에 포함된 기능들은 꽤 인상적임  
    고등학교 때 XHTML을 읽어본 이후로 명세 변화를 거의 따라가지 못했는데, 가끔은 뭐가 바뀌었는지 살펴봐야겠음  
    다만 브라우저 호환성은 그때나 지금이나 여전히 골치 아픔
  - **datalist 예제**는 내 iPhone에서는 확실히 동작함  
    네이티브 iOS 키보드 위의 자동완성 제안 영역에 통합됨  
    다만 모든 제안을 훑어보는 방법은 없고, 애초에 datalist의 의도된 사용 방식도 아닐 것 같음
    
    하지만 `group`의 `disabled` 속성은 확실히 동작하지 않음
  - Android의 **Firefox**에서도 동작하지 않음
  - 첫 직장에서 일하던 오래전에는 **Firefox에서 datalist**가 동작하지 않았고, 그 때문에 Firefox가 지원 브라우저 목록에서 빠졌음
    
    Chrome 이외의 브라우저를 지원하려면 오랫동안 문제가 되어 온 기능임
  - iOS의 **GBoard**와 함께 쓰면 잘 동작하지 않음

- `optgroup`에 `disabled` 속성을 추가해 일부 옵션을 선택 못 하게 하는 예제가 **Mobile Safari**에서는 깨진 것 같음  
  실제로는 비활성화되지 않고, 비활성 항목도 여전히 선택할 수 있음
  - 최신 Safari에서는 동작해야 하므로 깨진 건 아니고 이상한 상태에 가까움
    
    [https://caniuse.com/mdn-html_elements_optgroup_disabled](<https://caniuse.com/mdn-html_elements_optgroup_disabled>)
    
    **Safari 버그**일 가능성이 있어 보임
  - 기본적인 것 이상에 **네이티브 HTML**을 쓰기 어려운 이유가 이런 데 있음  
    충분히 읽고 확신을 갖고 이런 글을 쓸 수 있을 만큼 알아도, 댓글에는 결국 브라우저와 기기 조합별 특이 동작, 제한, 미지원 정보가 따라붙음
    
    `div` 범벅은 반대쪽으로 너무 간 선택일 수 있지만, 그래도 적어도 특이 동작과 한계가 꽤 일관되고 눈에 잘 보임  
    내가 직접 썼거나 프레임워크가 만든 것과 더 일관되게 맞물리기 때문임

- 재미있고 포괄적인 글임
    
  안타깝게도 요즘은 **HTML을 배우지 않고 React로 바로 들어간 개발자**가 많고, 이제 LLM까지 있으니 HTML을 아예 배우지 않을 가능성이 큼
    
  그래서 단순 HTML이면 충분한 곳에도 React 컴포넌트부터 찾게 됨
  - 그래도 괜찮다고 봄
    
    처음 XML을 써야 했을 때는 **XML 명세**를 배우고 직접 출력해야 했음  
    직렬화 라이브러리가 사실상 없던 시절이었음  
    이후 후배 세대가 XML, 나중에는 JSON을 교환 형식으로 쓰면서도 완전히 배우지는 않는 걸 봤지만, 별일은 없었음
    
    AJAX도 뜨거운 신기술에서 약어가 뭔지 모르는 단계로 갔고, 지금은 대부분 그 용어 자체도 잘 못 알아봄  
    AJAX는 죽은 게 아니라 너무 흔해져서 더 이상 별도 단어가 필요 없어진 것임
  - 내 문제는 20년 전에 **HTML**을 철저히 배웠고, 그 이후 어떻게 바뀌고 개선됐는지는 우연히 조금씩만 알게 됐다는 것임  
    CSS는 더더욱 그렇다
  - 솔직히 HTML은 번거로움
    
    예를 들어 컨트롤의 일부를 스타일링하는 HTML식 접근은 **의사 클래스**를 쓰는 것인데, 브라우저마다 선택자가 다를 때도 있음  
    그러면 실제로 제대로 동작하는지 알 수 없으니 브라우저별 테스트를 해야 함
    
    React는 더 쉬울 뿐 아니라 더 믿을 만함  
    React와 `div`들로 만들면 모든 브라우저에서 동일하게 동작할 거라고 예상할 수 있음

- 좋은 내용이지만 `datalist`에 너무 기대하면 안 됨  
  실제로 유용하게 쓰기엔 **연결 지점**이 부족해서, 작은 프로토타입 이상의 용도에는 맞지 않음
  - 자동완성 제안에 **datalist**를 써 봤는데 아주 잘 동작했음
  - 예전에 datalist로 **콤보박스**를 만들려고 했던 것 같은데 잘 안 됐음

- HTML 린터가 정말 이런 차이를 구분하는 데 도움이 되는지 궁금함  
  이런 종류의 **시맨틱 태그 선택**을 강제할 수 있는 린터가 있는지도 알고 싶음
  - 시맨틱 태그를 강제한다는 건 잘 와닿지 않음  
    HTML은 무엇보다 작성자가 창의적으로 쓰도록 만들어진 것이고, 특정 태그를 다른 태그보다 강제하는 건 말이 안 된다고 봄  
    접근성은 중요하지만 이미 제약은 충분히 많음
  - 내가 아는 가장 가까운 것은 [https://github.com/kristoff-it/superhtml#diagnostics](<https://github.com/kristoff-it/superhtml#diagnostics>)임
    
    **SuperHTML**은 문법뿐 아니라 요소 중첩과 속성 값도 검증함  
    전체 HTML 명세를 검증 코드에 구현한 다른 언어 서버는 없음

- 오늘 새로 알았음  
  왜 더 많은 프레임워크가 이걸 활용하지 않는지 궁금함
  - 사용자 경험 관점에서는 일반적인 목록과 동일하기 때문임  
    코드를 이해하는 데 도움이 된다면 써도 되지만, 브라우저의 **접근성 트리**와 그 밖의 모든 면에서는 그냥 순서 없는 목록일 뿐임
    
    어떤 것이 동작 목록이라는 걸 전달하려면 ARIA 속성을 추가해야 함  
    글에서는 `role=menu`를 언급하지만 그것만으로는 충분하지 않고, 각 항목에도 `menuitem` 역할이 필요함  
    WAI Authoring Practices Guide가 역할과 상호작용 기대치를 설명하지만, 코드 예제는 그대로 복사하지 말고 특히 내비게이션 메뉴에 이 역할을 쓰면 안 됨
    
    [https://www.w3.org/WAI/ARIA/apg/patterns/menubar/](<https://www.w3.org/WAI/ARIA/apg/patterns/menubar/>)
  - 똑똑한 사람은 어려운 HTML 말 안 배우고 `div` 여러 개로 해결함
  - 요즘 HTML에는 재미있는 기능이 많음
    
    어떤 요소가 뭘 한다고 생각하는지 사람들에게 물어보는 걸 좋아함  
    나도 처음엔 전혀 맞히지 못했음

- 몇 년 동안 프런트엔드 리드로 일했는데도 몰랐던 유용한 정보가 많음  
  회사에서도 확실히 써 보기 시작할 것 같음

- 디자이너들이 **기본 datalist 외형**을 좋아하기만 했다면 좋았을 텐데
  - 내 경험상 **스타일 커스터마이즈 부족**이 네이티브 HTML 기능을 쓰는 가장 큰 장애물임

- 블로그 글은 참 좋은데, 블로그의 모든 글 목록을 한 번에 볼 방법을 찾을 수가 없음
    
  [https://blog.frankmtaylor.com/archive](<https://blog.frankmtaylor.com/archive>)는 안 되고
    
  [https://blog.frankmtaylor.com/archives](<https://blog.frankmtaylor.com/archives>)도 아니고
    
  [https://blog.frankmtaylor.com/posts](<https://blog.frankmtaylor.com/posts>)도 안 됨
    
  [https://blog.frankmtaylor.com/all](<https://blog.frankmtaylor.com/all>)도 없음
    
  [https://blog.frankmtaylor.com/blog](<https://blog.frankmtaylor.com/blog>)도 아님
    
  북마크가 1만 개 넘는 사람도 많으니, 설명이나 글 전체 없이 지금까지 쓴 모든 글을 나열하는 **단일 목록 페이지**가 있으면 정말 편할 것임
  - 말하는 건 **사이트맵** 아닌가 싶음  
    대부분의 블로그에는 모든 글을 나열한 `sitemap.xml`이 있음
    
    그리고 글 235개를 전부 훑어보고 싶은 이유도 궁금함
