第12回:総合制作②(実装・開発)
🎯 学習目標
前回の企画・設計をもとに、実際にWebサイトの実装を進めます。これまで学習した全ての技術を統合して活用します。
- 実装力: 設計書に基づいて実際にコーディングができる
- 統合力: HTML、CSS、JavaScriptを適切に組み合わせて使える
- 問題解決力: 実装中に発生する問題を自分で解決できる
- 品質意識: 保守性とパフォーマンスを考慮したコードが書ける
📚 導入(10分)
前回の振り返り
- 企画書の内容確認
- ワイヤーフレームのレビュー
- 技術仕様の最終確認
今回の作業フロー
- 基本構造の実装(HTML)
- スタイリング(CSS)
- インタラクション(JavaScript)
- テスト・調整
- 最適化
💡 理論学習(20分)
1. 実装のベストプラクティス
1.1 セマンティックなHTML構造
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="サイトの説明">
<title>サイトタイトル</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>
<nav aria-label="メインナビゲーション">
<ul>
<li><a href="#home">ホーム</a></li>
<li><a href="#about">アバウト</a></li>
<li><a href="#contact">お問い合わせ</a></li>
</ul>
</nav>
</header>
<main>
<section id="hero">
<h1>メインタイトル</h1>
<p>サイトの説明文</p>
</section>
<section id="content">
<article>
<h2>コンテンツタイトル</h2>
<p>コンテンツの詳細</p>
</article>
</section>
</main>
<footer>
<p>© 2024 サイト名</p>
</footer>
<script src="js/main.js"></script>
</body>
</html>1.2 効率的なCSS設計
/* リセット・基本設定 */
* {
box-sizing: border-box;
}
:root {
--primary-color: #3498db;
--secondary-color: #2c3e50;
--text-color: #333;
--background-color: #fff;
--max-width: 1200px;
}
/* レイアウト */
.container {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 1rem;
}
/* コンポーネント */
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
background-color: var(--primary-color);
color: white;
text-decoration: none;
border-radius: 4px;
transition: background-color 0.3s ease;
}
.btn:hover {
background-color: darken(var(--primary-color), 10%);
}
/* レスポンシブ */
@media (max-width: 768px) {
.container {
padding: 0 0.5rem;
}
}1.3 モジュラーなJavaScript
// モジュールパターン
const WebSite = {
// 初期化
init() {
this.bindEvents();
this.loadContent();
},
// イベントバインディング
bindEvents() {
document.addEventListener('DOMContentLoaded', () => {
this.setupNavigation();
this.setupForms();
this.setupAnimations();
});
},
// ナビゲーション設定
setupNavigation() {
const navLinks = document.querySelectorAll('nav a');
navLinks.forEach(link => {
link.addEventListener('click', this.smoothScroll);
});
},
// スムーススクロール
smoothScroll(e) {
e.preventDefault();
const target = document.querySelector(e.target.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth'
});
}
},
// フォーム処理
setupForms() {
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', this.handleFormSubmit);
});
},
// フォーム送信処理
handleFormSubmit(e) {
e.preventDefault();
const formData = new FormData(e.target);
console.log('フォームデータ:', Object.fromEntries(formData));
// 実際のAPI送信処理をここに実装
}
};
// 初期化実行
WebSite.init();2. パフォーマンス最適化
2.1 画像最適化
<!-- レスポンシブ画像 -->
<img src="image-small.jpg"
srcset="image-small.jpg 480w,
image-medium.jpg 800w,
image-large.jpg 1200w"
sizes="(max-width: 480px) 100vw,
(max-width: 800px) 50vw,
25vw"
alt="画像の説明"
loading="lazy">2.2 CSS・JavaScript最適化
<!-- CSS最適化 -->
<link rel="preload" href="css/critical.css" as="style">
<link rel="stylesheet" href="css/critical.css">
<link rel="stylesheet" href="css/non-critical.css" media="print"
onload="this.media='all'">
<!-- JavaScript最適化 -->
<script src="js/critical.js"></script>
<script src="js/non-critical.js" defer></script>🛠️ 実習(50分)
ステップ1: プロジェクト構造の準備(10分)
ファイル構成の作成
# ディレクトリ構造
project/
├── index.html
├── css/
│ ├── reset.css
│ ├── style.css
│ └── responsive.css
├── js/
│ ├── main.js
│ └── components.js
├── images/
├── assets/
└── README.mdreset.cssの設定
/* reset.css */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-size: 62.5%; /* 1rem = 10px */
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: #333;
}
img {
max-width: 100%;
height: auto;
}
a {
color: inherit;
text-decoration: none;
}
button {
border: none;
background: none;
cursor: pointer;
}
ul, ol {
list-style: none;
}ステップ2: HTMLの実装(15分)
基本構造の作成
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>マイプロジェクト</title>
<meta name="description" content="プロジェクトの説明">
<!-- スタイルシート -->
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/responsive.css">
</head>
<body>
<!-- ヘッダー -->
<header class="header">
<div class="container">
<div class="header__logo">
<h1>サイトロゴ</h1>
</div>
<nav class="nav">
<ul class="nav__list">
<li class="nav__item">
<a href="#home" class="nav__link">ホーム</a>
</li>
<li class="nav__item">
<a href="#about" class="nav__link">アバウト</a>
</li>
<li class="nav__item">
<a href="#services" class="nav__link">サービス</a>
</li>
<li class="nav__item">
<a href="#contact" class="nav__link">お問い合わせ</a>
</li>
</ul>
<!-- ハンバーガーメニュー -->
<button class="nav__toggle" aria-label="メニューを開く">
<span></span>
<span></span>
<span></span>
</button>
</nav>
</div>
</header>
<!-- メインコンテンツ -->
<main>
<!-- ヒーローセクション -->
<section id="home" class="hero">
<div class="container">
<div class="hero__content">
<h2 class="hero__title">メインキャッチコピー</h2>
<p class="hero__text">サイトの説明文がここに入ります。</p>
<a href="#contact" class="btn btn--primary">お問い合わせ</a>
</div>
</div>
</section>
<!-- その他のセクション -->
<section id="about" class="section">
<div class="container">
<h2 class="section__title">アバウト</h2>
<p class="section__text">アバウト内容</p>
</div>
</section>
</main>
<!-- フッター -->
<footer class="footer">
<div class="container">
<p>© 2024 サイト名 All rights reserved.</p>
</div>
</footer>
<!-- JavaScript -->
<script src="js/main.js"></script>
</body>
</html>ステップ3: CSSスタイリング(15分)
メインスタイル
/* CSS変数 */
:root {
--primary-color: #3498db;
--secondary-color: #2c3e50;
--accent-color: #e74c3c;
--text-color: #333;
--bg-color: #fff;
--border-color: #ddd;
--max-width: 1200px;
--header-height: 70px;
}
/* 共通スタイル */
.container {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 2rem;
}
.section {
padding: 6rem 0;
}
.section__title {
font-size: 3.2rem;
margin-bottom: 2rem;
text-align: center;
}
.btn {
display: inline-block;
padding: 1.2rem 2.4rem;
border-radius: 4px;
font-weight: 600;
text-align: center;
transition: all 0.3s ease;
cursor: pointer;
}
.btn--primary {
background-color: var(--primary-color);
color: white;
}
.btn--primary:hover {
background-color: #2980b9;
transform: translateY(-2px);
}
/* ヘッダー */
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: var(--header-height);
background-color: var(--bg-color);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.header .container {
display: flex;
align-items: center;
justify-content: space-between;
height: 100%;
}
/* ナビゲーション */
.nav__list {
display: flex;
gap: 3rem;
}
.nav__link {
font-weight: 500;
transition: color 0.3s ease;
}
.nav__link:hover {
color: var(--primary-color);
}
/* ハンバーガーメニュー */
.nav__toggle {
display: none;
flex-direction: column;
width: 24px;
height: 24px;
}
.nav__toggle span {
width: 100%;
height: 2px;
background-color: var(--text-color);
margin: 2px 0;
transition: all 0.3s ease;
}
/* ヒーローセクション */
.hero {
padding-top: calc(var(--header-height) + 8rem);
padding-bottom: 8rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
text-align: center;
}
.hero__title {
font-size: 4.8rem;
margin-bottom: 2rem;
animation: fadeInUp 1s ease-out;
}
.hero__text {
font-size: 1.8rem;
margin-bottom: 3rem;
animation: fadeInUp 1s ease-out 0.3s both;
}
/* アニメーション */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* フッター */
.footer {
background-color: var(--secondary-color);
color: white;
text-align: center;
padding: 3rem 0;
}ステップ4: JavaScript実装(10分)
インタラクション機能
class WebSiteController {
constructor() {
this.init();
}
init() {
this.setupEventListeners();
this.setupSmoothScroll();
this.setupMobileMenu();
this.setupScrollEffects();
}
setupEventListeners() {
document.addEventListener('DOMContentLoaded', () => {
console.log('サイトが読み込まれました');
});
window.addEventListener('scroll', () => {
this.handleScroll();
});
}
setupSmoothScroll() {
const navLinks = document.querySelectorAll('.nav__link');
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const targetId = link.getAttribute('href');
const targetSection = document.querySelector(targetId);
if (targetSection) {
const headerHeight = document.querySelector('.header').offsetHeight;
const targetPosition = targetSection.offsetTop - headerHeight;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
});
});
}
setupMobileMenu() {
const toggleBtn = document.querySelector('.nav__toggle');
const navList = document.querySelector('.nav__list');
if (toggleBtn) {
toggleBtn.addEventListener('click', () => {
navList.classList.toggle('active');
toggleBtn.classList.toggle('active');
});
}
}
setupScrollEffects() {
const sections = document.querySelectorAll('.section');
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -100px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
}
});
}, observerOptions);
sections.forEach(section => {
section.style.opacity = '0';
section.style.transform = 'translateY(20px)';
section.style.transition = 'all 0.6s ease';
observer.observe(section);
});
}
handleScroll() {
const header = document.querySelector('.header');
if (window.scrollY > 50) {
header.classList.add('scrolled');
} else {
header.classList.remove('scrolled');
}
}
}
// 初期化
const website = new WebSiteController();📝 まとめ・質疑応答(10分)
実装のポイント
- 段階的な実装: HTML → CSS → JavaScript の順序で進める
- モバイルファースト: 小さな画面から設計を始める
- コンポーネント指向: 再利用可能な部品として作成
- パフォーマンス意識: 最適化を考慮した実装
よくある問題と解決策
- レイアウトの崩れ: Flexbox/Gridの適切な使用
- JavaScript エラー: console.logでのデバッグ
- モバイル対応: メディアクエリの調整
Q&A
- 実装中の技術的な質問
- デザインの調整について
- JavaScript機能の追加方法
🏠 宿題
必須課題
-
サイト実装の完成
- HTML/CSS/JavaScriptの統合
- モバイル対応の確認
-
機能テスト
- 全てのリンク動作確認
- フォーム送信テスト
- レスポンシブデザイン確認
オプション課題
-
追加機能実装
- アニメーション効果
- API連携
- ローディング機能
-
パフォーマンス最適化
- 画像圧縮
- CSS/JavaScript圧縮
提出物
- 完成したWebサイト(全ファイル)
- デモ用URL(GitHub Pages等)
- 実装報告書(機能説明)
次回予告: 第13回では完成したサイトの発表とコース全体の振り返りを行います。自分の作品を自信を持って発表できるよう、今回で完成度を高めましょう!
Last updated on