정의
드래그 손잡이(⣿ 같은) 아이콘이나 장식 문자를 화면에는 보여주고 싶지만, 사용자가 본문을 복사할 때 그 장식 글자까지 딸려 복사되는 걸 막고 싶을 때 쓰는 지식이다.
배경 개념 두 가지: Selection.toString()(현재 선택 영역을 문자열로 뽑는 브라우저 API)과 복사 시의 직렬화(선택 영역을 클립보드용 텍스트로 변환하는 과정)는 모두 DOM의 텍스트 노드(HTML 안의 실제 글자 데이터)를 기준으로 문자열을 만든다. 그래서 흔히 막는 데 쓰는 user-select: none(마우스 드래그 선택을 막는 CSS)은 사용자가 새로 드래그해서 선택하는 것만 어렵게 할 뿐, 이미 잡힌 선택의 복사 결과에서 그 글자를 완전히 빼준다고 보장하지 않는다. 확실히 빼려면 그 문자를 텍스트 노드가 아니라 CSS ::before / ::after의 content(generated content — HTML에는 없고 CSS로만 그려 넣는 가짜 콘텐츠)로 두는 편이 안전하다.
왜 필요한가
문제 상황: 블록 에디터의 드래그 손잡이, 장식 아이콘, 숨김 라벨을 DOM에 진짜 텍스트로 넣어두면, 사용자가 그 블록을 선택해 복사할 때 손잡이 글리프(⣿ 같은 아이콘 문자)가 본문 텍스트와 섞여 클립보드에 들어간다. 붙여넣으면 "⣿ 실제 내용" 처럼 지저분해진다.
이때 user-select: none만으로는 부족하고, draggable={false}(요소를 끌 수 없게 하는 속성)는 드래그 동작만 막을 뿐 복사 문자열과는 무관하다. 그래서 "화면에 보이는 장식"과 "복사되는 의미 있는 텍스트"를 분리하는 접근이 필요하다.
동작 원리
- 사용자가 범위를 드래그하면
Selection이 DOM 텍스트 노드를 가리킨다. - 복사 시 브라우저는 선택 범위의 텍스트를 직렬화한다. 경로·브라우저마다 블록 경계 개행 수(
\nvs\n\n)가 다를 수 있다. user-select: none은 포인터로 그 노드를 선택 범위에 넣기 어렵게 하지만, 부모 선택·프로그래밍 방식 선택·일부 직렬화 경로에서는 여전히 포함될 수 있다.::before { content: "…" }는 생성 콘텐츠라 DOM 텍스트 노드가 아니므로, 일반적인Selection.toString()/ 클립보드 경로에 잘 포함되지 않는다.
| 항목 | 설명 | 주의점 |
|---|---|---|
user-select: none | 포인터 선택을 어렵게 함 | Selection/복사 완전 제외 보장 아님 |
::before content | 생성 콘텐츠, DOM 텍스트 아님 | a11y 대체 텍스트는 별도 설계 |
draggable=false | 네이티브 요소 드래그 억제 | img/a 기본 동작 차단용 |
| 클립보드 직렬화 | 브라우저·경로마다 개행 상이 | 테스트는 비어 있지 않은 라인으로 정규화 |
실무 적용
선택/복사에서 빼야 하는 글리프는 CSS generated content로 옮긴다.
미디어·링크의 의도치 않은 드래그는 draggable={false}로 막는다. 클립보드 E2E는 브라우저별 개행 차이를 허용하도록, 비어 있지 않은 라인만 비교해 정규화한다.
스크린 리더가 핸들 의미를 알아야 한다면 aria-label 등 접근성 트리로 별도 제공한다. generated content만으로는 a11y가 해결되지 않는다.
트레이드오프
- pseudo content는 복사 오염을 줄이지만, 일부 브라우저/도구에서 생성 콘텐츠를 다르게 취급할 수 있다. 핵심 경로는 실기기에서 확인한다.
- 장식을 DOM에서 빼면 스타일·히트 영역 설계가 CSS에 더 의존한다.
사용하면 안 되는 경우
- 해당 문자가 의미 있는 본문일 때 — 복사되어야 하므로 텍스트 노드로 둔다.
- 장식을 선택 가능하게 해야 하는 UX(예: 핸들 자체를 선택해 조작) — 다른 인터랙션 모델을 쓴다.
흔한 실수
user-select: none만으로 “클립보드에서 제외됐다”고 가정한다.- 핸들 글리프를 텍스트 노드로 두고 복사 결과에 섞인 채로 둔다.
- 클립보드 테스트를 개행 문자 수까지 엄격히 비교해 브라우저마다 flake가 난다.
- a11y를 무시하고 시각 글리프만 pseudo로 옮긴다.
관련 개념
- html5-drag-and-drop — 핸들·이미지·링크가 드래그/선택을 가로채는 문제와 함께 다룬다.