[Project] 초간단 카드 뒤집기를 해보자!

힛짱·2022년 12월 13일
1

Project

목록 보기
2/3
post-thumbnail

동료들에게 발표했던 '카드 뒤집기 초간단 실습 예제'포스팅입니다! 프로젝트를 하면서 가장 인상 깊고 재밌는 기능들도 같이 정리했습니다! 실습 예제부터 시작합니다😉


⚡️ 실습 예제 ⚡️


👉 실습 예제는 깃헙에서!

이 실습은 HTML, CSS, JSON으로만 구현한 간단한 실습 예제입니다! 이 포스팅에서는 HTML과 CSS 코드만 가져오겠습니다. 위의 링크로 가서 클론 후 직접 작업해보세요!

HTML

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="img/pikachu.png">
    <title>✨스프라이트 기법 써보기✨</title>
    <link rel="stylesheet" href="css/style.css">
</head>

<body>
    <ul class="list-card"></ul>

    <script>
        const $cardList = document.querySelector('.list-card');

        // json 데이터 가져오기
        const getCardData = fetch("card.json")
            .then((res) => res.json())
            .then((data) => cardData(data))

        function cardData(data) {
            // 랜덤 배열 생성
            data.sort(() => Math.random() - 0.5);

            // 데이터 출력
            data.forEach((card) => {
                const template = `
                    <li class="card">
                        <div class="back-card"></div>
                        <div class="front-card" style="background-position: ${card.position.x}px ${card.position.y}px;"></div>
                    </li>
                `;

                // HTML에 추가하기
                // $cardList.innerHTML += template;

                // innerHtml보다 작업이 덜 드므로 빠르다.
                // https://developer.mozilla.org/ko/docs/Web/API/Element/insertAdjacentHTML
                $cardList.insertAdjacentHTML('beforeend', template);
            })
        }
    </script>
</body>

</html>

먼저 json 파일을 fetch 해서 데이터를 가져온 후, cardData 함수를 실행해서 데이터를 보내주고, forEach 로 받아온 데이터를 출력해봅시다!

여기서 포인트가 background-position 값에 json 파일에 있는 position 값을 넣어주는 것이지요. json 파일을 보면 position의 x, y값들이 잘 들어가 있습니다.

이걸로 이미지 스프라이트 기법을 이용한 데이터 뿌리기 끝입니다! 정말 초초간단하죠?

CSS

* {
    margin: 0;
    padding: 0;
    list-style: none;
}

.list-card {
    width: 50%;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    justify-items: center;
    margin: 50px auto;
    gap: 20px;
}

.card {
    position: relative;
    outline: 4px solid #00479d;
    /* 3D 효과가 적용된 요소의 자식 요소에 3D 효과가 전달 */
    transform-style: preserve-3d;
    width: 100%;
    max-width: 150px;
    max-height: 205px;
    min-width: 100px;
    min-height: 136px;
    aspect-ratio: 193 / 264;
    border-radius: 10px;
    background-color: #ffeea2;
    transition: all 1s;
}

.card:hover {
    transform: rotateY(180deg);
}

.back-card {
    background-image: url("../img/card-back.png");
    background-size: contain;
    width: 100%;
    height: 100%;
    background-repeat: no-repeat;
    /* 요소의 뒷쪽에서 앞면이 보이게 할지 정하는 속성 */
    backface-visibility: hidden;
}

.front-card {
    position: absolute;
    top: 50%;
    left: 50%;
    margin: 0 auto;
    background-image: url("../img/pokemon.png");
    background-color: #ffeea2;
    width: 100px;
    height: 100px;
    display: block;
    transform: translate(-50%, -50%) rotateY(180deg);
    backface-visibility: hidden;
    transition: all 1s;
}

CSS 코드를 보면 자주 사용하지 않았던 속성 몇 개가 보이시죠? 카드 뒤집기를 구현할 때 가장 중요한 기능이니, 밑에서 더 알아보도록 하겠습니다!

✨ 재밌는 기능 알아보기 ✨


🪄 랜덤 배열 만들기

let num = [1, 2, 3, 4, 5];

