BETA

CSSヤクザになりたい人生だった

投稿日:2020-05-11
最終更新:2020-05-19

はじめに

CSSヤクザ is 何

こういうCSSの使い方をする人を言います。
臆病な魔女
CSSAnimationを使った2Dアニメーションまとめ / Twitter
嗚呼、恐ろしいですね。

この記事について

CSS & CSSアニメーション初心者がCSSヤクザになろうと奮闘したけど現実は難しいよねっていう話です。
yui540さんとCSSアニメーションを知ったのは最近ですが、完全に魅せられてしまいました。要はただのファンです。

追記

お目に留めて頂いたようです!ありがとうございます!!

アニメーションって何をすればいいのか

何をすればいいのか。何を作ればいいのか。アイディアが存在しません。なのでまずは「まねぶ」ことから始めようと思います。

お手本を見て、真似る。
「動き」のあるWebサイトを支えるCSSアニメーション技術(スライド 25)|yui540|note

お手本はyui540さんのTwiiterにいっぱいあります。
その中から、私は「動画モーダル」をチョイスしました。

選定理由は以下の2つ。

  • 動きが好き
  • 何が起きているのかはわかる(どう作ればいいかは知らない)

「動きが好き」について、好きなアニメーションであれば、再現も苦ではないだろうということです。CSSが疎いとたくさん試行錯誤することになるので、好きは最後までやり通すために重要な要素だと思っています。
「何が起きているのかはわかる」について、見てわからないものは再現しようがないです。そのため、個々の動作を分割して考えやすいものにしました。

真似た結果

調整と妥協の産物です。

アニメーションを大まかに分割してみる

いきなりあの動作を完成させるには困難なので分割しましょう。
その後、小さなアニメーションを1つ1つ完成させて繋げればいいのです。

動画モーダルを大まかに分けると以下の6つでしょうか。

  • 四角が回転しつつ、拡大する
  • 斜め上から白い四角が出てくる
  • 上から画像が降ってくる
  • 画像がバウンドする
  • 画像の名前が下から出てくる
  • ボタンが右に転がる

語彙力の無さを痛感しています。

回転と拡大が同時に起きるアニメーション

アニメーション(0s~1s)をよーく見ると、回転しながら拡大していることがわかると思います。
(さらによく見ると拡大した後に縮小して元のサイズに戻っています)
これらはtransform: rotatetransform: scaleを使えば再現できそうです。
また、何もないところから緑のウィンドウが現れているので、opacityを使って、透明度の変化もアニメーションに含める必要がありそうです。

.frame {    
    width: 300px;  
    height: 200px;  

    animation: scaling_rotation 1s linear 0s 1 reverse forwards;  

    opacity: 0;  
    border-radius: 2px;  
    background-color: #d5848b;  
    box-shadow: 3px 3px 2px 1px #e8eaec;  
}  

@keyframes scaling_rotation {  
    0% {  
        transform: rotate(0deg) scale(1.0);  

        opacity: 1;  
    }  
    50% {  
        transform: rotate(1deg) scale(1.1);  

        opacity: 0.5;  
    }  
    100% {  
        transform: rotate(-60deg) scale(0.2);  

        opacity: 0;  
    }  
}  

ハマりどころ

複数のtransformを同時に動かす

初めはtransformを2つ書いていたのですが、アニメーションが片方だけしか反映されず困っていました。

transform: rotate(-60deg);  
transform: scale(0.2);  

transformはプロパティですので、複数記述すると最後のtransformプロパティのみ反映されます。
例えば、移動と回転を指定するときは、transformプロパティを複数記述せずに、値に続けて記述してください。
値に複数記述するときは、半角スペースを空けて続けて記述してください。
【CSS3】Transform(変形)関連のまとめ - Qiita

この記事を参考にして、下記のように直すとうまくいきました。

transform: rotate(-60deg) scale(0.2);  

アニメーションを逆再生する

初めはtransformをkeyframes以外で書けるとは思っていなかったので、そんな縛りの中、なんとか捻り出した結果生まれました。
そのため、元々は拡大しながら時計周りに回転するアニメーションですが、縮小しながら反時計周りに回転するkeyframesを作成し、これを逆再生しています。

逆再生のメリットは、最後に見せたい配置に対してアニメーションを適用できることでしょうか。

