본문 바로가기
CSS

애니메이션 : 강아지 애니메이션

by 코딩 척척학사 2022. 8. 18.
728x90

강아지 애니메이션

강아지가 꼬리를 흔들며 고개를 갸웃거리는 애니메이션을 CSS로 작성해 보았습니다. 원본의 애니메이션 소스를 보고 연습한 후, 약간 수정해 보았습니다.

See the Pen dog by hjkang306 (@hjkang306) on CodePen.


CSS

다음은 해당 애니메이션의 CSS 코드입니다.

CSS코드 보기
body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    }
    
    html, body {
    background: #FFE16E;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    }
    
    *, *:before, *:after {
    box-sizing: border-box;
    position: relative;
    }
    
    .dog {
    width: 100px;
    height: 100px;
    z-index: 1;
    }
    .dog:before {
    content: "";
    display: block;
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.03);
    transform: translatey(-30%) scale(1.5);
    }
    .dog * {
    position: absolute;
    }
    
    .dog-body, .dog-head, .dog-torso {
    border-radius: 50%;
    background: white;
    position: absolute;
    width: 100%;
    height: 100%;
    }
    
    .dog-body {
    top: -50%;
    box-shadow: inset 0 -15px 0 0 #eaebec;
    animation: dog-body 200ms ease-in-out infinite alternate;
    }
    .dog-body:before {
    content: "";
    position: absolute;
    bottom: 90%;
    right: 50%;
    width: 90%;
    height: 90%;
    background: rgba(255, 255, 255, 0.4);
    border-top-left-radius: 100%;
    border-bottom-left-radius: 10%;
    border-bottom-right-radius: 10%;
    transform-origin: right bottom;
    animation: dog-tail-blur 200ms 33.3333333333ms ease-in-out infinite alternate both;
    }
    @keyframes dog-tail-blur {
    0% {
        transform: rotate(0);
        opacity: 0;
    }
    50% {
        opacity: 1;
    }
    100% {
        opacity: 0;
        transform: rotate(90deg);
    }
    }
    @keyframes dog-body {
    0% {
        transform: translatex(-10%);
    }
    100% {
        transform: translatex(10%);
    }
    }
    
    .dog-head {
    animation: dog-head 1800ms cubic-bezier(0.11, 0.79, 0, 0.99) infinite;
    }
    @keyframes dog-head {
    0% {
        transform: rotate(45deg);
    }
    33% {
        transform: rotate(-45deg);
    }
    66% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(45deg);
    }
    }
    
    .dog-torso {
    top: -20px;
    background-color: white;
    box-shadow: inset 0 -15px 0 0 #eaebec;
    animation: dog-torso 200ms ease-in-out infinite alternate-reverse;
    }
    @keyframes dog-torso {
    0% {
        transform: translatex(-5%);
    }
    100% {
        transform: tranlatex(5%);
    }
    }
    
    .dog-eyes {
    width: 60%;
    top: 55%;
    left: 20%;
    z-index: 1;
    }
    .dog-eyes:before {
    content: "";
    display: block;
    width: 50px;
    height: 60px;
    border-radius: 30px;
    background: orange;
    position: absolute;
    top: -30px;
    left: -20px;
    z-index: 0;
    border: 4px solid white;
    border-left-width: 0;
    border-bottom-width: 0;
    border-top-width: 0;
    }
    
    .dog-eye {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #000;
    z-index: 1;
    }
    .dog-eye:first-child {
    left: 0;
    }
    .dog-eye:last-child {
    right: 0;
    }
    
    .dog-muzzle {
    width: 60%;
    left: 20%;
    height: 50%;
    border-bottom-left-radius: 100%;
    border-bottom-right-radius: 100%;
    bottom: -15%;
    background-color: #fff;
    }
    .dog-muzzle:before, .dog-muzzle:after {
    content: "";
    display: block;
    position: absolute;
    }
    .dog-muzzle:before {
    width: 4px;
    height: 20px;
    bottom: 0;
    background: #eaebec;
    left: calc(50% - 3px);
    }
    .dog-muzzle:after {
    background: black;
    width: 20px;
    height: 15px;
    bottom: 12px;
    left: calc(50% - 10px);
    border-bottom-left-radius: 60% 60%;
    border-bottom-right-radius: 60% 60%;
    border-top-left-radius: 50% 40%;
    border-top-right-radius: 50% 40%;
    }
    
    .dog-ears {
    width: 40%;
    top: 25%;
    left: 30%;
    }
    
    .dog-ear {
    bottom: -10px;
    height: 50px;
    width: 50px;
    background: pink;
    }
    .dog-ear:first-child {
    right: 60%;
    border-bottom-left-radius: 50%;
    border-top-right-radius: 80%;
    box-shadow: inset -15px 15px 0 1px orange;
    transform: rotate(10deg);
    }
    .dog-ear:last-child {
    left: 60%;
    border-top-left-radius: 80%;
    border-bottom-right-radius: 50%;
    box-shadow: inset 15px 15px 0 0 orange;
    transform: rotate(-10deg);
    }
    
    .dog-tongue {
    width: 40%;
    height: 100%;
    left: calc(50% - 20px);
    z-index: -1;
    transform-origin: center top;
    }
    .dog-tongue:before {
    content: "";
    position: absolute;
    left: 8px;
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 40px;
    background: #fd3163;
    animation: dog-tongue-inner 100ms ease-in-out infinite alternate;
    }
    @keyframes dog-tongue-inner {
    from {
        transform: translatey(5%);
    }
    to {
        transform: translatey(22%);
    }
    }
    
    .dog-tail {
    width: 22px;
    height: 24.2px;
    background: white;
    bottom: 40%;
    left: calc(50% - 11px);
    border-radius: 11px;
    transform-origin: center bottom;
    }
    .dog-tail .dog-tail .dog-tail .dog-tail .dog-tail {
    background: orange;
    }
    .dog-tail .dog-tail {
    animation: dog-tail-segment 200ms ease-in-out infinite alternate;
    }
    @keyframes dog-tail-segment {
    0% {
        transform: rotate(-10deg);
    }
    100% {
        transform: rotate(10deg);
    }
    }
    
    .dog-body > .dog-tail {
    bottom: 90%;
    }

