Tridge Social Marketplace의 Buyer, Supplier Business Card를 Flip 하는 기능을 구현하던 도중 만나게 된 Safari issue를 해결한 경험을 소개합니다.
아래는 실제 Production이 아닌 이슈를 재현하기 위한 Demo 영상입니다. Chrome 131에서는 카드를 뒤집을 때 앞면과 뒷면이 모두 문제 없이 잘 보여지지만, Safari 15.6의 경우 카드를 뒤집었을 때 뒷면이 사라지는 현상이 발견되었습니다.
Chrome 131
Safari 15.6
아래는 위 Demo를 구현하고 있는 HTML, CSS 내용인데요, 크게 transform: rotateY , transform-style: preserve-3d , backface-visibility: hidden 속성을 사용하여 구현했습니다.
front에는 transform 속성을 적용하지 않고, back에 transform: rotateY(180deg) 를 적용하여 카드의 앞면과 뒷면을 구현합니다. 이후 버튼을 클릭하거나 하는 유저의 이벤트가 발생했을 때 root element에 transform: rotateY(180deg) 를 적용하여 front와 back 모두 회전시키게 합니다. 이 때, backface-visibility: hidden 속성을 적용하여 현재 유저가 보고 있는 화면 기준으로 카드 뒷면에 있는 면은 보이지 않도록 구현합니다.
하지만, backface-visibility spec을 살펴보면 backface를 판단할 때, accumulated 3D transformation matrix를 계산해서 matrix of (3, 3) value가 음수면 backface 라고 판단한다고 합니다.
accumulated 3D transformation matrix는 주어진 element에 대해 3D 렌더링 컨텍스트의 root 요소로부터 transform matrix를 누적 계산하여 적용되는 것인데요, 그렇기 때문에 root element에 transform-style: preserve-3d 속성을 적용하여 3D 렌더링 컨텍스트를 생성해주어야합니다. 이렇게 되면 root 요소의 transform matrix 가 수정될 때 child인 front, back element의 accumulated 3D transformation matrix가 수정되면서 자연스럽게 뒷면은 hidden되고 앞면만 보여지도록 하는 것이죠.
<div class="root">
<div class="front">
<div class="front-content">
</div>
</div>
<div class="back">
<div class="back-content">
</div>
</div>
</div>
.back {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
flex: 1;
display: flex;
flex-direction: column;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transform: rotateY(180deg);
}
.root {
position: relative;
border-radius: 8px;
flex-direction: column;
display: flex;
height: 100%;
background-color: black;
transition: transform 0.6s;
transform-style: preserve-3d;
overflow: unset;
}
.root.fliped {
transform: rotateY(180deg);
}
.front {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
이슈를 해결하기 위해, css transform: rotateY 속성이 적용되는 과정을 살펴볼 필요가 있었습니다.
3D Transform functions에 따르면 rotateY function은 rotate3d(0, 1, 0, <angle>)과 동일하기 때문에, rotateY(180deg) = rotate3d(0, 1, 0, 180deg) 입니다.
rotate3d 계산 과정을 살펴보면, 아래와 같습니다.
아래 계산식으로 계산하면, sc = sin(90deg) * cos(90deg) = 0 이고, sq = sin^2(90deg) = 1 입니다.