CSS 3D animation : 종이처럼 뒤집히는 사진 만들기

조 은길·2022년 4월 21일
0

Html & CSS

목록 보기
57/66
post-thumbnail

UI 만들기 전에 생각해보셨나요??

실제 서비스를 운영할 때,

상품 이미지에 마우스를 올려야 상품정보가 표시되도록 하면 되겠어요??

안되겠죠!! 왜냐면, 매우 불편할 것같습니다.

UI 디자인 만들때, 원칙을 잘 지켜야 한다.

디자인의 취향은 누구나 선호도가 다를 수 있다.

그러나, 편리한 건 호불호가 갈리지 않는다!! 무조건 편리한 게 최고!!

그래서, UI 디자인할 때, 항상 이게 편리한지 불편한지 꼭 생각해보자!!

대표적인 UI 원칙

  • 한 번에 내가 원하는 정보를 빨리 찾을 수 있나??
  • 배치하는 위치도 중요
    • 사람들은 UI를 볼 때, 왼쪽 위를 먼저 본다.
      - 책 읽는 습관에 영향이라고 한다.
      => 중요한 정보를 보여줄 위치도 반드시 신경쓰자!!

CSS 3D animation

transform을 쓰면 3D 스타일 회전이 가능하다

transform : rotateX(180deg);
transform : rotateY(180deg);
transform : rotateZ(180deg);

X축 회전 vs Y축 회전

각각 X,Y,Z축 회전이 가능합니다.

X축은 가로줄입니다. 그래서 rotateX()는 가로줄을 축으로 회전이 들어갑니다.

뭔소린지 모르겠으면 연필을 모니터에 가로로 대보십시오.

그리고 그 연필을 돌돌 말아봅니다.

그게 X축 회전, rotateX() 입니다.

아니면 직접 CSS로 박스나 글자를 rotateX() 줘보면 알 수 있습니다.

Y축은 세로줄입니다. 모니터에 연필을 세로로 놓고 돌돌 말면 그게 Y축 회전입니다.

Z축은 여러분 얼굴과 모니터 간의 가상의 선을 하나 그려보십시오.

그 선을 회전시키면 그것이 Z축 회전입니다.

즉,

▲ 오늘 만들어볼 간단한 애니메이션

이것은 Y축 회전을 이용해야한다.


perspective 속성 - 공간을 3D로 만드는 시작

아래 예제 같은 경우는 180도 회전이라 이 속성이 안 들어가도 작동은 한다.

그러나, 일반적으로 특정공간에 3D 속성을 주기 위해서는 perspective: 800px; 속성을 줘야한다.
=> px단위가 커질수록 입체감이 더 커진다.

perspective는 어디에 주는가에 따라 차이가 난다

- 전체 3D 컨테이너에 줄때 => 각 물체마다 시점이 다름

이 경우,

3개의 문의 시점이 달라보인다.
=> 자세히 보면, 3개의 문의 시점이 미묘하게 다르다.

- 3D 동작이 직접적으로 일어나는 태그에 줄때 => 모든 물체가 시점이 동일함

=> perspective는 위와 같이 transform 속성에 더해져서 줄 수도 있다. 참고하자!!

이 경우는 위와 같이 시점이 달라보이지 않고, 문들이 일정하게 표현된다.

어떤 것이 옳다 그르다가 아니라, 2가지 상황의 차이점을 알고 "디자인 의도"에 맞게 잘 쓰면 된다!!


step 1. 앞면과 뒷면 레이아웃을 각각 만들어줍니다

<div class="flip-outer">
    <div class="flip-inner">
      <img src="profile.png" class="front">
      <div class="back">
        <h4>개발자 조은길</h4>
        <p>Frontend Developer</p>
      </div>
    </div>
 </div> 

앞면엔 사진, 뒷면엔 글씨 몇개를 집어넣고 싶어서 저렇게 했습니다.

그리고 중요한건 flip-inner라고 작명한 앞뒷면 둘다 싸매는 박스를 하나 만들어줘야합니다. => flip-outer

즉, 앞면과 뒷면을 싸메는 flip-inner
그리고 그 flip-inner를 감싸는 flip-outer까지 필요하다!!

왜냐면

1. 마우스를 올리면, 앞면과 뒷면을 각각 회전시키기 보다는 저 박스 전체를 회전시키면 편리하니까요.

2. 앞면과 뒷면은 position : absolute로 띄워야 앞뒤로 배치가 가능합니다. 그래서 position : relative를 어딘가에 줘야하는데 그걸 싸매는 박스에 주면 편리합니다.

step2. 앞면과 뒷면에 position : absolute를 줍니다

앞면/뒷면 배치는 position: absolute;


그래서, 위의 img와 div에 각각 position: absolute;를 줄거다.
=> 이 2개의 요소를 겹치게하기 위해서!!

position: absolute;를 주려면, 부모 태그에 position: relative;도 줘야한다.
WHY?
position: absolute;를 주면, (0,0)으로 달라붙기 위해서 position: relative;를 가진 태그를 찾는다.

(css파일)

.flip-outer {
  width: 300px;
  height: 300px;
}

.flip-inner {
  width: 100%;
  height: 100%;
  position: relative;
}

.front {
  width: 100%;
  position: absolute;
  z-index : 1;   //안나오면 이것도 추가
}

.back {
  width: 100%;
  position: absolute;
  transform: rotateY(180deg);
} 

absolute를 이용해서 앞뒷면으로 배치를 잘 한 모습입니다.

앞면이 안보이면 앞면사진에 z-index : 1; 이것도 추가해봅시다.

그리고 뒷면은 rotateY(180deg)를 먼저 쥐어줍니다.

그래야 최종완성본에서 마우스를 올려 회전시켰을 때 제대로 글씨가 보이겠죠?
=> 이미지를 뒤집었을 때,

