CSSだけでマルバツゲームを作成する方法について

CSSだけでマルバツゲームを作成する方法を紹介します。

順を追って説明していきますので、サンプルソースをコピーしてマルバツゲームを作成してみてください。また、一部の手順では詳細を説明していますので、仕組みを知りたい方は参考にしてみてください。

はじめに

マルバツゲームの作成方法を順に追って説明していきます。基本的に後に追記するようにしてください。指定がある場合、その場所に追記してください。

手順によっては詳細を説明するようにしています。

手順1.〇と×を配置するボードを作成します

〇と×を配置するボードのイメージは、以下のようになります。

ボードのイメージ
ボードのイメージ

HTMLとCSSは、以下のようになります。

<!-- 手順3はここに記載します -->

<div class="board-grid board-display">
    <div id="display-1" class="board-display-item"></div>
    <div id="display-2" class="board-display-item"></div>
    <div id="display-3" class="board-display-item"></div>
    <div id="display-4" class="board-display-item"></div>
    <div id="display-5" class="board-display-item"></div>
    <div id="display-6" class="board-display-item"></div>
    <div id="display-7" class="board-display-item"></div>
    <div id="display-8" class="board-display-item"></div>
    <div id="display-9" class="board-display-item"></div>
</div>
.board-grid {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
    column-gap: 5px;
    row-gap: 5px;
    padding: 15px;
    width: max-content;
}


.board-display {
    background: #333;
    border-radius: 15px;
}

.board-display .board-display-item {
    background-color: #55ff55;
}

ボードの表示方法について

ボードの表示には、3×3のマス目を表現するために「display: grid;」を利用します。

横方向のマス目の幅・数は「grid-template-columns」で表現し、縦方向のマスの高さ・幅は「grid-template-rows」で表現しています。

「grid-template-columns」と「grid-template-rows」の説明

マス目の隙間は「column-gap」「row-gap」で表現しています。

「column-gap」「row-gap」の説明

手順2.〇と×の選択個所を作成します

〇と×の選択個所は以下のように表現します。赤色が〇で青色が×になります。

〇の選択可能な個所
〇の場合
×の選択可能な個所
×の場合

HTMLとCSSは、以下のようになります。

board-item-voidクラスを非表示にして、board-itemクラスだけ表示させています。そのため、基本的にボードの色違いになります。board-item-voidクラスは後で利用していきます。

<div class="board-grid board-precedence">
    <label class="board-item item-1" for="precedence-1"></label>
    <div class="board-item-void item-1"></div>
    <label class="board-item item-2" for="precedence-2"></label>
    <div class="board-item-void item-2"></div>
    <label class="board-item item-3" for="precedence-3"></label>
    <div class="board-item-void item-3"></div>
    <label class="board-item item-4" for="precedence-4"></label>
    <div class="board-item-void item-4"></div>
    <label class="board-item item-5" for="precedence-5"></label>
    <div class="board-item-void item-5"></div>
    <label class="board-item item-6" for="precedence-6"></label>
    <div class="board-item-void item-6"></div>
    <label class="board-item item-7" for="precedence-7"></label>
    <div class="board-item-void item-7"></div>
    <label class="board-item item-8" for="precedence-8"></label>
    <div class="board-item-void item-8"></div>
    <label class="board-item item-9" for="precedence-9"></label>
    <div class="board-item-void item-9"></div>
</div>

<div class="board-grid board-second">
    <label class="board-item item-1" for="second-1"></label>
    <div class="board-item-void item-1"></div>
    <label class="board-item item-2" for="second-2"></label>
    <div class="board-item-void item-2"></div>
    <label class="board-item item-3" for="second-3"></label>
    <div class="board-item-void item-3"></div>
    <label class="board-item item-4" for="second-4"></label>
    <div class="board-item-void item-4"></div>
    <label class="board-item item-5" for="second-5"></label>
    <div class="board-item-void item-5"></div>
    <label class="board-item item-6" for="second-6"></label>
    <div class="board-item-void item-6"></div>
    <label class="board-item item-7" for="second-7"></label>
    <div class="board-item-void item-7"></div>
    <label class="board-item item-8" for="second-8"></label>
    <div class="board-item-void item-8"></div>
    <label class="board-item item-9" for="second-9"></label>
    <div class="board-item-void item-9"></div>
