このガイドでは、HTMLとCSSを使い、最終的に以下のような多機能Todoリストの「見た目」を完成させます。
一歩ずつ、着実に進めていきましょう。
まず、コーディングを始めるための準備をします。
TodoList
など好きな名前でフォルダを作成します。index.html
という名前で新しいファイルを作成します。index.html
に !
を入力し、Tab
キーを押してHTMLのひな形を生成します。<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多機能Todoリスト</title>
</head>
<body>
</body>
</html>
✅ これで準備完了です!これ以降の作業は、すべてこのファイルの<body>
と<head>
内で行います。
ページの部品を一つずつ、ゆっくりと配置していきます。
<div>
タグは、Webページの要素をまとめるための汎用的な「箱」です。class
属性で名前をつけることで、後からデザインを適用しやすくなります。
<body>
タグの中に、全体を包むコンテナ用のdiv
を一つだけ追加しましょう。
<body>
<___ class="container"></___>
</body>
正解
<body>
<div class="container"></div>
</body>
<header>
タグは、その名の通りページの「ヘッダー部分」であることを示す、意味のあるdiv
のようなものです。ヘッダーとはページの上部にある特別な部分です。
先ほど作った<div class="container">
の中に、ヘッダー用の箱を入れましょう。
<div class="container">
<___></___>
</div>
正解
<div class="container">
<header></header>
</div>
<h1>
タグは、ページで最も重要な「大見出し」を表します。
<header>
の中に、h1
タグでタイトルを入れましょう。
<header>
<___>📝 多機能Todoリスト</___>
</header>
正解
<header>
<h1>📝 多機能Todoリスト</h1>
</header>
<p>
タグは、「段落 (Paragraph)」を表し、一般的な文章に使います。
<h1>
タグの下に、<p>
タグで説明文を追加しましょう。
<header>
<h1>📝 多機能Todoリスト</h1>
<___>効率的なタスク管理で生産性を向上</___>
</header>
正解
<header">
<h1>📝 多機能Todoリスト</h1>
<p>効率的なタスク管理で生産性を向上</p>
</header>
✅ 中間確認
現在の<body>
タグの中身は以下のようになっています。
<body>
<div class="container">
<header>
<h1>📝 多機能Todoリスト</h1>
<p>効率的なタスク管理で生産性を向上</p>
</header>
</div>
</body>
<header>
の次に、統計情報を表示するための新しいセクションを作ります。
セクションごとに<div>
で囲むことで、ページの構造が整理され、管理しやすくなります。
先ほど作成した<header>
タグの下に、stats
というクラス名を持つdiv
を追加してください。
<div class="container">
<header>
...
</header>
<___ class="___"></___>
</div>
正解
<div class="container">
<header>
<h1>📝 多機能Todoリスト</h1>
<p>効率的なタスク管理で生産性を向上</p>
</header>
<div class="stats"></div>
</div>
stats
エリアの中に、最初の統計項目(総タスク数)を作ります。
<span>
タグは、p
タグやdiv
タグと違い、改行されないインラインのグループ化要素です。基本的に、pタグ内などのテキストの一部を強調したいときに使います
<div class="stats">
の中に、最初の項目を入れてください。
<div class="stats">
<div class="stat">
<span class="stat-number" id="totalTasks">___</span>
<div class="stat-label">______</div>
</div>
</div>
正解
<div class="stats">
<div class="stat">
<span class="stat-number" id="totalTasks">0</span>
<div class="stat-label">総タスク数</div>
</div>
</div>
今回stat-labelクラスのdivがもし、divでなくpである場合は、改行されずに横並びに表示されます。
それは、divがブロック要素と呼ばれ、必ず改行された後に表示されるものだからです。
対して、spanはインライン要素と呼ばれ、改行はされずにその場所に表示されます
今後インラインブロック要素というものも出てきます
コーディングでは、同じ構造をコピー&ペーストして中身だけを変える、という作業が頻繁に発生します。
先ほど作った<div class="stat">...</div>
をまるごとコピーし、下に3回貼り付けて、中身のテキストとid
を完成版に合わせて変更してください。
正解
<div class="stats">
<div class="stat">
<span class="stat-number" id="totalTasks">0</span>
<div class="stat-label">総タスク数</div>
</div>
<div class="stat">
<span class="stat-number" id="completedTasks">0</span>
<div class="stat-label">完了済み</div>
</div>
<div class="stat">
<span class="stat-number" id="pendingTasks">0</span>
<div class="stat-label">未完了</div>
</div>
<div class="stat">
<span class="stat-number" id="completionRate">0%</span>
<div class="stat-label">完了率</div>
</div>
</div>
🚀 このように、一つずつ要素を追加し、繰り返しを使いながらHTMLを構築していきます。この後の「入力フォーム」や「タスクリスト」も、<div>
で箱を作る → 中に<label>
や<input>
を入れる → 繰り返す という手順で作成します。
統計エリアの次に、新しいタスクを入力するためのフォーム全体を囲むセクションを作ります。
<label>
は、入力欄の項目名を示すタグです。for
属性の値と、関連する入力要素のid
属性の値を一致させることで、両者を関連付けます。
例えば、示されるコードでは、taskTitleというタグで一致しています。
<input>
は、ユーザーがデータを入力するための要素です。type
属性で入力フィールドの種類(テキスト、日付など)を指定します。
種類として、テキスト入力用のtype="text"
、日付選択用のtype="date"
、チェックボックス用のtype="checkbox"
などがあります。
またrequired属性を追加することで、必須入力項目にすることができます。
.stats
クラスのdiv
の下に、入力セクションを追加してください。まず、全体を囲むdiv
、項目名を示すlabel
、そして一行テキスト入力のinput
を配置します。
<div class="stats">
...
</div>
<div class="input-section">
<div class="input-container">
<div class="input-group">
<label for="taskTitle">タスク名 *</label>
<input type="text" id="taskTitle" placeholder="新しいタスクを入力..." required>
</div>
</div>
</div>
<select>
は、ドロップダウンリストを作成するタグです。内部に<option>
タグを配置して、選択肢のリストを定義します。
最初のinput-group
の下に、カテゴリ選択用の新しいinput-group
とselect
要素を追記します。
<div class="input-container">
<div class="input-group">
...
</div>
<div class="input-group">
<label for="taskCategory">カテゴリ</label>
<select id="taskCategory">
<option value="仕事">🏢 仕事</option>
<option value="個人">👤 個人</option>
<option value="学習">📚 学習</option>
<option value="健康">💪 健康</option>
<option value="買い物">🛒 買い物</option>
<option value="その他">📌 その他</option>
</select>
</div>
</div>
<textarea>
は、複数行のテキスト入力を可能にするタグです。rows
属性で、表示する行数を指定します。
.input-container
の下に、詳細説明用のtextarea
を含む新しいinput-group
を追記します。
<div class="input-container">
<div class="input-group">
...
<select id="taskCategory">
...
</select>
</div>
<div class="input-group">
<label for="taskDescription">詳細説明</label>
<textarea id="taskDescription" rows="3" placeholder="タスクの詳細を入力(任意)"></textarea>
</div>
</div>
<button>
は、クリック可能なボタンを定義するタグです。
textarea
を含むinput-group
の下に、タスク追加用のbutton
を追記します。
<div class="input-group">
...
</div>
<button class="btn-primary" onclick="">
➕ タスクを追加
</button>
入力セクションの次に、フィルターとタスク一覧を含む、リスト表示エリア全体を囲むdiv
を配置します。
.input-section
の終了タグの下に、todo-list
というクラス名を持つdiv
を追加してください。
<div class="input-section">
...
</div>
<___ class="___">
</___>
正解
<div class="input-section">
...
</div>
<div class="todo-list">
</div>
リスト表示エリアの中に、タスクを絞り込むためのボタン群を格納するdiv
を配置します。
div
を入れ子にすることで、セクション内の構造をさらに細かく整理します。
先ほど作成した.todo-list
の中に、filters
というクラス名を持つdiv
を追加してください。
<div class="todo-list">
<___ class="__">
</___>
</div>
正解
<div class="todo-list">
<div class="filters">
</div>
</div>
class
属性には、スペースで区切って複数のクラス名を指定できます。
.filters
の中に、最初のボタンを配置します。ここではfilter-btn
とactive
という2つのクラスを指定します。
このactiveクラスは、現在選択されているフィルターボタンを示すために使用します。
<div class="filters">
<___ class="filter-btn active">すべて</___>
</div>
正解
<div class="filters">
<button class="filter-btn active">すべて</button>
</div>
同じ構造の要素は、既存のコードを複製し、内容を修正することで効率的に作成します。
最初のボタンの下に、残り2つのフィルターボタンを追記してください。
<div class="filters">
<button class="filter-btn active">すべて</button>
<button class="filter-btn">未完了</button>
<button class="filter-btn">完了済み</button>
</div>
フィルターボタンの次に、タスク検索用の入力欄を配置します。
既存のクラスを再利用することで、スタイルの一貫性を保ちます。ここでは以前使用した.input-group
クラスを使います。
最後のbutton
の下に、input-group
とsearch-box
クラスを持つdiv
と、その中にinput
タグを追記してください。
<div class="filters">
...
<button class="filter-btn">完了済み</button>
<div class="______">
<___ type="text" id="searchInput" placeholder="🔍 タスクを検索...">
</div>
</div>
正解
<div class="filters">
...
<button class="filter-btn">完了済み</button>
<div class="input-group search-box">
<input type="text" id="searchInput" placeholder="🔍 タスクを検索...">
</div>
</div>
id
属性は、ページ内で一意の識別子を要素に与えます。CSSやJavaScriptから特定の要素を正確に指定するために使用します。
.filters
の終了タグの下に、タスク一覧が実際に表示されるコンテナとして、todo-container
というid
を持つdiv
を追加してください。
<div class="todo-list">
<div class="filters">
...
</div>
<___ id="___">
</___>
</div>
正解
<div class="todo-list">
<div class="filters">
...
</div>
<div id="todo-container">
</div>
</div>
<h3>
タグは、3番目のレベルの見出しを表します。<h1>
より重要度が低い小見出しに使用します。
タスクが一つもない場合に表示するメッセージを、#todo-container
の中にdiv
、h3
、p
タグを使って作成します。
<div id="todo-container">
<div class="empty-state">
<div style="font-size: 4em; margin-bottom: 20px;">📝</div>
<___>タスクがありません</___>
<___>新しいタスクを追加して始めましょう!</___>
</div>
</div>
正解
<div id="todo-container">
<div class="empty-state">
<div style="font-size: 4em; margin-bottom: 20px;">📝</div>
<h3>タスクがありません</h3>
<p>新しいタスクを追加して始めましょう!</p>
</div>
</div>
✅ これでHTMLの全ての骨格が完成しました。
HTMLの骨格ができたら、CSSで見た目を整えます。<head>
タグの中に<style>
タグを追加し、そこに記述していきます。
*
(アスタリスク)は、すべてのHTML要素を対象とするセレクタです。ここで全要素の余白(margin
, padding
)を0にリセットし、ブラウザによる表示のズレを防ぎます。
margin, paddingについてはデフォルトでゼロに設定し、各要素ごとに独自に設定するのが従うべきやり方(ベストプラクティス)です
またbox-sizingとは、要素の幅や高さを計算する際に、paddingやborderを含めるかどうかを指定するプロパティです。これを使うことで、要素のサイズをより直感的に扱うことができます。
<head>
内に<style>
タグを作り、以下を記述
<head>
...
<title>多機能Todoリスト</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</>
</head>
:root
内に--変数名: 値;
と書くことで、CSSで使える変数を定義できます。後でvar(--変数名)
として呼び出せるため、色の管理が非常に楽になります。
また、ダークモードの作成においても、この変数の値のみを変化させれば、簡単に対応できます。
先ほどのstyle
タグ内に、色を管理するための変数を定義します。
<style>
* { ... }
:root {
--primary-color: #667eea;
--text-primary: #2d3748;
--text-secondary: rgba(0, 0, 0, 0.6);
--bg-secondary: #ffffff;
--gradient-1: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--border-color: #e2e8f0;
}
</style>
ここでは基本的な色をカラーコードで設定しています。
色が変わる特別なデザインをlinear-gradientに作成しています。
このlinear-gradientは覚えなくてもよいです。
このような、機能がcssにはたくさんあるので、必要になったらその都度調べると良いです。
font-family
は、要素内のテキストのフォント(書体)を指定します。複数をカンマ区切りで指定するのが一般的です。
Segoe UI, sans-serif
のように書くと、「まずSegoe UI
フォントを試してみて、もしユーザーのPCになければ、そのPCにインストールされているゴシック体(sans-serif
)のどれかを使ってください」という意味になります。これをフォントスタックと呼びます。
body
にfont-family
を追加して、ページの基本フォントを設定しましょう。
body {
font-family: 'Segoe UI', sans-serif;
}
background
プロパティは、要素の背景を設定します。色、画像、そしてグラデーションなどを指定できます。今回は、以前:root
で定義したグラデーションの変数--gradient-1
を使いましょう。
body
にbackground
を追加します。
body {
font-family: 'Segoe UI', sans-serif;
background: var(--gradient-1); /* ここを追記 */
}
color
プロパティは、テキストの色を指定します。body
に指定すると、中の子要素にもその色が引き継がれるため、ページ全体の基本の文字色を設定するのに使われます。
body
にcolor
を追加して、基本の文字色を定義した変数--text-primary
に設定します。
body {
font-family: 'Segoe UI', sans-serif;
background: var(--gradient-1);
color: ___(___);
}
正解
body {
font-family: 'Segoe UI', sans-serif;
background: var(--gradient-1);
color: var(--text-primary);
}
max-width
は、要素の最大の横幅を指定します。ウィンドウの幅がこれより狭い場合は要素も一緒に縮みますが、広い場合でもこの幅以上に広がることはありません。これにより、大きな画面でもデザインが崩れにくくなります。
.container
にmax-width
を設定しましょう。
.container {
___: 800px;
}
正解
.container {
max-width: 800px;
}
margin: 20px auto;
は、「上下に20px
の余白、左右はauto
(自動)」という意味です。auto
を指定すると、ブラウザが利用可能な左右の余白を均等に割り振るため、結果として要素が中央に配置されます。
このmarginのように4辺あるなどで、複数の値を指定するcssプロパティがあります。
これらは指定する値の数に応じて、挙動が変わります。
値が二つの時は「上下」と「左右」、
値が4つの時は「上」、「右」、「下」、「左」 (時計回り) となります。
.container
にmargin
を追加して中央に配置します。
.container {
max-width: 800px;
margin: 20px auto; /* ここを追記 */
}
background
プロパティで、要素の背景に色や画像を指定できます。今回は、以前:root
で定義した変数--bg-secondary
(白)を使います。
.container
にbackground
を追加します。
.container {
max-width: 800px;
margin: 20px auto;
___: ___(___);
}
正解
.container {
max-width: 800px;
margin: 20px auto;
backgroud: var(--bg-secondary);
}
border-radius
は、要素の角の丸みをピクセル(px
)単位で指定します。数値が大きいほど、角はより丸くなります。
.container
にborder-radius
を追加して、カードのような見た目にします。
.container {
max-width: 800px;
margin: 20px auto;
background: var(--bg-secondary);
border-radius: 20px;
}
✅ これでコンテナの基本スタイルが完成しました。
padding
は、要素の内側の余白です。コンテンツ(文字や画像)と、その要素の枠線との間にスペースを作りたいときに使います。
header
にpadding
を追加して、文字の周りにゆとりを持たせます。
header {
padding: 30px;
}
text-align: center;
は、要素内のテキストやインライン要素を水平方向の中央に揃えます。
header
にtext-align
を追加します。
header {
padding: 30px;
text-align: center; /* ここを追記 */
}
color
プロパティは、テキストの色を指定します。ここではwhite
(白)を指定し、背景には以前定義したグラデーションの変数を使います。
header
にcolor
とbackground
を追加して、デザインを完成させます。
header {
padding: 30px;
text-align: center;
color: white; /* ここを追記 */
background: var(--gradient-1); /* ここを追記 */
}
統計エリアの項目を横並びに配置します。
display: flex;
は、要素のレイアウト方法を**「Flexbox」**に変更します。これを親要素(今回は.stats
)に指定するだけで、その直下の子要素(.stat
)が自動的に横並びになります。
このFlexboxは、要素を柔軟に配置するため、現代のWebデザインで非常に広く使われています。
.stats
にdisplay: flex;
を追加しましょう。
.stats {
display: flex;
}
justify-content
は、Flexboxの横方向の配置方法を指定します。space-around
を指定すると、各項目の両側に均等なスペースが作られ、結果として項目が程よい間隔で並びます。
.stats
にjustify-content
を追加します。
.stats {
display: flex;
justify-content: space-around; /* ここを追記 */
}
最後に、統計エリア全体の内側にpadding
を追加して、コンテナの端との間にスペースを作ります。
.stats {
display: flex;
justify-content: space-around;
padding: 20px; /* ここを追記 */
}
最後に、横並びになった個々の項目(.stat
)をデザインします。
.stat
の各項目を白いカードのように見せるため、背景色、内側の余白、角の丸みを設定します。
.stat {
background: white;
padding: 10px;
border-radius: 10px;
text-align: center;
}
box-shadow
は、要素に影をつけます。box-shadow: X Y Blur Color;
のように指定します。
rgba
を使うと透明度も指定できます).stat
に薄い影をつけて、少し浮き上がっているように見せます。
.stat {
background: white;
padding: 10px;
border-radius: 10px;
text-align: center;
box-shadow: 0 2px 10px rgba(0,0,0,0.05); /* ここを追記 */
}
transform: translateY(Y);
は、要素をY軸(垂直方向)に移動させます。負の値は上方向への移動を示します。
.stat
要素にマウスを乗せた時、少し上に動くようにtransform
プロパティを追加します。
.stat:hover {
___: translateY(-2px);
}
正解
.stat:hover {
transform: translateY(-2px);
}
transition
は、CSSプロパティの値が変化する際のアニメーションを指定します。all 0.2s ease
は、「すべてのプロパティの変化(all)を0.2秒かけて滑らか(ease)に実行する」という意味です。
all以外に特定のプロパティを指定することもできます。例えば、transition: transform 0.2s ease;
のように書くと、transform
プロパティの変化だけが対象になります。
.stat
クラス本体にtransition
プロパティを追加し、ホバー時の動きが滑らかになるようにします。
.stat {
/* ...既存のスタイル... */
___: all 0.2s ease;
}
正解
.stat {
/* ...既存のスタイル... */
transition: all 0.2s ease;
/* または transition: transform 0.2s ease; */
}
font-weight
は、文字の太さを指定するプロパティです。bold
や数値(例: 600
)で指定します。
文字と数値の対応は、
normal
: 400
bold
: 700
となります。
また、lighter
やbolder
を使うと、親要素のフォントウェイトに対して相対的に太さを調整できます。
.stat-number
クラスにスタイルを適用し、数字を大きく太くします。
.stat-number {
font-size: 1.8em;
font-weight: bold;
color: var(--primary-color);
}
display: block;
は、要素をブロックレベル要素として表示します。span
のようなインライン要素に指定すると、改行され、幅や高さ、上下のmargin
が有効になります。
.stat-number
クラスにdisplay: block;
を追加します。
.stat-number {
font-size: 1.8em;
font-weight: bold;
color: var(--primary-color);
___: block;
}
正解
.stat-number {
font-size: 1.8em;
font-weight: bold;
color: var(--primary-color);
display: block;
}
.stat-label
クラスにmargin-top
を追加し、数字との間に少し余白を作ります。
.stat-label {
font-size: 0.9em;
color: var(--text-secondary);
___: 5px;
}
正解
.stat-label {
font-size: 0.9em;
color: var(--text-secondary);
margin-top: 5px;
}
.btn-primary
クラスに、背景色、文字色、影を追加します。
border: none;
は、ボタンのデフォルトの枠線を消去します。
.btn-primary {
background: var(--gradient-1);
color: white;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
border: none;
padding: 12px;
border-radius: 10px;
font-size: 1.1rem;
width: 200px;
}
.input-section
クラスにpadding
を追加して、セクションの内側に余白を設定してください。
.input-section {
___: 20px;
}
正解
.input-section {
padding: 20px;
}
<div class="knowledge">
display: flex;
は、要素のレイアウト方法をFlexboxに変更します。子要素を柔軟に配置するために使用します。
</div>
.input-container
クラスでFlexboxレイアウトを有効にしてください。
.input-container {
___: ___;
}
正解
.input-container {
display: flex;
}
<div class="knowledge">
flex-direction
は、Flexboxの主軸の方向を指定するプロパティです。column
を指定すると、子要素が縦方向に配置されます。
</div>
.input-container
に`で入力欄のグループが縦に並ぶようにしてください。
.input-container {
display: flex;
___: ___;
}
正解
.input-container {
display: flex;
flex-direction: column;
}
<div class="knowledge">
gap
は、FlexboxやGridレイアウトのアイテム間の間隔を指定するプロパティです。
</div>
.input-container
にgap
を追加して、各入力欄グループの間に15px
の間隔を設定してください。
.input-container {
display: flex;
flex-direction: column;
___: ___;
}
正解
.input-container {
display: flex;
flex-direction: column;
gap: 15px;
}
セレクタをカンマ(,
)で区切ると、複数の要素に同じスタイルを一度に適用できます。
input
, select
, textarea
の全てに共通するスタイルを定義します。
ここでは、復習として、widthは親要素の横幅と同じにし、角丸を10pxで指定してみてください。
input, select, textarea {
width: ___;
padding: 12px 15px;
border: 2px solid var(--border-color);
___: 10px;
}
正解
input, select, textarea {
width: 100%;
padding: 12px 15px;
border: 2px solid var(--border-color);
border-radius: 10px;
}
outline: none;
は、フォーカス時にブラウザがデフォルトで表示する枠線(アウトライン)を非表示にします。
入力欄がフォーカスされた時に、枠線の色を変え、影をつけるスタイルを定義します。
input:___, select:___, textarea:___ {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
正解
input:focus, select:focus, textarea:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.filters
クラスにFlexboxと、アイテム間の間隔を10pxに設定して、フィルターボタンと検索ボックスを横に並べられるようにします。
.filters {
___: ___;
___: 10px;
align-items: center;
margin-bottom: 15px;
}
正解
.filters {
display: flex;
gap: 10px;
align-items: center;
margin-bottom: 15px;
}
<div class="knowledge">
cursor: pointer;
は、要素にマウスを乗せた時のカーソルの形状を、クリック可能であることを示す指の形に変更します。
</div>
.filter-btn
クラスにスタイルを適用してください。
.filter-btn {
padding: 8px 12px;
border: none;
border-radius: 5px;
___: pointer;
background: #e2e8f0;
color: var(--text-primary);
}
正解
.filter-btn {
padding: 8px 12px;
border: none;
border-radius: 5px;
cursor: pointer;
background: #e2e8f0;
color: var(--text-primary);
}
<div class="knowledge">
.class1 .class2
のようにクラス名を繋げて記述するセレクタは、「class1とclass2の両方を持つ要素」を指定します。
</div>
.filter-btn.active
セレクタにスタイルを適用し、選択されているボタン文字色をを白色にしてください。
.filter-btn.active {
background: var(--primary-color);
color: ___;
}
正解
.filter-btn.active {
background: var(--primary-color);
color: white;
}
<div class="knowledge">
flex: 1;
は、Flexboxのアイテムが、コンテナ内の余ったスペースをすべて埋めるように伸長することを指定します。
</div>
.search-box
クラスにflex: 1;
を追加して、検索ボックスがフィルターエリアの残りの幅をすべて使用するようにしてください。
.search-box {
___: 1;
}
正解
.search-box {
flex: 1;
}
<div class="knowledge">
min-height
は、要素の最小の高さを指定します。コンテンツがなくても、この高さが確保されます。
</div>
#todo-container
に最小の高さを設定し、.empty-state
にスタイルを適用して、メッセージを中央に表示してください。
#todo-container {
___: 200px;
}
.empty-state {
text-align: center;
color: var(--text-secondary);
padding: 40px;
}
正解
#todo-container {
min-height: 200px;
}
.empty-state {
text-align: center;
color: var(--text-secondary);
padding: 40px;
}
✅ これで主要なコンポーネントのスタイリングが完了しました。残りの細かいスタイルは、最終コードで確認し、同様の手順で一つずつ適用していくことで完成させることができます。
完成版コード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>多機能Todoリスト</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #667eea;
--text-primary: #2d3748;
--text-secondary: rgba(0, 0, 0, 0.6);
--bg-secondary: #ffffff;
--gradient-1: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--border-color: #e2e8f0;
}
body {
font-family: "Segoe UI", sans-serif;
background: var(--gradient-1);
color: var(--text-primary);
}
.container {
max-width: 800px;
margin: 20px auto;
background: var(--bg-secondary);
border-radius: 20px;
}
header {
padding: 30px;
text-align: center;
color: white;
background: var(--gradient-1);
}
.stats {
display: flex;
justify-content: space-around;
padding: 20px;
}
.stat {
background: white;
padding: 10px;
border-radius: 10px;
text-align: center;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
transition: all 0.2s ease;
}
.stat:hover {
transform: translateY(-2px);
}
.stat-number {
font-size: 1.8em;
font-weight: bold;
color: var(--primary-color);
display: block;
}
.stat-label {
font-size: 0.9em;
color: var(--text-secondary);
margin-top: 5px;
}
.input-section {
padding: 20px;
}
.input-container {
display: flex;
flex-direction: column;
gap: 15px;
}
.input-group {
display: flex;
flex-direction: column;
}
input,
select,
textarea {
width: 100%;
padding: 12px 15px;
border: 2px solid var(--border-color);
border-radius: 10px;
}
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.btn-primary {
background: var(--gradient-1);
color: white;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
border: none;
padding: 12px;
border-radius: 10px;
font-size: 1.1rem;
width: 200px;
}
.todo-list {
padding: 20px;
}
.filters {
display: flex;
gap: 10px;
align-items: center;
margin-bottom: 15px;
}
.filter-btn {
padding: 8px 12px;
border: none;
border-radius: 5px;
cursor: pointer;
background: #e2e8f0;
color: var(--text-primary);
}
.filter-btn.active {
background: var(--primary-color);
color: white;
}
.search-box {
flex: 1;
}
.search-box input {
width: 100%;
}
#todo-container {
min-height: 200px;
}
.empty-state {
text-align: center;
color: var(--text-secondary);
padding: 40px;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>📝 多機能Todoリスト</h1>
<p>効率的なタスク管理で生産性を向上</p>
</header>
<div class="stats">
<div class="stat">
<span class="stat-number" id="totalTasks">0</span>
<div class="stat-label">総タスク数</div>
</div>
<div class="stat">
<span class="stat-number" id="completedTasks">0</span>
<div class="stat-label">完了済み</div>
</div>
<div class="stat">
<span class="stat-number" id="pendingTasks">0</span>
<div class="stat-label">未完了</div>
</div>
<div class="stat">
<span class="stat-number" id="completionRate">0%</span>
<div class="stat-label">完了率</div>
</div>
</div>
<div class="input-section">
<div class="input-container">
<div class="input-group">
<label for="taskTitle">タスク名 *</label>
<input type="text" id="taskTitle" placeholder="新しいタスクを入力..." required />
</div>
<div class="input-group">
<label for="taskCategory">カテゴリ</label>
<select id="taskCategory">
<option value="仕事">🏢 仕事</option>
<option value="個人">👤 個人</option>
<option value="学習">📚 学習</option>
<option value="健康">💪 健康</option>
<option value="買い物">🛒 買い物</option>
<option value="その他">📌 その他</option>
</select>
</div>
<div class="input-group">
<label for="taskDescription">詳細説明</label>
<textarea id="taskDescription" rows="3" placeholder="タスクの詳細を入力(任意)"></textarea>
</div>
<button class="btn-primary">➕ タスクを追加</button>
</div>
</div>
<div class="todo-list">
<div class="filters">
<button class="filter-btn active">すべて</button>
<button class="filter-btn">未完了</button>
<button class="filter-btn">完了済み</button>
<div class="input-group search-box">
<input type="text" id="searchInput" placeholder="🔍 タスクを検索..." />
</div>
</div>
<div id="todo-container">
<div class="empty-state">
<div style="font-size: 4em; margin-bottom: 20px">📝</div>
<h3>タスクがありません</h3>
<p>新しいタスクを追加して始めましょう!</p>
</div>
</div>
</div>
</div>
</body>
</html>