コンテンツ用の枠を斜め上からスライドさせるアニメーション

アニメーション(1s~1.5s)を見ると、少し透明な四角形が右上からスライドしてきて、遅れて白い四角形が右上からスライドしているように見えます。
さらに良く見ると、初めにスライドが見えるところは、緑のウィンドウと途中からです。

考えられる選択肢として

  1. 単純に右上からtranserateを使ってスライドさせて、はみ出る部分はhiddenで隠す

  2. transform-originscaleする原点を変えて、縮小の状態から拡大をする

があると思います。どちらも最終位置から逆再生で再現できそうです。

1. 単純に右上からtranserateを使ってスライドさせて、はみ出る部分はhiddenで隠す

hiddenによってcontentの外は隠し、content::beforecontent::afterを透明にしてcontent外に配置。
アニメーションによって外側からcontent::beforecontent::afterを時間差でスライドさせます(実際は、内側から外へスライドするアニメーションを逆再生させています)。

.content {  
    position: absolute;  

    overflow: hidden;  

    width: 290px;  
    height: 170px;  
    margin: 5px;  

    border-radius: 2px;  
    background-color: transparent;  
}  

.content::before, .content::after {  
    position: absolute;  

    width: 290px;  
    height: 170px;  

    content: "";  

    opacity: 0;  
    border-radius: 2px;  
}  

.content::before {  
    z-index: 1;  

    animation: fade_in_top_right 0.35s linear 0.80s 1 reverse forwards;  

    background-color:rgba(255,255,255,0.6);  
}  

.content::after {  
    z-index: 2;  

    animation: fade_in_top_right 0.3s linear 0.95s 1 reverse forwards;  

    background-color: white;  
}  

@keyframes fade_in_top_right {  
    from {  
        transform: translate(0, 0);  

        opacity: 1;  
    }  
    to {  
        transform: translate(100%, -100%);  

        opacity: 1;  
    }  
}  

2.transform-originscaleする原点を変えて、縮小の状態から拡大をする

content::beforecontent::afterを透明にしてcontent内に配置。
アニメーションによってcontent::beforecontent::afterを時間差で縮小の状態から拡大させます(実際は右端を原点として等倍から縮小させるアニメーションを逆再生させています)。

.content {  
    position: absolute;  

    overflow: hidden;  

    width: 290px;  
    height: 170px;  
    margin: 5px;  
}  

.content::before, .content::after {  
    position: absolute;  

    width: 290px;  
    height: 170px;  

    content: "";  
    transform-origin: top right;  

    opacity: 0;  
    border-radius: 2px;  
}  

.content::before {  
    z-index: 1;  

    animation: minimizing 0.35s linear 0.80s 1 reverse forwards;  

    background-color: rgba(255,255,255,0.6);  
}  

.content::after {  
    z-index: 2;  

    animation: minimizing 0.3s linear 0.95s 1 reverse forwards;  

    background-color: white;  
}  

@keyframes minimizing {  
    from {  
        transform: scale(1);  

        opacity: 1;  
    }  
    to {  
        transform: scale(0.01);  

        opacity: 1;  
    }  
}  

ハマりどころ

2においてframecontentのクラスを統一できると思ったのですが、あとで追加する画像をうまく処理できませんでした。そのため、あとで使うcontentは残してあります。

content: "";がなくて表示されないことも地味にハマりました。

フレーム外から画像をストンと落とすアニメーション

画像がcontent上からいきなり落ちてきます。そのため、hiddenを使ってcontent外では見えなくする必要がありそうです。また、最初は透明にして、アニメーション開始時に不透明にするようにします。理由は、逆再生を使うのでアニメーションの開始前はcontentの中にimageがあるからです。加えて、imageframeの下にくるようにz-indexframeよりも小さな値に設定しておきます。

.image {  
    position: absolute;  
    z-index: 3;  

    width: 280px;  
    height: 160px;  
    margin: 5px;  

    animation: fade_in_top 0.2s linear 1.5s 1 reverse forwards,  
               shaking 0.6s ease-in 1.71s 1 normal forwards;  

    opacity: 0;  
}  

@keyframes fade_in_top {  
    from {  
        transform: translateY(0);  

        opacity: 1;  
    }  
    to {  
        transform: translateY(-100%);  

        opacity: 1;  
    }  
}  

ハマりどころ

