魔法少女サイト

これは、魔法少女になれなかった男の記録である。

ニートに学ぶCSS Animation演出講座 4時間目

あいさつ

f:id:yuki540com:20180503160414j:plain

どうもどうも、また会いましたね。風邪気味のyuki540です。

先日、東京に遊びに行ってきましたが体調不良により、2日で地元に帰ってしまいました。でも、めっちゃ楽しかったです!

また近々、東京にもう一回行くと思うので、今度は1週間ぐらい滞在したいです。

今回はどんな作る?

で、今回作るものですが、

↓ この花火(?)みたいな弾けた感じのものを作っていきたいと思います。

いろんなところで使えるアニメーションパターンだと思うので、ぜひ作ってみてください。

作ろう

最終的に出来上がるものはこちらになります。

はい。作っていきましょう。

マークアップ

今回は3種類の弾けるアニメーションを解説するので、.effect_type_1~.effect_type_3という風に要素を分けます。

僕はdivタグしか知らないので、クソマークアップに関しては指摘されても無視しますのでご理解ください。

<main class="stage">
  <!-- effect_type_1 -->
  <section class="effect effect_type_1">
    <div></div><div></div><div></div><div></div>
    <div></div><div></div><div></div><div></div>
  </section>
      
  <!-- effect_type_2 -->
  <section class="effect effect_type_2">
    <div></div><div></div><div></div><div></div>
    <div></div><div></div><div></div><div></div>
  </section>
      
  <!-- effect_type_3 -->
  <section class="effect effect_type_3">
    <div></div><div></div><div></div><div></div>
    <div></div><div></div><div></div><div></div>
  </section>
</main>

スタイルをあてる

まずは、土台となる.stageのスタイルをあてていきましょう。

* {
  margin: 0;
  padding: 0;
}

/**
 * stage
 */
.stage {
  position: absolute;
  width: 100%; height: 100%;
  background-color: #D3C7C0;
}
.stage:before,
.stage:after { position: absolute; content: ""; display: block; }

.stage:before {
  top: 20px; left: 20px;
  width: calc(100% - 40px); height: calc(100% - 40px);
  border: dashed 5px #635256;
  border-radius: 30px;
  box-sizing: border-box;
  opacity: 0.3;
}
.stage:after {
  width: 400px; height: 400px;
  top: calc(50% - 200px); left: calc(50% - 200px);
  border-radius: 50%;
  background-color: #635256;
}

.stage:beforeで画面の周りに破線を引いて、.stage:afterで後々アニメーションの繋ぎで使う茶色のボールを作っています。

今回の重要なのは、.effect_type_1~.effect_type_3なので、.stageは好きなように装飾してもらっても大丈夫です。

次に.effect_type_1にスタイルをあてていきます。

/**
 * effect
 */
.effect {
  position: absolute;
  width: 400px; height: 400px;
  border-radius: 50%;
  overflow: hidden;
}
.effect div {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
.effect div:after {
  content: ""; display: block;
  position: absolute;
  opacity: 0;
}
.effect div:nth-child(1) { transform: rotate(0deg);   }
.effect div:nth-child(2) { transform: rotate(45deg);  }
.effect div:nth-child(3) { transform: rotate(90deg);  }
.effect div:nth-child(4) { transform: rotate(135deg); }
.effect div:nth-child(5) { transform: rotate(180deg); }
.effect div:nth-child(6) { transform: rotate(225deg); }
.effect div:nth-child(7) { transform: rotate(270deg); }
.effect div:nth-child(8) { transform: rotate(315deg); }


/*** effect_type_1 ***/
.effect_type_1 {
  top: calc(50% - 200px); left: calc(50% - 200px);
}
.effect_type_1 div:after {
  top: 5px; left: calc(50% - 20px);
  border-top: solid 70px #635256;
  border-left: solid 20px transparent;
  border-right: solid 20px transparent;
  transform: translateY(130px);
}

.effectで共通の部分をまとめてスタイルをあてています。

400 x 400の円を作って、子要素を45degずつ回転してるだけですね。

.effect_type_1では三角形を弾けさせたので、borderで縦長の三角形を作っています。

.stage:afterで隠れている&opacity: 0;で非表示になっているので、確認しづらいでしょうがこんな感じになってます。

f:id:yuki540com:20180503172606p:plain

また、初期状態ではtranslateYで中央に子要素を寄せています。

次に.effect_type_2にスタイルをあてていきましょう。

/*** effect_type_2 ***/
.effect_type_2 {
  top: 50%; left: calc(50% - 400px);
}
.effect_type_2 div:after {
  top: 0px; left: calc(50% - 40px);
  width: 40px; height: 40px;
  background-color: #8db3b1;
  border-radius: 50%;
  transform: translateY(170px);
}

.effect_type_2は、中央から少し左下にズレた位置に配置して、弾けさせる子要素は円にしています。 f:id:yuki540com:20180503173957p:plain

次に.effect_type_3にスタイルをあてていきましょう。

/*** effect_type_3 ***/
.effect_type_3 {
  top: calc(50% - 400px); left: 50%;
}
.effect_type_3 div:after {
  top: 0px; left: calc(50% - 20px);
  width: 40px; height: 40px;
  background-color: #9994A6;
  transform: translateY(150px);
}

.effect_type_3は、中央から少し右上にズレた位置に配置して、弾けさせる子要素は四角形にしています。

f:id:yuki540com:20180503174047p:plain

これでレイアウト的には完成です。

アニメーションさせよう

では、アニメーションさせていきましょう。

/*********************************************************************************
 *  animation
 *********************************************************************************/

/*** stage ***/
.stage:after { animation: hidden-ball 0.6s ease 0s forwards; }

/*** effect_type_1 ***/
.effect_type_1 div:after {
  animation:
    fadein 0.3s ease 0.5s forwards,
    show-type-1 0.6s ease 0.5s forwards;
}

/*** effect_type_2 ***/
.effect_type_2 { animation: rotate360 4s ease 0.6s forwards; }
.effect_type_2 div:after {
  animation:
    fadein 0.3s ease 1.1s forwards,
    show-type-2 0.6s ease 1.1s forwards;
}

/*** effect_type_3 ***/
.effect_type_3 div:after {
  animation:
    fadein 0.3s ease 1.7s forwards,
    show-type-3 0.6s ease 1.7s forwards;
}


/*********************************************************************************
 *  keyframes
 *********************************************************************************/
@keyframes hidden-ball {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.4); }
  100% { transform: scale(0); }
}
@keyframes show-type-1 {
  from { transform: translateY(130px); }
  to   { transform: translateY(-75px); }
}
@keyframes show-type-2 {
  from { transform: translateY(170px); }
  to   { transform: translateY(-40px); }
}
@keyframes show-type-3 {
  from { transform: translateY(150px) rotate(0deg); }
  to   { transform: translateY(-40px) rotate(270deg); }
}

