Skip to content

[fix] 앱 웹뷰에서 본문 텍스트를 선택·복사할 수 있게 한다 - #2257

Open
seongwon030 wants to merge 3 commits into
develop-fefrom
fix/#2256-webview-text-selectable-MOA-1229
Open

seongwon030 wants to merge 3 commits into
develop-fefrom
fix/#2256-webview-text-selectable-MOA-1229

Conversation

@seongwon030

@seongwon030 seongwon030 commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Close #2256

문제

앱 웹뷰에서 동아리 소개·연락처 같은 본문을 길게 눌러 복사할 수 없다. WebviewGlobal.styles.ts가 body에 user-select: none을 걸어서 상속으로 페이지의 모든 텍스트 선택이 막힌다. 원래는 /webview/* 화면에서 컨트롤을 길게 눌렀을 때 선택되거나 메뉴가 뜨는 걸 막으려던 스타일(1900a7a38)이다. 그런데 지금은 App.tsx에서 앱 웹뷰 전체에 적용된다.

해결

선택 차단(user-select)과 길게 누르기 메뉴 차단(-webkit-touch-callout)을 body에서 빼고 button, [role='button'], img에만 건다. a는 넣지 않는다. linkifyText가 소개·FAQ 본문의 URL을 인라인 <a>로 렌더해서, a를 막으면 오픈채팅·구글폼 주소를 복사할 수 없다. 컨트롤을 길게 눌러도 선택되지 않는 원래 의도는 그대로 두고, 본문만 선택할 수 있게 푼다. 웹(비웹뷰) 스타일은 건드리지 않았다.

검증

Playwright(iPhone 13 에뮬, UA에 MoadongApp)로 동아리 상세 소개 탭을 열고 본문과 버튼을 더블클릭해 선택 결과를 전후로 비교했다.

본문 버튼(소개내용) 본문 user-select
수정 전 "" "" none
수정 후 "탐험하는" "" auto

본문 URL은 dev 데이터에 해당 동아리가 없어서, linkifyText와 같은 마크업(<a target="_blank">가 든 문단)을 동아리 상세 페이지에 넣고 문단 전체를 선택해 비교했다.

셀렉터 문단 복사 결과 링크 user-select
a 포함(첫 커밋) "오픈채팅 로 문의" (URL 빠짐) none
a 제외(현재) "오픈채팅 https://open.kakao.com/o/probe 로 문의" auto
  • typecheck·prettier 통과. 이 스타일을 덮는 테스트는 없다
  • iOS·Android 실기기에서 길게 눌러 복사하는 동작은 확인하지 못했다

영향 범위

앱 웹뷰에만 닿는다(isInAppWebView()일 때만 주입). 학생·관리자 웹은 영향이 없다. 드래그 제스처가 있는 SwipeableEventRow(관리자 캘린더)와 BuskingPage pan은 자체 선택 차단이 없어서, 길게 누르면 안의 글자가 선택될 수 있다(실기기 미확인). LongPressReorderItem·PhotoModal·QuestionBuilder는 자체 user-select: none이 있다. 컨트롤로 쓰는 링크는 전역에서 막지 않고 컴포넌트에서 막는다. 본문 링크를 빠뜨려 URL을 복사하지 못하는 쪽(기능 손실)보다, 컨트롤 링크를 빠뜨려 길게 눌렀을 때 글자가 선택되는 쪽(보기 문제)이 덜 해롭기 때문이다.

  • 막음: MenuPage InfoLink(메뉴 행), RecommendedClubs Tag(추천 동아리 태그). 앱 UA로 /menu를 열어 확인했다(InfoLink 선택 9자 → 0자)
  • 안 막음: ClubProfileCard SocialLinkItem. 안에 SNS 아이디(displayName)가 보여서 복사할 수 있어야 한다
  • 확인 못 함: RecruitPage PositionCard·BackLink, Footer PolicyLink, ClubUnionPage SnsLink, ContactButton 2곳. 실기기에서 거슬리는 곳만 후속으로 막는다

- body에 건 user-select: none이 상속돼 앱 웹뷰의 모든 본문 텍스트 선택이 막혀 있었다
- 선택 차단과 길게 누르기 메뉴 차단을 button, a, [role='button'], img에만 건다
@seongwon030 seongwon030 self-assigned this Oct 28, 2026
@vercel

vercel Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
moadong Ready Ready Preview Oct 28, 2026 7:37am UTC

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 52 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between e9ef711 and 41f9283.

Files selected for processing: 2
  • frontend/src/pages/MenuPage/MenuPage.styles.ts
  • frontend/src/pages/PeacePage/components/RecommendedClubs/RecommendedClubs.styles.ts

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between aeb857f and e9ef711.

Files selected for processing: 1
  • frontend/src/styles/WebviewGlobal.styles.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

웹뷰 전역 스타일에서 body에 지정했던 텍스트 선택 및 터치 콜아웃 비활성화 선언을 button, [role='button'], img에 적용하도록 변경했습니다. body의 cursor: default 선언은 유지했습니다.

Changes

웹뷰 텍스트 선택

Layer / File(s) Summary
선택 차단 대상 변경
frontend/src/styles/WebviewGlobal.styles.ts
user-select, -webkit-user-select, -webkit-touch-callout 선언을 body에서 button, [role='button'], img로 옮겼습니다. a는 새 선택자에 포함되지 않았습니다.

Priority: Normal

Estimated code review effort: 1 (Trivial) | ~3 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: oesnuj

Merge Risk: Low · previous review e9ef7

Some social-link controls may become selectable in app webviews, exposing link-selection menus during long press. Scope the exemption to prose links before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Linked Issues check Warning [#2256] 요구사항: body의 user-select·-webkit-touch-callout을 button, a, [role='button'], img로 옮긴다. 확인된 변경(frontend/src/styles/WebviewGlobal.styles.ts, base 대비 head): body에서 두 선언을 제거했고, button, [role='button… 둘 중 하나를 맞춘다. (1) 이슈 #2256의 체크리스트와 선택자 목록을 갱신해 a 제외를 명시한다. 갱신 근거는 인라인 링크 URL 복사 불가 문제이다. (2) 구현을 이슈 요구대로 a를 포함하도록 바꾸고, 본문 링크 영역에 user-select: text 등 예외를 따로 적용해 URL 복사가 되도록 한다. 두 경우 모두 앱 UA에서 본문 링크 URL 복사와 버튼 선택 차단을 전후로 다시 확인한다.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed PR 제목은 앱 웹뷰에서 본문 텍스트를 선택하고 복사할 수 있도록 바꾸는 주요 변경과 일치합니다. 변경 내용은 WebviewGlobal.styles.ts에서 user-select와 -webkit-touch-callout 선언을 body에서 button, [role='button'], img로 옮기는 것입니다. 이 방식으로 본문 텍스트는 선택 가능해지고 버튼…
Out of Scope Changes check Passed 이 PR의 변경은 frontend/src/styles/WebviewGlobal.styles.ts 의 CSS 선언 이동(+3/-1)으로 확인된다. 변경 내용은 body의 user-select, -webkit-user-select, -webkit-touch-callout을 button, [role='button'], img로 옮기고 cursor: default…
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Full details: Title check

Explanation

PR 제목은 앱 웹뷰에서 본문 텍스트를 선택하고 복사할 수 있도록 바꾸는 주요 변경과 일치합니다. 변경 내용은 WebviewGlobal.styles.ts에서 user-select와 -webkit-touch-callout 선언을 body에서 button, [role='button'], img로 옮기는 것입니다. 이 방식으로 본문 텍스트는 선택 가능해지고 버튼과 이미지는 보호됩니다. 목표 이슈와 커밋 메시지에 따르면 최종 선택자 범위에서 a는 제외되었습니다. 제목은 이 세부 범위를 다루지 않지만, 주요 변경 의도는 정확히 반영합니다.

Full details: Out of Scope Changes check

Explanation

이 PR의 변경은 frontend/src/styles/WebviewGlobal.styles.ts 의 CSS 선언 이동(+3/-1)으로 확인된다. 변경 내용은 body의 user-select, -webkit-user-select, -webkit-touch-callout을 button, [role='button'], img로 옮기고 cursor: default는 body에 남기는 것이다. 이는 #2256의 요구(본문 선택 허용, 컨트롤 선택 차단)와 직접 연결된다. 웹(비웹뷰) 스타일이나 다른 컴포넌트 파일 변경은 확인되지 않았다. 다른 파일 변경 여부는 whole-PR 파일 목록 전체를 읽지 않아 완전히 확인하지는 못했다. 그러나 PR 요약에 해당 파일만 언급되어 있다.

Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 1 files.

Full details: Linked Issues check

Explanation

[#2256] 요구사항: body의 user-select·-webkit-touch-callout을 button, a, [role='button'], img로 옮긴다. 확인된 변경(frontend/src/styles/WebviewGlobal.styles.ts, base 대비 head): body에서 두 선언을 제거했고, button, [role='button'], img 선택자에 추가했다. a 선택자는 없다. 따라서 명시된 선택자 목록 중 a가 빠졌다. 핵심 목표인 본문 선택 허용과 버튼·이미지 선택 차단은 구현되어 있다. PR 설명의 Playwright 결과(본문 선택 '탐험하는', 버튼 선택 없음, body user-select auto)는 이 PR의 설명에 기록된 결과다. 이 결과는 실행 환경에서 직접 재현하지 않았다. a를 뺀 이유는 linkifyText가 만든 인라인 링크 URL이 복사되지 않기 때문이다. 이 이유는 PR 설명과 커밋 메시지에 기록되어 있고, 첫 커밋 결과(URL 누락)가 근거다. 그러나 이슈 본문의 체크리스트는 a 포함을 요구하며 아직 수정되지 않았다. 따라서 요구사항과 구현이 일치하지 않는다.

Resolution

둘 중 하나를 맞춘다. (1) 이슈 #2256의 체크리스트와 선택자 목록을 갱신해 a 제외를 명시한다. 갱신 근거는 인라인 링크 URL 복사 불가 문제이다. (2) 구현을 이슈 요구대로 a를 포함하도록 바꾸고, 본문 링크 영역에 user-select: text 등 예외를 따로 적용해 URL 복사가 되도록 한다. 두 경우 모두 앱 UA에서 본문 링크 URL 복사와 버튼 선택 차단을 전후로 다시 확인한다.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the 💻 FE Frontend label Oct 28, 2026
@reviewer-harry

reviewer-harry Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Claude finished @seongwon030's task in 32s —— View job


harry 리뷰 총평

  • 리뷰 기준(.github/harry-review-rules.md) 확인
  • PR diff 확인 (origin/develop-fe...HEAD)
  • 영향 범위 확인 (본문 링크 렌더링 경로)
  • 인라인 코멘트 작성

선택 차단을 body 전역에서 컨트롤로 좁힌 방향은 좋아요. 변경 범위도 작고 웹 스타일을 건드리지 않았어요. 전후 비교 표와 실기기 미확인 경로를 PR 본문에 적어 둔 것도 좋았어요 👍

다만 셀렉터에 a가 들어가서 본문 안의 URL은 여전히 복사할 수 없어요. linkifyText가 소개·FAQ 본문의 URL을 인라인 <a>로 바꾸기 때문에, 오픈채팅·구글폼 같은 연락처 링크는 선택도, iOS "링크 복사" 메뉴도 막혀요. 문단을 통째로 복사할 때도 URL만 빠질 수 있어요. 자세한 내용과 수정 제안은 인라인 코멘트에 남겼어요.

그 밖에 harry 기준(색상 토큰, 폴더 구조, 주석, 보안)에 걸리는 부분은 없어요. 이 스타일을 덮는 테스트가 없다는 점은 PR 본문에 이미 적혀 있어서 따로 지적하지 않았어요.

@diboreview-e2e-bot diboreview-e2e-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

켜진 규칙 위반이 없어요.

지적 0개 · 버린 지적 0개 · 중복 제외 0개 · 비용 $0.0146

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

🎨 UI 변경사항을 확인해주세요

변경된 스토리를 Chromatic에서 확인해주세요.

구분 링크
🔍 변경사항 리뷰 undefined
📖 Storybook undefined

3개 스토리 변경 · 전체 193개 스토리 · 67개 컴포넌트

-webkit-text-size-adjust: 100%;
cursor: default;
}
button, a, [role='button'], img {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a까지 막으면 본문 안의 URL은 이번 수정 후에도 복사할 수 없어요.

ClubIntroContent의 활동 소개·인재상·혜택·FAQ 답변은 linkifyText(@/utils/linkifyText.tsx)를 거쳐서 본문 속 https://...가 인라인 <a>로 렌더돼요. 동아리들이 오픈채팅·구글폼 주소를 여기에 적는 경우가 많은데, 이 셀렉터 때문에 다음 문제가 생겨요.

  • 링크 텍스트만 길게 눌러 선택할 수 없어요.
  • 문단을 통째로 잡아 복사해도 WebKit은 user-select: none 구간을 빼고 복사해서 URL만 빠질 수 있어요.
  • -webkit-touch-callout: none 때문에 iOS의 "링크 복사" 메뉴도 막혀요.

PR이 풀려는 "연락처를 길게 눌러 복사" 시나리오에 정확히 걸리는 부분이라, a는 전역 셀렉터에서 빼는 게 좋아요. 카드처럼 쓰이는 링크(예: SocialLinkItem)에서 선택이 거슬리면 그 컴포넌트 스타일에 따로 거는 편이 안전해요.

Suggested change
button, a, [role='button'], img {
button, [role='button'], img {

PR 검증 표에도 본문 URL 케이스(링크가 포함된 소개 문단)를 한 줄 추가해 주세요.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞아요, a를 셀렉터에서 뺐어요. e9ef711

linkifyText와 같은 마크업의 문단을 동아리 상세에 넣고 전체를 선택해 비교했더니, a를 막았을 때는 복사 결과가 "오픈채팅 로 문의"로 URL이 빠졌고, 지금은 URL까지 복사돼요. PR 본문 검증 절에 표로 추가했어요. MenuPage처럼 컨트롤로 쓰는 링크는 거슬리면 그 컴포넌트에 따로 걸게요.

- linkifyText가 소개·FAQ 본문의 URL을 인라인 <a>로 렌더해서, a에 건 user-select: none 때문에 문단을 복사하면 URL만 빠지고 iOS 링크 복사 메뉴도 막혔다
-webkit-text-size-adjust: 100%;
cursor: default;
}
button, [role='button'], img {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[변경 범위] 커밋 의도는 "본문 속 링크"를 선택 가능하게 하는 건데, a를 전역 셀렉터에서 빼면 웹뷰 안의 모든 <a>가 같이 풀려요. MenuPage의 InfoLink(styled(Link)), RecommendedClubs의 Tag, ClubProfileCard의 SocialLinkItem처럼 버튼·행 역할을 하는 링크도 이제 길게 누르면 텍스트 선택이 잡히고, iOS에서는 -webkit-touch-callout까지 풀려 링크 미리보기/복사 메뉴가 떠요. 이전 커밋에서 "컨트롤은 막는다"던 기준과도 어긋나고요.

본문 링크만 풀고 싶다면 전역에서는 a를 유지하고, 본문 컨테이너 쪽에서만 해제하는 게 좁고 안전해 보여요. 예를 들면:

/* 전역 */
button, a, [role='button'], img { user-select: none; ... }
/* 본문 렌더 영역 스타일 */
.description a { user-select: text; -webkit-user-select: text; -webkit-touch-callout: default; }

