[에러 해결] 화면에 css 스크립트가 노출되는 에러

Mandy·2023년 9월 6일
2
post-thumbnail

에러 발생

아앗;; 안돼!!

회사에서 업무 중 css style 스크립트가 화면상에 아주 잠시동안 노출되는 에러가 발생했다.
(회사 코드다 보니 첨부하긴 어렵지만 우리가 흔히 아는 css style 스크립트가 그대로 화면상에 보였다고 생각하면 된다.)

여기서 아주 잠시라는것은 새로고침을 하는 순간 대략 0.1초정도 사람이 식별할수는 있으나 매우 짧은 찰나를 말한다.

하지만, 새로고침을 하는 순간 그런 눈에 띄는 오류가 보이는것만으로 사용자 경험은 저하되고 마는것이다.😥




에러를 해결해보자

해당 오류와 관련해서 이런 비슷한 현상을 구글과 chatGPT와 bing등 온갖 물어볼 수 있는 곳에는 전부 다 검색을 해보았다.

그랬더니 비슷하긴 하지만 다른 경우인 FOUC 라는 현상을 알게되었다.

FOUC(Flash Of Unstyled Content)는 외부의 CSS가 불러오기 전에 잠시 스타일이 적용되지 않은 웹 페이지가 나타나는 현상으로

간혹 우리가 HTML로만 이루어진 페이지를 아주 짧은 시간에 목격하거나, CSS가 부분 적용되어 일부만 CSS가 입혀진 페이지를 목격하게 되는 현상이다.

대략 이런 화면이 아주 짧은 시간 목격되는 것으로 사용자는 기대했던 페이지가 아닌 투박하고 생소한 화면이 나타나 당혹스러울 수 있을 것이다.

이를 해결하기 위해서는 @import의 사용을 자제하고 해당 이슈가 발생하는 컴포넌트를 js가 모두 로드되기 전에는 로딩중으로 나타낼 수 있도록 변경하는 방법이 있다.

이는 html을 먼저 서버로부터 전달받아서 화면에 그리고 css를 입히는 과정에서 css를 불러오기 전에 화면이 보여지는 바람에 발생하는 이슈이기 때문에 <body> 가 아닌 <head> 안쪽에 css와 js를 링크시키는 것이 에러 해결에 도움이 된다.



흠...
하지만 이 현상은 내가 마주한 현상과 다른 양상을 띄고 있기 때문에 해결책이 유효하다고 볼 수 없었다.

왜냐하면, 이 현상은 단지 css가 html보다 적용되는 시간의 차이가 커서 발생할 뿐 정상적으로 html과 그 이후 css가 적용된 페이지를 보여주게 되는것이고, 나는 css 스크립트 자체가 화면에 보이는 문제가 발생한 것이다.

그렇기 때문에 보통의 css와는 다른 이 현상의 원인이 아무래도 Emotion인 것 같기에 Emotion에 대해 알아보게 되었다.




이것저것 시도해보기

문제가 발생한 코드로 돌아가서 Emotion 스타일 부분에서 여러가지 시도를 해보기로 했다.

해결방안1 : 해당 컴포넌트의 부모컴포넌트에서 자식선택자로 스타일 부여하기

정말 단순한 방법이자 Hoxy..? 하고 시도해본 방법인데 이게 왜 인지는 모르겠으나 문제를 해결했다.

자식선택자, 우리가 흔히 아는 부모 css 스타일 코드 부분에

div { /*스타일...*/ }

이와 같은 선택자를 통해 스타일을 부여하는 방식으로 이 방법은 왜인지 모르지만 오류를 해결했다.

문제는 왜인지 모른다는 것으로, 이게 문제가 발생한 태그가 Next에서 제공하는 Link 태그 이기 때문인건지 아니면 다른 이유인지는 여러 실험을 반복해봤으나 확실히 이해할 수 없기때문에 받아들이기 힘든 방법이였다.

이 방안은 만약을 위한 보험으로 남겨두고 에러의 원인과 해결이 납득 가능한 솔루션을 더 시도해보기로 했다.

그러기 위해 개발자 도구를 켜서 과연 html은 어떤식으로 로드가 되고 있는지를 확인하기 위해 열어보니 충격적인 진실을 마주하게 되었다 ...