@keyframes fadein {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes rotate360 {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

単純なので説明する必要はないとは思いますが、一応説明しますと、

hidden-ballキーフレームで、.stage:afterをバイーンとした感じで画面から消します。

次にshow-type-1, fadeinキーフレームで.effect_type_1 divを弾ける感じでアニメーションさせています。(よく使いそうなキーフレームは、fadeinのように細かく分けて、カンマ区切りでanimationプロパティに適用するようにすると、色々便利です)

.effect_type_2 divも同じようにshow-type-2, fadeinキーフレームで弾けた感じでアニメーションさせますが、rotate360キーフレームで、.effect_type_2自体も回転させながら表示しています。

.effect_type_3 divは、show-type-3, fadeinキーフレームで四角形が回転しながら、弾けたアニメーションをさせています。

終わり

どうでしょう?上手く動きましたか?

上手くいかない方は、こちらのコードを参照しながらもう一度試してみてください。

さいごに

この記事を書いてる途中に気づきましたが、safariではborder-radius: 50%; overflow: hidden;をしても、円状に非表示してくれないみたいですね。

f:id:yuki540com:20180503181332p:plain

safariでは上手く動きませんが、アニメーションを作るときのヒントにでもなれば幸いです。

最後まで見てくれてありがとうございました。

できるだけ、簡単なものを作って記事に書いていく予定なので次回も見てくれると嬉しいです。

じゃーねー。

FANBOX始めました。)

f:id:yuki540com:20180503181755p:plain f:id:yuki540com:20180503181817p:plain

専門学校に入学して3ヶ月で絶望し、退学してニートになった男の話

はじめに

f:id:yuki540com:20180503150519p:plain

どーもーココロヤミ状態のyuki540です😈

ニートに学ぶCSS Animation演出講座書けよ!」って思う人もいるかもしれませんが、"Effective CSS Animation"って読み物を書いてpdfで無料配布する予定なので待っててね。

で、現在ニート(2018/04/10時点)の僕ですが、僕のことをあまり知らない人は「なんでニートなの?」「就職先はあるの?」「親は怒ってない?」「あんた頭大丈夫?」というようなことを思っている人が多いと思うので、そこらへんのことも説明しながら書いていけたらな思います。

あ、先に言っておくと、ピクシブ株式会社様から内定を頂いているので1年後にはニートを脱却します。

なんの根拠もなく、希望を持って入学した専門学校

僕は低学歴なので、大学に行く頭がなかったので専門学校に入学するわけですが、今思えばこの時点で僕にとっての悪夢は始まっていたのかもしれません。

希望を抱いていた僕は入学してすぐに、周り同級生や先輩などに「趣味でプログラム書いてる?」や「どんな言語使ってる?」「なんの技術好き?」というような質問を投げかけていました。(先輩には敬語使ってます)

でも、みんな口を濁してアニメの話(アニメ好きなのでそれはそれで楽しい)などに会話をそらされていました。

仕方ないので、学校内に開発サークルみたいな感じよくわからん集まりがあったので見学しましたが、そこでも結局、ほとんど開発していなくて過去の成果物が 当時の僕でも1時間半あれば、再現可能なwebページ でした。本当によくわからん集まりです。

この時点で僕は本当の意味で一人だということ悟りました。

※ 僕のワガママに付き合ってくれるいい友達はいます。彼にはこの場を使って感謝させていただきます。

なんのために通っているのかわからなくなった学校

入学して3ヶ月ぐらいで、ITパスポート, C言語検定 2級を取って、並行で自分の好きなコードを書いたりしていました。(それ以降、資格は取ってません)

資格対策の授業は問題集をひたすらやるような感じだったので、先生はほとんどいてもいなくてもいい状態でした。

唯一の救いだと思っていたプログラミングの授業も酷いものでした(ここでは内容は言えませんが)

上記のようなこともあり、1年生の後半から〜3年生で退学するまで、ほとんど授業を聞いていませんでした。(僕はただの悪い生徒だったので、学生の皆さんはちゃんと授業聞きましょうね)

学校の同級生達とは違うやり方でやってみる

先輩達の就職活動の季節が来ると、「内定出た」など会話が飛び交っているので話を聞いてみると、学校にコネがある会社から内定を貰っている人たちばかりでした。(その会社をディスってる訳ではありません)

ただ、その会社で働きたいから入社するのではなく、「内定出た!これで就活しなくて済む!」という人たちが大半でした。

そこで感じたのが、「この学校の雰囲気に流されたままだと、入りたい会社に行くことは夢のまた夢になってしまう」でした。

周りの同級生たちは、授業以外でプログラムを書くことはなく、資格勉強も仕方なくやっているという感じでした。

なので当時、僕は授業と資格を捨てて、自分が書きたいコードを書いて、それをネットに公開していくことを決めました。

satella.io開発の始まり & 地獄の日々 & 反撃

で、当時のものはポートフォリオには載ってませんが、「コメントが流れるチャットサイト」をcometを自前で実装して作ったり、「YouTubeプレイヤー上に絵を描けるサイト」を作ったり、niconicoAPIを利用して色々遊んでいました。

それからしばらくして、たまたまLive2Dの紹介動画(Euclidの試作版だったかな?)をみて、衝撃を受けました。

そして、「技術ってこういう使い方もできるんだ」と感じ「自分も同じようなものを作ってみたい」と思い、開発を始めたのはいい思い出です。

↓ 最初は3D技術は使わず、canvas2Dで各パーツに動きの誤差を与えながら、それっぽく動かしていました。


キャラクターをスマートフォンで動かせるサービスを作ってみた。

で、これの後継となるsatella.ioが今では学生時代の一番重要な作品となりました。(現在公開しているものはβ版ですが)

ですが、satella.ioの開発中のモチベーションは壊滅的でした。

というのも、教師達からは「君には作ることができない」「それはIT学科が作るものじゃない」「すでにそんなソフトは出回っているので作る意味はない」といった言葉をかけられきたからです。

また、周りに技術的な相談をする人もいなく、そもそも動く状態にまで持っていけるのかわからないまま開発を続けるのは非常に苦しかったです。

それでも、開発を続けられたのは「可愛いキャラをこの手で動かしてみたい」という気持ちがあったからでした。

そして、結果的に一応が動く状態にまで持っていくことができ、学校の作品発表会でも、たくさんの方から賞賛の声をいただきました。

f:id:yuki540com:20180410151042j:plain

f:id:yuki540com:20180410151055j:plain

また、僕のことを批難していた教師達もこれを機に僕の開発を褒めるようになりました。(僕の中では反撃に成功したと思っています)

インターンシップへの参加が人生のターニングポイントになった

それから先は、インターンシップに参加することを目標にし、結果的に面白法人カヤック, ドワンゴ, ピクシブインターンシップに参加しました。

今までの学校生活と違い、僕よりも圧倒的にレベルの高いインターン同期の人たちや、優秀なメンターの方々に囲まれて、何かができることに感動したことを今でも覚えています。

そして、インターンシップをきっかけにピクシブ株式会社様から内定を頂くことができ、僕にとってインターンシップへの参加が人生のターニングポイントとなりました。

その後

で、内定が出たのは嬉しいのですが、あと一年、学校に通わないといけませんでした(4年制なので)

ここ半年近く体調も良くないことと、「このまま学校に通い続ける意味はない」という結論に至り、退学し、現在ニートです。(一年後ちゃんと働きます)

親は、ちゃんと就職先も見つけて、一年分の学費も浮くので逆に喜んでくれています。(親もピクシブに入社することに大賛成しているので)

僕自身は、この一年を自分の作りたいものや活動に使っていく予定です。(最近はcss animationネタが多いですが)

伝えたかったこと

「就職するために頑張ること」が書かれた記事をちらほら見かけたので、それに乗っかり書きました。

で、伝えたかったのは "僕みたいな低学歴で学校を退学したニートでも 、周りに自分と同じ志を持った人が一人もいなくても" 夢を叶えることができるということです。

僕と同じような境遇の人で、「今の状況を変えたいけど、怖くてうまく行動できない」という人はぜひ、いっぱい何か作ったり、活動したりしてどんどん公開していってみてください。

もしかしたら、今の状況が何か変わるかもしれません。

ちょっと長くなりましたが、これが僕の専門学校入学から〜退学までのお話です。

つまんなかったかもしれませんが、最後まで読んでくれてありがとうございます!

じゃーねー。

f:id:yuki540com:20180410155837p:plain

ニートに学ぶCSS Animation演出講座 3時間目

あいさつ

f:id:yuki540com:20180503144545p:plain

ハロー、yuki540だよ!ピロリン

↑ このテンションしんどいのでやめます

改めまして、yuki540です。

前回の記事読んでくれましたか?読んでない方は、ぜひ読んでみてください。

今回はキャラクターイラストを使ったアニメーション表現を紹介できたらなと思います。

で、今回作るのものはこちら。

Twitterで「3時間目はこれにする!」って言ってたものがコロコロ変わってしまってすみません...)