아니면 UI용 링크 쪽에 개별로 user-select: none을 붙이는 방법도 있어요. 메뉴 행·태그 같은 링크를 앱 웹뷰에서 길게 눌러 봤는지 한 번 확인해 주세요.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했어요(41f9283). 다만 전역에 a를 다시 거는 대신, 컨트롤 링크를 컴포넌트에서 막는 쪽으로 갔어요.

두 방식 모두 새 화면에서 빠뜨릴 수 있는데, 빠뜨렸을 때 결과가 달라요. 전역 a를 막고 본문만 풀면, 본문 링크를 하나 빠뜨렸을 때 URL 복사가 안 되는 이번 버그가 그대로 돌아와요(linkifyText 말고도 LetterDetailPage의 react-markdown 링크가 있어요). 반대로 컨트롤 링크를 빠뜨리면 길게 눌렀을 때 글자가 선택되는 정도라 덜 해롭다고 봤어요.

  • 막음: MenuPage InfoLink, RecommendedClubs Tag. 앱 UA로 /menu에서 InfoLink 선택이 9자 → 0자가 되는 걸 확인했어요.
  • 안 막음: SocialLinkItem. 안에 SNS 아이디(displayName)가 보여서 복사할 수 있어야 해요.
  • 나머지 컨트롤 링크(PositionCard·BackLink·PolicyLink·SnsLink·ContactButton)는 실기기에서 길게 눌러 보지 못했어요. 거슬리는 곳만 후속으로 막을게요. PR 본문 영향 범위에 적어 뒀어요.