SSG & Emotion 이슈

현재 문제가 발생한 페이지는 Next.js 13버전, React 18버전, Emotion 11버전으로 모두 최신 버전을 사용하고 있었다.

여기서 주목해야 할 점은 Emotion도 있겠지만, Next.js를 사용한다는 점이다!

왜냐하면, 새로고침 이후 찰나의 시간동안만 문제가 발생한다는 것은 FOUC의 발생 원인과 비슷하게 css가 적용되는 타이밍의 문제일 가능성이 매우 높기 때문이다.

그리고 Next.js로 해당 페이지를 SSG로 렌더링하기 때문에 문제가 생길 여지가 있는것이다.

(이전 포스팅을 참고하면 SSG에 대해서 알 수 있다.)

SSG는 "빌드 시점" 에 페이지를 만들게 되는데 이것이 Emotion이 "런타임 시점"에 스타일이 적용된다는 사실과 충돌하여 문제를 발생시키는 것이다.


그런데 갑자기 충격적인 진실과 이게 무슨 상관이냐는 것일까?

바로, 새로고침한 직후 에러가 보인 그 순간의 html 코드에 <style> 태그가 포함되는데 그 내용물이 css 스크립트였던 것이다...

즉, SSG 특성상 이미 빌드시점에 완성된 페이지가 로드되고 (html이 화면에 보이는 상태) 아직 Emotion은 런타임 중이라 css가 전부 적용되지 않았는데 Emotion으로 작성한 스타일 부분이 <style> 태그로 보이게 되어 그 안에 포함된 css 스크립트가 노출된 것이다.

그렇다면...

해결방안2 : global.css 파일에서 style 태그를 display : none 처리

이런 방안이 떠오르게 된다! 그리고 이 방안은 원인과 해결이 분명히 납득가기에 완벽하다 생각했다.

이렇게 하면 <style> 태그가 html에 포함되더라도 display: none이기에 사용자 눈에는 안보일 것이라 생각했기 때문이다.

그런데 실제로 시도해보니 css 파일을 로드하기도 전에 html 파일만 로드했을때부터 style 스트링을 그대로 렌더링하는 시간 차이가 생겨서 여전히 문제가 발생했고,

global.css 다운로드로 인한 시간차로 해결이 안된 것으로 결론이 났다.

그런데 이 현상 어디서 많이 보지 않았는가...?

바로 이전에 찾아봤던 FOUC 현상과 뭔가 비슷한 원인으로 보인다. 그렇다면 FOUC 해결방안을 활용해서 적용해보면 어떨까?

해결방안3 : 해결방안2를 이용해서 _document.tsx에서 직접 <body>에 { display:none} 적용

FOUC는 <head> 태그 안에서 css와 js를 링크하라고 했지만, 내가 마주한 에러는 <body> 에서 스타일을 적용하기만 하면 된다.

이유는, 페이지 html 코드 중 눈에 보이는 부분은 <body> 태그에 포함되어 있고 여기서 문제가 발생하는 것이기 때문이다.

그러므로, Next.js의 가장 바깥쪽인 _document.tsx에서 직접 <body>{ display:none} 적용을 했다.

그랬더니 아주 깔끔하게 문제가 되는 현상이 사라졌다!




마무리

에러가 발생한 원인을 정리해보자면 SSG 사용으로 html 파일을 생성하는데 Emotion 사용으로 js 파일 실행 타이밍이 맞지않아서 생긴 문제로 요약할 수 있다.

새로고침 직후 정적으로 생성된 html과 모든 작업이 끝난 html 을 비교해보면 <style> 태그는 자바스크립트가 수행되고나서 맨 위(<head>)로 올라가서 사용자의 눈에는 안보이는게 정상인데,

이 상황에서는 js 파일 실행 타이밍이 맞지않아서 <style> 태그의 내용이 화면에 보이게 된 것이다.

에러의 원인이 라이브러리, 프레임워크의 동작 원리와 연관이 깊다는 사실을 깨닫고 새삼 공식문서를 통한 공부의 중요성을 깨달았다.



-끝

profile
즐코 행코 하세용

0개의 댓글