これまでは、Web上のキッチンタイマーを開いて使っていました。しかし、せっかくなら自分で作ってみたい。
このシリーズについて
AIと作業を分担して作ります
今回のWebアプリ制作では、ソースコードの作成を、のんびり研究所のAI「ノン」に担当してもらっています。
私は、どのような機能が必要なのか、どのように動いてほしいのかを考え、ノンと細かく相談しながら仕様を決めています。

欲しい機能や使い方は私が考えるけど、ソースコードの作成はノンにお願いするよ。

私がコードを作り、きょろぽんが実際に動かして確認します。気になるところがあれば、相談しながら修正していきましょう。
今回の役割分担は、次のような形です。
- 人が、目的や必要な機能、使い方を考える
- AIが、HTML・CSS・JavaScriptのソースコードを作る
- 人が、実際に動かして確認し、気になる部分や修正点をAIへ伝える
私はソースコードを一から書かないため、私の担当部分だけを見ると、ノーコードに近い進め方です。ただし、完成したWebアプリの内部では、HTML・CSS・JavaScriptが動いています。
完成したコードから勉強することもできます
コードの中で気になる部分があったり、自分でもプログラミングを覚えたいと思ったりした場合は、AIへ「この部分は何をしているの?」と質問できます。変数、条件分岐、ボタンを押したときの処理など、完成したソースコードを教材にして、興味を持った部分から少しずつ学ぶこともできます。
今回は、プログラミング言語を最初からすべて覚えてから作るのではなく、AIと作業を分担して先に動くものを完成させ、必要になった部分や興味を持った部分を後から学べる制作方法を試します。
そこで今回から、HTML・CSS・JavaScriptを使って、試験用のタイマーを少しずつ作っていきます。

模擬試験で使うキッチンタイマーが1個欲しいんだよね。どうせなら、自分で作ってみようかな。

いいね。最初から大きな仕組みを作ろうとせず、まずは停止・再開・リセットができる単体タイマーを完成させよう。
今回作るもの
第1回では、次の機能を持つシンプルなキッチンタイマーを作ります。
- 分と秒を入力できる
- スタートできる
- 途中で一時停止できる
- 停止したところから再開できる
- リセットして最初の状態へ戻せる
- 残り時間が0秒になったら停止する
- 0分0秒では開始できない
- 秒は0~59の範囲で入力する
今回は、まずパソコンで動くところまで作ります。スマートフォンでも見やすくする調整は、次回行う予定です。
今回の目標
見た目を作り込むことよりも、タイマーが正しく動き、停止・再開・リセットまで一通り操作できることを優先します。
使用するもの
今回は、次の環境で制作します。
| 項目 | 内容 |
|---|---|
| パソコン | Windowsパソコン |
| エディター | Visual Studio Code |
| 使用する言語 | HTML・CSS・JavaScript |
| 必要な費用 | 無料 |
| 動作確認 | Webブラウザ |
| AI | ChatGPT(ノン) |
特別な開発ソフトや有料サービスは使いません。Visual Studio CodeとWebブラウザがあれば始められます。
HTML・CSS・JavaScriptの役割
今回作るタイマーは、3種類のファイルを組み合わせて動かします。
| ファイル | 役割 |
|---|---|
index.html | 文字、入力欄、ボタンなど、画面の土台を作る |
style.css | 色、余白、文字サイズ、ボタンなど、見た目を整える |
script.js | カウントダウン、停止、再開、リセットなどの動きを作る |

家に例えると、HTMLが柱や壁、CSSが壁紙や家具、JavaScriptが照明や自動ドアみたいな感じかな。

そのイメージで大丈夫。今回は3つを分けて作るので、どのファイルが何を担当しているか確認しやすいよ。
Visual Studio Codeをインストールする
まずは、プログラムを書くためのエディターとして、Visual Studio Codeをインストールします。
Visual Studio Codeは、一般に「VS Code」と呼ばれています。無料で利用でき、HTML・CSS・JavaScriptを使ったWeb制作にも向いています。