이렇게 되면, 글씨를 읽을 수 있는 가독성이 떨어지니 이미지를 뒤집더라도, 글자가 제대로된 순서로 나오게 하자!!
=> 즉, 뒷면은 뒤집었을 때 정확히 보이도록 미리 디자인해놔야함

의심스러우면 이걸 빼고 한번 실험해봅시다.

그래서,

.back {
        position: absolute;
        width: 100%;
        text-align: center;
        transform: rotateY(180deg); // 이 속성을 줘보면
  		// 글자가 뒤집힌다.
      }


뒷면의 글자들이 사전에 뒤집어진 것을 볼 수있다.
=> 이렇게 해놓으면, 나중에 뒤집었을 때 뒷면글자가 제대로 보인다.

이제 실제로 :hover를 통해, 이미지를 뒤집어보자!!

 .flip-inner:hover {
        transform: rotateY(180deg);
      }

step3. 마우스를 올렸을 때 Y축으로 180도 회전시키라고 애니메이션을 줍니다

.flip-inner {
  width: 100%;
  height: 100%;
  position: relative;
  transition: all 1s;
  transform-style: preserve-3d;
}

.flip-inner:hover {
  transform: rotateY(180deg);
} 

hover시 Y축 180도 회전을 주라고 했다.
=> .flip-inner 안의 앞면과 뒷면이 모두 뒤집힌다.

근데 애니메이션처럼 동작하도록 transition도 포함했습니다.
transition: all 1s;를 주면, 천천히 스무스하게 돌아간다.

그런데, 이미지가 앞면에서 뒷면에서 보여야할 글씨들이 보인다.

이 문제를 해결해보자!!

transform-style: preserve-3d; 속성을 집어넣기!!
=> 진짜 3D 박스처럼 동작하게 하기
=> 현재는 2D 상태인데, .flip-inner가 3D적으로 작동함!!
=> 이제는 3D적으로 요소들이 배치됨
=> 이 속성이 없으면 뒷면이 이상해지거나, 앞뒷면끼리 겹치는 현상 발생!!

그리고 중요한건 transform-style: preserve-3d; 이 속성이 있어야 어떤 요소를 회전시킬 때 우리가 평소에 생각하는 3d 사물처럼 동작합니다.

.flip-inner {
        width: 100%;
        height: 100%;
        position: relative;
        transition: all 1s;
        transform-style: preserve-3d;
      }

문제는 크롬 브라우저 상에서 강의처럼 글자가 없어지지 않는다.

 .front {
        position: absolute;
        width: 100%;
        backface-visibility: hidden; //
        z-index: 1; // 이거 2개 넣으니까 해결되기는 함
      }

step4. 뒷면에 비치는 그림자를 안보이게 처리하려면

이제 앞면에 글자는 없어졌는데,

사진이 뒤집혔을 때, 앞면의 이미지도 보인다. (뒤집힌 채로)

이게 보기 싫으니, 뒤집혔을 때 앞면의 모습을 없애주자!!

backface-visibility: hidden;
=> 이미지의 뒷면이 안보이게 해준다!!

뒷면이 심심하니, 앞면처럼 원형으로 만들어보자!!

.back {
        position: absolute;
        width: 100%;
        height: 100%;
        background-color: gray;
        border-radius: 100%;
        text-align: center;
        transform: rotateY(180deg);
      }

.back {
        position: absolute;
        width: 100%;
        height: 100%;
        background-color: gray;
        border-radius: 100%;
        text-align: center;
        transform: rotateY(180deg);
        /* 글자 위치를 좀 더 예쁘게 하기 위해 */
        padding-top: 50px;
        box-sizing: border-box;
      }

이렇게해서 완성!!

브라우져마다 CSS 3D 지원사항이 다르다

크롬에서는 CSS 3D가 완벽하게 작동하지만, 사피리나 MS edge같은 브라우져에서는 지원이 안 되는 속성들도 존재한다. (IE는 더 말할 필요없고...)
그래서, 브라우져마다 완성된 코드를 테스트해보고, 반드시 수정해나가야 최종적으로 서비스를 배포할 수있다.

대부분 vender prefix를 이용해서, 해결할 수 있다.

"사파리"같은 경우, 크롬과 같이 webkit 기반으로 만들어졌기 때문에, 지원이 안되는 속성에 -webkit- 접두어를 붙여주면, 작동하게 할 수있다.

예를 들어,

사파리는 backface-visibility: hidden; 속성을 지원하지 않는다.

-webkit-backface-visibility: hidden; 이렇게 수정해서 문제를 해결할 수있다.

추가적으로,
-webkit-backface-visibility: hidden;

backface-visibility: hidden;을 둘 다 써주는 게 좋다.

사피리에서는 -webkit-backface-visibility: hidden; 이 적용이 되고, 표준 속성을 지원하는 크롬에서는 backface-visibility: hidden;이 적용된다.


vender prefix (중요)

아직 표준으로 정해지지 않은 새로 나온 스펙들을 적용할 때, 사용한다.

각 브라우저마다 고유한 접두어들을 정해놨다.

webkit 기반 브라우저들은 -webkit- 이 붙고, moz 기반 브라우저들은 -moz-가 붙는다.

display: flex;도 한 때는 -webkit-을 붙여줘야 했다.


.test {
-ms-backface-visibility: hidden;
-o-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-webkit-backface-visibility: hidden;
backface-visibility: hidden; 
}

=> 반드시 표준 속성을 맨 마지막에 넣자!!
=> 맨 위에 넣으면, 표준 속성이 나머지를 덮어쓰기 때문에, 반드시 맨 마지막에 넣어야 한다.

profile
좋은 길로만 가는 "조은길"입니다😁

0개의 댓글