2024년, State of HTML

Sydney·2024년 11월 23일
post-thumbnail

어느덧 한 해의 끝자락에 다다르며, 올해도 어김없이 HTML 사용 현황을 파악하는 설문조사에 참여했다.
생각보다 모르는 것이 많았다는 사실에 놀라며, 이를 정리해보자는 마음으로 글을 시작했다. 내가 몰랐던 것들을 공유하면서, 이 글을 읽는 분들도 "오, 이런 게 있었구나!" 하고 작은 지식을 얻어가길 바란다.
참고로, 설문조사는 특정 태그에 대해 알고 있는지, 모르고 있는지, 또는 현재 사용 중인지 등을 묻는 객관식 형식으로 진행되었다.

Form

<datalist>
사용자 정의 옵션을 허용하면서 사용자가 양식 컨트롤에서 선택할 수 있는 사전 설정 목록을 제공하는 방법이다.
선택지를 나타내는 <option>태그가 존재한다.

<input name="country" list="countries">
<datalist id="countries">
  <option>Afghanistan</option>
  ...
</datalist>

HTML Media Capture
사용자의 카메라에서 입력을 캡처한다.

<input type="file" accept="video/*" capture>

accept 특성이 이미지나 비디오 캡처 데이터를 요구할 경우,
capture 특성으로는 어떤 카메라를 사용할지 지정할 수 있다.
user 값은 전면 카메라(사용자를 향한 카메라)와 마이크를, environment 값은 후면 카메라와 마이크를 사용해야 함을 나타낸다.
capture 특성을 누락한 경우 사용자 에이전트가 어떤 쪽을 선택할지 스스로 결정한다.

input.showPicker()
색상 선택기, 날짜 입력 등이 있는 선택기를 연다.

<input id="dateInput" type="date">
<button onclick="dateInput.showPicker()">Select date</button>

contenteditable속성의 plaintext-only

요소의 원시 텍스트 편집을 허용하지만 서식 있는 텍스트 형식은 허용하지 않는다.

<h2 class="title" contenteditable="plaintext-only"></h2>

plaintext-only 예시

EditContext
EditContext 인터페이스는 EditContext API를 사용하여 편집 가능하게 된 요소의 텍스트 편집 컨텍스트를 나타낸다.

const canvas = document.createElement("canvas");
const editContext = new EditContext();
canvas.editContext = editContext;

EditContext API는 IME(입력기) 구성, 이모티콘 선택기 또는 기타 플랫폼별 편집 관련 UI 표면과 같은 고급 텍스트 입력 환경을 지원하는 서식 있는 텍스트 편집기를 웹에서 구축하는 데 사용할 수 있다.

주의) 실험적 기능이며 사파리와 파이어폭스는 지원하지 않는다.

caretPositionFromPoint
CaretPosition 객체를 반환하며, 이 객체는 DOM 노드와 해당 노드 내에서의 커서 위치 및 커서의 문자 오프셋 정보를 포함한다.

const range = document.caretPositionFromPoint(e.clientX, e.clientY);
const textNode = range.offsetNode;
const offset = range.offset;

주의) 실험적 기능이며 사파리는 지원하지 않는다.

Interactivity

<dialog>
대화 상자 또는 닫을 수 있는 경고 또는 하위 창과 같은 기타 대화형 구성 요소에 사용된다.

  <dialog id="confirm">
	<form method="dialog">
		Are you sure?
		<button value="1">Yes</button>
		<button value="0">No</button>
	</form>
</dialog>

<details> and <summary>
콘텐츠를 대화형으로 숨기거나 표시하도록 전환할 수 있는 공개 위젯

<details>
  <summary>Details</summary>
  Longer content
</details>

Exclusive accordion
그룹에서 한 번에 최대 하나만 열 수 있도록 <details> 요소를 그룹화

<details open name="sidebar_panel" id="main_info">
	<summary>Main info</summary>
	<!-- controls -->
</details>
<details name="sidebar_panel" id="style_settings">
	<summary>Style</summary>
	<!-- controls -->
</details>

Popover API
오버레이, 팝업, 메뉴 등과 같은 팝오버를 용이하게 하는 HTML 구문 및 JS API