インストーラーをダウンロードする
- Visual Studio Codeの公式サイトを開きます。
- Windows用のダウンロードボタンをクリックします。
- ダウンロードされたインストーラーを開きます。

Visual Studio Codeをインストールする
インストーラーを起動したら、画面の案内に沿って進めます。
- 使用許諾契約書を確認し、「同意する」を選択します。
- インストール先を確認します。
- スタートメニューへ登録する設定を確認します。
- 追加タスクを確認します。
- 「インストール」をクリックします。
- 完了画面が表示されたら、Visual Studio Codeを起動します。



画面が記事と少し違っても慌てなくて大丈夫です。
Visual Studio Codeのバージョンによって、ボタンの位置や文章が変わることがあります。インストール先などを特別に変更する理由がなければ、基本的には初期設定のまま進めます。
作業用フォルダを作る
次に、今回のタイマーに必要なファイルをまとめて保存するフォルダを作ります。
今回は例として、フォルダ名を次のようにします。
kitchen-timer- エクスプローラーを開きます。
- 分かりやすい場所へ新しいフォルダを作ります。
- フォルダ名を
kitchen-timerにします。
デスクトップへ作っても構いませんが、今後も開発を続ける場合は、ドキュメント内などに開発用フォルダを作ってまとめておくと管理しやすくなります。

Visual Studio Codeでフォルダを開く
Visual Studio Codeを起動します。(Continue without Signing Inをクリック)

テーマ設定が出ます。
- Dark 2026:見やすくて無難
- Dark High Contrast:文字をかなりくっきり見たい人向け
- Solarized Dark:少し色味が独特
テーマは好みで選んで問題ありません。今回はDark 2026を選択しました

VS CodeにはAIによる開発支援機能もありますが、今回は使用しません。右上ので閉じます。

上部メニューの「ファイル」をクリックします。
「フォルダーを開く」をクリックします。

先ほど作成したkitchen-timerフォルダを選択します。
「フォルダーの選択」をクリックします。

初めてフォルダを開いたときに、このフォルダ内のファイルの作成者を信頼するか確認される場合があります。
自分で作ったフォルダであることを確認し、「信頼する」を選びます。
使用しているVS Codeのバージョンや設定によっては、この確認画面が表示されないこともあります。今回の環境では表示されなかったため、そのまま次へ進みます。
3つのファイルを作る
Visual Studio Codeの左側にあるエクスプローラーから、次の3ファイルを作成します。

index.htmlstyle.cssscript.js

ファイル名は半角英数字で入力します。特に、ピリオドの後ろにある拡張子を間違えないようにしてください。
画面上部に「Restricted Mode」と表示された場合は、右側の「Manage」をクリックします。
自分で作成したフォルダであることを確認し、「Trust」を選択します。
右上の×で画面を閉じます。
- Manage:このフォルダを信頼するか設定する画面を開く
- Learn More:Workspace Trustの説明ページを開く



ファイルが3つになっただけで、急にプログラミングを始めた感じがするな……。

まだ中身は空っぽだけど、これで土台は完成。ここから1ファイルずつ役割を持たせていこう。
HTMLで画面の土台を作る
最初に、index.htmlへ画面の土台を書きます。
index.htmlをクリックして開き、次のコードを入力します。
index.htmlのソースコードを表示
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>キッチンタイマー</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="timer-app">
<h1>キッチンタイマー</h1>
<div class="time-inputs">
<label>
分
<input type="number" id="minutes" min="0" value="1">
</label>
<label>
秒
<input type="number" id="seconds" min="0" max="59" value="0">
</label>
</div>
<p id="error-message" class="error-message"></p>
<div id="display" class="timer-display">01:00</div>
<div class="buttons">
<button id="start-button" type="button">スタート</button>
<button id="pause-button" type="button" disabled>一時停止</button>
<button id="reset-button" type="button">リセット</button>
</div>
</main>
<script src="script.js"></script>
</body>
</html>入力後、Ctrl+Sを押して保存します。
HTMLの主な内容
<h1>でタイトルを表示しています。<input>で分と秒の入力欄を作っています。<div id="display">へ残り時間を表示します。<button>でスタート、一時停止、リセットのボタンを作っています。style.cssを読み込み、見た目を反映します。script.jsを読み込み、タイマーの動きを反映します。
idは部品の名前札id="minutes"やid="start-button"は、JavaScriptから目的の入力欄やボタンを見つけるための名前札として使います。

