CSS Custom Highlight API: 텍스트 범위를 DOM 수정 없이 하이라이트하는 현대적 방법 ("CSS Custom Highlight API")

okorion·2025년 12월 3일

1. 핵심 요약

  • CSS Custom Highlight API는 任의 텍스트 범위를 하이라이트할 수 있는 표준 API.
  • DOM을 수정하지 않고 Range + Highlight + CSS ::highlight()로 스타일 지정 가능.
  • 기존 ::selection, ::spelling-error 등 “브라우저가 정한 범위”를 넘어 개발자가 직접 정의한 텍스트 영역을 스타일링.
  • 검색 결과, 문법 오류, 협업 편집기, 코드 편집기 등 다양한 시나리오에서 활용 가능.
  • Chrome/Edge/Safari iOS 등 최신 브라우저 대부분 지원(2025년 기준).

2. 왜 필요한가 (Why)

기존 텍스트 하이라이트 방식의 문제:

  • DOM에 <span class="highlight"> 같은 래퍼 요소를 삽입해야 했음
    → DOM 오염, 성능 저하, range 관리 복잡
  • OS/브라우저가 결정한 특수 영역(::selection 등)만 스타일 가능
  • 협업 편집기처럼 여러 사용자 하이라이트 필요 시 구조가 복잡해짐

Custom Highlight API는 DOM을 건드리지 않고도 텍스트 범위를 정확하게 스타일링할 수 있게 해주는 해결책.


3. API 구조 개요 (What)

사용 순서:

  1. Range 생성
  2. Highlight 생성
  3. CSS.highlights(HighlightRegistry)에 등록
  4. CSS에서 ::highlight()로 스타일링

구조 시각화

[Range Objects] → [Highlight] → [CSS.highlights Registry] → CSS ::highlight()

4. Step 1 — Range 객체 생성

const parentNode = document.getElementById("foo");

const range1 = new Range();
range1.setStart(parentNode, 10);
range1.setEnd(parentNode, 20);

const range2 = new Range();
range2.setStart(parentNode, 40);
range2.setEnd(parentNode, 60);
  • Range는 “노드 내 문자 offset 기준”으로 범위를 지정
  • 여러 Range를 하나의 하이라이트로 묶을 수 있음

5. Step 2 — Highlight 객체 생성

여러 Range를 하나의 Highlight로 묶기:

const highlight = new Highlight(range1, range2);

사용 사례 예:

  • 협업 에디터: 사용자별 Range 집합을 다른 색으로 표시
const user1Highlight = new Highlight(user1Range1, user1Range2);
const user2Highlight = new Highlight(user2Range1, user2Range2, user2Range3);

6. Step 3 — HighlightRegistry에 등록

CSS.highlights.set("user-1-highlight", user1Highlight);
CSS.highlights.set("user-2-highlight", user2Highlight);
  • Registry는 Map처럼 동작
  • 삭제/초기화 가능
CSS.highlights.delete("user-1-highlight");
CSS.highlights.clear();

7. Step 4 — CSS ::highlight()로 스타일 지정

::highlight(user-1-highlight) {
  background-color: yellow;
  color: black;
}
  • highlight 이름을 CSS에서 그대로 사용
  • DOM node를 감싸는 시각적 래퍼가 아닌 텍스트 레이어 스타일링

8. API 구성 요소 (Interfaces)

Highlight

  • Range들의 집합

HighlightRegistry (CSS.highlights)

  • Highlight를 이름으로 등록·관리하는 Map-like 객체

9. 실전 예제 — 검색 결과 하이라이트

목표: 입력한 검색어와 일치하는 텍스트를 하이라이트

HTML

<label>Search within text <input id="query" type="text" /></label>
<article>
  <!-- paragraphs... -->
</article>

JS: 텍스트 노드 수집

const article = document.querySelector("article");

const treeWalker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
const allTextNodes = [];
let currentNode = treeWalker.nextNode();
while (currentNode) {
  allTextNodes.push(currentNode);
  currentNode = treeWalker.nextNode();
}

검색 → Range 생성 → Highlight 등록

query.addEventListener("input", () => {
  if (!CSS.highlights) return;

  CSS.highlights.clear();

  const str = query.value.trim().toLowerCase();
  if (!str) return;

  const ranges = allTextNodes
    .map((el) => ({ el, text: el.textContent.toLowerCase() }))
    .map(({ text, el }) => {
      const indices = [];
      let startPos = 0;

      while (startPos < text.length) {
        const index = text.indexOf(str, startPos);
        if (index === -1) break;
        indices.push(index);
        startPos = index + str.length;
      }

      return indices.map((index) => {
        const range = new Range();
        range.setStart(el, index);
        range.setEnd(el, index + str.length);
        return range;
      });
    });

  const searchResultsHighlight = new Highlight(...ranges.flat());
  CSS.highlights.set("search-results", searchResultsHighlight);
});

CSS

::highlight(search-results) {
  background-color: #ff0066;
  color: white;
}

→ 검색어 입력 즉시 DOM 구조 변경 없이 깔끔한 하이라이트 기능 제공.


10. 브라우저 지원(2025 기준)

브라우저지원
Chrome 105+
Edge 105+
Firefox 140+
Safari 17.2+
iOS Safari 17.2+
Android Chrome 105+
  • 대부분의 최신 브라우저에서 안정 지원
  • 일부 기능(highlightsFromPoint)은 실험적

11. 활용 시나리오 (How)

1) 코드 에디터

  • 오류 위치·lint 결과 강조
  • syntax highlight overlay

2) 협업 문서

  • 사용자별 커서/선택 범위 색상 표시

3) 검색 UI

  • Google Docs 같은 실시간 텍스트 강조
  • 대규모 문서에서도 DOM 오염 없이 처리 가능

4) 문법 검사기

  • grammar-error/spelling-error 패턴 확장 가능

원문 - CSS Custom Highlight API

profile
okorion's Tech Study Blog.

0개의 댓글