</div>
/* 〇の場合 */
.board-precedence .board-item {
    background-color: #cc5555;
}

/* ×の場合 */
.board-second .board-item {
    background-color: #5555cc;
}

/* 選択済みの表現で利用します。 */
.board-item-void {
    display: none;
}

手順3.〇と×の選択個所を表現します

〇と×の選択可能な個所を表現していきます。選択された箇所は、以下のように非表示になります。以下の画像は、真ん中を選択した例になります。

真ん中を選択して〇と×の選択個所から非表示になっている例

HTMLの最初 または 「<!– 手順3をここに記入します。 –>」の個所に以下のHTMLを記載します。

<!-- 〇の選択 -->
<input id="precedence-1" class="chk-board-item item-1" type="checkbox">
<input id="precedence-2" class="chk-board-item item-2" type="checkbox">
<input id="precedence-3" class="chk-board-item item-3" type="checkbox">
<input id="precedence-4" class="chk-board-item item-4" type="checkbox">
<input id="precedence-5" class="chk-board-item item-5" type="checkbox">
<input id="precedence-6" class="chk-board-item item-6" type="checkbox">
<input id="precedence-7" class="chk-board-item item-7" type="checkbox">
<input id="precedence-8" class="chk-board-item item-8" type="checkbox">
<input id="precedence-9" class="chk-board-item item-9" type="checkbox">

<!-- ×の選択 -->
<input id="second-1" class="chk-board-item item-1" type="checkbox">
<input id="second-2" class="chk-board-item item-2" type="checkbox">
<input id="second-3" class="chk-board-item item-3" type="checkbox">
<input id="second-4" class="chk-board-item item-4" type="checkbox">
<input id="second-5" class="chk-board-item item-5" type="checkbox">
<input id="second-6" class="chk-board-item item-6" type="checkbox">
<input id="second-7" class="chk-board-item item-7" type="checkbox">
<input id="second-8" class="chk-board-item item-8" type="checkbox">
<input id="second-9" class="chk-board-item item-9" type="checkbox">

CSSは、以下のようになります。

.chk-board-item {
    display: none;
}

.chk-board-item.item-1:checked ~ .board-grid .board-item.item-1,
.chk-board-item.item-2:checked ~ .board-grid .board-item.item-2,
.chk-board-item.item-3:checked ~ .board-grid .board-item.item-3,
.chk-board-item.item-4:checked ~ .board-grid .board-item.item-4,
.chk-board-item.item-5:checked ~ .board-grid .board-item.item-5,
.chk-board-item.item-6:checked ~ .board-grid .board-item.item-6,
.chk-board-item.item-7:checked ~ .board-grid .board-item.item-7,
.chk-board-item.item-8:checked ~ .board-grid .board-item.item-8,
.chk-board-item.item-9:checked ~ .board-grid .board-item.item-9 {
    display: none;
}

.chk-board-item.item-1:checked ~ .board-grid .board-item-void.item-1,
.chk-board-item.item-2:checked ~ .board-grid .board-item-void.item-2,
.chk-board-item.item-3:checked ~ .board-grid .board-item-void.item-3,
.chk-board-item.item-4:checked ~ .board-grid .board-item-void.item-4,
.chk-board-item.item-5:checked ~ .board-grid .board-item-void.item-5,
.chk-board-item.item-6:checked ~ .board-grid .board-item-void.item-6,
.chk-board-item.item-7:checked ~ .board-grid .board-item-void.item-7,
.chk-board-item.item-8:checked ~ .board-grid .board-item-void.item-8,
.chk-board-item.item-9:checked ~ .board-grid .board-item-void.item-9 {
    display: block;
}

選択された箇所を非表示にする方法について

選択された箇所を非表示にするために、board-item-voidクラスとboard-itemクラスの表示を切り替えています。表示の切り替えには、chk-board-itemクラスの選択状態を利用しています。

chk-board-itemクラスが選択されたときに同階層のboard-gridクラスを指定するために間接セレクタ(~)を利用しています。間接セレクタ(~)は基準となる要素以降に要素を指定することができます。

以下のCSSの場合、item-1クラスのchk-board-itemクラスが選択されることで、item-1クラスのboard-item-voidクラスとboard-itemクラスの表示を切り替えます。

.chk-board-item.item-1:checked ~ .board-grid .board-item.item-1 {
    display: none;
}

.chk-board-item.item-1:checked ~ .board-grid .board-item-void.item-1 {
    display: block;
}