CSSで見た目を整える
次に、style.cssへ見た目の設定を書きます。
style.css のソースコードを表示
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: sans-serif;
background: #f3f5f7;
color: #222;
}
.timer-app {
width: 520px;
padding: 32px;
border-radius: 16px;
background: #ffffff;
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.12);
text-align: center;
}
.timer-app h1 {
margin-top: 0;
}
.time-inputs {
display: flex;
justify-content: center;
gap: 24px;
margin-bottom: 16px;
}
.time-inputs label {
display: flex;
align-items: center;
gap: 8px;
font-weight: bold;
}
.time-inputs input {
width: 90px;
padding: 10px;
border: 1px solid #999;
border-radius: 8px;
font-size: 1.2rem;
text-align: right;
}
.error-message {
min-height: 1.5em;
margin: 0 0 8px;
color: #c62828;
font-weight: bold;
}
.timer-display {
margin: 16px 0 24px;
font-size: 5rem;
font-weight: bold;
line-height: 1;
letter-spacing: 0.05em;
}
.buttons {
display: flex;
justify-content: center;
gap: 12px;
}
.buttons button {
min-width: 120px;
padding: 12px 18px;
border: 0;
border-radius: 8px;
font-size: 1rem;
font-weight: bold;
cursor: pointer;
}
#start-button {
background: #2e7d32;
color: #ffffff;
}
#pause-button {
background: #f9a825;
color: #222222;
}
#reset-button {
background: #546e7a;
color: #ffffff;
}
.buttons button:disabled {
cursor: not-allowed;
opacity: 0.45;
}入力後、Ctrl+Sを押して保存します。
CSSで設定していること
- タイマー全体を画面中央へ配置する
- 白いパネルへ影を付ける
- 分と秒の入力欄を横並びにする
- 残り時間を大きく表示する
- ボタンごとに色を分ける
- 使用できないボタンを薄く表示する
色や大きさは、あとから自由に変更できます。今回は動作確認を優先するため、シンプルな見た目にしています。

