『兔了个兔』——星空下的兔兔

2,030 阅读5分钟

动画.gif

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

掘友们,🐇年快乐呀!😄

这是我第一次尝试在网上发表文章,希望可以让自己在新的一年有一个好的开始,有所成长!欢迎掘友们看完文章后在评论区里提出建议,相互学习。祝掘友们在新的一年里兔飞猛进、前兔似锦、前兔无量、大展宏兔!

制作步骤

  1. 绘制兔子
  2. 绘制星空背景

绘制兔子

效果预览

首先,让我们先看下兔子的整体页面结构:

    <div class="rabbit">
      <div class="rabbit-head">
        <!-- 脸部 -->
        <div class="rabbit-face">
          <div class="rabbit-face-main"></div>
        </div>
        <!-- 耳朵 -->
        <div class="rabbit-ear rabbit-left-ear"></div>
        <div class="rabbit-ear rabbit-right-ear"></div>
        <!-- 眼睛 -->
        <div class="rabbit-eye rabbit-left-eye">
          <div class="rabbit-eye-light"></div>
        </div>
        <div class="rabbit-eye rabbit-right-eye">
          <div class="rabbit-eye-light"></div>
        </div>
        <!-- 鼻子 -->
        <div class="rabbit-nose"></div>
        <!-- 嘴巴 -->
        <div class="rabbit-mouth"></div>
      </div>
      <div class="rabbit-body" ref="rabbitBody">
        <!-- 肚子 -->
        <div class="rabbit-body-tum">
        </div>
      </div>
      <!-- 手部 -->
      <div class="rabbit-hand rabbit-left-hand"></div>
      <div class="rabbit-hand rabbit-right-hand"></div>
      <div class="rabbit-foot rabbit-left-foot">
        <i class="toe"></i>
      </div>
      <div class="rabbit-foot rabbit-right-foot">
        <i class="toe"></i>
      </div>
    </div>

其次,让我们看看兔子的样式,这也是最重要的部分:

1.绘制脸部

利用三个宽高不一的椭圆重叠在一起,绘制出一个轮廓分明的脸部;

  
.rabbit {
  width: 200px;
  height: 300px;
  position: absolute;
  transform: scale(1.8);
  z-index: 10;
  bottom: 20%;
}

.rabbit-head {
  left: 0;
  position: absolute;
  z-index: 10;
  width: 163px;
  height: 200px;
  animation: swing 3s .15s linear infinite;
}

.rabbit-head::before, .rabbit-head::after {
  position: absolute;
  top: 70%;
  content: '';
  width: 30px;
  height: 15px;
  background-color: #F19A9D;
  opacity: 0.5;
  border-radius: 50%;
  z-index: 10;
  filter: blur(3px);
}

.rabbit-head::before {
  left: 10%;
}

.rabbit-head::after {
  right: 10%;
}

.rabbit-face {
  width: 163px;
  height: 200px;
  position: absolute;
  top: 0;
}

.rabbit-face::before, .rabbit-face::after {
  position: absolute;
  content: '';
  display: inline-block;
  background-color: #ffffff;
  border: 3px solid #000000;
  filter: blur(1px);
}

.rabbit-face-main {
  position: absolute;
  left: 50%;
  top: 60px;
  transform: translateX(-50%);
  z-index: 3;
  width: 152px;
  height: 125px;
  background-color: #ffffff;
  border-radius: 50%;
}

.rabbit-face::before {
  left: 50%;
  top: 55px;
  transform: translateX(-50%);
  width: 155px;
  height: 125px;
  border-radius: 50%;
}

.rabbit-face::after {
  left: 50%;
  top: 90px;
  z-index: 1;
  transform: translateX(-50%);
  width: 163px;
  height: 110px;
  border-radius: 110px;
  border-bottom: 0;
  border-width: 2px;
}

2.绘制耳朵和眼睛

眼睛和耳朵比较简单,使用border-radius属性就可以绘制出来了;

.rabbit-ear {
  width: 40px;
  height: 80px;
  background-color: #ffffff;
  border: 4px solid #000000;
  border-bottom: none;
  border-radius: 40% 50% 40% 50% / 50% 50% 50% 50%;
  position: absolute;
  z-index: 10;
  display: flex;
  justify-content: center;
  align-items: center;
  filter: blur(0.3px);
}

.rabbit-ear::before {
  content: '';
  display: inline-block;
  width: 50%;
  height: 60%;
  background-color: #F19A9D;
  border-radius: 50% 70%;
  opacity: 0.8;
  filter: blur(1px);
}

.rabbit-left-ear {
  left: 5px;
  top: -5px;
  transform: rotate(-30deg);
}

.rabbit-right-ear {
  right: 30px;
  top: -15px;
  transform: rotate(12deg);
}

.rabbit-eye {
  width: 30px;
  height: 50px;
  position: absolute;
  z-index: 10;
  border-radius: 50%;
  background: #ffffff;
  border: 2px solid #000000;
  overflow: hidden;
  animation: blink 4s infinite;
  animation-delay: .5s;
}

.rabbit-eye::before {
  position: absolute;
  content: '';
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 20;
  width: 30%;
  height: 30%;
  background-color: #ffffff;
  border-radius: 50%;
  animation: eye-ball-blink 4s infinite;
  animation-delay: .5s;
}

.rabbit-eye-light {
  position: absolute;
  z-index: 20;
  width: 5px;
  height: 5px;
  background-color: #ffffff;
  border-radius: 50%;
  animation: eye-ball-blink 4s infinite;
  animation-delay: .5s;
}

.rabbit-eye::after {
  position: absolute;
  content: '';
  width: 100%;
  height: 80%;
  bottom: -5px;
  background: #000000;
  /* fallback for old browsers */
  background: -webkit-linear-gradient(45deg, #434343, #000000);
  /* Chrome 10-25, Safari 5.1-6 */
  background: linear-gradient(45deg, #434343, #000000);
  /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
  border-radius: 50%;
  animation: eye-ball-blink 4s infinite ease-in-out;
  animation-delay: .5s;
}

.rabbit-left-eye {
  left: 22%;
  top: 90px;
  transform: rotate(-10deg);
}

.rabbit-left-eye::after {
  left: 5px;
}

.rabbit-left-eye .rabbit-eye-light {
  right: 25%;
  bottom: 20%;
}

.rabbit-right-eye {
  right: 22%;
  top: 85px;
  transform: rotate(-5deg);
}

.rabbit-right-eye .rabbit-eye-light {
  right: 60%;
  bottom: 15%;
}

3.绘制鼻子和嘴巴

.rabbit-nose {
  position: absolute;
  z-index: 10;
  top: 140px;
  left: 50%;
  width: 8px;
  height: 8px;
  border-bottom-left-radius: 6px;
  background-color: #000000;
  opacity: 0.7;
  filter: blur(0.5px);
  transform: rotate(-60deg) skewX(-30deg) scale(1, 0.866);
}

.rabbit-nose::before, .rabbit-nose::after {
  content: "";
  position: absolute;
  background: inherit;
  width: inherit;
  height: inherit;
  border-bottom-left-radius: 6px;
}

.rabbit-nose::before {
  transform: rotate(135deg) skewY(-45deg) scale(0.707, 1.414) translate(-50%, 0);
}

.rabbit-nose::after {
  transform: rotate(-135deg) skewX(-45deg) scale(1.414, 0.707) translate(0%, 50%);
}

.rabbit-mouth {
  width: 30px;
  height: 20px;
  position: absolute;
  z-index: 10;
  top: 155px;
  left: 75px;
  filter: blur(0.6px);
}

.rabbit-mouth::before, .rabbit-mouth::after {
  content: '';
  width: 50%;
  height: 100%;
  border: 0 solid #000000;
  position: absolute;
  border-radius: 50%;
  border-bottom-width: 3px;
}

.rabbit-mouth::before {
  left: 1px;
}

.rabbit-mouth::after {
  right: 1px;
}

动画部分

/* 眨眼 */
@keyframes blink {
  100% {
    margin-top: 15px;
    height: 30px;
    border: 2px solid #000000;
    border-radius: 50% 50% 0 0/100% 100% 0 0;
    border-bottom: none;
  }
  0% {
    margin-top: 0;
    height: 50px;
    border-radius: 50%;
  }
}

/* 睁闭眼,眼球状态 */
@keyframes eye-ball-blink {
  50%,
100% {
    opacity: 0;
  }
  0% {
    opacity: 1;
  }
}

/* 摇头 */
@keyframes swing {
  10% {
    transform: rotate(15deg);
  }
  20% {
    transform: rotate(-10deg);
  }
  30% {
    transform: rotate(5deg);
  }
  40% {
    transform: rotate(-5deg);
  }
  50%,
100% {
    transform: rotate(0deg);
  }
}

/* 挥手 */
@keyframes swingHand {
  0% {
    transform: rotateZ(160deg);
  }
  100% {
    transform: rotateZ(130deg);
  }
}

一开始本来是想画一整只兔子的,奈何能力有限,无从下手,兔子的下半身实在是想不出要怎么画,后来灵机一动,想着可以把兔子放在草丛中,而草丛刚好可以遮住下半身,这样就可以不用去考虑下半身了😎。

这样,我开始在网上寻找合适的草丛图片,在寻找的过程中,也在iconfont图标库中找到几个星星和月亮图片,添加上星空作为背景,页面也不再单调了,

随机星星以及闪烁动画

 <img src="moon.png" alt="月亮" class="moon">
 <div class="sky">
 </div>
 <div class="grassland">
 </div>

通过js动态生成不同形状、不同位置的星星,并且为了不让星星闪烁频率相同,我给每一颗星星都设置了随机的动画延迟时长。

window.onload = function(){
    creatStars()
  }
  const starImgs = ['./star1.png', './star2.png', './star3.png','./star4.png']
  function randomNum(minValue, maxValue) {
      return Math.floor(Math.random() * (maxValue - minValue + 1) + minValue);
    }
  function creatStars() {
      const skyDom = document.getElementsByClassName('sky')[0];
      const fragment = document.createDocumentFragment();
      const screenW = skyDom.clientWidth;
      const screenH = skyDom.clientHeight;
      const imgLens = starImgs.length;
      for (let i = 0; i < 150; i++) {
        var span = document.createElement('span');
        var x = parseInt(Math.random() * screenW);
        var y = parseInt(Math.random() * screenH);
        var curIndex = randomNum(0, imgLens - 1);
        span.style.backgroundImage = 'url(' + starImgs[curIndex] + ')';
        span.style.left = x + 'px';
        span.style.top = y + 'px';
        var rate = Math.random() * 1.5 + 1;
        span.style.animationDelay = rate + 's';
        var scale = Math.random() * 1.5;
        span.style.transform = 'scale(' + scale + ', ' + scale + ')';
        fragment.appendChild(span);
      }
      skyDom.appendChild(fragment);
    }

这里用了drop-shadow属性给星星和月亮实现了发光效果,让场景更加生动;

@keyframes flash {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

.sky {
  width: 100%;
  height: 100%;
  background: #4b6cb7;
  /* fallback for old browsers */
  background: -webkit-radial-gradient(#3d5896, #182848);
  /* Chrome 10-25, Safari 5.1-6 */
  background: radial-gradient(#3d5896, #182848);
  /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
  position: absolute;
  z-index: 1;
  overflow: hidden;
  filter: blur(1px);
}

.sky span {
  display: inline-block;
  width: 20px;
  height: 20px;
  position: absolute;
  z-index: 1;
  animation: flash 1s ease-in-out infinite;
  filter: drop-shadow(0px 0px 10px rgb(215, 234, 131 , .5));
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: center;
}

.moon{
  position: absolute;
  top: 5%;
  right: 5%;
  width: 100px;
  height: 100px;
  z-index: 20;
  border-radius: 50%;
  filter: drop-shadow(0px 0px 10px rgb(215, 234, 131 , .5));
  /* box-shadow: 0 5px 20px rgba(251, 152, 11, .5); */
  animation: swing 1s ease-in-out infinite;
}

.grassland {
  position: absolute;
  bottom: 0;
  z-index: 100;
  background-image: url(./grassland.png);
  filter: drop-shadow(0px 0px 10px rgba(106, 241, 129, 0.5));
  background-position: center;
  background-size: 100% 100%;
  width: 100%;
  height: 60%;
}

总结

这就是我的第一篇文章,写的比较粗糙,希望后续能够多写技术文章,提高自己的写作水平,欢迎掘友们在评论区留言。

最后,祝掘友们在新的一年里工作顺心,事业有成,进账似若水,存款似山河!🚀🚀🚀