<button popovertarget="foo">Toggle the popover</button>
<div id="foo" popover>Popover content</div>

주의) 사파리는 지원하지 않는다.

inert attribute
불리언(boolean) 값으로, 활성화되면 해당 요소와 관련된 사용자 입력 이벤트(예: 클릭, 포커스, 키보드 입력)를 브라우저가 무시하도록 설정한다.

보조 기술(예: 스크린 리더)도 해당 요소를 무시한다.

페이지 검색(예: Ctrl+F) 및 텍스트 선택도 비활성화된다.

모달 UI를 만들 때 유용하다.

<div id="background" inert>
<!-- 모달 외부의 콘텐츠 -->
<p>이 내용은 모달이 열려 있으면 비활성화됩니다.</p>
</div>
<div id="modal">
<!-- 모달 내부의 콘텐츠 -->
<p>모달 내용</p>
<button>닫기</button>
</div>

주의) 모든 브라우저에서 지원하지 않을 수 있으므로 확인이 필요하다.

Clipboard API
클립보드 명령(잘라내기, 복사 및 붙여넣기)에 응답할 수 있을 뿐만 아니라 시스템 클립보드에서 비동기적으로 읽고 쓸 수 있는 기능을 제공한다.

navigator.clipboard
.readText()
.then(
  (clipText) => (document.querySelector(".editor").innerText += clipText),
);

content

Content-Security Policy (CSP)
XSS 및 기타 공격을 탐지하고 완화하는 데 도움이 되는 추가 보안 계층

Content-Security-Policy: default-src 'self'

웹사이트가 사용자 에이전트(브라우저)에서 특정 리소스를 로드할 수 있는 규칙을 정의할 수 있도록 하는 HTTP 응답 헤더
예를 들어 브라우저는 해당 정책에 따라 스크립트, 스타일, 이미지 등을 어디서 로드할 수 있는지 제한받는다.

주요 기능

  • 주로 서버의 출처(origin) 및 스크립트 엔드포인트를 지정하는 규칙을 포함한다.
  • 웹사이트가 신뢰할 수 없는 소스에서 악성 리소스를 로드하지 않도록 제한한다.
  • 특히 XSS(Cross-Site Scripting)와 같은 공격을 방어할 수 있다.

fetchpriority attribute
브라우저가 다양한 리소스를 가져오는 우선순위를 정하는 데 도움이 되는 힌트를 지정할 수 있다.

<img src="logo.svg" fetchpriority="high" />

blocking="render"
리소스(스크립트, 스타일시트 등)가 로드될 때까지 렌더링을 차단하도록 지정한다.

<script blocking="render" async src="async-script.js"></script>

주의) 사파리(실험적)와 파이어폭스에서는 지원하지 않는다.

<model> for AR/VR/3D content
3D 그래픽 콘텐츠를 HTML에 삽입할 수 있다.

<model src="3d-assets/car"></model>

controlslist attribute
미디어 요소의 도구 모음에 특정 컨트롤이 표시되지 않도록 한다.

<video src="fun.mp4" controlslist="nodownload"></video>

주의) 사파리와 파이어폭스에서는 지원하지 않는다.

CSS Custom Highlight API
JavaScript를 사용하여 범위를 생성하고 CSS를 사용하여 스타일을 지정함으로써 문서에서 임의의 텍스트 범위에 스타일을 지정하는 메커니즘을 제공한다.

// css
::highlight(my-custom-highlight) {
background-color: blue;
}

// js
const parentNode = document.getElementById("foo");
const range1 = new Range();
range1.setStart(parentNode, 10);
range1.setEnd(parentNode, 20);
const highlight = new Highlight(range1);
CSS.highlights.set("my-custom-highlight", highlight);

setHtmlUnsafe()
HTML 문자열을 DocumentFragment로 변환하여 DOM 요소의 기존 하위 트리를 대체한다.
이 메서드는 HTML 문자열을 직접 DOM으로 파싱한다.
메서드 이름에 포함된 Unsafe는 이 메서드가 입력된 HTML의 안전성을 확인하거나 XSS(크로스 사이트 스크립팅) 관련 요소를 제거하지 않음을 의미하므로, 사용에 주의해야한다.