JavaScriptでタイマーを動かす
最後に、script.jsへタイマーの処理を書きます。
script.js のソースコードを表示
const minutesInput = document.getElementById("minutes");
const secondsInput = document.getElementById("seconds");
const display = document.getElementById("display");
const errorMessage = document.getElementById("error-message");
const startButton = document.getElementById("start-button");
const pauseButton = document.getElementById("pause-button");
const resetButton = document.getElementById("reset-button");
let timerId = null;
let endTime = 0;
let remainingMilliseconds = 0;
let isRunning = false;
let isPaused = false;
function getInputMilliseconds() {
const minutes = Number(minutesInput.value);
const seconds = Number(secondsInput.value);
if (!Number.isInteger(minutes) || minutes < 0) {
showError("分は0以上の整数で入力してください。");
return null;
}
if (!Number.isInteger(seconds) || seconds < 0 || seconds > 59) {
showError("秒は0~59の整数で入力してください。");
return null;
}
const totalMilliseconds = (minutes * 60 + seconds) * 1000;
if (totalMilliseconds === 0) {
showError("0分0秒では開始できません。");
return null;
}
clearError();
return totalMilliseconds;
}
function showError(message) {
errorMessage.textContent = message;
}
function clearError() {
errorMessage.textContent = "";
}
function formatTime(milliseconds) {
const totalSeconds = Math.max(0, Math.ceil(milliseconds / 1000));
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
}
function updateDisplay() {
if (!isRunning) {
return;
}
remainingMilliseconds = endTime - Date.now();
if (remainingMilliseconds <= 0) {
finishTimer();
return;
}
display.textContent = formatTime(remainingMilliseconds);
}
function startTimer() {
if (isRunning) {
return;
}
if (!isPaused) {
const inputMilliseconds = getInputMilliseconds();
if (inputMilliseconds === null) {
return;
}
remainingMilliseconds = inputMilliseconds;
}
endTime = Date.now() + remainingMilliseconds;
isRunning = true;
isPaused = false;
minutesInput.disabled = true;
secondsInput.disabled = true;
startButton.textContent = "スタート";
startButton.disabled = true;
pauseButton.disabled = false;
updateDisplay();
timerId = window.setInterval(updateDisplay, 200);
}
function pauseTimer() {
if (!isRunning) {
return;
}
remainingMilliseconds = Math.max(0, endTime - Date.now());
window.clearInterval(timerId);
timerId = null;
isRunning = false;
isPaused = true;
display.textContent = formatTime(remainingMilliseconds);
startButton.textContent = "再開";
startButton.disabled = false;
pauseButton.disabled = true;
}
function resetTimer() {
window.clearInterval(timerId);
timerId = null;
isRunning = false;
isPaused = false;
endTime = 0;
remainingMilliseconds = 0;
minutesInput.value = 1;
secondsInput.value = 0;
minutesInput.disabled = false;
secondsInput.disabled = false;
display.textContent = "01:00";
startButton.textContent = "スタート";
startButton.disabled = false;
pauseButton.disabled = true;
clearError();
}
function finishTimer() {
window.clearInterval(timerId);
timerId = null;
isRunning = false;
isPaused = false;
remainingMilliseconds = 0;
display.textContent = "00:00";
startButton.disabled = true;
pauseButton.disabled = true;
}
function updatePreview() {
if (isRunning || isPaused) {
return;
}
const minutes = Number(minutesInput.value);
const seconds = Number(secondsInput.value);
if (
Number.isInteger(minutes) &&
minutes >= 0 &&
Number.isInteger(seconds) &&
seconds >= 0 &&
seconds <= 59
) {
const totalMilliseconds = (minutes * 60 + seconds) * 1000;
display.textContent = formatTime(totalMilliseconds);
clearError();
}
}
startButton.addEventListener("click", startTimer);
pauseButton.addEventListener("click", pauseTimer);
resetButton.addEventListener("click", resetTimer);
minutesInput.addEventListener("input", updatePreview);
secondsInput.addEventListener("input", updatePreview);入力後、Ctrl+Sを押して保存します。

1秒ずつ数字を減らしていない理由
このタイマーでは、残り時間の変数を1秒ずつ減らすだけの方法ではなく、終了予定時刻と現在のパソコン時刻との差から残り時間を計算しています。
残り時間 = 終了予定時刻 − 現在の時刻開始時には、現在の時刻へ設定時間を加えて、終了予定時刻を作ります。
終了予定時刻 = 開始時の時刻 + 設定時間ブラウザの処理が一時的に遅れた場合でも、現在時刻との差を取り直すため、単純に1秒ずつ減らす方法より時間のずれを抑えやすくなります。

1秒減らして、また1秒減らして……じゃなくて、終了予定時刻まであと何秒かを毎回確認してるんだね。

そう。あとでタイマーを複数に増やしたり、ブラウザを再読み込みしたときの復元を考えたりする場合にも、この方法が使いやすいよ。
作ったタイマーをブラウザで開く
3つのファイルを保存したら、index.htmlをWebブラウザで開きます。
- エクスプローラーで
kitchen-timerフォルダを開きます。 index.htmlをダブルクリックします。- Webブラウザにタイマーが表示されることを確認します。

