1. 소개
이 섹션은 비규범적입니다.
커스텀 하이라이트 API는 하이라이트 의사요소(CSS Pseudo-Elements 4 § 3 하이라이트 의사요소 참조) 개념을 확장하여, 웹 개발자가 임의의 Range 객체의 텍스트를 스타일링할 수 있게 합니다. 이는 사용자 에이전트가 정의한 ::selection, ::inactive-selection, ::spelling-error, 그리고 '::grammar-error' 만으로 제한되지 않습니다. 이 기능은 다양한 상황에서 유용합니다. 예를 들면 자체 선택 기능을 구현하려는 편집 프레임워크, 가상화된 문서에서의 페이지 내 찾기, 온라인 협업을 위한 다중 선택, 또는 맞춤법 검사 프레임워크 등이 있습니다.
커스텀 하이라이트 API는 기본 DOM 구조에 영향을 주지 않으면서 프로그래밍적으로 하이라이트를 추가 및 제거할 수 있는 방법을 제공합니다. 대신 range 객체를 기반으로 텍스트에 스타일을 적용합니다. 이는 ::highlight() 의사요소를 통해 접근할 수 있습니다.
One two텍스트에 노란색 배경과 파란색 글자색을 적용합니다.
Highlight를
HighlightRegistry
에 추가하여 동작합니다(이 둘 모두 이 명세서에서 새롭게 소개된 개념입니다).
Highlight는
Range
를 포함하며, 그 경계점이 One two텍스트를 감쌉니다.
< style > : root :: highlight ( example-highlight ) { background-color : yellow ; color : blue ; } </ style > < body >< span > One</ span >< span > two</ span >< span > three…</ span > < script > let r= new Range(); r. setStart( document. body, 0 ); r. setEnd( document. body, 2 ); CSS. highlights. set( "example-highlight" , new Highlight( r)); </ script >
결과는 다음과 같이 표시됩니다:
2. 모듈 상호작용
이 모듈은 Infra 표준 [INFRA]와 WebIDL [WebIDL]에 의존합니다.
CSS와 DOM 표준 [DOM]에 대한 기본적인 이해를 전제로 하며, 특히 CSS Pseudo-Elements Module Level 4 [css-pseudo-4]에서 정의된 메커니즘을 확장하여 하이라이트 의사요소를 처리합니다. Selectors Level 4 [selectors-4] 명세는 의사요소가 일반적으로 어떻게 동작하는지 정의합니다.
전체 의존성 목록은 참고문헌을 참고하세요.
참고: 이 초안은 초기 버전입니다. 발전함에 따라 CSS-WG는 이를 독립 모듈로 유지할 수도 있고, [css-pseudo-4]나 그 이후 버전에 통합할 수도 있습니다.
3. 커스텀 하이라이트 설정
3.1. 커스텀 하이라이트 생성
커스텀 하이라이트는 문서의 일부 영역을 나타내는 range들의 집합입니다. 이들은 반드시 엘리먼트 트리에 맞춰질 필요가 없으며, 중첩 구조를 따르지 않고 자유롭게 엘리먼트 경계를 넘을 수 있습니다. 문서의 해당 부분의 외형을 변경하는 데 사용할 수 있습니다 (§ 4 커스텀 하이라이트 스타일링 참고), 또는 그와 관련된 이벤트를 처리할 때 사용할 수 있습니다 (§ 6 이벤트 처리 참고).
커스텀 하이라이트는 Highlight 객체로 표현되며, setlike 객체로서 set entries는 AbstractRange
객체가 됩니다. Range들은 생성자에 전달하거나,
setlike 객체의 일반적인 API를 사용하여 set
entries를 조작함으로써 커스텀 하이라이트에 추가할 수 있습니다.
참고: range가 커스텀 하이라이트 내에서 AbstractRange
객체이므로,
작성자는 Range
객체 또는 StaticRange
객체를 선택할 수 있습니다.
이에 대한 자세한 내용과 영향은 § 5.2 범위 업데이트 및 무효화를 참고하세요.
enum {HighlightType ,"highlight" ,"spelling-error" }; ["grammar-error" Exposed =Window ]interface Highlight {constructor (AbstractRange ...);initialRanges setlike <AbstractRange >;attribute long ;priority attribute HighlightType ; };type
§ 4.2.5 겹치는 하이라이트의 우선순위에서 priority
속성에 대한 자세한 정보를 확인할 수 있습니다.
§ 4.2.6 하이라이트 종류에서 type
속성에 대한 자세한 정보를 확인할 수 있습니다.
Highlight(AbstractRange... initialRanges) 생성자가 호출되면,
다음 절차를 실행합니다:
- highlight를 새로운
Highlight객체로 설정합니다. - highlight의
priority값을0으로 설정합니다. - highlight의
type값을highlight로 설정합니다. -
initialRanges의 각 range에 대해, rangeArg를 IDL 값을 ECMAScript 값으로 변환한 결과로 설정하고, 내장 setlike add 함수의 절차를 실행합니다. highlight를this값으로, rangeArg를 인자로 사용합니다. - highlight를 반환합니다.
3.2. 커스텀 하이라이트 등록
효과를 내려면, 커스텀 하이라이트는 등록되어 하이라이트 레지스트리에 포함되어야 합니다.
하이라이트 레지스트리는 highlights
속성을 통해 CSS
네임스페이스에서 접근하며,
커스텀 하이라이트가 등록되어 있는 현재 글로벌 객체의 연관된 Document 전체를 나타냅니다.
이는 maplike이며, 일반적인 메서드를 통해 갱신할 수 있습니다.
map entries는 처음엔 비어있습니다.
사용자 지정 하이라이트가 하이라이트 레지스트리에 있으면 등록된 것으로 간주한다. 나중에 제거되면 더 이상 등록된 것으로 간주하지 않는다.
partial namespace CSS {readonly attribute HighlightRegistry ; }; [highlights Exposed =Window ]interface {HighlightRegistry maplike <DOMString ,Highlight >; };
set 메서드를 호출한다. 그러면
내장 maplike set 함수의 단계가 실행되며,
컨텍스트 객체를 this 값으로,
전달된 사용자 지정 하이라이트
이름을 keyArg로,
전달된 하이라이트를 valueArg로 사용한다.
사용자 지정 하이라이트가 등록될 때 할당되는 사용자 지정 하이라이트 이름은 스타일 지정 중 하이라이트를 식별하는 데 사용된다 (§ 4 사용자 지정 하이라이트 스타일 지정 참조).
참고: 사용자 지정 하이라이트를 등록할 때, 작성자는 유효한 CSS 식별자인 사용자 지정 하이라이트 이름을 사용하는 것이 권장된다. 유효한 식별자가 아닌 이름을 사용하면 CSS를 통해 하이라이트에 스타일을 지정하기 어려워지고, 어떤 경우에는 불가능해질 수도 있다.
참고: 하나의 사용자 지정 하이라이트를 둘 이상의 사용자 지정 하이라이트 이름으로 등록할 수 있다. 그러나 둘 이상의 이름을 사용하여 하이라이트에 스타일을 지정하면 하이라이트에 서로 다른 여러 스타일 집합이 할당되며, 페인팅 중 이러한 집합 안에서 충돌하는 스타일의 쌓임 순서를 제어할 방법이 없다. 이는 작성자에게 제약이 될 수 있고 혼란스러운 페인팅 동작을 일으킬 수 있다 (자세한 맥락은 아래의 예 참조). 따라서 작성자는 스타일 지정 중 하이라이트마다 하나의 이름만 사용하는 것이 권장된다.
< style > div :: highlight ( bar ) { color : red ; } div :: highlight ( foo ) { color : green ; } </ style > < body >< div > abc</ div > < script > let div= document. body. firstChild; let r= new Range(); r. setStart( div, 0 ); r. setEnd( div, 1 ); let h= new Highlight( r); CSS. highlights. set( 'foo' , h); CSS. highlights. set( 'bar' , h); </ script >
위 예에서는
동일한 사용자 지정
하이라이트 객체가 foo 및 bar라는 이름으로 등록된다.
각 스타일 규칙이 동일한 하이라이트를 대상으로 하고 동일한 명시도를 가지므로,
작성자는 캐스케이딩 순서에서 마지막 규칙이 우선하여
하이라이트된 콘텐츠가 녹색으로 표시될 것이라고 예상할 수 있다.
그러나 각 하이라이트 이름은 독립적인 하이라이트 스타일 집합을 가지며,
하이라이트는 이름마다 한 번씩 페인팅된다.
이 경우 foo가 bar보다 먼저 등록되었으므로,
하이라이트는 먼저 foo의 색상(녹색)으로 페인팅되고
그다음 bar의 색상(빨간색)으로 페인팅된다.
그 결과 하이라이트된 콘텐츠는 빨간색으로 표시된다.
4. 커스텀 하이라이트 스타일링
4.1. 커스텀 하이라이트 의사요소: ::highlight()
::highlight(<custom-highlight-name>) 의사요소 (또는 커스텀 하이라이트 의사요소라고도 불림) 는 문서에서 포함 또는 부분적으로 포함된 range 전체를 나타냅니다. 해당 등록된 커스텀 하이라이트의 커스텀 하이라이트 이름 <custom-highlight-name>에 해당하는 부분이 있으면 적용됩니다. <custom-highlight-name>은 반드시 올바른 CSS <ident-token>이어야 합니다.
4.2. 처리 모델
4.2.1. 적용 가능한 속성
커스텀 하이라이트 의사요소는 기본 내장 하이라이트 의사요소와 마찬가지로 제한된 속성만 스타일링할 수 있습니다. 전체 속성 목록은 CSS Pseudo-Elements 4 § 3.2 하이라이트 스타일링을 참고하세요.
4.2.2. 기본 스타일
UA는 커스텀 하이라이트 의사요소에 대해 기본 UA 스타일시트에 스타일을 정의해서는 안 됩니다. 커스텀 하이라이트 의사요소는 자신의 원본 요소의 스타일을 상속받습니다.
4.2.3. 계단식 및 상속
계단식과 상속은 커스텀 하이라이트 의사요소에서도 내장 하이라이트 의사요소와 동일하게 처리됩니다. 자세한 내용은 CSS Pseudo-Elements 4 § 3.5 계단식과 요소별 하이라이트 스타일을 참고하세요.
4.2.4. 페인팅
커스텀 하이라이트의 페인팅은 내장 하이라이트 의사요소와 동일하게 처리됩니다. 관련 규정은 CSS Pseudo-Elements 4 § 3.4 하이라이트의 영역 및 CSS Pseudo-Elements 4 § 3.6 하이라이트 페인팅에 명시되어 있습니다. 아래와 같은 추가 설명이 있습니다:
- 접힘 range는 렌더링되지 않습니다.
-
하나의 커스텀 하이라이트
내에서 겹치는 range는
겹치는 부분을 하나의 합집합 range로 처리한 것처럼 렌더링됩니다.
아래 예시는 반투명 파란색 배경의 하나의 하이라이트로 렌더링되며, 겹치는 두 개의 투명 하이라이트가 아닌, 겹친 부분이 보이지 않는 방식입니다.
< style > :: highlight ( sample ) { background-color : rgba( 0 , 0 , 255 , 0.3 ); } </ style > < body > Lorem Ipsum.< script > let textNode= document. body. firstChild; let r1= new Range(); r1. setStart( textNode, 1 ); r1. setEnd( textNode, 5 ); let r2= new Range(); r2. setStart( textNode, 3 ); r2. setEnd( textNode, 7 ); CSS. highlights. set( "sample" , new Highlight( r1, r2)); </ script > 즉, 아래와 같이 렌더링되는 것이 올바릅니다:
Lorem Ipsum.반면, 아래와 같이 렌더링되는 것은 올바르지 않습니다:
Lorem Ipsum. - 하이라이트 오버레이의 커스텀 하이라이트는 내장 하이라이트 의사요소 오버레이보다 스택 순서에서 아래에 위치합니다. 관련 순서는 CSS Pseudo-Elements 4 § 3.6 하이라이트 페인팅을 참고하세요.
- 여러 하이라이트 오버레이의 커스텀 하이라이트끼리의 상대적 스택 순서는 priority에 의해 결정됩니다 (§ 4.2.5 겹치는 하이라이트의 우선순위 참고).
4.2.5. 겹치는 하이라이트의 우선순위
사용자 지정 하이라이트의
priority
속성은
해당 우선순위를 정의한다.
이는 페인팅 작업 중 대응하는 하이라이트 오버레이의 쌓임 순서를 결정하는 데 사용된다(§ 4.2.4
페인팅 참조).
더 높은 우선순위는
쌓임 순서에서 더 위에 배치되도록 한다.
사용자 지정 하이라이트의 priority
속성이 명시적으로 설정되지 않은 경우 기본 숫자 우선순위는 0이다.
둘 이상의 커스텀 하이라이트가
동일한 우선순위 값을 가지는 경우,
가장 최근에 등록된 것이 더 높은
실제 우선순위를 가집니다.
< style > : root :: highlight ( foo ) { color : blue ; background-color : yellow ; } : root :: highlight ( bar ) { background-color : orange ; } </ style > < body > Some text< script > let textNode= document. body. firstChild; let r1= new Range(); r1. setStart( textNode, 0 ); r1. setEnd( textNode, 6 ); let r2= new Range(); r2. setStart( textNode, 3 ); r2. setEnd( textNode, 9 ); let h1= new Highlight( r1); let h2= new Highlight( r2); CSS. highlights. set( "foo" , h1); CSS. highlights. set( "bar" , h2); </ script >
우선순위가 설정되지 않았으므로
(즉, h1과 h2가 동점임),
커스텀 하이라이트의 스타일은
하이라이트 레지스트리에
등록된 순서대로 쌓입니다.
렌더링 결과는 "Som"이 노란색 배경의 파란색 글자,
"e t"가 오렌지 배경의 파란색 글자,
"ext"가 오렌지 배경의 기본 글자로 나타납니다.
h1
를 설정하면 h1이 h2보다 더 위에 쌓이므로,
"Some t"가 노란색 배경의 파란색 글자,
"ext"가 오렌지 배경의 기본 글자로 나타납니다.
4.2.6. 하이라이트 종류
커스텀 하이라이트의
type
속성은
하이라이트의 의미를 명확히 나타내기 위해 작성자가 지정할 수 있습니다.
이를 통해 보조 기술이 해당 하이라이트의 의미를
사용자에게 전달할 수 있습니다.
커스텀 하이라이트의 type
속성을 명시적으로 지정하지 않으면 기본값은 highlight입니다.
참고: 작성자는 사용자 지정 하이라이트의 type을
해당 사용자 지정 하이라이트가 맞춤법이 틀린 콘텐츠를 강조하는 데 사용될 때 spelling-error로
설정하는 것이 권장된다.
작성자는 사용자 지정 하이라이트의 type을
해당 사용자 지정 하이라이트가 문법적으로 올바르지 않은
콘텐츠를 강조하는 데 사용될 때 grammar-error로
설정하는 것이 권장된다.
그 밖의 모든 사용 사례에서는 type을
highlight로
두는 것이 가장 좋다.
UA는 커스텀 하이라이트를 보조
기술에 제공해야 합니다.
플랫폼 접근성 API를 통해 하이라이트를 노출할 때,
UA는 해당 type
속성에 명시된 의미를
해당 접근성 API에서 가능한 한 구체적으로 표현해야 합니다.
참고: 예를 들어,
플랫폼 접근성 API가 맞춤법 오류와 문법 오류를 구체적으로 표현할 수 있는 기능을 제공하는 경우,
UA는 spelling-error
및 spelling-error인
하이라이트의 의미를
이러한 기능을 사용하여 전달할 것으로 기대된다.
접근성 API가 맞춤법 오류만 표현할 수 있는 기능을 제공하는 경우,
UA는 spelling-error
및 grammar-error인
두 하이라이트 모두를
맞춤법 오류 의미론을 사용하여 전달할 것으로 기대된다.
접근성 API가 맞춤법 오류와 문법 오류 중 어느 것도 표현하는 기능을 지원하지 않는 경우,
UA는 실제 type에
관계없이 모든 하이라이트를 일반적인 highlight로
노출한다.
참고: 이 초기 타입 집합은
Highlight API의 대표적 사용 사례로 예상되는 것과
플랫폼 접근성 API에서 이미 일부 의미 표현이 가능한 것들로 선정되었습니다.
현재 접근성 API는 Highlight API의 기타 예상 사용 사례의 구체적 의미를 표현할 수 없습니다.
향후 접근성 API가 추가적인 Highlight API 사용 사례의 의미를 표현할 수 있게 되면,
HighlightType에
더 많은 타입이 추가될 수 있습니다.
5. 변경 사항에 대응하기
5.1. 다시 그리기
하이라이트 레지스트리에 커스텀 하이라이트를 추가하거나 제거할 때, 또는 등록된 커스텀 하이라이트 내의 range를 추가하거나 제거할 때, 사용자 에이전트는 렌더링을 다시 평가하고 필요 시 다시 그려야 합니다.
사용자 에이전트는 또한 작성자가 priority를
변경하거나,
boundary points를 Range들의
등록된 커스텀 하이라이트에서 변경할 경우에도
필요에 따라 하이라이트를 다시 그려야 합니다.
이 재평가의 타이밍(동기/비동기)을 어떻게 명세해야 할까요? [Issue #4596]
5.2. Range 업데이트 및 무효화
작성자는 Range
또는 StaticRange를
사용해 커스텀 하이라이트를 만들 수
있습니다.
생성된 커스텀 하이라이트는 문서의 동일한 부분을 나타내며, 동일하게 스타일링할 수 있습니다. 하지만, 기본 문서가 수정될 경우 동작은 달라집니다.
Range는
라이브 range입니다.
사용자 에이전트는 Range의
boundary points를
해당 range와 겹치거나 경계에서 DOM 변경이 발생하면 조정하고,
다시 그리기를 실행합니다. boundary points는 라이브 range에서 작성자가 직접 변경할 수도 있습니다.
반면, StaticRange의
boundary points는
DOM 변경에 따라 사용자 에이전트가 조정하지 않으며,
생성 이후 작성자가 변경할 수도 없습니다.
사용자 에이전트는 실제 StaticRange
객체를 저장해야 하며,
라이브 Range로
대체해서는 안 됩니다.
Range
객체를 업데이트하는 것은 성능에 큰 부담을 줍니다.
DOM 변경을 감지하고 이에 따라 커스텀
하이라이트 내의 range를 조정하거나 재생성하려는 작성자는
불필요한 비용을 피하기 위해 StaticRange를
사용하는 것이 권장됩니다.
반대로 StaticRange를
사용하는 작성자는 DOM 변경을 관찰하고,
오래된 range 또는 커스텀 하이라이트를 폐기하고 새로 만들어야 합니다.
문서를 렌더링하는 방법을 계산할 때,
해당 문서의 window에 연관된 하이라이트 레지스트리 내의 어떤 range의 start node 또는 end
node가
해당 문서가 아닌 Node의
shadow-including root를 참조할 경우,
사용자 에이전트는 해당 range를 무시해야 합니다.
해당 문서의 window에 연관된 하이라이트 레지스트리 내의 어떤 StaticRange가
유효하지 않은 경우,
사용자 에이전트는 해당 range를 무시해야 합니다.
[css-contain-2]가 적용된 커스텀 하이라이트 내의 StaticRange의
상호작용은 문제를 일으킵니다:
완전히 포함된 요소에서는,
해당 요소의 하위에서 DOM 변경이 발생해도
포함된 요소 외부의 요소에 대해 무효화 및 재스타일/재페인팅이 발생하지 않아야 한다고 기대할 수 있습니다.
하지만 static range의 경계점이 포함된 서브트리 내부와 외부에 각각 있을 경우,
내부 경계점이 더 이상 유효한 노드를 가리키지 않게 되면,
전체 range가 무시되어야 하며,
이는 포함 서브트리 외부의 페인팅에도 영향을 미치게 됩니다.
이것은 스타일 포함의 취약점인지,
위의 무효화 논리의 문제인지,
아니면 다른 원인인지? [Issue #4598]
6. 이벤트 처리
이벤트 섹션은 https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/highlight/events-explainer.md 를 바탕으로 작성될 예정입니다.
커스텀 하이라이트에 전용 이벤트 처리 메커니즘을 도입해야 하는지, 아니면 의사요소 전반에 추가해야 하는지 검토가 필요합니다.
부록 A. 개인정보 및 보안 고려사항
이 섹션은 비규범적입니다.
이 명세는 새로운 보안 혹은 개인정보 문제를 야기하지 않는 것으로 보입니다. 만약 그렇지 않다고 의심되는 경우, CSS 워킹 그룹이나 공동 편집자에게 연락해 주시기 바랍니다.
부록 C. 변경 사항
이 섹션은 비규범적입니다.
2020년 12월 8일 워킹드래프트 이후 변경 사항
여러 편집적 개선 및 사소한 조정 외에, 주요 변경 사항은 다음과 같습니다:
-
HighlightsRegister를HighlightRegistry로 이름 변경 -
HighlightRegistry에서 중복되는add()메서드 삭제 (이슈 6092 참고) -
커스텀 하이라이트 오버레이가 네이티브 하이라이트 오버레이 아래에 쌓이도록 변경 (이슈 4595 참고)
-
하이라이트 우선순위를 실수 대신 정수로 처리하도록 변경 (이슈 4592 참고)
-
하이라이트 우선순위의 기본값을 0으로 정의 (이슈 6136 참고)
-
HighlightRegistry를 setlike에서 maplike로 변경하고, Highlight에서
name속성 제거 (이슈 5910 참고) -
잘못된 window에서 나온 range는 페인팅되지 않음을 명확히 함 (이슈 6417 참고)
-
커스텀 하이라이트에는 UA 스타일이 없다는 점을 명시 (이슈 6375 참고)
-
type속성을Highlight에 추가하여 하이라이트의 의미를 명확하게 함. 접근성 도구에 하이라이트를 노출할 수 있도록 지원. (이슈 6498 참고)
2020년 10월 22일 워킹드래프트 이후 변경 사항
2020년 10월 22일 워킹드래프트 이후에는 편집적 변경만 있었습니다; 차이점을 참고하세요.