본문 바로가기
개발 이야기/직접 해보기

[CSS] 마우스를 올리면 움직이는 3D 책 만들기

by thedev 2023. 11. 20.

 

마우스를 올리면 움직이는 3D 책 만들기

인터랙티브 웹과 어울리는 컴포넌트

 


 

3D 컴포넌트

 

Next.js 공식문서를 읽던 중, 3D 컴포넌트를 발견하였다.

 

https://nextjs.org/showcase

 

 

 마우스를 올리면 책이 움직인다. 이 컴포넌트를 보자마자 어떻게 구현한 것인지 궁금해져 바로 개발자도구를 켜서 이 페이지의 HTML, CSS를 구경해보았다. CSS 부분을 읽어보니 프레임워크나 라이브러리 없이 순수 CSS만을 이용해서 구현했다는 것을 알 수 있었다. 충분히 간단하게 구현해볼 수 있을 것 같다는 생각이 들었고, 바로 vscode를 켜서 만들어 보았다.

 

마우스 hover 전 / 후

 

 

 완성된 모습은 이렇게 생겼다. 라이브러리 없이 단순 CSS만으로 만들기 때문에 코드도 간단하고 자바스크립트 환경 어디서든 사용할 수 있다.

 

 

구현하는 방법

 

HTML

 

<div id="container">
   <div class="book">
     <div class="bookCover">
       <div class="binder"></div>
       <div class="content">
         <div class="title">제목을 입력하세요</div>
         <div class="subTitle">부제목을 입력하세요</div>
       </div>
     </div>
     <div class="bookSide"></div>
     <div class="bookBack"></div>    
   </div>
</div>

 

 

CSS

 

#container {
  display: flex;
  justify-content: center;
  align-items: center;
}

.book {
  display: flex;
  align-items: center;
  position: relative;
  width: 240px; /* 책 가로 길이 */
  height: 270px; /* 책 세로 길이 */
  border-radius: 6px; /* 책 모서리 둥근 정도 */

  .bookCover {
    z-index: 10;
    background-color: #e5e7eb; /* 책 색깔 */
    border-radius: inherit;
    box-shadow: inset -2px -2px 8px rgba(0, 0, 0, 0.03);
    display: flex;
    width: 100%;
    height: 100%;
    transition: transform 0.5s ease-in-out;
    transform: perspective(300px) rotateY(0deg);

    .binder {
      width: 15%; /* 책 표지 왼쪽에 있는 바인더의 가로 길이 */
      box-shadow: inset -2px -2px 5px rgba(0, 0, 0, 0.03);
      border-top-left-radius: 6px; /* 책 모서리 둥근 정도 */
      border-bottom-left-radius: 6px; /* 책 모서리 둥근 정도 */
    }

    .content {
      width: 85%; /* 바인더를 제외한 표지의 가로 길이 */
      padding: 36px;
      display: flex;
      border-top-right-radius: inherit;
      border-bottom-right-radius: inherit;
      flex-direction: column;
      align-items: center;
      
  /* 책 표지에 들어갈 내용들 */
      .title {
        font-weight: 600;
        margin-bottom: 3px;
      }

      .subTitle {
        font-size: 12px;
      }
    }
  }

  .bookSide {
    z-index: 5;
    position: absolute;
    right: 0;
    border-top-right-radius: 3px;
    border-bottom-right-radius: 3px;
    box-shadow: inset 4px 0 8px rgba(0, 0, 0, 0.1);
    background-color: white;
    width: 20px;
    height: 100%;
    transition: transform 0.5s ease-in-out;
    transform: perspective(300px) rotateY(90deg) translateX(20px);
  }

  .bookBack {
    position: absolute;
    right: 0;
    background-color: #e5e7eb; /* 책 색깔 */
    border-radius: inherit;
    width: 80%;
    padding-left: 20px;
    height: calc(100% - 10px);
    transition: transform 0.5s ease-in-out;
    transform: perspective(300px) rotateY(0deg);
  }
}

.book:hover {
  cursor: pointer;

  .bookCover {
    transition: transform 0.5s ease-in-out;
    transform: perspective(300px) rotateY(-5deg);
  }
  .bookSide {
    animation: transform 0.5s ease-in-out;
    transform: perspective(300px) rotateY(30deg) translateX(20px);
  }
  .bookBack {
    transition: transform 0.5s ease-in-out;
    transform: perspective(300px) rotateY(-5deg) translateX(20px);
  }
}

 

 

 CSS의 transform의 perspective, rotate, translate를 이용하였다. 이를 구현하면서 순수 CSS의 기능만으로도 3D 컴포넌트를 구현할 수 있다는 것을 처음 알게 되어 놀라웠다. 그동안 CSS 라이브러리만 계속해서 이용했다보니 오히려 순수 CSS에 대한 지식이 부족해지지 않았나, 라고 반성도 하였다😅 인터랙티브한 웹에 관심이 많아서 Three.js도 약간 사용해본 적이 있었는데, 오히려 앞으로는 이런 간단한 수준의 3D는 순수 CSS를 이용하게 될 것 같다.