変更が反映されない場合
Visual Studio Codeでファイルを保存してから、ブラウザの再読み込みボタンを押してください。Ctrl+Rでも再読み込みできます。
タイマーを動かしてみる
まずは短い時間を入力して、各機能を確認します。
スタートを確認する
- 分を0にします。
- 秒を5にします。
- 「スタート」をクリックします。
- 残り時間が減ることを確認します。
- 0秒で停止することを確認します。

一時停止と再開を確認する
- 10秒程度を設定してスタートします。
- 途中で「一時停止」をクリックします。
- 表示が止まることを確認します。
- 「再開」をクリックします。
- 停止した残り時間からカウントダウンが続くことを確認します。
一時停止した瞬間の残り時間を保存し、再開時のパソコン時刻へ加えて、新しい終了予定時刻を作っています。
新しい終了予定時刻 = 再開時の時刻 + 停止中に保存した残り時間リセットを確認する
- タイマーの動作中、または停止中に「リセット」をクリックします。
- 表示が
01:00へ戻ることを確認します。 - 分と秒の入力欄が再び使えることを確認します。
- ボタンが初期状態へ戻ることを確認します。
入力エラーを確認する
今回のタイマーでは、入力値を自動的に別の時間へ換算せず、間違った入力はエラーとして表示します。
| 入力内容 | 結果 |
|---|---|
| 0分0秒 | 開始できない |
| 分がマイナス | エラーを表示 |
| 秒がマイナス | エラーを表示 |
| 秒が60以上 | エラーを表示 |
| 数字以外や小数 | エラーを表示 |
たとえば、秒へ90と入力しても、1分30秒へ自動変換しません。「秒は0~59の整数で入力してください」と表示します。

秒に90って入れたら、勝手に1分30秒になるんじゃないのか……。

今回は入力ミスに気付きやすいように、範囲外の数字はエラーにしているよ。試験で使う時間だから、意図しない自動換算を避けよう。

うまく動かないときの確認
画面が表示されない、ボタンを押しても動かない場合は、次の点を確認します。
- 3つのファイルが同じフォルダに保存されているか
- ファイル名が
index.html、style.css、script.jsになっているか - 全角英数字や余分な空白がファイル名に入っていないか
- コードを最後まで貼り付けているか
- 各ファイルを保存したか
- ブラウザを再読み込みしたか
- 記号や引用符を消していないか
ファイルの拡張子に注意
Windowsの設定によっては、拡張子が表示されず、実際にはindex.html.txtになっている場合があります。ファイルの種類が「HTMLドキュメント」になっているか確認してください。
今回の完成形
これで、次の操作ができる単体キッチンタイマーが完成しました。
- 分と秒を入力する
- スタートする
- 一時停止する
- 停止した時間から再開する
- リセットする
- 0秒で停止する
- 間違った入力をエラーで知らせる
まだ見た目はパソコン向けの固定サイズです。スマートフォンで開くと、画面幅によっては見づらくなる可能性があります。

パソコンでは動いたけど、念のためスマートフォンでも使えるようにしておきたいな。

では次回は、画面の幅に合わせて大きさが変わるようにして、縦画面と横画面の両方を確認しよう。
完成したキッチンタイマーを使ってみる
まとめ
第1回では、Visual Studio Codeを導入し、HTML・CSS・JavaScriptの3ファイルを使って、単体キッチンタイマーを作りました。
HTMLで画面の部品を作り、CSSで見た目を整え、JavaScriptでカウントダウンやボタン操作を実装しています。
また、残り時間は単純に1秒ずつ減らすのではなく、終了予定時刻とパソコンの現在時刻との差から計算しています。
次回は、このタイマーをパソコンだけでなく、スマートフォンの縦画面・横画面でも見やすくなるように調整します。


