리액트/이슈 해결

드래그 앤 드롭 투명도 이슈 해결

lamarcK 2025. 4. 23. 16:14

1. 문제 상황

  • React-Sortablejs 사용 시 드래그하는 동안 요소가 반투명해지는 현상 발생
  • 기본적으로 HTML5 Drag & Drop API의 기본 동작으로 인해 발생하는 문제

2. 원인 분석

기술적 원인

  • HTML5 Drag & Drop API는 드래그 중인 요소에 자동으로 투명도를 적용
  • 브라우저의 기본 동작으로, 사용자에게 드래그 상태를 시각적으로 표시하기 위한 것
  • React-Sortablejs가 기본적으로 HTML5 Drag & Drop API를 사용하기 때문에 발생
  • 때문에 결과적으로 2개의 스타일이 중첩 적용됨

스타일 중첩 문제

// forceFallback이 false일 때 (기본값)
const StyledSortable = styled(ReactSortable)<{ list: Todo[] }>`
  display: flex;
  flex-direction: column;
  gap: 20px;

  .sortable-ghost {
    opacity: 0.5;  // 원래 위치에 남는 고스트 이미지는 완전히 불투명하게
    background-color: #f0f0f0; // 고스트 이미지 배경색
    border: 2px dashed #ccc; // 고스트 이미지 테두리
  }

  .sortable-drag {
  opacity: 1 !important; 
    border: 2px dashed blue;
  }
`;
  • HTML5 기본 투명도 효과와 커스텀 스타일이 동시에 적용됨
  • 의도하지 않은 시각적 효과가 발생하는 원인이 됨

3. 해결 방법

<ReactSortable
  forceFallback={true}
  // 기타 props...
>
  {/* 컴포넌트 내용 */}
</ReactSortable>

4. 해결 원리

  • forceFallback={true} 설정으로 HTML5 Drag & Drop API 대신 Sortable.js의 자체 구현 사용
  • HTML5 기본 투명도 효과 제거
  • 설정한 커스텀 스타일만 깔끔하게 적용됨

5. 스타일 적용 비교

forceFallback={false} (기본값)

  • HTML5 기본 투명도 + 커스텀 스타일 중첩 적용
  • 의도하지 않은 시각적 효과 발생

forceFallback={true}

  • HTML5 기본 효과 제거
  • 커스텀 스타일만 적용
  • 의도한 대로 깔끔한 드래그 효과 구현

6. 장점

  1. 구현 용이성
    • 단일 prop 설정으로 문제 해결
    • 추가적인 CSS나 JavaScript 코드 불필요
  2. 일관성
    • 브라우저 간 동일한 동작 보장
    • 커스터마이징이 용이

7. 참고사항

  • 필요한 경우 추가적인 스타일링을 통해 드래그 상태를 시각적으로 표현 가능
  • ghostClass, dragClass 등의 props를 활용하여 드래그 중인 요소의 스타일 커스터마이징 가능

※ 만약에 데이터를 동적으로 추가할 경우엔 이 방법을 사용하면 안됩니다. 새로 추가한 배열이 있다면 드래그가 막히기 때문에 직접 드래그를 구현하거나 다른 솔트 방법을 사용해야합니다.

8. 관련 코드 예시

 <StyledSortable
            list={todos}
            setList={handleSetList}
            animation={150}
            ghostClass="sortable-ghost"
            dragClass="sortable-drag"
            handle=".drag-handle"
            forceFallback={true}
            >


const StyledSortable = styled(ReactSortable)<{ list: Todo[] }>`
  display: flex;
  flex-direction: column;
  gap: 20px;

  .sortable-ghost {
    opacity: 0.5;  // 원래 위치에 남는 고스트 이미지는 완전히 불투명하게
    background-color: #f0f0f0; // 고스트 이미지 배경색
    border: 2px dashed #ccc; // 고스트 이미지 테두리
  }

  .sortable-drag {
  opacity: 1 !important; 
    border: 2px dashed blue;
  }
`;