WebGLっぽい立体表現を使った演出ですね。

perspective, transform-styleともに対応状況が良くなってきたので積極的に使っていい頃合いかなと思います。

f:id:yuki540com:20180318103631p:plain

(ただ今回作るもののような演出は、処理が重めなのであくまで「こういう演出もあるんだな〜」程度にみてください)

作ろう

まず、最終的に出来上がるものはこちらです。

はい。じゃあ一緒に作っていきましょう。

まず、時計から

まず、最初に↓の時計(?)から作っていきましょう。

f:id:yuki540com:20180318104743p:plain

マークアップはこんな感じになります。

<main class="stage">
  <div class="stage__inner">
    <section class="clock">
      <div class="clock__frame">
        <div></div><div></div><div></div><div></div>
        <div></div><div></div><div></div><div></div>
        <div></div><div></div><div></div><div></div>
        <div></div><div></div><div></div><div></div>
        <div></div><div></div><div></div><div></div>
        <div></div><div></div><div></div><div></div>
      </div>
      <div class="clock__hands">
        <div></div><div></div>
      </div>
      <div class="clock__image"></div>
    </section>
  </div>
  <div class="stage__filter"></div>
</main>

先に.stageにスタイルを適用してみましょう。

といってもサイズを画面全体にするだけです。単純ですね。

あと、.stage__filterbox-shadowで内側に影をつけて、回想シーンのような雰囲気を表現しています。