num.sort(() => Math.random() - 0.5);
  • 양수와 음수를 무작위로 반환하는 판별식을 이용해서 배열의 정렬 기능에 대입해 배열의 요소를 무작위로 바꿉니다.

  • Array.sort()

    • 배열의 요소 순서를 변경합니다.
    • 두 수의 크기를 비교할 때 리턴값 -1, 0, 1에 따라 두 값을 바꿀지 말지 결정합니다.
    • ASCII 우선순위에 따라 결정하기 때문에 숫자는 제대로 정렬이 안됩니다.
  • Math.random()

    • 0 ~ 1 미만의 값을 리턴 → 양수값만 출력 → 랜덤값이 한 방향으로만 편향 → 그것을 막기 위해서 0.5를 뺌

    • 반환받은 랜덤한 값에서 0.5를 빼면 음수 값과 양수 값을 무작위로 반환합니다.

    • Array.sort() 에 필요한 리턴값은 -1 과 1만 필요합니다. (즉, 음수나 양수 중 하나만 리턴하면 됨)


  • 단점 : Array.sort() 함수는 위와 같은 용도로 만들어진 메서드가 아니기 때문에 순열의 빈도수가 균일하게 나오지 않습니다.


💡 피셔-예이츠 셔플(Fishcer-Yates shuffle) 알고리즘 활용

  • 배열 끝 요소부터 시작해 앞으로 하나씩 나아가면서 해당 요소 앞에 있는 임의의 요소와 해당 요소를 바꿔치기하는 알고리즘

  • 위의 함수보다 더욱 고른 결과값을 획득할 수 있을 뿐만 아니라 피셔-예이츠 알고리즘은 ‘정렬' 연산도 없기 때문에 성능상 이점 또한 가지고 있습니다.

    function shuffle(array) {
        array.sort(() => Math.random() - 0.5);
    }
    
    // 1, 2, 3으로 만들 수 있는 모든 순열의 빈도를 세줍니다.
    let count = {
        123: 0,
        132: 0,
        213: 0,
        231: 0,
        321: 0,
        312: 0,
    };
    
    for (let i = 0; i < 1000000; i++) {
        let array = [1, 2, 3];
        shuffle(array);
        count[array.join("")]++;
    }
    
    // 만들 수 있는 모든 순열의 생성 빈도를 세서 출력해줍니다.
    for (let key in count) {
        alert(`${key}: ${count[key]}`);
    }

참고 :

🆚 insertAdjacentHTML 과 innerHTML 차이

$cardList.innerHTML += template;
// vs
$cardList.insertAdjacentHTML("beforeend", template);
  • innerHTML

    • 요소(element) 내에 포함된 HTML 또는 XML 마크업을 가져오거나 설정합니다.
    • 새로운 node로 교체하고, 추가적으로 파싱작업을 합니다.
    • 가급적 사용을 피하는게 좋습니다.
      • HTML 문자열을 그대로 추가하는 것이기 때문에 보안상으로도 문제가 되고 파싱 작업으로 인해 성능도 떨어집니다.
  • insertAdjacentHTML

    • HTML or XML 같은 특정 텍스트를 파싱하고, 특정 위치에 DOM tree 안에 원하는 node들을 추가합니다.
    • 이미 사용중인 element 는 다시 파싱하지 않습니다.
    • element 안에 존재하는 element를 건드리지 않습니다.
    • 추가 파싱없이 기존의 DOM tree안에 node를 추가하므로 innerHTML보다 작업이 덜 들고 빠릅니다.

참고 :

🎁 CSS 속성 살펴보기

❓ transform-style: preserve-3d 은 무엇일까?

  • transform-style CSS 속성은 요소의 자식이 3D 공간에 배치되는지 또는 요소의 평면에서 병합되는지 여부를 설정합니다.
  • preserve-3d 3D 효과가 적용된 요소의 자식 요소에 3D 효과가 전달
  • 이 속성이 없다면 자식 요소에게 3D효과를 줄 수 없습니다.
  • IE 지원 X

참고 :

❓ backface-visibility: hidden 은 무엇일까?

  • ‘뒷면을 보여준다’ 라는 의미
  • 사용자의 시점에서 요소의 뒷면이 보이는지 여부를 설정하는 속성
    • 요소의 뒷면은 표시되는 앞면의 좌우반전된 이미지
    • 2D에서는 보이지 않지만 변형으로 인해 3D 공간에서 요소가 회전하면 뒷면이 보일 수 있습니다.
    • 이 속성은 원근감이 없는 2D 변환에는 영향을 주지 않습니다.

참고 :
profile
프론트엔드 개발자 장희수입니다😉

2개의 댓글

comment-user-thumbnail
2022년 12월 14일

멋있어요 희수님!!

1개의 답글