회사에서 svg 영역안에서만 슬롯머신이 돌아가는 애니메이션이 보여지도록 하는 작업을 맡게 되었다.
온갖 영어로 된 문서들을 다 뒤져봐도 한눈에 잘 정리 된 페이지가 없어서 지난 일주일간 시행착오를 통해 내가 찾은 방법을 기록하고자 한다.
이 글을 보는 분들은 부디 나처럼 삽질하지 말고 쉽게 가세요...
작업에서 어려움을 겪었던 단계는 아래와 같다.(산 넘어 산이었다)
1. clip-path를 사용할 때 path()안에 넣어야 할 내용을 svg에서 어떻게 확인할 수 있는가?
2. 누끼가 따진 이미지의 크기를 어떻게 반응형으로 조절할 수 있을까?
3. 브라우저에 따라 되는 브라우저가 있고 안되는 브라우저가 있는데 어떻게 해결할 수 있을까?
총 세번의 산을 넘어서야 문제를 최종 해결할 수 있었다.
또한 3번 문제를 해결하기 위해 1,2 당시에 사용했던 코드를 다른 방식으로 수정하였다.
성질 급한 사람은 3번 코드만 보면 되고, 각 문제를 해결하기 위해 거쳤던 과정을 보려면 순서대로 보면 된다.
에디터:VSCODE
라이브러리:react cli
css 관리:styled-component
1. clip-path를 사용할 때 path()안에 넣어야 할 내용을 svg에서 어떻게 확인할 수 있는가?
svg 이미지 그대로 누끼를 따는 아이디어는 회사 동료를 통해 얻을 수 있었다. 인터넷 검색을 통해 알아보니 clip-path를 통해 원 및 다각형등 여러 모양의 누끼를 딸 수 있었다. 특히 다각형의 경우 point를 찍어 원하는 모양의 다각형을 clip-path로 제공하는 사이트도 있었다.
https://bennettfeely.com/clippy/
Clippy — CSS clip-path maker
About Clip Paths The clip-path property allows you to make complex shapes in CSS by clipping an element to a basic shape (circle, ellipse, polygon, or inset), or to an SVG source. CSS Animations and transitions are possible with two or more clip-path shape
bennettfeely.com
하지만 나의 경우는 보다 디자이너가 제작해준 보다 정확한 모양의 선글라스 그대로 Path를 따는 것이 중요했다. 처음에는 위 사이트에 point를 찍어 선글라스 비슷하게 만들어보고자하는 시도 하였으나 너무 노가다고 정확도가 떨어져 다른 방법을 모색하였다.
(1) 디자이너분에게 누끼의 영역이 될만한 정확한 선글라스 모양의 svg 이미지를 받는다
(2) svg 파일을 vs code로 옮겨 path가 될만한 영역이 무엇인지 확인한다
(3) 발견한다!!
clip-path:path("M114...")
아마 (2)에서 잘 찾아보면 M으로 시작하는 PATH가 있을 것이다. 당연하게도 누끼를 따고자하는 영역이 복잡하면 복잡할수록 매우 길다. 이때 특정 부분은 제대로 누끼가 따지는데 특정부분은 누끼가 제대로 따지지 않는 현상이 발생할 수 있다.
clip-path가 적용된 코드 부분에 width와 height를 제대로 적용해주지 않았기 때문이다. 무턱대고 width와 height 100% 혹은 100vw 등으로 주면 안된다. 왜냐하면 path()안에 기록된 영역은 svg의 절대 경로이고 이는 원본 svg 파일의 width와 height 상에서 그러한 경로를 가지기 떄문이다. (이 부분은 백엔드 사수 분께서 아이디어를 주셔서 해결할 수 있었다)
그럼 어떻게 width, height를 확인하냐고?
(2) 단계에서 svg 파일을 다시 잘 살펴보면 viewbox 부분이 있다. 총 네개의 숫자로 이루어져 있는데, 0,0,987,394의 경우 세번째 항목인 987px이 width 네번째 항목인 394px이 height가 된다. 따라서 위의 코드를
width:987px;
height:394px;
clip-pathLpath("M144...");
와 같이 수정해주면 디자이너에게 받은 원본 사이즈 그대로인 상태로 svg 영역만큼 누끼가 따지게 된다.
2. 누끼가 따진 이미지의 크기를 어떻게 반응형으로 조절할 수 있을까?
transform:scale()의 속성을 이용하여 누끼가 따진 이미지의 크기를 조정할 수 있다.
transform:scale(0.8)은 원본의 이미지의 크기를 0.8배로 축소시켜주며, scale(x,y) 이렇게 두개의 파라미터를 넣으면 가로 세로 값을 각기 다르게 지정해서 줄 수 있다.
SUNGLASS_DEFAULT_WIDTH = 987px
width =20, 30 과 같이 전체 화면의 크기에서 얼마만큼의 크기를 차지하고 있는지의 number값
windowWidth = document.body.clientWidth (브라우저의 넓이)
1,05, GLASS_WIDTH_CORRECTION_FACTOR => svg의 이미지 크기와 실제 내가 누끼를 따려고 한 이미지간의 크기 차이가 나서 보정을 해주기 위함 상수 값( 예를 들어 svg에서는 선글라스의 테두리가 포함되어 있지만, 실제 내가 누끼 따고 싶었던 이미지는 선글라스의 테두리를 제외한 부분이었다)
선글라스의 부모에 position을 relative로 두고, 선글라스의 위치는 absolute를 주었으며, top과 left를 적절하게 준다.
postion:absolute;
top: 59%;
left:3%;
transform: scale(
${(props) =>
(props.width * props.windowWidth * 1.05 * GLASS_WIDTH_CORRECTION_FACTOR) /
100 /
SUNGLASS_DEFAULT_WIDTH}
);
3. 브라우저에 따라 되는 브라우저가 있고 안되는 브라우저가 있는데 어떻게 해결할 수 있을까?
여기까지 진행을 했을 때, Window에서는 clip-path가 제대로 작동되지 않고, 맥에서만 제대로 작동되는 것을 확인하였다.
시간이 좀 지나서 정확히 기억이 나지는 않지만 구글링을 통해 clip-path를 mask-image 관련 코드로 변경해주고 윈도우와 맥 두군데서 모두 제대로 누끼가 따지는 것을 확인하였다.
최종 코드는 아래와 같다.
const TextArea = styled.div<TextAreaProps>`
width: ${SUNGLASS_DEFAULT_WIDTH}px;
height: ${SUNGLASS_DEFAULT_HEIGHT}px;
position: absolute;
margin: 0 auto;
top: 59%;
left:3%;
mask-image:url("data:image/svg+xml,%3Csvg id='_레이어_2' data-name='레이어 2 xmls="....");
-webkit-mask-image:url("data:image/svg+xml,%3Csvg id='_레이어_2' data-name='레이어 2 xmls="...."))
-webkit-mask-repeat:no-repeat;
mask-repeat:no-repeat;
-webkit-mask-size: cover;
mask-size: cover;
transform: scale(
${(props) =>
(props.width * props.windowWidth * 1.05 * GLASS_WIDTH_CORRECTION_FACTOR) /
100 /
SUNGLASS_DEFAULT_WIDTH}
);
transform-origin: top left;
zindex: 10000;
`;
가장 주의해야 할 점은 mask-image: url("")안에 들어갈 svg의 정보를 제대로 기입하는 것이다.