const value = "<p>This is a string of text</p>";
document.getElementById("target").setHTMLUnsafe(value);

Intl.Segmenter API
텍스트를 locale에 따른 언어에 따라 문자소, 단어 또는 문장으로 분할한다.

const segmenterFr = new Intl.Segmenter('fr', { granularity: 'word' });
const string1 = 'Que ma joie demeure';

const iterator1 = segmenterFr.segment(string1)[Symbol.iterator]();

console.log(iterator1.next().value.segment);
// Expected output: 'Que'

console.log(iterator1.next().value.segment);
// Expected output: ' '

Defining Custom Elements
아래처럼 custom elements를 사용할 수 있다.

class MyElement extends HTMLElement {}
customElements.define("my-element", MyElement);

Scoped Custom Element Registries
단일 태그 이름에 대한 여러 custom elements 정의가 페이지 내에 존재하도록 허용한다.

const registry = new CustomElementRegistry();
registry.define('sub-element', SubElement);

Shadow DOM
외부에서 보이지 않는 요소를 캡슐화하고 페이지의 나머지 부분에 영향을 주지 않는 CSS로 스타일을 지정한다.

this.shadowRoot = this.attachShadow({mode: "open"});

Declarative Shadow DOM
HTML로 shadow tree를 정의한다.

<host-element>
  <template shadowrootmode="open">
      <!-- Shadow content -->
  </template>
</host-element>

Imperative slot assignment
HTML <slot> 요소는 웹 컴포넌트 사용자가 자신만의 마크업으로 채워 별도의 DOM 트리를 생성하고, 컴포넌트와 함께 표현할 수 있는 웹 컴포넌트 내부의 placeholder이다.
컴포넌트 사용자가 slot을 명시적으로 관리하지 않아도, 컴포넌트 내부에서 원하는 요소를 특정 slot에 직접 배치할 수 있다.

기본적으로 slot 요소는 자동으로 콘텐츠를 할당한다.
컴포넌트 소비자가 제공한 slot 콘텐츠가 이름 또는 기본 슬롯에 따라 자동으로 아래처럼 매핑된다.

<my-component>
  <div slot="foo">Hello</div>
</my-component>

위의 경우, slot="foo"를 통해 div는 자동으로 "foo" 슬롯에 할당된다.
그러나 slotAssignment: "manual"을 사용하면, 자동 매핑을 비활성화하고, 개발자가 JavaScript를 통해 직접 요소를 특정 슬롯에 할당할 수 있다.

// 1. Shadow DOM 생성
this.attachShadow({
mode: "open",
slotAssignment: "manual", // 수동 슬롯 할당 모드 활성화
});

// 2. 특정 슬롯 가져오기
const fooSlot = this.shadowRoot.querySelector("slot[name=foo]");

// 3. 특정 요소를 해당 슬롯에 수동으로 할당
fooSlot.assign(element);

ElementInternals API
웹 컴포넌트에서 접근성(ARIA) 속성, 양식 연동, 및 기본 DOM 행동을 관리하기 위해 사용되는 강력한 도구
사용자 정의 요소에 대해 브라우저와 더 나은 상호작용을 가능하게 하며, 특히 접근성과 양식 통합에 중요한 역할

this.#internals = this.attachInternals()
this.#internals.ariaChecked = true;

Accessibility

focusgroup
특정 요소 그룹 내에서 키보드 화살표 키를 사용해 포커스를 탐색할 수 있도록 설계된 기능
접근성을 향상시키고 키보드 내비게이션을 보다 직관적으로 만듦

<div focusgroup="wrap horizontal">
	<!-- child elements -->
</div>

<search>
검색 래핑을 위한 시맨틱 요소

<search>
<form action="search.php">
  <label>Find: <input name="q" type="search"></label>
  <button>Go!</button>
</form>
</search>

웹 사이트를 만들 때 고려할 수 있는 사용자 장애
-> 설문조사에서는 어떤 것을 고려하는지 선택지로 나와있었다. 실제로도 이러한 내용에 대해 고려해 보면 좋을 것 같다.