imgに対してafterをつけようとして反映されず???になってました。調べるとimgに擬似要素はつけられないようです。

画像が上下に跳ねるアニメーション

画像が下に落ちた後、上下に跳ねています。2回ほど跳ねているように見えるので translateYを使ってそれらしくなるように調整すれば良さそうです。

@keyframes shaking {  
    0% {  
        transform: translateY(0%);  
    }  
    25% {  
        transform: translateY(-5%);  
    }  
    50% {  
        transform: translateY(0%);  
    }  
    75% {  
        transform: translateY(-2%);  
    }  
    100% {  
        transform: translateY(0%);  
    }  
}  

ハマりどころ

逆再生させるので、マイナス方向にtranslateYさせています。普通にcontent上に画像を配置して落とすとするとtranslateY0%ではなく100%-2%ではなく98%になります。

画像の名前が下から表示されるアニメーション

画像名はframe外から出てきているように見えるので、実際の表示位置から画面外に移動するアニメーションを逆再生しています。

.image_text {  
    position: absolute;  
    z-index: 6;  
    bottom: 0;  

    width: 100%;  

    animation: fade_in_bottom 0.5s ease-in 1.7s 1 reverse forwards;  
    text-align: center;  

    opacity: 0;  
    color: white;  
}  

@keyframes fade_in_bottom {  
    0% {  
        transform: translateY(0);  

        opacity: 1;  
    }  
    to {  
        transform: translateY(100%);  

        opacity: 0;  
    }  
}  

ボタンを右方向に転がすアニメーション

bottun::beforebottun::afterのそれぞれで左右方向からの斜めの線でバツ印を作ります。
また、画像が落ちてくるまでボタンは見えていないので、透明度もアニメーションに加える必要がありそうです。
あとは横移動しつつ、回転させれば完成します。これも調整です。

.bottun_wapper {  
    position: absolute;  
    z-index: 5;  
    top: -4px;  
    right: -5px;  

    width: 40px;  
    height: 40px;  
}  

.bottun {  
    position: relative;  
    z-index: 1;  

    width: 40px;  
    height: 40px;  

    animation: fade_rotation 1.2s cubic-bezier(1, 0.01, 0.8, 0.64) 1.8s 1 reverse forwards;  

    opacity: 0;  
    border-radius: 2px;  
    background-color: white;  
    box-shadow: 1px 1px 1px 1px #e8eaec;  
}  

.bottun::before, .bottun::after {  
    position: absolute;  
    top: 50%;  

    width: 20px;  
    height: 2px;  
    margin: 0 10px;  

    content: "";  

    background-color: #d5848b;  
}  

.bottun::before {  
    z-index: 2;  

    transform: rotate(45deg);  
}  

.bottun::after {  
    z-index: 3;  

    transform: rotate(-45deg);  
}  

@keyframes fade_rotation {  
    0% {  
        transform: translateX(0%) rotate(2deg);  

        opacity: 1;  
    }  
    100% {  
        transform: translateX(-200%) rotate(-180deg);  

        opacity: 0;  
    }  
}  

答え合わせ

真似たのはいいけど、実際のコードはどうなのか気になるところです。
幸にしてyui540さんは作成したコードをGitHubに上げています。

学習教材がたくさん。自宅でのお勉強も捗りますね。
さて、今日作った動画モーダルは名前的に以下のリンク先に置いてありそうです。

color-movieのGIFは。

color-modal

というわけで、何が違うのかを確認し、修正するとしましょうか。

リンク先でファイルを物色して思うこと。

  • フォルダ内にCSSファイルが存在しないんですが
  • style.jsにCSSらしき記述があるんですか

これが意味することは

CSSヤクザになるにはCSSだけじゃダメなんだって!!!
厳しい現実ですね。時代に順応しなきゃやってられないのはどこのヤクザ界隈も同じなのかもしれません。


気を取り直して、srcの中身を見てみるとなんだか動画モーダルのソースコードではなさそうです。
modalと書いてあったので動画モーダルかと思ったのですが早とちりだったみたいです。
commitメッセージのadd: 「CSSアニメーションを使った状態変化パターンの提案」をまとめて追加を頼りに探してみましょうか。

動画モーダルを探す

color-modal
GIFもsrcもcolor-modalしていました

color-profile
GIFもsrcもcolor-profilesしていました