デモを用意しましたので体験してみてください。

手順4.〇と×をボードに配置します

〇と×の選択個所が選択されたときに、対応するボードの位置に〇と×を以下のように配置していきます。

〇と×の配置例

CSSは、以下のようになります。〇と×の表示にはカスタムプロパティ(–mark)を利用しています。〇と×の選択個所が選択されることで「–mark」の値が更新され、ボードに〇か×が表示されます。

.board-display-item {
    display: flex;
    align-items: center;
    justify-content: center;
}

.board-display-item::before {
    --mark: "";
    content: var(--mark);
    font-size: 100px;
}

#precedence-1:checked ~ .board-grid #display-1::before,
#precedence-2:checked ~ .board-grid #display-2::before,
#precedence-3:checked ~ .board-grid #display-3::before,
#precedence-4:checked ~ .board-grid #display-4::before,
#precedence-5:checked ~ .board-grid #display-5::before,
#precedence-6:checked ~ .board-grid #display-6::before,
#precedence-7:checked ~ .board-grid #display-7::before,
#precedence-8:checked ~ .board-grid #display-8::before,
#precedence-9:checked ~ .board-grid #display-9::before {
    --mark: "〇";
}

#second-1:checked ~ .board-grid #display-1::before,
#second-2:checked ~ .board-grid #display-2::before,
#second-3:checked ~ .board-grid #display-3::before,
#second-4:checked ~ .board-grid #display-4::before,
#second-5:checked ~ .board-grid #display-5::before,
#second-6:checked ~ .board-grid #display-6::before,
#second-7:checked ~ .board-grid #display-7::before,
#second-8:checked ~ .board-grid #display-8::before,
#second-9:checked ~ .board-grid #display-9::before {
    --mark: "×";
}

手順5.ターンを制御します

手順3で用意した選択個所を交互に表示させてターンを表現します。

CSSは、以下のようになります。

.board-grid.board-precedence {
    display: var(--precedence-board);
}

.board-grid.board-second {
    display: var(--second-board);
}

.board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid {
    --precedence-board: grid;
    --second-board: none;
}

.chk-board-item:checked ~ .board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid {
    --precedence-board: none;
    --second-board: grid;
}

ターンの制御について

ターンの制御は、chk-board-itemクラスの選択された数で行っています。chk-board-itemクラスの選択された数が偶数の場合は〇のターンになります。奇数の場合は×になります。

手順6.結果を表示します

結果を以下のように表示するようにします。分かりやすく赤枠で囲っていますが、実際は囲われていません。

勝利の表示イメージ

また、結果を表示する際に選択個所を非表示にすることでゲームを終了させます。

HTMLとCSSは、以下のようになります。

<div class="board-result"></div>
.board-result::before {
    --result: "";
    content: var(--result);
}

#precedence-1:checked ~ #precedence-2:checked ~ #precedence-3:checked ~ .board-result::before,
#precedence-4:checked ~ #precedence-5:checked ~ #precedence-6:checked ~ .board-result::before,
#precedence-7:checked ~ #precedence-8:checked ~ #precedence-9:checked ~ .board-result::before,
#precedence-1:checked ~ #precedence-4:checked ~ #precedence-7:checked ~ .board-result::before,
#precedence-2:checked ~ #precedence-5:checked ~ #precedence-8:checked ~ .board-result::before,
#precedence-3:checked ~ #precedence-6:checked ~ #precedence-9:checked ~ .board-result::before,
#precedence-1:checked ~ #precedence-5:checked ~ #precedence-9:checked ~ .board-result::before,
#precedence-3:checked ~ #precedence-5:checked ~ #precedence-7:checked ~ .board-result::before {
    --result: "〇の勝利";
}

#second-1:checked ~ #second-2:checked ~ #second-3:checked ~ .board-result::before,
#second-4:checked ~ #second-5:checked ~ #second-6:checked ~ .board-result::before,
#second-7:checked ~ #second-8:checked ~ #second-9:checked ~ .board-result::before,
#second-1:checked ~ #second-4:checked ~ #second-7:checked ~ .board-result::before,
#second-2:checked ~ #second-5:checked ~ #second-8:checked ~ .board-result::before,
#second-3:checked ~ #second-6:checked ~ #second-9:checked ~ .board-result::before,
#second-1:checked ~ #second-5:checked ~ #second-9:checked ~ .board-result::before,
#second-3:checked ~ #second-5:checked ~ #second-7:checked ~ .board-result::before {
    --result: "×の勝利";
}

