케이스 ce-0265-caret-jump-non-editable-chrome-ko · 시나리오 scenario-caret-jump-non-editable

Chrome에서 비편집 요소 옆 삭제 시 캐럿 점프

OS: Windows 10/11 기기: Desktop Any 브라우저: Chrome 120+ 키보드: English (QWERTY) 초안
caretcursornon-editablechromedelete

현상

Chrome의 contenteditable 요소 안에서 비편집 요소(contenteditable=false) 옆에 있는 글자를 삭제할 때, 캐럿이 남아 있는 내용의 끝으로 점프합니다.

재현 예시

  1. contenteditable 요소에 포커스합니다.
  2. 비편집 요소(contenteditable=“false”)가 포함된 텍스트가 있습니다 (예: “안녕하세요 @사용자 다시 오세요”).
  3. 비편집 요소 바로 앞에 있는 글자를 삭제합니다 (Backspace 또는 Delete 키).
  4. ❌ 캐럿이 비편집 요소 옆이 아니라 전체 contenteditable 끝으로 점프합니다.

관찰된 동작

  • 캐럿 점프: 캐럿이 삭제된 글자 옆이 아니라 전체 에디터 끝으로 이동함
  • 계속 타이핑 불가: 다음 글자를 입력하면 에디터 끝에 입력됨
  • 수동 클릭 필요: 올바른 위치에 계속 타이핑하려면 비편집 요소 옆을 직접 클릭해야 함
  • Chrome 특유: Firefox에서는 발생하지 않음

예상 동작

  • 캐럿이 비편집 요소 바로 옆에 유지되어야 함
  • 바로 다음 글자를 입력할 수 있어야 함
  • 수동 클릭 필요 없이

참고사항 및 가능한 해결 방향

  • display: inline-block: contenteditable 요소에 display: inline-block; CSS 추가
  • zero-width space: 비편집 요소 뒤에 ZWSP(U+200B) 문자 추가
  • 빈 span 플레이스홀더: 비편집 요소 뒤에 빈 <span> 요소 추가
  • 프로그래매틱 캐럿 복원: input 이벤트에서 캐럿 점프를 감지하고 원 위치로 복원
  • 외부 래퍼: 편집 가능한 내용을 별도 div로 래핑

코드 예시

const editor = document.querySelector('div[contenteditable]');
const nonEditable = document.querySelector('span[contenteditable="false"]');

let lastCaretPosition = null;

// 캐럿 위치 감지
function getCaretPosition() {
  const selection = window.getSelection();
  if (selection.rangeCount > 0) {
    const range = selection.getRangeAt(0);
    return {
      node: range.startContainer,
      offset: range.startOffset
    };
  }
  return null;
}

// input 이벤트로 캐럿 점프 감지
editor.addEventListener('input', (e) => {
  const currentPos = getCaretPosition();
  
  if (lastCaretPosition && currentPos) {
    // 캐럿이 의치치 않게 점프했는지 확인
    const distance = Math.abs(currentPos.offset - lastCaretPosition.offset);
    
    if (distance > 10) { // 임계값
      console.warn('Caret jump detected:', lastCaretPosition, currentPos);
      
      // 캐럿 복원
      const selection = window.getSelection();
      const range = document.createRange();
      
      // 비편집 요소 앞으로 복원
      if (nonEditable) {
        range.setStartBefore(nonEditable);
        range.collapse(true);
        selection.removeAllRanges();
        selection.addRange(range);
      }
    }
  }
  
  lastCaretPosition = currentPos;
});

// CSS 해결책
editor.style.display = 'inline-block';

이 시나리오의 변형

케이스 OS 브라우저 상태
ce-0265-caret-jump-non-editable-chrome-ko Windows 10/11 Chrome 120+ 초안
ce-0266-caret-jump-non-editable-firefox-en-ko macOS 13+ Firefox 120+ 확인됨
ce-0267-caret-jump-non-editable-safari-ko macOS 13+ Safari 17+ 초안

Playground for this case

Use the reported environment as a reference and record what happens in your environment while interacting with the editable area.

Reported environment
OS: Windows 10/11
Device: Desktop Any
Browser: Chrome 120+
Keyboard: English (QWERTY)
Your environment
Sample HTML:
Event log
Use this log together with the case description when filing or updating an issue.
0 events
Interact with the editable area to see events here.