* {
  margin: 0;
  padding: 0;
}
.stage {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  overflow: hidden;
}
.stage__inner,
.stage__filter {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
.stage__filter { box-shadow: 0 0 300px #444 inset; }

次に時計の縁(?)の部分にスタイルを適用してみましょう。

500px x 500pxの時計を画面の中心に配置しています。

そして、縁の部分の.clock__frame divを24分割して、15deg間隔を空けながら回転させています。(24個それぞれにスタイルをあてるのはsassなりを使うべきですね...)

f:id:yuki540com:20180318112425p:plain

/**
 * clock
 */
.clock {
  position: absolute;
  top: calc(50% - 250px); left: calc(50% - 250px);
  width: 500px; height: 500px;
  background-color: rgba(100, 100, 100, 0.1);
  border-radius: 50%;
}

/*** frame ***/
.clock__frame {
  position: absolute;
  top: 20px; left: 20px;
  width: calc(100% - 40px); height: calc(100% - 40px);
}
.clock__frame:before,
.clock__frame:after {
  content: ""; display: block;
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  border: solid 1px #444;
  border-radius: 50%;
  box-sizing: border-box;
}
.clock__frame:after {
  top: 10px; left: 10px;
  width: calc(100% - 20px); height: calc(100% - 20px);
}
.clock__frame div {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
.clock__frame div:after {
  content: ""; display: block;
  position: absolute;
  top: 0; left: calc(50% - 2.5px);
  width: 5px; height: 10px;
  background-color: #444;
}
/* 24分割して回転 --------------------------------------- */
.clock__frame div:nth-child(1)  { transform: rotate(0deg); }
.clock__frame div:nth-child(2)  { transform: rotate(15deg); }
.clock__frame div:nth-child(3)  { transform: rotate(30deg); }
.clock__frame div:nth-child(4)  { transform: rotate(45deg); }
.clock__frame div:nth-child(5)  { transform: rotate(60deg); }
.clock__frame div:nth-child(6)  { transform: rotate(75deg); }
.clock__frame div:nth-child(7)  { transform: rotate(90deg); }
.clock__frame div:nth-child(8)  { transform: rotate(105deg); }
.clock__frame div:nth-child(9)  { transform: rotate(120deg); }
.clock__frame div:nth-child(10) { transform: rotate(135deg); }
.clock__frame div:nth-child(11) { transform: rotate(150deg); }
.clock__frame div:nth-child(12) { transform: rotate(165deg); }
.clock__frame div:nth-child(13) { transform: rotate(180deg); }
.clock__frame div:nth-child(14) { transform: rotate(195deg); }
.clock__frame div:nth-child(15) { transform: rotate(210deg); }
.clock__frame div:nth-child(16) { transform: rotate(225deg); }
.clock__frame div:nth-child(17) { transform: rotate(240deg); }
.clock__frame div:nth-child(18) { transform: rotate(255deg); }
.clock__frame div:nth-child(19) { transform: rotate(270deg); }
.clock__frame div:nth-child(20) { transform: rotate(285deg); }
.clock__frame div:nth-child(21) { transform: rotate(300deg); }
.clock__frame div:nth-child(22) { transform: rotate(315deg); }
.clock__frame div:nth-child(23) { transform: rotate(330deg); }
.clock__frame div:nth-child(24) { transform: rotate(345deg); }

次に長針と短針と時計の中央に配置する画像にスタイルをあてていきましょう。

.clock__hands div:nth-child(1)(長針)が高さ50%で、.clock__hands div:nth-child(2)(短針)が高さ40%にしています。

.clock__imageは、時計の中央に配置する画像ですね。100% - 90px(410px)という大きさにしています。

f:id:yuki540com:20180318113820p:plain

画像は、お好みのものを用意してください。

/*** hands ***/
.clock__hands {
  position: absolute;
  top: 35px; left: 35px;
  width: calc(100% - 70px); height: calc(100% - 70px);
}
.clock__hands div {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
.clock__hands div:after {
  content: ""; display: block;
  position: absolute;
  top: 0; left: calc(50% - 5px);
  width: 10px;
  background-color: #444;
  border-radius: 5px;
}
.clock__hands div:nth-child(1):after { height: 50%; }
.clock__hands div:nth-child(2):after { height: 40%; top: 10%; }

/*** image ***/
.clock__image {
  position: absolute;
  top: 45px; left: 45px;
  width: calc(100% - 90px); height: calc(100% - 90px);
  background-image: url(/* お好きな画像を指定 */);
  background-size: auto 100%;
  background-position: center;
  background-repeat: no-repeat;
}

このままだと、止まったままなので時計っぽくありませんね。(特に画像を重ねているので)

なので、時計の針を動かしていきましょう。

.clock__hands:nth-child(2)(短針)が360deg.clock__hands:nth-child(1)(長針)が360 * 12 = 4320deg回転するようにします。(これよりいい方法がありますが脳死でいきます)

時計なので、イージングにはlinear(一定のスピードでアニメーション)を使っています。

/*********************************************************************************
  animation
*********************************************************************************/
.clock__hands div:nth-child(1) { animation: rotate4320 30s linear 0s infinite; }
.clock__hands div:nth-child(2) { animation: rotate360 30s linear 0s infinite; }

/*********************************************************************************
  keyframes
*********************************************************************************/
@keyframes rotate360 {
  from { transform: rotate(0deg); }   
  to   { transform: rotate(360deg); }   
}
@keyframes rotate4320 {
  from { transform: rotate(0deg); }
  to   { transform: rotate(4320deg); }
}

どうでしょうか?

↓のような時計ができましたか?できましたね。はい。次。

次に行く前に一旦、.clockdisplay:noneしておいてください。

回想シーンパネルのようなもの

f:id:yuki540com:20180318121027p:plain

次は↑の円状の回想シーンのパネルのようなものを作っていきましょう。

まず、↓のマークアップを追加してください。

<main class="stage">
  <div class="stage__inner">
    <section class="clock"><!-- 省略 --></section>

    <!-- 追加: ここから -->
    <section class="memories memories_layer_1">
      <div class="memories__image memories__image_type_1"></div>
      <div class="memories__frame"></div>
    </section>
    <section class="memories memories_layer_2">
     <div class="memories__image memories__image_type_2"></div>
     <div class="memories__frame"></div>
    </section>
    <section class="memories memories_layer_3">
      <div class="memories__image memories__image_type_3"></div>
      <div class="memories__frame"></div>
    </section>
    <section class="memories memories_layer_4">
      <div class="memories__image memories__image_type_4"></div>
      <div class="memories__frame"></div>
    </section>
    <section class="memories memories_layer_5">
      <div class="memories__image memories__image_type_5"></div>
      <div class="memories__frame"></div>
    </section>
    <!-- 追加: ここまで -->
      
  </div>
  <div class="stage__filter"></div>
</main>

先に縁の部分を作っていきましょう。

.memoriesの大きさは.clockと同様に500px x 500pxです。

ここでは一旦、.memories__image_type_2 ~ .memories__image_type_5display:noneで非表示にします(重なってしまって、これからデザインが確認しづらいため)

縁部分の内側(.memories__frame:before)が通常の線で、外側(.memories__frame:after)が波のような滑らかな線にしていきます。

f:id:yuki540com:20180318122301p:plain

滑らかな線は、border-topborder-bottomのような2点だけを指定するできます。

/**
 * memories
 */
.memories {
  position: absolute;
  top: calc(50% - 250px); left: calc(50% - 250px);
  width: 500px; height: 500px;
}

/*** 一旦、.memories__image_type_1だけを表示 ***/
.memories__image_type_2,
.memories__image_type_3,
.memories__image_type_4,
.memories__image_type_5 { display: none; }

/*** frame ***/
.memories__frame {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
.memories__frame:before,
.memories__frame:after {
  content: ""; display: block;
  position: absolute;
  border-radius: 50%;
  box-sizing: border-box;
}
.memories__frame:before {
  top: 25px; left: 25px;
  width: calc(100% - 50px); height: calc(100% - 50px);
  border: solid 1px #444;
}
.memories__frame:after {
  top: 0; left: 0;
  width: 100%; height: 100%;
  border-top: solid 10px #444;
  border-bottom: solid 10px #444;
}

次にパネルの画像にスタイルをあてていきます。

ちょっと透明にしているのは、あとでレイヤー間を通り過ぎる感覚をより際立たせるためです。

あと、内側にbox-shadowで影をつけて回想シーン感をまた出します。

f:id:yuki540com:20180318123526p:plain

画像はお好みのものを。

/*** image ***/
.memories__image {
  position: absolute;
  top: 50px; left: 50px;
  width: calc(100% - 100px); height: calc(100% - 100px);
  border-radius: 50%;
  background-size: cover;
  background-position: center;
  opacity: 0.8;
}
.memories__image:after {
  content: ""; display: block;
  position: absolute;
  width: 100%; height: 100%;
  border-radius: 50%;
  box-shadow: 0 0 40px #333 inset;
}
.memories__image_type_1 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_2 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_3 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_4 { background-image: url(/* お好きな画像を指定 */); }
.memories__image_type_5 { background-image: url(/* お好きな画像を指定 */); }

このままだとつまらないので、滑らかな線(memories__frame:after)を回転させましょう。

キーフレームはrotate360を使い回しましょう。

.memories__frame:after { animation: rotate360 3.5s linear 0s infinite; }

ここまできたら、.clock.memories__image_type_2 ~ .memories__image_type_5display:noneを消してください。

立体空間をすり抜ける

最後にお待ちかねの立体空間をすり抜けるようなアニメーションですが、それを実現するためにperspectivetransform-styleを使います。

perspectiveは、"ユーザの視点" から "コンテンツ(要素)"の距離を指定することができます。

なので、対象の要素が傾いていた場合、perspectiveの値が小さければ小さいほど傾きが大きく、perspectiveの値が大きければ大きいほど傾きが小さくなります。

詳しくはこちら

f:id:yuki540com:20180318130014p:plain

transform-styleは、親要素の傾きに対して、子要素は3D空間の位置を保持するかを指定できます。

デフォルトではflatですが、preserve-3dにするとパララックス効果(視差効果)を出すことができます。

で、まず視点の基準として.stageperspectiveを指定し、各3D空間に配置する要素の親要素である.stage__innertransform-styleを指定します。

.stage { perspective: 20px; }
.stage__inner { transform-style: preserve-3d; }

次に.clock.memories_layer_1 ~ .memories_layer_5を3D空間の位置に配置しましょう。

translateZ100px間隔を空けながら、3D空間に配置していきます。

f:id:yuki540com:20180318132836p:plain

translateZを指定すると、perspectiveの値により、本来より大きくなったり小さくなったりするので、ある地点で本来の大きさになるようにscaleで調整します。

.clock { transform: translateZ(50px) scale(calc(1 - (50 / 100))); }
.memories_layer_1 { transform: translateZ(150px) scale(calc(1 - (150 / 200))); }
.memories_layer_2 { transform: translateZ(250px) scale(calc(1 - (250 / 300))); }
.memories_layer_3 { transform: translateZ(350px) scale(calc(1 - (350 / 400))); }
.memories_layer_4 { transform: translateZ(450px) scale(calc(1 - (450 / 500))); }
.memories_layer_5 { transform: translateZ(550px) scale(calc(1 - (550 / 600))); }

あとは"ユーザの視点"を行ったり来たりするためにcameraキーフレームを使います。

行き来するのは、cameraキーフレームを0% ~ 100%100% ~ 0%にするだけなので、キーフレームをカンマで区切り、reverseオプションで100% ~ 0%にすることができます。

あとswayキーフレームで斜めに揺らして、より立体感と浮遊感を表現しています。

f:id:yuki540com:20180318133700p:plain

/*********************************************************************************
  animation
*********************************************************************************/
.stage {
  animation:
    camera 8s ease-in-out 0s forwards,
    camera 4s ease 8s reverse forwards;
}
.stage__inner { animation: sway 0.7s ease-in-out 0s alternate infinite; }

/*********************************************************************************
  keyframes
*********************************************************************************/
@keyframes camera {
  from { perspective: 20px; }
  to   { perspective: 600px; }
}
@keyframes sway {
  from { transform: translate(3px, 3px); }
  to   { transform: translate(-3px, -3px); }
}

これで完成したはずです。

記述ミスや記述漏れがあるかもしれませんので、完成したコードはこちらにありますのでご確認ください。

さいごに

今回はperspectiveを使った演出を解説しましたが、いかがでしたでしょうか?

立体的に見せるだけで表現の幅がかなり広がりましたね。

また、今回の回想シーンのような表現にも注目して欲しいなと思います。対象の作品(今回はリゼロ)の雰囲気をいかに出せるかがキャラクターイラストを使った演出のキモだと僕は思います。

ですが、実際のページで使うには、まだパフォーマンスが良くないのでWebGLでの演出なんかの参考になれば幸いです。

次回も何か面白いアニメーションを用意するので、よければ見てください。

じゃーねー

f:id:yuki540com:20180318134559p:plain

ニートに学ぶCSS Animation演出講座 2時間目

あいさつ

f:id:yuki540com:20180503144631p:plain

ハロー、yuki540だよ!ピロリン

みんな、前回の記事は見てくれたかな?

見てない人は、ぜひ見て実践してみてね!

さてと、じゃあ今回は何をするか説明するね。

今回作るのは、こちら!!!

前回より長めのアニメーションだね。

あと、画面を広く使っているところと画像を一切使ってないところにも注目してほしいな。

これは、yuki540.com_version4.0.0の「共依存」でも使った演出だよ!

実は、一部「東京喰種:re テレビcm」のアニメーションを参考にしてるよ!


東京喰種:re 1巻テレビCM

自分でアニメーション演出を考えるときは、自分の好きな動画なんかから動かし方のヒントをもらうのがおすすめだよ!(僕の場合は、アニメopとかMADからヒントをもらってるよ!)

今回は、コードがちょっと多くなるから、しんどいかもしれないけど頑張って!

それでは、早速やっていきまーしょう!

やっていきまーしょう!

まず完成したものを見たいと思うので、完成品はこちら。(PCを想定して作っているのでPCで見てね)

見ましたね?はい、じゃあエディタを立ち上げて一緒にコードを書きましょう!

今回のアニメーションは#prologue#episode-1っていう風に物語っぽい感じにパートを区切ってます。

prologue

まずは、#prologueから作っていきましょう。

マークアップ

まずはマークアップからしてみましょう。

<main id="stage">
  <section id="prologue">
    <div class="word-1">
      <div><p></p></div>
      <div><p></p></div>
      <div><p></p></div>
      <div><p></p></div>
    </div>
    <div class="word-2">
      <div><p></p></div>
      <div><p></p></div>
      <div><p></p></div>
    </div>
    <div class="connect-line">
      <div class="line line-1"></div>
      <div class="line line-2"></div>
      <div class="point point-1"></div>
      <div class="point point-2"></div>
      <div class="point point-3"></div>
    </div>
  </section>
</main>

表示するテキストはお好きなものを!

ちょっと今回コードが多いので細かい説明は省きます...

スタイル

html, body {
  margin: 0;
  padding: 0;
}
p { margin: 0; }

#stage {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  min-width: 1100px; min-height: 650px;
  overflow: hidden;
}

/**
 * #prologue
 */
#prologue {
  position: absolute;
  top: 0; left: 0;
  width: 200%; height: 100%;
}


/*** 共通: .word-1, .word-2 ***/
#prologue .word-1,
#prologue .word-2 {
  position: absolute;
  top: calc(50% - 60px);
  height: 120px;
}
#prologue .word-1 div,
#prologue .word-2 div {
  float: left;
  width: 120px; height: 120px;
  border: dashed 1px #888;
  border-right: none;
  box-sizing: border-box;
}
#prologue .word-1 div p,
#prologue .word-2 div p {
  width: 100%; height: 100%;
  font-size: 80px;
  color: #777;
  text-align: center;
  line-height: 120px;
  opacity: 0;
}
#prologue .word-1 div:last-child,
#prologue .word-2 div:last-child { border-right: dashed 1px #888; }
#prologue .word-1:after,
#prologue .word-2:after {
  content: ""; display: block; clear: both;
}

