[실무 기록] <link rel="stylesheet">로 CSS 불러오는데 간헐적으로 CORS 에러가 나던 이유 (해결: crossorigin 제거)

2026. 1. 13. 08:03·FrontEnd/web

어느 날부터 서비스에서 CSS가 간헐적으로 안 먹는 현상이 생겼다
콘솔을 보면 CORS 관련 에러가 뜨고, 화면은 스타일이 빠진 채로 깨져 보였다

힘들었던 포인트는 이거였다

  • 어떤 브라우저에서는 안 터지고
  • 어떤 브라우저/디바이스에서는 터지고
  • 같은 환경에서도 가끔은 되고, 가끔은 실패

원인 파악이 너무 어려웠다.


결론

우리는 써드파티 라이브러리/CSS를 버저닝 + 캐싱 목적 때문에 회사 S3에 올려두고, 서비스에서는 그 S3 주소로 직접 로드하고 있었다.

그런데 <link>로 CSS를 불러올 때 예전에 넣어둔

crossorigin="anonymous"

 

이 속성 때문에, 브라우저가 CSS를 CORS 모드로 요청하면서 간헐적인 CORS 에러가 발생했다.

그래서 나는 crossorigin="anonymous"를 제거했고, 그 뒤로 문제는 멈췄다


당시 구조 (문제의 시작)

대략 이런 식이었다

  • third-party.css 같은 파일을 S3에 업로드
  • 서비스 HTML에서는 S3 URL로 바로 로드
<link
  rel="stylesheet"
  href="https://{우리S3도메인}/third-party/xxx/v123/third-party.css"
  crossorigin="anonymous"
/>

 

그리고 어느 순간부터, 일부 환경에서 CSS 로드가 실패하면서 CORS 에러가 터졌다


왜 ‘간헐적’이었나?

나는 처음에 S3 CORS 설정을 의심했다
근데 "항상"이 아니라 "간헐적"이어서 더 헷갈렸다

결론적으로 내 케이스는 crossorigin 속성 때문에 요청 모드가 달라지는 상황이 섞여서 체감이 랜덤처럼 보였던 거였다

  • 어떤 상황에서는 정상 응답/캐시된 응답으로 넘어가서 문제 없어 보이고
  • 어떤 상황에서는 CORS 체크가 빡세게 걸리면서 실패

특히 S3/캐시/CDN이 섞인 환경에서는 응답이 200/304/리다이렉트/에러 응답 등으로 갈릴 수 있고,
그 중 일부 응답에 CORS 헤더가 빠져 있으면 브라우저가 막아버리는 경우가 생길 수 있다.

(내가 겪은 건 “정확히 언제”라기보다 "어떤 응답이 걸리느냐"에 따라 달라졌던 느낌)


결정적 힌트: <link>의 crossorigin이 CORS 요청을 강제한다

구글링하다가 아래 글을 보고 방향이 잡혔다

  • 참고 레퍼런스: https://codingeverybody.kr/html-crossorigin-%EC%86%8D%EC%84%B1-%EC%98%AC%EB%B0%94%EB%A5%B8-%EC%9D%B4%ED%95%B4%EC%99%80-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95/

요약하면 이런 느낌이다

  • crossorigin 속성이 있으면 브라우저가 CORS 모드로 리소스를 요청한다
  • 그러면 서버(S3)가 Access-Control-Allow-Origin 같은 헤더로 허용해줘야 한다
  • 허용이 안 되면 브라우저가 “안 가져온 것처럼” 막아버린다

나는 CSS를 “그냥 적용만” 하면 되는 상황이었고,
crossorigin="anonymous"를 붙여둘 이유가 딱히 없었다.


해결: crossorigin="anonymous" 제거

문제의 속성을 제거했다

Before

<link
  rel="stylesheet"
  href="https://{우리S3도메인}/third-party/xxx/v123/third-party.css"
  crossorigin="anonymous"
/>

After

<link
  rel="stylesheet"
  href="https://{우리S3도메인}/third-party/xxx/v123/third-party.css"
/>

 