color-message-form
GIFはないけどsrcはcolor-message-formしていました

color-content
GIFもsrcもcolor-contentしていました

color-loading
GIFは動画モーダルだけどsrcはcolor-loadingしていました

color-people
GIFは動画モーダルだけどsrcはcolor-peopleしていました

color-catalog
GIFもsrcもcolor-catalogしていました

color-tomodati
GIFは動画モーダルだけどsrcはcolor-tomodatiしていました

GIFは動画モーダルなの、ちょっとしたトラップですね。

GithubのHistryからyui540/ChocolateCake/src/scripts/config/content.jsを見る限り、add: 「CSSアニメーションを使った状態変化パターンの提案」をまとめて追加で追加されたのは8モーションのみ。

また、contents内でcolor-movieを検索しましたが該当するディレクトリはなさそうです。

yui540/ChocolateCake/tree/master/public/images/thumb/largeにあるサムネ一覧にもなさそうです。

動画モーダルのソースコードってどこにあるのでしょうか。結局見つけられず、答え合わせはできませんでした。そもそもコードを上げていない可能性もありそうです。GitHubの検索が部分一致なら「本編PV」とかで検索すると一瞬なんですけどね。

今後もコード漁ることになると思うのでので、見つけることができたら答え合わせすることにします。

最後に

CSSは「大学の初年時教養程度しか知らない」+「もう覚えていない」状態だったので、調べながら作ったのですが、5日ほどかかってしまいました。
うーん、今のところ若衆にもなれる気がしないです。

勝手に告知

ピクシブのインターンでyui540さん本人から学べるようです。CSSつよつよな皆さんは是非応募しましょう。

ワークショップをやるらしいです。これを機にCSS道を歩んでみてはいかがですか?

ソースコード

<!DOCTYPE html>  
<html lang="ja">  
<head>  
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <meta http-equiv="X-UA-Compatible" content="ie=edge">  
    <link rel="stylesheet" type="text/css" href="modal.css">  
    <title>CSSアニメーション</title>  
</head>  
<body>  
    <div class="stage">  
        <div class="centering">  
            <div class="frame">  
                <div class="content">  
                    <img class="image" src="sunset-3008779_640.jpg" alt="猫と夕日">  
                </div>  
                <div class="bottun_wapper">  
                    <div class="bottun"></div>  
                </div>  
                <div class="image_text">にゃんこ</div>  
            </div>  
        </div>  
    </div>  
</body>  
</html>  

.stage {  
    position: absolute;  
    top: 0;  
    right: 0;  
    bottom: 0;  
    left: 0;  
}  

.centering {  
     position: absolute;  
     top: 50%;  
     left: 50%;  

     display: block;  

     width: 300px;  

     transform: translate(-50%, -50%);  
 }  

/* 以下が動画モーダル */  

.frame {  
    position: relative;  

    width: 300px;  
    height: 200px;  

    animation: scaling_rotation 1s cubic-bezier(0.18, 0.33, 0.13, 1.04) 0s 1 reverse forwards;  

    opacity: 0;  
    border-radius: 2px;  
    background-color: #d5848b;  
    box-shadow: 3px 3px 2px 1px #e8eaec;  
}  

.content{  
    position: absolute;  

    overflow: hidden;  

    width: 290px;  
    height: 170px;  
    margin: 5px;  
}  

.content::before, .content::after {  
    position: absolute;  

    width: 290px;  
    height: 170px;  

    content: "";  
    transform-origin: top right;  

    opacity: 0;  
    border-radius: 2px;  
}  

.content::before {  
    z-index: 1;  

    animation: minimizing 0.35s linear 0.80s 1 reverse forwards;  

    background-color: rgba(255,255,255,0.6);  
}  

.content::after {  
    z-index: 2;  

    animation: minimizing 0.3s linear 0.95s 1 reverse forwards;  

    background-color: white;  
}  

.image {  
    position: absolute;  
    z-index: 3;  

    width: 280px;  
    height: 160px;  
    margin: 5px;  

    animation: fade_in_top 0.2s linear 1.5s 1 reverse forwards,  
               shaking 0.6s ease-in 1.71s 1 normal forwards;  

    opacity: 0;  
}  

