なるべくCSSだけでアナログ時計を作る
CSS だけでアナログ時計を作ってみます。ただ CSS だけではどうしてもできないことがあるので、その部分は JavaScript にやってもらい、なるべく CSS だけでアナログ時計を作ります。
まずは CSS だけでできる範囲で
最終的には JavaScript に頼りますが、まずは CSS だけでどこまで出来るのか作ってみます。
HTML
<div id="clock">
<div id="hour-hand"></div>
<div id="minute-hand"></div>
<div id="second-hand"></div>
</div>
上から、時針、分針、秒針です。
CSS
/* 時計本体 */
#clock {
height: 700px; /* 高さは固定 */
margin: 40px auto;
max-width: 700px; /* 幅のレスポンシブ対応 */
position: relative;
}
/* 秒針 */
#second-hand {
animation: rotation-s 60s linear infinite; /* 60秒かけて一周 */
background-color: #999;
border-radius: 2px;
height: 4px; /* 線幅 */
position: absolute;
right: calc(50% - 2px); /* 位置調整 線幅の半分ずらす */
top: calc(50% - 2px); /* 位置調整 線幅の半分ずらす */
transform-origin: calc(100% - 2px) center; /* アニメーションの中心軸 線幅の半分ずらす */
width: 50%;
}
/* 分針 */
#minute-hand {
animation: rotation-m 3600s linear infinite; /* 3600秒、1時間かけて一周 */
background-color: #000;
border-radius: 5px;
height: 10px; /* 線幅 */
position: absolute;
right: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
top: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
transform-origin: calc(100% - 5px) center; /* アニメーションの中心軸 線幅の半分ずらす */
width: 40%;
}
/* 時針 */
#hour-hand {
animation: rotation-h 86400s linear infinite; /* 86400秒、12時間かけて一周 */
background-color: #cc3b3b;
border-radius: 5px;
height: 10px; /* 線幅 */
position: absolute;
right: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
top: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
transform-origin: calc(100% - 5px) center; /* アニメーションの中心軸 線幅の半分ずらす */
width: 25%;
}
/* 秒針の回転アニメーション */
@keyframes rotation-s {
0% {transform: rotate(90deg)} /* 初期位置 0秒の位置 */
100% {transform: rotate(450deg)} /* 初期位置 + 360deg で一周 */
}
/* 分針の回転アニメーション */
@keyframes rotation-m {
0% {transform: rotate(90deg)} /* 初期位置 0分の位置 */
100% {transform: rotate(450deg)} /* 初期位置 + 360deg で一周 */
}
/* 時針の回転アニメーション */
@keyframes rotation-h {
0% {transform: rotate(150deg)} /* 初期位置 2時の位置 */
100% {transform: rotate(510deg)} /* 初期位置 + 360deg で一周 */
}
calc を使って大量に微調整をしているので若干見にくいです。position に関しては top: 50% right:50% を基本とし、origin は要素の端、100% の位置とすることで針が回っているアニメーションにしています。
0deg が初期位置で9時の位置になるため、90deg が12時の位置になります。
CSS だけで出来るサンプル
2時スタートの CSS のみで作った時計のサンプルです。
秒針は60秒かけて1周、分針は60分かけて1周、時針は12時間かけて1周します。
CSS だけで出来る限界
上のサンプルの通り CSS だけでは時計を現在時刻に合わせることが出来ません。
そこで、JavaScript で現在時刻を取得しアニメーションの初期位置と終了位置、
/* 秒針の回転アニメーション */
@keyframes rotation-s {
0% {transform: rotate(90deg)} /* 初期位置 0秒の位置 */
100% {transform: rotate(450deg)} /* 初期位置 + 360deg で一周 */
}
/* 分針の回転アニメーション */
@keyframes rotation-m {
0% {transform: rotate(90deg)} /* 初期位置 0分の位置 */
100% {transform: rotate(450deg)} /* 初期位置 + 360deg で一周 */
}
/* 時針の回転アニメーション */
@keyframes rotation-h {
0% {transform: rotate(150deg)} /* 初期位置 2時の位置 */
100% {transform: rotate(510deg)} /* 初期位置 + 360deg で一周 */
}
を調整することで現在時刻に合わせることにします。針の回転自体は CSS のアニメーションに任せます。
また CSS だけでも幅のレスポンシブ対応はできますが、高さが 700px と固定です。時計本体をレスポンシブな正方形になるよう JavaScipt で幅を取得し高さを決めます。
JavaScript を使って現在時刻に合わせる
上記の方針で JavaScript を組んでみます。
HTML
<div id="clock2">
<div id="hour-hand2"></div>
<div id="minute-hand2"></div>
<div id="second-hand2"></div>
</div>
id 名を変更しています。
CSS
/* 時計本体 */
#clock2 {
margin: 40px auto;
max-width: 700px; /* 幅のレスポンシブ対応 、height 値は JavaScript で決める*/
position: relative;
}
/* 秒針 */
#second-hand2 {
animation: rotation-s2 60s linear infinite; /* 60秒かけて一周 */
background-color: #999;
border-radius: 2px;
height: 4px; /* 線幅 */
position: absolute;
right: calc(50% - 2px); /* 位置調整 線幅の半分ずらす */
top: calc(50% - 2px); /* 位置調整 線幅の半分ずらす */
transform-origin: calc(100% - 2px) center; /* アニメーションの中心軸 線幅の半分ずらす */
width: 50%;
}
/* 分針 */
#minute-hand2 {
animation: rotation-m2 3600s linear infinite; /* 3600秒、1時間かけて一周 */
background-color: #000;
border-radius: 5px;
height: 10px; /* 線幅 */
position: absolute;
right: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
top: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
transform-origin: calc(100% - 5px) center; /* アニメーションの中心軸 線幅の半分ずらす */
width: 40%;
}
/* 時針 */
#hour-hand2 {
animation: rotation-h2 86400s linear infinite; /* 86400秒、12時間かけて一周 */
background-color: #cc3b3b;
border-radius: 5px;
height: 10px; /* 線幅 */
position: absolute;
right: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
top: calc(50% - 5px); /* 位置調整 線幅の半分ずらす */
transform-origin: calc(100% - 5px) center; /* アニメーションの中心軸 線幅の半分ずらす */
width: 25%;
}
keyframes アニメーションを JavaScript で作ります。
JavaScript
// 現在時刻の設定
var time = new Date();
var second = time.getSeconds();
var minute = time.getMinutes();
var hour = time.getHours();
// 現在時刻を元にした角度の設定
var secondDeg = (second * 360 / 60) + 90 ;
var minuteDeg = (minute * 360 / 60) + ((second * 360 / 60) / 60) + 90;
var hourDeg = (hour * 360 / 12) + ((minute * 360 / 60) / 12) + ((second * 360 / 60) / 720) + 90;
// style 要素を作り、その中に keyframes アニメーションを入れる
var animation = document.createElement("style");
animation.innerHTML = "@keyframes rotation-s2 {0% {transform: rotate(" + secondDeg + "deg)}100% {transform: rotate(" + (secondDeg + 360) + "deg)}}@keyframes rotation-m2 {0% {transform: rotate(" + minuteDeg + "deg)}100% {transform: rotate(" + (minuteDeg + 360) + "deg)}}@keyframes rotation-h2 {0% {transform: rotate(" + hourDeg + "deg)}100% {transform: rotate(" + (hourDeg + 360) + "deg)}}";
document.head.appendChild(animation);
// レスポンシブな正方形を作る
document.getElementById("clock2").style.height = document.getElementById("clock2").scrollWidth + "px";
secondDeg、minuteDeg、hourDeg で角度の計算をしています。分や秒での時針、分針のズレも計算に入れているので若干複雑です。
作った角度を、作った style 要素に innerHTML で入れて最後に head に入れます。
レスポンシブな正方形を作る対応も最終行でしています。
現在時刻に合わせたサンプル
現在の時刻で時計が動いています。狭い画面で見ると縦幅も収縮しているはずです。
まとめ
簡単なアニメーションで動かしているため「カチッカチッ」と動く時計ではなく、スムーズに動くアナログ時計が出来ました。時計を動かすのは JavaScript の setInterval あたりを使って動かすのが主流ですが、CSS だけでもこんな感じで動かせます。ただし、CSS のアニメーションの時間はそんなに正確じゃないので時間が経てば経つほどズレていきます。
CSS だけでもカチカチ動く秒針は再現可能ですが、アニメーションの記述が丈長になるためここでは書きません。step 値あたりと組み合わせれば可能です。
Web ページ自体に時計を表示する意味はほぼないので、なんともですが CSS だけでもほぼ動く時計のようなものは作れるってお話でした。