이렇게 바꾸고 나서, 내가 겪던 간헐적 CORS 에러/스타일 미적용 현상이 사라졌다


주의: crossorigin이 필요한 경우도 있음

이 글의 요지는 "무조건 빼라"가 아니라,
왜 붙여둔 건지 목적을 확인하자는 거다.

예를 들면 이런 경우에는 crossorigin이 필요할 수 있다

  • 브라우저가 리소스를 검증하려면 CORS가 필요해지는 케이스가 있음
  • JS에서 stylesheet 내용(cssRules)을 접근하려는 경우 (CORS 허용이 필요)

그런 목적이 있다면, 속성을 빼는 대신

  • S3(또는 CloudFront)에서 CORS 헤더가 항상 붙도록 설정을 정리

하는 게 맞다.

하지만 나처럼 "그냥 CSS 적용"만 목적이라면,
불필요한 crossorigin 때문에 오히려 장애 포인트가 될 수 있다.


마무리

정리하면,

  • 써드파티 CSS를 S3에 올려서 서비스에서 직접 로드하는 구조에서
  • <link>에 crossorigin="anonymous"가 붙어 있으면
  • 브라우저가 CORS 모드로 가져오면서 간헐적으로 막히는 상황이 생길 수 있다

나처럼 증상이 랜덤하게 보이면 더 헤매기 쉬우니,
일단 <link>에 crossorigin이 붙어 있는지부터 확인해보는 걸 추천한다

저작자표시 비영리 변경금지 (새창열림)

'FrontEnd > web' 카테고리의 다른 글

[실무 기록] 렌더링 차단(Render‑blocking) 줄이려고 preconnect / preload를 썼는데… 진짜 뭐가 좋아지나?  (0) 2026.03.06
[실무 기록] (2탄) macOS에서 adb가 "개발자 신원을 확인할 수 없습니다"로 막혀 Chrome Inspect가 또 안 될 때  (0) 2026.03.05
[실무 기록] Chrome Inspect에서 Pending authentication만 뜨고 안드로이드 디버깅이 안 될 때  (0) 2026.01.12
[실무 기록] 웹뷰 브릿지, 이거 누가 책임져야 하지?  (0) 2025.12.10
검색 엔진 크롤링과 자바스크립트 렌더링 정리  (3) 2025.09.08
'FrontEnd/web' 카테고리의 다른 글
  • [실무 기록] 렌더링 차단(Render‑blocking) 줄이려고 preconnect / preload를 썼는데… 진짜 뭐가 좋아지나?
  • [실무 기록] (2탄) macOS에서 adb가 "개발자 신원을 확인할 수 없습니다"로 막혀 Chrome Inspect가 또 안 될 때
  • [실무 기록] Chrome Inspect에서 Pending authentication만 뜨고 안드로이드 디버깅이 안 될 때
  • [실무 기록] 웹뷰 브릿지, 이거 누가 책임져야 하지?
프론트엔드 개발자 jbeat
프론트엔드 개발자 jbeat
프론트엔드 개발자 블로그인데 일상도 쪼그으믐
  • 프론트엔드 개발자 jbeat
    jbeat 님의 블로그
    프론트엔드 개발자 jbeat
  • 전체
    오늘
    어제
    • 분류 전체보기 (44)
      • FrontEnd (43)
        • TypeScript (6)
        • JavaScript (18)
        • Next.js (3)
        • React (1)
        • Testing (2)
        • Third Party (1)
        • web (10)
        • Tooling (1)
        • coding test (0)
        • A.I (1)
      • 일상 (1)
        • wedding (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    고차함수
    preconnect
    Android
    주니어
    yjs
    playwright
    CRDT
    Next.js
    javascript
    배열
    WebSocket
    Utility
    코테
    pick
    컬렉션
    TypeScript
    타입스크립트
    이터러블
    CrossOrigin
    omit
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
프론트엔드 개발자 jbeat
[실무 기록] <link rel="stylesheet">로 CSS 불러오는데 간헐적으로 CORS 에러가 나던 이유 (해결: crossorigin 제거)
상단으로

티스토리툴바