.image_text {  
    position: absolute;  
    z-index: 6;  
    bottom: 0;  

    width: 100%;  

    animation: fade_in_bottom 0.5s ease-in 1.7s 1 reverse forwards;  
    text-align: center;  

    opacity: 0;  
    color: white;  
}  

.bottun_wapper {  
    position: absolute;  
    z-index: 5;  
    top: -4px;  
    right: -5px;  

    width: 40px;  
    height: 40px;  
}  

.bottun {  
    position: relative;  
    z-index: 1;  

    width: 40px;  
    height: 40px;  

    animation: fade_rotation 1.2s cubic-bezier(1, 0.01, 0.8, 0.64) 1.8s 1 reverse forwards;  

    opacity: 0;  
    border-radius: 2px;  
    background-color: white;  
    box-shadow: 1px 1px 1px 1px #e8eaec;  
}  

.bottun::before, .bottun::after {  
    position: absolute;  
    top: 50%;  

    width: 20px;  
    height: 2px;  
    margin: 0 10px;  

    content: "";  

    background-color: #d5848b;  
}  

.bottun::before {  
    z-index: 2;  

    transform: rotate(45deg);  
}  

.bottun::after {  
    z-index: 3;  

    transform: rotate(-45deg);  
}  

@keyframes scaling_rotation {  
    0% {  
        transform: rotate(0deg) scale(1.0);  

        opacity: 1;  
    }  
    50% {  
        transform: rotate(1deg) scale(1.1);  

        opacity: 0.5;  
    }  
    100% {  
        transform: rotate(-60deg) scale(0.2);  

        opacity: 0;  
    }  
}  

@keyframes minimizing {  
    from {  
        transform: scale(1);  

        opacity: 1;  
    }  
    to {  
        transform: scale(0.01);  

        opacity: 1;  
    }  
}  

@keyframes fade_in_top {  
    from {  
        transform: translateY(0);  

        opacity: 1;  
    }  
    to {  
        transform: translateY(-100%);  

        opacity: 1;  
    }  
}  

@keyframes shaking {  
    0% {  
        transform: translateY(0%);  
    }  
    25% {  
        transform: translateY(-5%);  
    }  
    50% {  
        transform: translateY(0%);  
    }  
    75% {  
        transform: translateY(-2%);  
    }  
    100% {  
        transform: translateY(0%);  
    }  
}  

@keyframes fade_rotation {  
    0% {  
        transform: translateX(0%) rotate(2deg);  

        opacity: 1;  
    }  
    100% {  
        transform: translateX(-200%) rotate(-180deg);  

        opacity: 0;  
    }  
}  

@keyframes fade_in_bottom {  
    0% {  
        transform: translateY(0);  

        opacity: 1;  
    }  
    to {  
        transform: translateY(100%);  

        opacity: 0;  
    }  
}  

にゃんこ

日没 猫 影 - Pixabayの無料写真

参考文献

Atom+Emmetで爆速なHTML,CSSコーディング環境を入手する – スペース・アイ株式会社
css border-radius の使い方。円や扇をジェネレータで描いてみる | コード7区
【初心者向け】CSS positionで位置指定でする方法・使い方 | WEBST8
CSS「position:relative」と「position:absolute」で画像や文字を重ねる方法
CSS - positionプロパティにrelative指定した時の基準位置は常に兄弟ブロック? 親 ブロックが基準位置になることは絶対にない? |teratail
【初心者向け】CSSの擬似要素と擬似クラスを理解しよう! : ビジネスとIT活用に役立つ情報
CSSでbefore,after要素が表示されなくて困ったとき - emuramemo
imgタグにafter要素(疑似要素)はつけれないだとーーー!! - Ich habe hunger
RGBA値で背景を半透明にする | CSS
重ねて表示する!CSSのz-indexの使い方 | TechAcademyマガジン
CSSで中央寄せする9つの方法(縦・横にセンタリング)
カラー配色で迷わない!シーン別配色見本32パターン | Web制作会社スタイル

CSSアニメーション 入門 - Qiita
【CSS3】@keyframes と animation 関連のまとめ - Qiita
【CSS3】Transition(変化)関連のまとめ - Qiita
【CSSアニメーション】ひとつの要素に複数のキーフレームを追加 | なるほどブログ。
transform-origin - CSS: カスケーディングスタイルシート | MDN
PIXIV TECH FES.のLPを支えるCSSアニメーションテクニック - pixiv inside

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

A03kiの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう