🗓️

雪降るアドベントカレンダーを作る

2022/12/01に公開

アドベントカレンダーを作る

HTML

カレンダーなのでたくさんの玉が必要です。<template>を使って玉の雛形を作り、JavaScriptで量産しました。

玉のtemplate

<div id="calendar" class="calendar-container"></div>
<template id="date_cell">
    <a href="#">
        <div class="date-cell">
            <div class="cell-inside">
                <div class="cell-door">
                    <span class="date-number"></span>
                    <div class="door-nob"></div>
                </div>
            </div>
        </div>
    </a>
</template>

JS

このdataにurlを追加することで、日付をクリックすると飛ぶようになります。

const data = [
    {url:'#'},
    省略
]
data.forEach((elm, index) => {
    const clone = date_cell.content.cloneNode(true);
    clone.querySelector('.date-number').textContent = index + 1;
    clone.querySelector('a').setAttribute("href", elm.url);
    calendar.append(clone);
});

CSS

CSSも基本的なものしか使用していないので特に書くこともないのですが、ドアを再現する際にいくつか初め使ったものがあったで書き残しておきます。

transform-origin: left;
transform: perspective(900px) rotateY(-30deg);
transition: all 0.5s ease-in-out;
属性/関数 説明
transform-origin 座標変換の原点を決めます。今回は扉が開いているように見せたかったので、左を基準に回転させるために使用しました。
transform: perspective(900px) ユーザーと画面までの距離を定義し、3次元であるかのように見せます。これを使う際はtransformの先頭に置く必要があります。
transform: rotateY(-30deg) Y軸で30度回転させます。

雪を降らせる

ピュアなHTML/CSS/JSで雪を降らせてみようとしましたが、ほぼSVGです。

HTML

htmlでは、雪を降らせたい要素にcssクラスを与えるだけです。

<body class="snow">
</body>

CSS

CSS Animationを利用して雪が降り続けるようにします。
https://developer.mozilla.org/ja/docs/Web/CSS/animation
雪を降らせるCSS

.snow {
    background-position: 0px 0px;
    animation: animatedBackground 15s linear infinite;
}
  
@keyframes animatedBackground {
  100% {
    background-position: 0px 100vh;
  }
}

JS

雪の結晶となる要素をJavaScriptを使って作ります。
SVGをJavaScriptで生成して、.snowbackgroudImageに設定することで雪を作っています。
雪を作るJS

(() => {
    const rndInt = max => Math.floor(Math.random() * max);
    let snow_style = "url(\"data:image/svg+xml,\
<svg xmlns='http://www.w3.org/2000/svg'%20\
viewBox='0 0 50 50'>\
<style type='text/css'>\
.st0{opacity:0.7;fill:%23FFFFFF;}\
.st1{opacity:0.3;fill:%23FFFFFF;}\
</style>";
    for (let index = 0; index < 100; index++) {
       snow_style += `<circle class='st${rndInt(2)}' cx='${rndInt(50)}' cy='${rndInt(50)}' r='${Math.random() * 0.2}'/>` 
    }
    snow_style += "</svg>\")";
    document.querySelector(".snow").style.backgroundImage = snow_style;
})();

SVG

svgについては詳しく知らなかったので、ここで少しまとめてます。

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50'>
<style type='text/css'>
.st0{opacity:0.7;fill:%23FFFFFF;}
.st1{opacity:0.3;fill:%23FFFFFF;}
</style>
<circle class='st${rndInt(2)}' cx='${rndInt(50)}' cy='${rndInt(50)}' r='${Math.random() * 0.2}'/>
...
</svg>

versionについて

ネットで検索すると、version='1.1'と書いてあるものもありますが、最新版のSVG2ではバージョンの指定は非推奨になっているようです。
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/version

xmlnsとは

xmlnsは、xmlの名前空間を設定するものです、
SVGの元となっているXMLにはさまざまな派生言語があり、派生言語によってタグの意味が異なります。
それぞれのタグの名前が衝突しないようにするために、名前空間を設定する必要があります。

styleタグ

HTMLのstyleタグと全く同じように、SVGコンテンツ内に直接スタイルシートを埋め込めます。

circleタグ

クラス属性を持っているので、styleタグないで設定したスタイルを適用することができます。
cxcyrはそれぞれ、x座標、y座標、半径です。
今回はJSを使って、ランダムにこれらを設定しました。

成果物

GitHub Pagesに今回作ったものを置きました。
果たしてAdvent Calendarは全て埋まるのか...
https://k41531.github.io/2022-AdventCalendar/

Discussion