/*** .word-1 ***/
#prologue .word-1 { left: calc(25% - 240px); }

/*** .word-2 ***/
#prologue .word-2 { right: 80px; }


/*** .connect-line ***/
#prologue .connect-line {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
#prologue .connect-line .point {
  position: absolute; top: calc(50% + 90px);
  width: 20px; height: 20px;
  background-color: #666;
  border-radius: 50%;
}
#prologue .connect-line .point-1 { left: calc(25% - 250px); }
#prologue .connect-line .point-2 { left: calc(25% + 230px); }
#prologue .connect-line .point-3 { right: 70px; transform: scale(0); }

#prologue .line {
  position: absolute;
  top: calc(50% + 99px);
  height: 1px;
  overflow: hidden;
}
#prologue .line:after {
  content: ""; display: block;
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background-color: #666;
  transform: translateX(-100%);
}
#prologue .line-1 { width: 480px; left: calc(25% - 240px); }
#prologue .line-2 {
  width: calc(((50% - 480px) / 2) + (50% - 80px));
  right: 80px;
}

flexじゃなく、癖でfloat使っちゃうので「floatなんて使いたくない」って方はflexなりを使ってください。

↓ 実際にこんな風にレイアウトが組まれるようになっています。

左側

f:id:yuki540com:20180303205302p:plain

右側

f:id:yuki540com:20180303205312p:plain

注目してほしいところは

  • #prologuewidth200%であること
  • .line:after(擬似要素)が設定されていること

の2点です。

アニメーション

では、アニメーションをつけていきましょう。

/*** .word-1 ***/
#prologue .word-1 div:nth-child(1) p { animation: show-word 0.6s ease-out 0.0s forwards; }
#prologue .word-1 div:nth-child(2) p { animation: show-word 0.6s ease-out 0.2s forwards; }
#prologue .word-1 div:nth-child(3) p { animation: show-word 0.6s ease-out 0.4s forwards; }
#prologue .word-1 div:nth-child(4) p { animation: show-word 0.6s ease-out 0.6s forwards; }

/*** .line-1 ***/
#prologue .line-1:after { animation: draw-line 1.2s ease 0s forwards; }

/*** #prologue: ここで右側に移動する ***/
#prologue { animation: move-prologue 0.8s ease 1.2s forwards; }

/*** .line-2 ***/
#prologue .line-2:after { animation: slash-line 1.6s ease 1.2s forwards; }

/*** .point-3 ***/
#prologue .point-3 { animation: put-point 1s ease-out 2s forwards; }

/*** .word-2 ***/
#prologue .word-2 div:nth-child(1) p { animation: show-word 0.6s ease-out 1.6s forwards; }
#prologue .word-2 div:nth-child(2) p { animation: show-word 0.6s ease-out 1.8s forwards; }
#prologue .word-2 div:nth-child(3) p { animation: show-word 0.6s ease-out 2.0s forwards; }

/*** .word-2: ここで次のパートに繋ぐための回転 ***/
#prologue .word-2 { animation: rotate-word-2 0.4s ease 2.6s forwards; }

/*********************************************************************************
  keyframes
**********************************************************************************/
@keyframes show-word {
  0%   { transform: scale(0.4); opacity: 0; }
  70%  { transform: scale(1.05); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes draw-line {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(0%); }
}
@keyframes slash-line {
  0%   { transform: translateX(-100%); }
  50%  { transform: translateX(0%); }
  100% { transform: translateX(100%); }
}
@keyframes move-prologue {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}
@keyframes put-point {
  0%   { transform: scale(0); }
  70%  { transform: scale(2); }
  100% { transform: scale(0); }
}
@keyframes rotate-word-2 {
  0%   { transform: rotate(0deg); opacity: 1; }
  100% { transform: rotate(-90deg); opacity: 0; }
}

はい...泥臭い書き方になってきましたね...

そうなんです。css animation自体が今回のような長めのアニメーションを作るための機能でないため、どうしてもコードが煩雑になってしまいます。

僕はこの煩雑なコーディングを「丹精込めた手打ちkeyframes」と呼んでいます。

で、解説しますと、

まず、.word-1show-wordで0.2秒間隔を開けながら、アニメーションします。

f:id:yuki540com:20180304110155p:plain

それと同時に.word-1の下にある.line-1draw-lineで0.8秒かけながらアニメーションします。

ここで.line-1で線を引くのにwidthを変更せずに.line-1:aftertranslateXで右側に移動させることで線を引いているように見せているのは描画コストを下げるためです。

f:id:yuki540com:20180304103514p:plain

次に#prologue自体をmove-prologueで右側に移動させます。

これも同様にtranslateXを使ってできるだけ描画コストを下げます。

このようなダイナミックな画面移動が画面を広く使ったアニメーション演出をより盛り上げてくれます。

f:id:yuki540com:20180304105240p:plain

#prologueが移動すると同時に.line-2slash-lineでアニメーションさせます。

draw-lineと違い、translateX(-100%) ~ translateX(100%)で通り過ぎています。

通り過ぎることで、.point-3put-pointアニメーションに吸い込まれているような表現になります。

f:id:yuki540com:20180304111607p:plain

次は、word-1と同様に.word-2show-wordで0.2秒間隔を開けながらアニメーションさせます。

あとは、.word-2rotate-word-2で-90度回転させれば、prologueのパートは完成です。

episode-1

次は、#episode-1をやっていきましょう。

マークアップ

<main id="stage">
  <section id="prologue"><!-- 省略 --></section>
  <!-- ここから -->
  <section id="episode-1">
    <div class="message-panel">
      <div class="message">
        <p class="char"></p>
        <p class="char"></p>
        <p class="char"></p>
        <small class="text">ハロー、ミライアカリだよ!ピロリン</small>
      </div>
      <div class="message">
        <p class="char"></p>
        <p class="char"></p>
        <p class="char"></p>
        <p class="char"></p>
        <small class="text">CSS Animation演出講座、みんなも受けてね!</small>
      </div>
      <div class="message">
        <p class="char"></p>
        <p class="char"></p>
        <p class="char"></p>
        <p class="char"></p>
        <small class="text">それでは、やっていきまーしょう!</small>
      </div>
    </div>
  </section>
  <!-- ここまで -->
</main>

上記のものを追加してください。(これもテキストはお好きなものを)

スタイル

/**
 * episode-1
 */
#episode-1 {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
#episode-1 .message-panel {
  position: absolute;
  top: calc(50% - 180px); right: 80px;
  width: 360px; height: 360px;
  transform: rotate(90deg);
}
#episode-1 .message-panel .message {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}
#episode-1 .message-panel .message .char {
  float: left;
  width: 170px; height: 170px;
  font-size: 150px;
  color: #333;
  text-align: center;
  line-height: 170px;
  opacity: 0;
}
#episode-1 .message-panel .message .char:nth-child(1),
#episode-1 .message-panel .message .char:nth-child(2) { margin-bottom: 20px; }
#episode-1 .message-panel .message .char:nth-child(2n-1) { margin-left: 20px; }
#episode-1 .message-panel .message .text {
  position: absolute;
  top: 165px; left: 40px;
  width: 320px; height: 30px;
  display: block;
  font-size: 14px;
  color: #555;
  line-height: 30px;
  opacity: 0;
}
#episode-1 .message-panel .message:after {
  content: ""; display: block;
  position: absolute;
  top: 0; left: 0;
  width: 15px; height: 100%;
  background-color: #5D97BD;
  opacity: 0;
}

レイアウトは以下のように組まれます。

f:id:yuki540com:20180304114622p:plain

特に説明することがないので、スタイルの説明は省きます。

アニメーション

/*** .message-panel ***/
#episode-1 .message-panel {
  animation:
    rotate-message-panel 0.7s ease 2.6s forwards,
    move-left-message-panel 0.5s ease 3.6s forwards,
    move-right-message-panel 0.5s ease 4.7s forwards;
}

/*** .message:nth-child(1):after ***/
#episode-1 .message-panel .message:nth-child(1):after {
  animation: show-bar 0.5s ease 2.8s forwards; }

/*** .char ***/
#episode-1 .message-panel .message:nth-child(1) .char:nth-child(1) {
  animation: show-char 0.35s ease 2.8s forwards; }
#episode-1 .message-panel .message:nth-child(1) .char:nth-child(2) {
  animation: show-char 0.35s ease 2.9s forwards; }
#episode-1 .message-panel .message:nth-child(1) .char:nth-child(3) {
  animation: show-char 0.35s ease 3.0s forwards; }

/*** .text ***/
#episode-1 .message-panel .message:nth-child(1) .text {
  animation: show-text 0.5s ease 3.1s forwards; }

/*** .message:nth-child(1) ***/
#episode-1 .message:nth-child(1) { animation: fadeout 0.5s ease 3.6s forwards; }

/*** .message:nth-child(2):after ***/
#episode-1 .message-panel .message:nth-child(2):after {
  animation: show-bar 0.5s ease 3.8s forwards; }

/*** .char ***/
#episode-1 .message-panel .message:nth-child(2) .char:nth-child(1) {
  animation: show-char 0.35s ease 3.8s forwards; }
#episode-1 .message-panel .message:nth-child(2) .char:nth-child(2) {
  animation: show-char 0.35s ease 3.9s forwards; }
#episode-1 .message-panel .message:nth-child(2) .char:nth-child(3) {
  animation: show-char 0.35s ease 4.0s forwards; }
#episode-1 .message-panel .message:nth-child(2) .char:nth-child(4) {
  animation: show-char 0.35s ease 4.1s forwards; }

/*** .text ***/
#episode-1 .message-panel .message:nth-child(2) .text {
  animation: show-text 0.5s ease 4.2s forwards; }

/*** .message:nth-child(2) ***/
#episode-1 .message:nth-child(2) { animation: fadeout 0.5s ease 4.7s forwards; }

/*** .message:nth-child(3):after ***/
#episode-1 .message-panel .message:nth-child(3):after {
  animation: show-bar 0.5s ease 4.9s forwards; }

/*** .char ***/
#episode-1 .message-panel .message:nth-child(3) .char:nth-child(1) {
  animation: show-char 0.35s ease 4.9s forwards; }
#episode-1 .message-panel .message:nth-child(3) .char:nth-child(2) {
  animation: show-char 0.35s ease 5.0s forwards; }
#episode-1 .message-panel .message:nth-child(3) .char:nth-child(3) {
  animation: show-char 0.35s ease 5.1s forwards; }
#episode-1 .message-panel .message:nth-child(3) .char:nth-child(4) {
  animation: show-char 0.35s ease 5.2s forwards; }

/*** .text ***/
#episode-1 .message-panel .message:nth-child(3) .text {
  animation: show-text 0.5s ease 5.3s forwards; }

