나의 작은 버그 리포트 🧨

Hugo Kim·2021년 6월 17일
5

웹 표준 Deep Dive

목록 보기
2/2
post-thumbnail

⛔ 본문은 프론트엔드 개발자가 보면 슬퍼질 수 있는 버그를 다룬 글입니다.

출시를 앞두고 있는 프로젝트를 진행하다가 이상한 버그🐛 하나를 마주하게 됐다.

바로 css 속성 변경 시에 일정 시간에 걸쳐 서서히 변경되도록 해주는 transition이 엘리먼트에 설정된 초기 값에도 적용되는 버그였다. 이렇게 설명하면 이해가 어려우니 예시와 함께 설명하겠다.

버그

<div class="rect"></div>

여러분들이 아주 잘 아는 div 엘리먼트가 있다. 그리고 엘리먼트를 호버했을 때 색깔이 서서히 바뀌도록 transition을 추가했다.

/* style */
.rect {
  width: 200px;
  height: 200px;
  background-color: red;
  transition: background-color 1s;
}

.rect:hover {
  background-color: blue;
}

위 코드를 html 파일로 작성해보면 아래와 같다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>bug is not reported</title>
    <style>
        .rect {
            width: 200px;
            height: 200px;
            background-color: red;
            transition: background-color 1s;
            }

            .rect:hover {
            background-color: blue;
        }
    </style>
</head>

<body>
    <div class="rect"></div>
</body>

</html>

이 예시는 우리가 예상했던 대로 엘리먼트를 호버하게 되면 엘리먼트가 초기값으로 설정한 빨간색에서 파란색으로 1초간 서서히 바뀌게 된다. (데모, 소스)

하지만 일반적으로 css를 사용할 때 style 태그로 작성하지 않고 별도의 css 파일로 분리해서 사용한다. 문제는 지금부터 발생하게 되는데 style.css 파일로 분리해서 사용하게 되면 엘리먼트를 호버하는 경우 뿐만 아니라 최초 문서 로드 시에도 브라우저 기본 배경색인 하얀색에서 style.css에서 설정한 빨간색으로 transition이 발생하게 된다. 이 현상은 Chromium 기반 브라우저(Chrome, 웨일, Edge 등)에서 모두 발생하고 있고 transition이 일어날 수 있는 모든 속성(color, top, transform, font-size 등)에서 발생할 수 있다. (데모, 소스)

⚠️주의사항

최초 로드 시엔 버그가 발생하지만, 이후부터는 강력 새로고침(ctrl + shift + r)을 해야 재현 가능하다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>bug is reported</title>
    <link rel="stylesheet" href="./style.css" />
</head>

<body>
    <div class="rect"></div>
</body>

</html>

요소에 설정된 초기 값에 transition이 적용되는 되는 경우를 본 적이 없었기 때문에 당연히 버그라고 생각했다. 확인해보니 이 현상은 2012년부터 존재했다. (참고 1, 참고 2)

해결 방법

내가 이 현상을 마주할 수 없었던 이유가 바로 이 해결방법에 있다. 이 현상의 해결 방법은 놀랍게도 script 태그를 html문서에 추가해주는 것이다. (deferasync 속성이 없어야 한다.) 하지만 빈 script 태그를 넣으면 해결되지 않고, 최소한 하나의 문자를 입력해줘야 한다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>bug is reported</title>
    <link rel="stylesheet" href="./style.css" />
</head>

<body>
    <div class="rect"></div>
    <!-- 빈 script 태그은 현상 해결 안됨! -->
  	<!-- 공백 문자 입력도 가능 -->
    <script> </script>
</body>

</html>

원인

결론부터 말하자면 이 해결 방법이 동작하는 원인은 정확히 알 수 없다. (아시는 분은 댓글로!) 하지만 stackoverflow의 한 대답에 의하면 script 엘리먼트 삽입으로 브라우저의 DOM 로드 이후 CSS 적용을 늦추는 것일지도 모른다.

Transition Deep Dive

사실 이 현상은 버그가 아니다. 정확히 말하자면, CSS3 명세를 위반하지 않는 동작이다.

CSS3 Transition 명세를 확인해보면 다음과 같은 문장을 확인할 수 있다.

Transition 명세 본문 중에서..
However, when an implementation updates the computed value of a property on an element to reflect one of these changes, or computes the computed value of a property on an element newly added to the document, it must update the computed value for all properties and elements to reflect all of these changes at the same time (...)
This processing of a set of simultaneous style changes is called a style change event. (...)

Since this specification does not define when a style change event occurs, and thus what changes to computed values are considered simultaneous, authors should be aware that changing any of the transition properties a small amount of time after making a change that might transition can result in behavior that varies between implementations, since the changes might be considered simultaneous in some implementations but not others.

⚠️오역이 다소 포함되어 있을 수 있습니다.

하지만, 구현이 이런 변화 중 하나를 반영하기 위해 요소의 계산된 값을 업데이트하거나, 문서에 새롭게 추가된 요소의 계산된 값을 계산할 때, 구현은 모든 속성과 요소에 대해 계산된 값을 업데이트해서 모든 변경을 동시에 반영해야 한다.
이 일련의 동시 스타일 변화를 처리하는 것을 style change 이벤트라고 한다. (...)

이 명세는 style change 이벤트가 일어나는 시점과 어떤 값의 변화들이 동시에 고려되는지 정의하지 않기 때문에, 저자들은 transition이 발생할 수 있는 스타일 변화 이후에 잠시동안 어떤 transition 속성의 변화로 인해 구현(브라우저)마다 다른 동작이 발생할 수 있다. 일부 구현에서는 변경이 동시에 고려될 수 있지만 다른 구현에서는 고려되지 않을 수 있다.

명세에 나와있는 위 부분을 보면, Chromium 브라우저에서 왜 이런 현상이 발생하는지 알 수 있다. 바로 명세에서 style change 이벤트의 발생 시점을 정의하고 있지 않기 때문이다. 만약 명세에서 style change 이벤트의 발생 시점을 document 로드 이후로 정의했다면 논란의 여지없이 크롬의 버그라고 할 수 있었겠지만, 그렇지 않기 때문에 이 현상을 버그라고 하기는 어렵다. 다만, 이 현상이 일어나게 된 가장 큰 원인은 명세라고 생각한다.

참고 자료

profile
ts와 react를 사랑하는 프론트엔드 개발자입니다.

0개의 댓글