純 CSS 實現像極了愛情

shanyuhai123發表於2019-03-28

介紹

最近突然回想到之前看過的一個動畫,是一個正方體向球體表示愛意,被拒絕,改變自己的小動畫。

找了半天終於找到了,個人感覺是一個很棒的動畫,強烈安利:

《方塊》

效果預覽

純 CSS 實現像極了愛情

github.io 瀏覽

原始碼地址

github.com/shanyuhai12…

程式碼解讀

1. 導演上場

這個動畫中存在鏡頭轉換,所以我們需要一個導演把控全域性,寫個簡單效果進行測試。

場景 love 就位,導演 director 就位,龍套們 actors 就位:

<figure class="love">
  <div class="director">
    <p class="actors">
      丙辰中秋,歡飲達旦,大醉,作此篇,兼懷子由。
      明月幾時有?把酒問青天。不知天上宮闕,今夕是何年。我欲乘風歸去,又恐瓊樓玉宇,高處不勝寒。起舞弄清影,何似在人間?
      轉朱閣,低綺戶,照無眠。不應有恨,何事長向別時圓?人有悲歡離合,月有陰晴圓缺,此事古難全。但願人長久,千里共嬋娟。
    </p>
    <p class="actors">
      紅藕香殘玉簟秋。輕解羅裳,獨上蘭舟。雲中誰寄錦書來,雁字回時,月滿西樓。
      花自飄零水自流。一種相思,兩處閒愁。此情無計可消除,才下眉頭,卻上心頭。
    </p>
  </div>
</figure>
複製程式碼

場景過於簡陋,需要美化升級一下,演員們也要稍微裝飾一下:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  position: relative;
  height: 100vh;
  width: 100vw;
  background-color: #f1f1f1;
  overflow: hidden;
}

.love {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* 不定寬高垂直居中推薦 flex,此處玩玩而已 */
  width: 800px;
  height: 500px;
  background-color: #b5bfc0;
  overflow: hidden;
}

.director {
  width: 1200px;
  height: 100%;
  border: 1px dashed red;
  display: flex;
  justify-content: space-between;
}

.actors {
  width: 45%;
  border: 1px solid purple;
}
複製程式碼

鏡頭 len 準備,導演試機:

.director {
  animation: len 5s linear .2s infinite;
}

@keyframes len {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-400px);
  }
}
複製程式碼

測試完成。

2. 豬腳 cube 登場

龍套們退場,豬腳登場。

豬腳要有玉樹凌風之姿,一米八的身高配上微微側身,先來一張豬腳的海報吸引人氣吧:

純 CSS 實現像極了愛情