SCSS

다음은 해당 애니메이션의 SCSS 코드입니다. SCSS는 CSS를 좀 더 편하게 작성 가능하도록 발전한 언어입니다. 결과는 CSS와 같지만 문법이 조금 다릅니다. 가상 클래스 선택자는 CSS와 동일하게 사용이 가능합니다.

SCSS코드 보기
$dog-width: 100px; //css에서 변수를 선언하는 것과 같습니다. 이름에 속성을 저장합니다.
$interval: 200ms;
$color-gray: #eaebec;
$easing: ease-in-out;

//
body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
html, body {
    background: #FFE16E;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}
*, *:before, *:after {
    box-sizing: border-box;
    position: relative;
}

// dog
.dog {
    width: $dog-width;
    height: $dog-width;
    z-index: 1;
    
    &:before {  //가상요소를 속성의 안에서 설정하는 것이 css문법과의 차이점입니다. SCSS가 좀 더 편리합니다.
        content: '';
        display: block;
        position: absolute;
        width: 100%;
        height: 100%;
        border-radius: 50%;
        background: rgba(black, 0.03);
        transform: translatey(-30%) scale(1.5);
    }
    
    * {
        position: absolute;
    }
}

.dog-body, .dog-head, .dog-torso {
    border-radius: 50%;
    background: white;
    position: absolute;
    width: 100%;
    height: 100%;
}
// dog-body
.dog-body {
    top: -50%;
    box-shadow: inset 0 -15px 0 0 $color-gray;
    animation: dog-body $interval $easing infinite alternate;
    
    &:before {
        content: '';
        position: absolute;
        bottom: 90%;
        right: 50%;
        width: 90%;
        height: 90%;
        background: rgba(white, 0.4);
        border-top-left-radius: 100%;
        border-bottom-left-radius: 10%;
        border-bottom-right-radius: 10%;
        transform-origin: right bottom;
        animation: dog-tail-blur $interval $interval / 6 $easing infinite alternate both;
        
        @keyframes dog-tail-blur {
            0% {
                transform: rotate(0);
                opacity: 0;
            }
            50% {
                opacity: 1;
            }
            100% {
                opacity: 0;
                transform: rotate(90deg);
            }
        }
    }
    
    @keyframes dog-body {
        0% {transform: translatex(-10%)}
        100% {transform: translatex(10%)}
    }
}

// dog-head
.dog-head {
    animation: dog-head $interval * 9 cubic-bezier(0.11, 0.79, 0, 0.99) infinite;
    
    @keyframes dog-head {
        0% {transform: rotate(45deg)}
        33% {transform: rotate(-45deg)}
        66% {transform: rotate(0deg)}
        100% {transform: rotate(45deg)}
    }
}

// dog-torso
.dog-torso {
    top: -20px;
    background-color: white;
    box-shadow: inset 0 -15px 0 0 $color-gray;
    animation: dog-torso $interval $easing infinite alternate-reverse;
    
    @keyframes dog-torso {
    0% {transform: translatex(-5%);}
    100% {transform: tranlatex(5%);}
    }
}

// dog-eyes
.dog-eyes {
    width: 60%;
    top: 55%;
    left: 20%;
    z-index: 1;
    
    &:before {
        content:'';
        display: block;
        width: 50px;
        height: 60px;
        border-radius: 30px;
        background: orange;
        position: absolute;
        top: -30px;
        left: -20px;
        z-index: 0;
        border: 4px solid white;
        border-left-width: 0;
        border-bottom-width: 0;
        border-top-width: 0;
    }
}

.dog-eye {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #000;
    z-index: 1;

    &:first-child {
        left: 0;
    }
    &:last-child {
        right: 0;
    }
}

// dog-muzzle
.dog-muzzle {
    width: 60%;
    left: 20%;
    height: 50%;
    border-bottom-left-radius: 100%;
    border-bottom-right-radius: 100%;
    bottom: -15%;
    background-color: #fff;
    
    &:before, &:after {
        content: '';
        display: block;
        position: absolute;
    }
    
    &:before {
        width: 4px;
        height: 20px;
        bottom: 0;
        background: $color-gray;
        left: calc(50% - 3px);
    }
    
    &:after {
        background: black;
        width: 20px;
        height: 15px;
        bottom: 12px;
        left: calc(50% - 10px);
        border-bottom-left-radius: 60% 60%;
        border-bottom-right-radius: 60% 60%;
        border-top-left-radius: 50% 40%;
        border-top-right-radius: 50% 40%;
    }
}

// dog-ears
.dog-ears {
    width: 40%;
    top: 25%;
    left: 30%;
}
.dog-ear {
    bottom: -10px;
    height: 50px;
    width: 50px;
    background: pink;
    
    &:first-child { //n번째 요소를 선택하는 가상 클래스 선택자는 CSS에서와 동일하게 사용이 가능합니다.
        right: 60%;
        border-bottom-left-radius: 50%;
        border-top-right-radius: 80%;
        box-shadow: inset -15px 15px 0 1px orange;
        transform: rotate(10deg);
    }
    &:last-child {
        left: 60%;
        border-top-left-radius: 80%;
        border-bottom-right-radius: 50%;
        box-shadow: inset 15px 15px 0 0 orange;
        transform: rotate(-10deg);
    }
}
// dog-tongue
.dog-tongue {
    width: 40%;
    height: 100%;
    left: calc(50% - 20px);
    z-index: -1;
    transform-origin: center top;
    
    &:before {
        content: '';
        position: absolute;
        left: 8px;
        display: block;
        width: 100%;
        height: 100%;
        border-radius: 40px;
        background: #fd3163;
        animation: dog-tongue-inner $interval / 2 $easing infinite alternate;
        
        @keyframes dog-tongue-inner {
            from {transform: translatey(5%)}
            to {transform: translatey(22%)}
        }
    }
}

// dog-tail
.dog-tail {
    $tail-width: 22px;
    width: $tail-width;
    height: $tail-width * 1.1;
    background: white;
    bottom: 40%;
    left: calc(50% - #{$tail-width / 2});
    border-radius: $tail-width / 2;
    transform-origin: center bottom;
    
    .dog-tail .dog-tail .dog-tail .dog-tail {
        background: orange;
    }
    
    .dog-tail {
        animation: dog-tail-segment $interval $easing infinite alternate;
        
        @keyframes dog-tail-segment {
            0% {transform: rotate(-10deg)}
            100% {transform: rotate(10deg)}
        }
    }
}

.dog-body > .dog-tail {
    bottom: 90%;
}

HTML

다음은 해당 애니메이션의 HTML 코드입니다.

HTML코드 보기

<div class="dog">
    <div class="dog-body">
        <div class="dog-tail">
        <div class="dog-tail">
            <div class="dog-tail">
            <div class="dog-tail">
                <div class="dog-tail">
                <div class="dog-tail">
                    <div class="dog-tail">
                    <div class="dog-tail"></div>
                    </div>
                </div>
                </div>
            </div>
            </div>
        </div>
        </div>
    </div>
    <div class="dog-torso"></div>
    <div class="dog-head">
        <div class="dog-ears">
        <div class="dog-ear"></div>
        <div class="dog-ear"></div>
        </div>
        <div class="dog-eyes">
        <div class="dog-eye"></div>
        <div class="dog-eye"></div>
        </div>
        <div class="dog-muzzle">
        <div class="dog-tongue"></div>
        </div>
    </div>
    </div>

Pug

다음은 해당 애니메이션의 Pug 코드입니다. Pug는 HTML을 좀 더 편하게 작성 가능하도록 발전한 언어입니다. 결과는 HTML과 같지만 문법이 조금 다릅니다. Pug는 태그 형식이 아닌 클래스 명을 통해 div 박스를 생성합니다. 시작 태그와 끝나는 태그를 작성할 필요가 없어 좀 더 간편합니다. 부모/자식 요소의 구분은 탭(tab)을 통해 구분합니다. 들여쓰기 된 코드가 자식 요소가 됩니다.

Pug코드 보기
.dog
    .dog-body
        .dog-tail
            .dog-tail
                .dog-tail
                    .dog-tail
                        .dog-tail
                            .dog-tail
                                .dog-tail
                                    .dog-tail
    .dog-torso
    .dog-head
    .dog-ears
        .dog-ear
        .dog-ear
    .dog-eyes
        .dog-eye
        .dog-eye
    .dog-muzzle
        .dog-tongue
728x90

댓글


HTML이 적힌 썸네일 이미지
CSS가 적힌 썸네일 이미지
JAVASCRIPT가 적힌 썸네일 이미지

JAVASCRIPT

자세히 보기