.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-result::before {
    --result: "引き分け";
}

/* 勝敗が追加時に選択できないようにします。 */
#precedence-1:checked ~ #precedence-2:checked ~ #precedence-3:checked ~ .board-grid,
#precedence-4:checked ~ #precedence-5:checked ~ #precedence-6:checked ~ .board-grid,
#precedence-7:checked ~ #precedence-8:checked ~ #precedence-9:checked ~ .board-grid,
#precedence-1:checked ~ #precedence-4:checked ~ #precedence-7:checked ~ .board-grid,
#precedence-2:checked ~ #precedence-5:checked ~ #precedence-8:checked ~ .board-grid,
#precedence-3:checked ~ #precedence-6:checked ~ #precedence-9:checked ~ .board-grid,
#precedence-1:checked ~ #precedence-5:checked ~ #precedence-9:checked ~ .board-grid,
#precedence-3:checked ~ #precedence-5:checked ~ #precedence-7:checked ~ .board-grid,
#second-1:checked ~ #second-2:checked ~ #second-3:checked ~ .board-grid,
#second-4:checked ~ #second-5:checked ~ #second-6:checked ~ .board-grid,
#second-7:checked ~ #second-8:checked ~ #second-9:checked ~ .board-grid,
#second-1:checked ~ #second-4:checked ~ #second-7:checked ~ .board-grid,
#second-2:checked ~ #second-5:checked ~ #second-8:checked ~ .board-grid,
#second-3:checked ~ #second-6:checked ~ #second-9:checked ~ .board-grid,
#second-1:checked ~ #second-5:checked ~ #second-9:checked ~ .board-grid,
#second-3:checked ~ #second-5:checked ~ #second-7:checked ~ .board-grid,
.chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .chk-board-item:checked ~ .board-grid {
    --precedence-board: none;
    --second-board: none;
}

勝利条件について

勝利条件は、縦・横・斜めで8通り存在しています。

その勝利条件は以下のCSSで表現しています。以下のCSSは〇のパターンになります。

#precedence-1:checked ~ #precedence-2:checked ~ #precedence-3:checked ~ .board-result::before,
#precedence-4:checked ~ #precedence-5:checked ~ #precedence-6:checked ~ .board-result::before,
#precedence-7:checked ~ #precedence-8:checked ~ #precedence-9:checked ~ .board-result::before,
#precedence-1:checked ~ #precedence-4:checked ~ #precedence-7:checked ~ .board-result::before,
#precedence-2:checked ~ #precedence-5:checked ~ #precedence-8:checked ~ .board-result::before,
#precedence-3:checked ~ #precedence-6:checked ~ #precedence-9:checked ~ .board-result::before,
#precedence-1:checked ~ #precedence-5:checked ~ #precedence-9:checked ~ .board-result::before,
#precedence-3:checked ~ #precedence-5:checked ~ #precedence-7:checked ~ .board-result::before {
    --result: "〇の勝利";
}

ボードの番号は以下のようになっております。例えば「1」「2」「3」が〇で選択された場合、〇の勝利になります。

ボードの番号

手順7.ボードと選択個所を重ねます

ボードと選択個所がずれているので重ねていきます。

今まで記載してきたHTMLを以下のHTMLで囲みます。

<div class="board">
    <!-- 今までの内容はここに記載します -->
</div>

CSSは、以下のようになります。

/* 手順7 */
.board {
    position: relative;
}

.board-precedence,
.board-second {
    top:0;
    left: 0;
    position: absolute;
}

完成!!

今まで記載した内容は、以下のようになります。デモもありますので楽しんでみてください。

おまけ:見た目をゲームのようにしてみる

当記事で紹介した内容を利用して以下のように見た目をよりゲームのようにしてみました。見た目を変更するためにHTML・CSSを変更していますが、基本的に当記事で紹介した内容を利用しています。

実際に遊ぶことができますので、よければ体験してみてください。

やり直しボタンについて

やり直しボタンは、buttonタグのtype属性を「reset」にすることでHTMLだけで表現しています。

buttonタグのtype属性「reset」をformタグで囲むことにより、buttonタグが選択された時にformタグ内のinputタグが初期化されます。