thumbnail
WEB
2025.09.30.
TIL
Deep_Dive

왜 어떤 건 드래그가 되고, 어떤 건 안 될까?

한 번쯤은 ID를 복사하려고 드래그했는데 파란색이 안 생겨서 당황한 적 있을 겁니다. 예전 회사 admin의 모든 화면에서 드래그가 안된다고 민원이 들어와서 누군가 글로벌로 선언 해놨던 user-select: none;한 줄을 제거 했을 뿐인데 어떻게 이렇게 빨리 해결했냐고 좋아하시던게 생각난다. 이 일화 자체는 사소할 수 있지만, 여기서 알 수 있는 사실은 분명합니다. 웹에서의 텍스트 선택은 단순히 보이는 인터랙션이 아니라 브라우저의 렌더링 과정 전반과 맞닿아 있는 기능이라는 점입니다. 사용자가 문장을 복사할 수 있는지 여부는 단순한 옵션 문제가 아니라, 콘텐츠를 어떤 방식으로 표현했는지와 브라우저가 이를 어떻게 해석하고 렌더링하는지에 따라 달라집니다.
이 글에서는 텍스트 선택이 작동하는 원리, 선택이 차단되는 대표적인 사례, 그리고 실무에서 유의해야 할 포인트를 정리해 보겠습니다.

목차

  • 텍스트 선택이 가능해지는 조건
  • 선택이 차단되는 대표적인 사례
  • 렌더링 파이프라인과 선택 영역
  • 마무리

텍스트 선택이 가능해지는 조건

브라우저가 텍스트 노드를 생성하고 레이아웃 상에 실제 글리프를 배치할 때 선택 기능이 활성화된다. 즉, DOM에서 Text 노드로 취급되는 콘텐츠가 있어야 하고, 해당 노드가 렌더 트리에 포함되어야 한다.

<span>경기 제목</span>

위와 같이 HTML에 직접 입력된 문자열은 파싱 과정에서 텍스트 노드로 분리되며, 레이아웃과 페인트 단계까지 전달되기 때문에 기본적으로 드래그 선택이 가능하다. ::selection 같은 CSS를 통해 강조 색상을 조정하는 것도 이 단계에서 이뤄진다.

선택이 차단되는 대표적인 사례

텍스트처럼 보이지만 실상은 픽셀로만 존재하는 요소는 선택 범위에 포함되지 않는다.

  • <img> 태그로 삽입된 비트맵 이미지
  • 패스와 쉐이프로 구성된 <svg> 아이콘
  • CSS background-image 혹은 캔버스 렌더링 결과처럼 텍스트가 아닌 그림

이 경우 브라우저는 선택 가능한 텍스트 노드를 찾을 수 없으므로 드래그해도 파란 하이라이트가 나타나지 않는다. 또한 CSS UI 모듈에서 제공하는 user-select: none;을 선언하면 텍스트 노드가 존재해도 선택이 강제로 막힌다. 버튼, 토글 스위치처럼 클릭 중심인 컴포넌트에서 의도적으로 적용하는 패턴이다.

그 밖에 다음과 같은 요소도 실수하기 쉬운 케이스다.

  • position: absolute 요소가 텍스트 위를 덮어 투명 오버레이를 만들 때 (실제 선택은 오버레이에서 멈춤)
  • pointer-events: none이 선언되지 않은 커스텀 툴팁이나 모달 배경이 포인터 이벤트를 가로챌 때
  • contenteditable="false" 속성이 적용된 영역

렌더링 파이프라인과 선택 영역

선택 가능 여부는 브라우저 렌더링 파이프라인 중간에서 결정된다.

  1. DOM 생성: HTML 파싱 → 요소와 텍스트 노드 생성
  2. CSSOM 생성: CSS 파싱 → 규칙 트리 생성
  3. 렌더 트리 구성: DOM + CSSOM → 실제 화면에 표시할 노드만 추림 (display: none은 제외)
  4. 레이아웃: 각 노드의 위치와 크기 계산
  5. 페인트 & 합성: 텍스트 노드는 글리프(문자 모양)로 그려지고, 여러 레이어를 합쳐 화면에 출력

사용자가 드래그할 때 브라우저는 레이아웃 단계에서 계산된 인라인 박스 정보를 토대로 범위를 인식한다. 즉, 텍스트 노드가 DOM에 있고 렌더 트리에 포함되어 있으며 CSS가 막지 않으면 선택이 된다. 반대로 <img>나 배경 그림처럼 텍스트가 아닌 픽셀은 선택 대상이 아니다.

UX 관점

  • 복사/붙여넣기가 필요한 값(예: 계정 ID, 에러 메시지, 토큰)은 user-select를 기본값(text)으로 유지한다.
  • 아이콘, 배경 장식 등은 user-select: none 혹은 pointer-events: none으로 사용자의 드래그 경험을 방해하지 않도록 조정한다.
  • 긴 텍스트를 절단하는 ellipsis 처리 시 선택이 불가능해지는지 확인한다 (-webkit-line-clamp 조합 등).

디버깅 관점

  • DevTools의 Elements 패널에서 실제 텍스트 노드가 존재하는지, 오버레이가 덮고 있지 않은지 확인한다.
  • getSelection() 또는 document.activeElement를 활용해 스크립트 관점에서 선택 영역이 어떻게 잡히는지 점검한다.
  • SSR/CSR 전환 과정에서 텍스트가 이미지로 대체되는 시점이 있는지(예: 서버에서 렌더링된 캔버스 출력)를 살핀다.

마무리

텍스트 선택은 “텍스트 노드가 렌더 트리에 존재하느냐”와 “CSS가 이를 차단하지 않느냐”에 의해 결정된다. 단순한 이론처럼 보이지만, 실제 서비스에서는 작은 선택 가능 여부가 복사 편의성과 오류 복구 경험에 큰 영향을 준다. UI를 설계할 때 언제 사용자가 드래그할 수 있어야 하는지, 그리고 어떤 요소는 반드시 선택에서 배제해야 하는지를 의도적으로 판단해 두면 유지보수와 디버깅 모두 수월해진다.

참고

댓글 불러오는 중…
Thank You for Visiting My Blog 😎.
© 2022 Developer Jae Hyuk, Powered By Gatsby.