1. 저시력: 실명, 고도 근시 등
2. 비정형 색각: 색맹
3. 이동성 장애: 관절염, 손목 터널 증후군 등
4. 전정 장애: 간질, 현기증, 등
5. 학습 장애: 난독증, 난산증 등
6. 기타 인지 장애: 불안, 자폐증, 강박 장애, ADHD 등
7. 청각 장애: 청력 상실, 이명 등

웹 접근성을 높이기 귀한 전략

1. 직관적인 키보드 탐색
탭 순서 이외.

2. alt 속성
이미지의 목적이나 내용을 설명하는 대체 텍스트를 제공

3. skip to content 링크
사용자가 페이지의 주요 콘텐츠로 바로 건너뛸 수 있다

4. <fieldset> and <legend>
<fieldset><legend>를 사용하여 관련 양식 요소를 그룹화

5. 정보 계층
페이지의 정보 계층을 올바르게 나타내는 제목(<h1> - <h6>) 사용

6. 의미 있는 링크 텍스트
링크 텍스트가 문맥에 맞지 않는지 확인

7. form control label
모든 form 컨트롤에 <label>(또는 aria-label 등)이 있는지 확인

8. Visible Focus Ring
필요할 때 focus 한 윤곽선이 명확하게 보이도록 보장

9. 포인터에만 의존하지 않음
포인터 상호 작용(예: 호버)에 키보드 대안이 있는지 확인

10. 충분한 대비
충분한 색상 대비를 보장하기 위해 대비 체커를 사용

11. 색상에만 의존하지 않음
색상만으로는 어떤 정보도 전달되지 않도록 함

12. `prefers-reduced-motion` 미디어 쿼리
감소된 모션을 선호하는 사용자를 위한 대체 CSS를 제공

13. 'prefers-contrast' 미디어 쿼리
대비 증가를 선호하는 사용자를 위한 대체 CSS를 제공

Native Web Apps

File System Access API
사용자의 로컬 장치에 있는 파일 및 디렉터리에 액세스한다.

const handle = await window.showSaveFilePicker(opts);

Badging API
업데이트된 상태에 대해 덜 방해적이고 지속적인 방식으로 알리기 위한 웹 애플리케이션 아이콘 배지

navigator.setAppBadge(unreadCount)

Web Share API
사용자가 선택한 다양한 대상에 콘텐츠를 공유하기 위한 메커니즘을 노출

navigator.share(shareData)

Launch Handler API
PWA가 실행 방법을 제어할 수 있도록 허용. ex)새 창이나 탭

"launch_handler": {"client_mode": "navigate-new"}

File Handling API
PWA가 특정 파일 형식에 대한 처리기로 자신을 등록할 수 있도록 허용합니다.

    "file_handlers": [{
    "action": "/open-file",
    "accept": {
      "image/svg+xml": ".svg",
      "image/png": ".png"
    }
  }]

Window Controls Overlay API
PWA가 제목 표시줄 영역 위에 사용자 정의 콘텐츠를 표시할 수 있으며 해당 컨트롤은 오버레이가 됩니다

"display_override": ["window-controls-overlay"]

Isolated Web Apps
PWA에 대한 기본과 유사한 패키징, 권한 및 서명된 업데이트.

isolated-app://4tkr2qbhf7rlz2a3wo3rh4wqaaic/index.html

느낀점

무심코 마크업을 하다 보면 의미 없는 div 태그가 남발되어 구조가 뒤엉키기 쉽다. 또한, 스타일 라이브러리를 사용하다 보면 실제로 어떤 HTML 태그가 적용되고 있는지 모른 채 작업할 때도 있었다. 이번 설문조사는 이러한 부분을 돌아보고 올바른 태그 사용을 되짚어보며 개발자 경험(DX)을 개선할 수 있는 좋은 기회가 된 것 같다.

reference

https://survey.devographics.com/ko-KR/survey/state-of-html/2024
mdn

profile
숲을 보며 나무를 심는 프론트엔드 개발자🌳

0개의 댓글