<div class="director">
  <header>
    <h1 class="title">Cube</h1>
  </header>
  <section class="cube">
    <div class="cube__body">
      <div class="cube__face cube__face_front">(❁´▽`❁)</div>
      <div class="cube__face cube__face_back"></div>
      <div class="cube__face cube__face_left"></div>
      <div class="cube__face cube__face_right"></div>
      <div class="cube__face cube__face_top"></div>
      <div class="cube__face cube__face_bottom"></div>
    </div>
  </section>
</div>
複製程式碼
h1 {
  position: absolute;
  left: 100px;
  top: 100px;
  font-size: 140px;
  letter-spacing: 6px;
  color: #fff;
  user-select: none;
  text-shadow: 0 0 5px rgba(0, 0, 0, .05), 0 1px 3px rgba(0, 0, 0, .2), 0 3px 5px rgba(0, 0, 0, .2), 0 5px 10px rgba(0, 0, 0, .2), 0 10px 10px rgba(0, 0, 0, .2), 0 20px 20px rgba(0, 0, 0, .3);
}

.cube {
  position: absolute;
  left: 540px;
  --size: 180px;
  width: var(--size);
  height: var(--size);
  perspective: 600px;
}

.cube__body {
  position: relative;
  width: inherit;
  height: inherit;
  transform-style: preserve-3d;
  transform: rotateY(15deg);
}

.cube__face {
  position: absolute;
  width: inherit;
  height: inherit;
  opacity: .5;
  display: flex;
  align-items: center;
  justify-content: center;
  color: black;
  background-color: lightcyan;
  border: 2px solid #fff;
  box-shadow: inset 0 0 15px rgba(0, 0, 0, .5);
}

.cube__face_front {
  transform: rotateY(0) translate3d(0, 0, calc(var(--size) / 2));
}

.cube__face_back {
  transform: rotateY(180deg) translate3d(0, 0, calc(var(--size) / 2));
}

.cube__face_left {
  transform: rotateY(-90deg) translate3d(0, 0, calc(var(--size) / 2));
}

.cube__face_right {
  transform: rotateY(90deg) translate3d(0, 0, calc(var(--size) / 2));
}

.cube__face_top {
  transform: rotateX(90deg) translate3d(0, 0, calc(var(--size) / 2));
}

.cube__face_bottom {
  transform: rotateX(-90deg) translate3d(0, 0, calc(var(--size) / 2));
}
複製程式碼

豬腳表示它並不想吊威亞,那就放它下來吧,試鏡發現化的妝也濃了,這張海報不合格:

.love {
  display: flex;
  align-items: flex-end;
  padding-bottom: 80px;
}

.cube__face {
  box-shadow: inset 0 0 2px rgba(0, 0, 0, .5);
}
複製程式碼

重新拍一張海報,用來宣傳:

純 CSS 實現像極了愛情

這樣豬腳看起來還是眉清目秀的。

3. 替身救場

原本是計劃著豬腳兩個前滾翻進入下一場景,奈何缺乏動作指導無法實現(求一個動作指導幫幫豬腳),這時候就只能靠替身救場了。

豬腳的前滾翻:

.cube__body {
  animation: woo 2s linear forwards;
}

@keyframes woo {
  0% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(0);
  }
  5% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(0);
  }
  50% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(.25turn);
  }
  99% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(.25turn);
  }
  100% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(.25turn);
    visibility: hidden;
  }
}
複製程式碼

替身接替前滾翻:

<section class="substitute">
  <div class="substitute__body">
    <div class="cube__face cube__face_front">替身</div>
    <div class="cube__face cube__face_back"></div>
    <div class="cube__face cube__face_left"></div>
    <div class="cube__face cube__face_right"></div>
    <div class="cube__face cube__face_top"></div>
    <div class="cube__face cube__face_bottom"></div>
  </div>
</section>
複製程式碼
.substitute__body {
  animation: woo_sub 2s 1.85s linear forwards;
  visibility: hidden;
}
@keyframes woo_sub {
  1% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(0);
    visibility: hidden;
  }
  5% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(0);
    visibility: hidden;
  }
  50% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(.25turn);
    visibility: visible;
  }
  100% {
    transform-origin: 100% 100%;
    transform: rotateY(0) rotateZ(.25turn);
    visibility: visible;
  }
}
複製程式碼

鏡頭準備,再一次試鏡:

純 CSS 實現像極了愛情

場景長度不夠,等下配角們站哪裡?趕緊加點預算:

.director {
  width: 1700px;
}

@keyframes len {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-900px);
  }
}
複製程式碼

4. 配角 sphere 上場

由於導演全域性把控能力太差,所以需要分鏡頭拍攝:

.director {
  /* animation: len 6s linear .2s forwards; */
  transform: translateX(-900px);
}

.cube__body {
  /* animation: woo 2s 1s linear forwards; */
}
.substitute__body {
  /* animation: woo_sub 2s 2.85s linear forwards; */
}
複製程式碼

配角們身高一米六,化好妝後登場:

<section class="sphere__wrap">
  <div class="sphere sphere_left"></div>
  <div class="sphere sphere_right"></div>
</section>
複製程式碼
.sphere__wrap {
  position: absolute;
  bottom: 0;
  right: -840px;
  height: 320px;
  width: 450px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
}

.sphere {
  --sphere-size: 160px;
  width: var(--sphere-size);
  height: var(--sphere-size);
  border-radius:50%;
  box-shadow:
    0 3em 2.5em -2.5em rgba(53,64,73,.6),
    0 0 1em -0.35em rgba(255,255,255,.2),
    0 -1em 1.1em 0 rgba(255,255,255,.5) inset,
    0 0 2.5em 0 rgba(227,249,250,.4) inset;
  background:
    radial-gradient(circle at 33% -25%,rgba(227,249,250,0) 40%,rgba(0, 0, 0,.07) 50%),
    radial-gradient(circle at 50% 135%, rgba(0, 0, 0,.23) 43%,rgba(227,249,250,0)),
    radial-gradient(circle at 50% -35%, rgba(227,249,250,.8) 45%,rgba(227,249,250,0)),
    radial-gradient(circle at 50% 0, #fff,lightcyan);
  background-size: 150%, 100%, 100%, 100%;
}
複製程式碼

喂,身為一個演員動作要豐富,不是讓你站著當花瓶的:

.sphere_left {
  animation: move 1s ease-in forwards;
}
@keyframes move {
  to {
    transform: translateX(50px) rotate(.05turn);
  }
}
複製程式碼

還要有豐富的感情,你以為是小鮮肉面無表情就可以嗎:

.love {
  --color-love: #ed5a65;
}

.sphere_left::after {
  content: "❤";
  font-size: 42px;
  color: var(--color-love);
  position: absolute;
  top: 0;
  right: 0;
  transform: scale(0);
  animation: love_gen 1s .8s linear forwards;
}

@keyframes love_gen {
  from {
    transform: scale(0) translate(0, 0);
  }
  to {
    transform: scale(1) translate(25px, -40px) rotate(-.05turn);
  }
}
複製程式碼

OK,試鏡:

純 CSS 實現像極了愛情

看起來還不錯,下一個鏡頭。

5. 豬腳示愛

配角們的鏡頭拍完了,還需要補拍豬腳示愛的鏡頭,這時候就要展現豬腳炸裂的演技了,從示愛到心碎:

.substitute__body::after {
  content: "❤";
  font-size: 30px;
  color: var(--color-love);
  position: absolute;
  top: 0;
  right: 0;
  transform: scale(0);
  animation: love_vip 5s 4s linear forwards;
}

@keyframes love_vip {
  0% {
    transform: scale(0) translate(-100px, -200px);
  }
  10%, 80% {
    transform: scale(1) translate(-125px, -110px) rotate(-.25turn);
  }
  100% {
    content: "?";
    transform: scale(1) translate(-125px, -110px) rotate(-.25turn);
  }
}
複製程式碼

試鏡:

純 CSS 實現像極了愛情

敬業的豬腳對這個效果不滿意,要求重拍:

<span class="heart" data-text="❤"></span>
複製程式碼
.heart {
  font-size: 40px;
  color: transparent;
  position: absolute;
  top: 0;
  left: 0;
  user-select: none;
  transform: translate(50px, -50px) rotate(-.25turn) scale(0);
  animation: love_vip 5s 4s linear forwards;
}
.heart::before,
.heart::after {
  position: absolute;
  content: attr(data-text);
  top: 0;
  left: 0;
  color: var(--color-love);
}
.heart::before {
  clip-path: polygon(0 0, 60% 0, 30% 100%, 0 100%);
  animation: love_broken_left 1s 8s linear forwards;
}
.heart::after {
  clip-path: polygon(60% 0, 100% 0, 100% 100%, 30% 100%);
  animation: love_broken_right 1s 8s linear forwards;
}

@keyframes love_vip {
  0% {
    transform: scale(0) translate(50px, -50px) rotate(-.25turn);
  }
  20%, 80% {
    transform: scale(1) translate(10px, -125px) rotate(-.25turn);
  }
  100% {
    transform: scale(1) translate(30px, -125px) rotate(-.25turn);
  }
}
@keyframes love_broken_left {
  to {
    left: -.15em;
    transform: rotate(-5deg);
    top: -0.05em;
  }
}
@keyframes love_broken_right {
  to {
    left: .15em;
    transform: rotate(5deg);
    top: 0.05em;
  }
}
複製程式碼

試鏡:

純 CSS 實現像極了愛情

好了,這一幕可以過了。

6. 豬腳失戀

導演:你要充分表現這個失戀的情緒:哀傷、自閉、最後化成一堆碎片……

豬腳:我是誰,我在哪……

旁白:敬業的豬腳因完成不了導演的要求,選擇離開潛心學習表演技巧,並表示因為自己演技不夠所以不要這份報酬了……

7. 預告版

投資商作為豬腳的親爹,表示相信豬腳一定可以鍛鍊好演技,於是請了百萬後期來修整一下片子作為預告版吸引人氣,並宣稱延期釋出正式版(預告版請上翻到效果預覽處),這一部分過多修改,具體請看原始碼地址。

最後

友情提示:CSS 雖然很有意思,但還是推薦重心放在 JavaScript 上。

參考資料

  1. 取色

相關文章