/********************************************************************************
  keyframes
*********************************************************************************/
@keyframes fadeout {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes fadein {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes rotate-message-panel {
  0%   { transform: rotate(90deg); }
  60%  { transform: rotate(-5deg); }
  100% { transform: rotate(0deg); }
}
@keyframes show-char {
  0%   { transform: translateX(100px); opacity: 0; }
  100% { transform: translateX(0); opacity: 1; }
}
@keyframes show-text {
  0%   { transform: translateX(-100px); opacity: 0; }
  100% { transform: translateX(0); opacity: 1; }
}
@keyframes show-bar {
  0%   { width: 300px; opacity: 0; }
  100% { width: 15px; opacity: 1; }
}
@keyframes move-left-message-panel {
  0%   { right: 80px; }
  100% { right: calc(100% - 450px); }
}
@keyframes move-right-message-panel {
  0%   { right: calc(100% - 450px); }
  100% { right: 80px; }
}

さっきから意味不明なキーフレーム名ですが、単に僕の英語力と英単語のバリエーションがないだけなので、自分でお好きなキーフレーム名を設定していただいて大丈夫です...

で、解説しますと、

まず、.message-panelrotate-message-panelで前のパートの回転を引き継いでいるように見せます。

f:id:yuki540com:20180304122905p:plain

で、.message-panelに複数のキーフレームをカンマ区切りで指定していますね。

実は、animationプロパティは複数のキーフレームを適用することができます。

これを使うことでアニメーションを繋げていくこともできますし、複数のキーフレームを同時に適用することもできます。

回転しながら、.message:aftershow-barでアニメーションさせ、.charshow-charで0.1秒間隔を空けながらアニメーションさせます。

その次に.textshow-textで0.5秒かけてアニメーションします。

↓ 言葉で説明するのが難しいですが、こんな感じになります。

回転しすぎて、バウンドしているようにみせることで、より気持ちのいいアニメーションになります。

後は、.message-panelmove-left-message-panelで左側に移動させながら、.message:nth-child(1)fadeoutで非表示して、.message:nth-child(2)側にアニメーションを引き継がせるだけです。

さっきと同じ書き方なので説明は省きます。

違いは、.message-panelが移動しているだけです。

終わり。

どうでしょうか?動きましたか?

コードが多めなのに説明が雑ですみません...

完成したコードはこちらにあるので、うまくいかない方はご覧ください。

おわりに

今回も説明が下手 & 説明が雑で読みづらかったと思いますが、最後までみてくださりありがとうございました。

画面を広く使うことでアニメーションに迫力が出ることと、画像を使わなくても楽しい表現ができることがちょっとでも伝わってくれたなら幸いです。

これからも毎週日曜更新で続けていきますので、よかったらまたみてください。

じゃーねー!

f:id:yuki540com:20180304131107j:plain

ニートに学ぶCSS Animation演出講座 1時間目

あいさつ

f:id:yuki540com:20180503144733p:plain

ほんとはミライアカリになりきって、記事書きたかったんですが怒られそうだったんでやめます ↓

f:id:yuki540com:20180225031307p:plain

ニートに教わっても面白くないと思うので、僕のことを美少女だと思い込んで講座を受けてください。

はい。改めまして。

ハロー、yuki540だよ!ピロリン

結構、需要があったみたいなので今回から僕が今まで作ったcss animation作品の演出パターンを解説していくよ!

ホントにやってることは単純でcssの初歩的な知識で再現できるものなので、みんななら10秒あれば理解できると思います!

この講座では、sassとかpugは使わず、あくまで素のhtml, cssを使っていきます。

それでは、早速やっていきまーしょう!

今回のアニメーション

↑ 今回は僕がよく使う演出の「スライドショーのようなアニメーション」を解説していきます。

これは、共依存でも使った演出で、シンプルかつ応用がきくパターンだと思うのでぜひ、試しに一緒に作って見てください。

解説

まず、完成したものを実際に見たいかと思うので、最終的に出来上がるものはこちらです。

はい。見ましたね。 さあ、エディタを立ち上げて一緒にコード書きましょう!

マークアップしよう

まずは、土台となるマークアップから。

<main id="root">
  <div id="screen">
    <section class="images">
      <div class="image"></div>
      <div class="image"></div>
      <div class="image"></div>
      <div class="image"></div>
    </section>
    <section class="paint"></section>
  </div>
</main>

いたって単純ですね。(#rootは正直いらないけど癖で書きます)

で、これを大まかに分けると

#screenがスライドショーの土台

.imagesが画像一覧の要素

.paintが最初にスライドショー全体に覆いかぶせる要素

です。(説明が下手で申し訳ない)

スタイルをあてよう

マークアップが終わったら、次はスタイルを当てていきましょう。

最初に#root#screenから。

html, body {
  margin: 0;
  padding: 0;
}
#root {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  min-width: 1100px; min-height: 650px;
  background-color: #eee;
}

#screen {
  position: absolute;
  left: calc(50% - 330px);
  top: calc(50% - 235px);
  width: 650px; height: 450px;
  background-color: #fff;
  border: solid 10px #fff;
  box-shadow: 0 0 20px #444;
  overflow: hidden;
}

全体の外枠の#rootを画面全体にして、#screenが中央にくるようにスタイルを当てます。

calc使いたくないよ!」って方は、left: 50%; margin-left: -330px;などで代用してください。

次に画像一覧のスタイル

.images {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
}

.images .image {
  position: absolute;
  top: 0; left: 0;
  width: 0%; height: 100%;
  overflow: hidden;
}
.images .image:after {
  content: "";
  display: block;
  position: absolute;
  top: 0; left: 0;
  width: 650px; height: 450px;
  background-size: cover;
  background-position: center;
}
.images .image:nth-child(1):after { background-image: url(./images/1.png); }
.images .image:nth-child(2):after { background-image: url(./images/2.png); }
.images .image:nth-child(3):after { background-image: url(./images/3.png); }
.images .image:nth-child(4):after { background-image: url(./images/4.png); }

4枚の画像は自分のお気に入りのものを使ってね!

.images自体は#screenのサイズに合わせるだけですが、注目してほしいのは

  • .imagewidth0%であること

  • .imageoverflow: hiddenがあてられていること

  • .image:afterのサイズ指定が%ではなくpxで数値を固定していること

この3点です。

今回のスライドショーのように中身の画像の形を保持したままwidthを変更していくには、.imageの子要素(めんどくさかったので擬似要素で代用)である.image:afterwidthを固定させる必要があります。

仮に%指定でスタイルをあてると、親要素(.image)のwidthに合わせようとするので、親要素(.image)のwidthが変更されるたびに子要素(.image:after)の画像が動いているように見えてしまいます。

%指定の場合

f:id:yuki540com:20180225101922p:plain

px指定の場合

f:id:yuki540com:20180225102106p:plain

で、px指定するだけでは、親要素より子要素が大きい場合、はみ出て表示されるのでoverflow: hiddenをあてる必要があるということになります。

次に.paintのスタイル

.paint {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background-color: #444;
}

終わり。.paintは最初、全体に覆いかぶせるだけなので。

アニメーションをあてる

下準備は済んだので、お待ちかねのアニメーションをあてていきましょう!

皆さんは@keyframes {}animationの使い方と書き方は知っているでしょうか?

知っている人が多いと思いますが、一応、簡単に説明しますね。

css animationは単純な動き(ホバーした時に色が変わるなど)の場合は、transitionプロパティを使うのが一般的ですが、僕のHPのように動画並に長い&複雑なアニメーションでは使うことができません。

そこで登場するのがanimationプロパティです。

animationプロパティは、下記のように記述します。

.demo {
  animation: fadeout 0.5s ease 0s forwards;
}

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

これはページが表示されて、0.5秒かけながら要素が徐々に透明になって消えるアニメーション(フェードアウト)です。

animationプロパティの各パラメータは以下のようになっています。

animation: [キーフレーム名] [アニメーション時間] [アニメーションのイージング指定] [アニメーション開始時間] [アニメーション終了後プロパティをどのように保持するか]

まだまだオプションはありますが、今回はこれだけで十分です。

で、重要なのが@keyframes {}です。

これは0% ~ 100%(from toでも代用可)の間にプロパティを指定して、アニメーションを作っていくものです。

動画編集するときのキーフレームと同じ考えです。中間点を細かく打っていくことで複雑なアニメーションも組むことができます。

「ちょっとよくわからない...」って方は、こちらを参考にしてください。

.paintのアニメーション

はい。では先にスライドショー全体に覆いかぶさっている.paintをどけるアニメーションを作っていきましょう。

@keyframes fadeout_paint {
  0% { /* 初期状態 */
    transform: translate(0, 0) scale(1);
    width: 100%; height: 100%;
    border-radius: 0;
  }
  30% { /* 小さなボール状に変化 */
    transform: translate(305px, 205px) scale(1);
    width: 40px; height: 40px;
    border-radius: 50%;
  }
  50% {
    transform: translate(305px, 205px) scale(1.3);
    width: 40px; height: 40px;
    border-radius: 50%;
  }
  70% { /* バウンドしたように弾ませる */
    transform: translate(305px, 205px) scale(1);
    width: 40px; height: 40px;
    border-radius: 50%;
  }
  100% { /* 画面左に逃げていく */
    transform: translate(-40px, 205px) scale(1);
    width: 40px; height: 40px;
    border-radius: 50%;
  }
}

なにやら煩雑な書き方ですが、多めに見てください。

0% ~ 30%の間は小さくなり丸みを帯びながら、ボール状になります。

30% ~ 70%の間はボールがバウンドしているようにscaleで少し拡大縮小をさせます。

70% ~ 100%の間はtranslateで左に逃げていくようにします。

アニメーションをたくさん使う場合は、今回のようにtranslatescaleのような描画コストが少ないものできるだけ指定してあげてください。

あとは、.paintにアニメーションを登録してあげてください。

/*** 画面表示のアニメーション ***/
.paint { animation: fadeout_paint 1s ease 0.5s forwards; }

画面表示から0.5秒後に1秒かけながらアニメーションする指定ですね。

あと、forwardsでアニメーション終了後もプロパティが100%のときのものを保持するようにします。

.imageのアニメーション

.imageは単純です。 widthを0%から100%に変えるだけです。

@keyframes show_image {
  0%   { width: 0%; }
  100% { width: 100%; }
}

あとは、各.imageにアニメーションを登録してあげてください。

/*** スライドショーのアニメーション ***/
.images .image:nth-child(1) { animation: show_image 0.6s ease 1.5s forwards; }
.images .image:nth-child(2) { animation: show_image 0.6s ease 1.7s forwards; }
.images .image:nth-child(3) { animation: show_image 0.6s ease 1.9s forwards; }
.images .image:nth-child(4) { animation: show_image 0.6s ease 2.1s forwards; }

.paintのアニメーションが終了後、0.2秒間隔を開けながら、各.imageがアニメーションが開始されるようにします。

はい!これで完成です!

ブラウザをリロードして見てください!

はい!完成!あなたは天才!

全てのコードはこちらにあります。

終わりに

僕は英語ができないことが知られていますが、もはや日本語すらダメでした。

読みづらくて申し訳ない...

「わかりづらい!こうして!」や「こんな説明欲しい!」みたいなものがあったらtwitterでリプライ飛ばしてください。

css animationはひたすら、@keyframesの調整と自身の工夫が重要なのでどんどんパラメータやプロパティを変更していってみてください!

皆さんのcss animationの新しいアイデアの手助けになれば幸いです!

毎週日曜に更新していくので、サザエさん感覚でみてください。

じゃーねー!

f:id:yuki540com:20180225112914p:plain