- 전역 셀렉터에서 a를 빼면서 행·태그처럼 버튼 역할을 하는 링크도 길게 누르면 텍스트가 선택되고 iOS 링크 메뉴가 떴다
- MenuPage InfoLink와 RecommendedClubs Tag에만 user-select·touch-callout 차단을 건다
Comment on lines +137 to +139
user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[같이 수정되는 코드 함께 두기] 같은 세 줄(user-select·-webkit-user-select·-webkit-touch-callout)이 이번 커밋에서 RecommendedClubs.styles.ts의 Tag에도 똑같이 들어갔고, WebviewGlobal.styles.ts·LongPressReorderItem.styles.ts에도 이미 있어요. 나중에 -webkit-tap-highlight-color 같은 속성을 하나 더 넣어야 할 때 한 곳만 고치고 나머지를 빠뜨리기 쉬워요. @/styles에 noSelectOnLongPress 같은 이름의 css 조각으로 빼서 같이 쓰는 걸 생각해 보면 좋겠어요.

그리고 이 세 줄은 앱 웹뷰에서 길게 눌러도 링크가 선택되지 않게 하려는 거라, 코드만 봐서는 이유가 보이지 않아요. "본문 링크와 달리 메뉴 행은 길게 눌러도 선택되지 않게 한다" 정도로 한 줄 주석을 달아 두면, 나중에 누가 a 선택 차단을 다시 손볼 때 왜 여기만 따로 막았는지 알 수 있어요. 지금 이 스타일은 웹뷰가 아닌 일반 웹에도 적용된다는 점도 같이 확인해 주세요.

This branch was successfully deployed

1 active deployment
Preview — 41f92834 Deployed Oct 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FE Frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant