🐍
コード0行、20分の対話だけ。AIでサイトを大改造した記録
コード0行、20分の対話だけ。AIでサイトを大改造した記録
はじめに
以前、「一切コーディングせずにAI連携だけでWebサイトを作った話」という記事で、Zennとnoteの記事を一箇所で見られるサイトを完全ノーコードで作成しました。
あれから数ヶ月、AIのコーディング能力が大幅に向上したことで、「そろそろサイトをアップデートしたいな」と思い立ちました。
今回も私は一行もコードを書いていません。
すべてClaude Sonnet 4.5(Cursor経由)との対話だけで、8つの新機能を実装しました。その過程と結果を記録します。
完成サイト
Before(旧版)

- シンプルなカードレイアウト
- 記事タイトルと説明文のみ
- ライトモードのみ
After(新版)

- サムネイル付きリッチカード
- フィルター機能でZenn/note切り替え
- ダークモード対応
- ホバーアニメーション
実装した8つの新機能
1. 📸 記事のサムネイル表示

実装内容:
- ZennのRSSフィード(
<enclosure>タグ)から画像URL取得 - noteのRSSフィード(
<media:thumbnail>タグ)から画像URL取得 - 横長サムネイルを文章の上部に配置
技術的ポイント:
# RSSフィードからの画像抽出処理
# enclosureタグ、media:thumbnail、descriptionのimgタグから順に探索
# media:thumbnailはテキストとして格納されているケースに対応
media_thumbnail = item.find("{http://search.yahoo.com/mrss/}thumbnail")
if media_thumbnail is not None:
if media_thumbnail.text:
image_url = media_thumbnail.text.strip()
2. 🏷️ 記事の出典バッジ

実装内容:
- サムネイル右上にZenn(青 #3EA8FF)/note(緑 #41C9B4)のバッジを表示
- 一目でどのプラットフォームの記事かわかる
- absolute配置で画像の上に重ねて表示
3. ⚡ 画像のLazy Loading
実装内容:
-
loading="lazy"属性を追加 - 画面に表示される直前に画像を読み込み
- パフォーマンス向上とデータ通信量削減
4. 🎛️ フィルター機能

実装内容:
- 「すべて (37)」「Zenn (12)」「note (25)」の切り替えボタン
- Reactのstateで動的フィルタリング
- Material Designの丸みのあるボタンデザイン
- 記事数をリアルタイムでカウント表示
技術的ポイント:
const [filter, setFilter] = useState('all');
const filteredArticles = filter === 'all'
? articles
: articles.filter(article => article.source === filter);
5. 🖱️ カード全体クリック対応
実装内容:
- カード全体を
<a>タグでラップ - サムネイル、タイトル、説明文どこをクリックしても記事に遷移
- リンクのネストを避けるため"Read more"を
<span>に変更
6. 📏 カードの高さ統一

実装内容:
- タイトル:最大3行固定(
WebkitLineClamp: 3、高さ4.2em) - 説明文:最大3行固定(
WebkitLineClamp: 3、高さ4.2em) - グリッドレイアウトで同じ行のカードを揃える
技術的ポイント:
style={{
height: "4.2em",
lineHeight: "1.4",
display: "-webkit-box",
WebkitLineClamp: 3,
WebkitBoxOrient: "vertical",
overflow: "hidden"
}}
7. ✨ カードのホバーアニメーション強化
実装内容:
- マウスホバーで8px浮き上がる(
translateY(-8px)) - 影を強化(通常
0 2px 8px→ ホバー0 8px 24px) - Material Designの標準イージング関数(
cubic-bezier(0.4, 0, 0.2, 1))採用 - 0.3秒のスムーズなトランジション
8. 🌙 ダークモード対応

実装内容:
- 右下に固定のトグルボタン(🌙/☀️)
- CSS Custom Propertiesでテーマ切り替え
- LocalStorageで設定を永続化
- システムのダークモード設定を自動検出(
prefers-color-scheme) - MutationObserverでクラス変更を監視し、全コンポーネントに反映
カラーパレット:
/* ライトモード */
--bg-primary: #f6f8fa;
--bg-secondary: #fff;
--text-primary: #222;
--accent: #1976d2;
/* ダークモード */
--bg-primary: #121212;
--bg-secondary: #1e1e1e;
--text-primary: #e0e0e0;
--accent: #BB86FC; /* Material Design 3 Purple */
今回の開発フロー
私がやったこと
- 「サムネイルを表示したい」と日本語で伝える
- 「ダークモードを実装して」と依頼
- 「カードの高さを揃えて」「3行にして」と微調整
- ブラウザで確認してOKを出す
Claude Sonnet 4.5 がやったこと
- RSSフィードの構造を分析し、画像抽出ロジックを実装
- Reactコンポーネントを作成(ArticleFilter.jsx、DarkModeToggle.jsx)
- CSS Custom Propertiesでテーマシステムを構築
- LocalStorageとMutationObserverでダークモード永続化
- レスポンシブ対応とアクセシビリティ対応
Claude Sonnet 4.5 の進化ポイント
以前(他のAI)との比較
| 項目 | 以前(o3/Codex/Cursor組み合わせ) | 今回(Claude Sonnet 4.5単体) |
|---|---|---|
| AI切り替え | 4つのAIを手動で切り替え | 1つのAIで完結 |
| コンテキスト理解 | 仕様書を細かく書く必要 | 曖昧な要望でも意図を汲む |
| デバッグ | エラーログをコピペして質問 | 自発的に動作確認まで提案 |
| UI調整 | 「16px空けて」など具体的指示 | 「いい感じに」で伝わる |
| 実装時間 | 半日〜1日 | 20分 |
特に優れていた点
-
コンテキスト保持能力
- 100以上のやり取りでも過去の変更を覚えている
- 「さっきの修正を戻して」が通じる
- 「やっぱ3行」のような言い直しにも対応
-
段階的実装の提案
- 「1つずつ実装しましょう」と自発的に提案
- 各機能の優先度と実装時間を見積もり
- おすすめの実装順序まで提示
-
エラー予測と対策
- 「この変更でレイアウトが崩れるかも」と事前警告
- 代替案を複数提示
- 修正後の動作確認方法まで案内
-
ユーザー体験への配慮
- 「カードの高さを揃えた方が見やすい」と提案
- Lazy Loadingなどパフォーマンス最適化を自発的に実装
- アクセシビリティ対応(aria-label等)も自動で追加
開発時間
| フェーズ | 時間 | 内容 |
|---|---|---|
| サムネイル表示 | 3分 | RSS解析→画像取得→表示 |
| バッジ表示 | 2分 | 色とポジショニング |
| Lazy Loading | 1分 | 属性追加のみ |
| フィルター機能 | 3分 | React state管理 |
| 全体クリック | 2分 | a タグラップ |
| 高さ統一 | 5分 | 3行固定調整含む |
| ホバー効果 | 2分 | transform追加 |
| ダークモード | 3分 | テーマシステム構築 |
| 合計 | 約20分 | すべて対話のみ |
従来なら半日〜1日かかる作業量が、コーヒー1杯飲む時間で完了。
まとめ — AIコーディングの新時代
できるようになったこと
- ✅ 複雑な状態管理(React state + MutationObserver)
- ✅ CSS Custom Propertiesのテーマシステム
- ✅ アクセシビリティ対応(aria-label等)
- ✅ パフォーマンス最適化(Lazy Loading)
- ✅ レスポンシブ対応の自動調整
それでも人間に残る役割
- 🎯 「何を作りたいか」のビジョン
- 👀 最終的なUIの良し悪しの判断
- 🔄 優先順位の決定(「次はダークモード」)
- ✨ UXの細かい調整(「3行がいい」「やっぱ3行」)
次の展開
今回実装しなかった機能候補:
- 検索機能
- 記事の統計情報表示
- OGP画像の自動生成
- 読了時間の推定
Claude Sonnet 4.5 なら、これらも対話だけで実装できそうです。
付録 — 実装コード抜粋
RSSから画像取得(fetch_feeds.py)
# media:thumbnailから取得(noteで使用)
# テキストとして格納されている場合に対応
media_thumbnail = item.find("{http://search.yahoo.com/mrss/}thumbnail")
if media_thumbnail is not None:
if media_thumbnail.text:
image_url = media_thumbnail.text.strip()
else:
# 属性として格納されている場合も考慮
image_url = media_thumbnail.get("url", "")
ダークモードトグル(DarkModeToggle.jsx)
const toggleDarkMode = () => {
const newIsDark = !isDark;
setIsDark(newIsDark);
if (newIsDark) {
document.documentElement.classList.add('dark-mode');
localStorage.setItem('theme', 'dark');
} else {
document.documentElement.classList.remove('dark-mode');
localStorage.setItem('theme', 'light');
}
};
// 初期状態を取得(システム設定も考慮)
useEffect(() => {
const savedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const shouldBeDark = savedTheme === 'dark' || (!savedTheme && prefersDark);
setIsDark(shouldBeDark);
if (shouldBeDark) {
document.documentElement.classList.add('dark-mode');
}
}, []);
カードのホバー効果(ArticleCard.jsx)
style={{
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
transform: "translateY(0)"
}}
onMouseOver={e => {
e.currentTarget.style.boxShadow = "0 8px 24px rgba(0,0,0,0.15)";
e.currentTarget.style.transform = "translateY(-8px)";
}}
onMouseOut={e => {
e.currentTarget.style.boxShadow = "0 2px 8px rgba(0,0,0,0.08)";
e.currentTarget.style.transform = "translateY(0)";
}}
フィルター機能(ArticleFilter.jsx)
const [filter, setFilter] = useState('all');
const [isDark, setIsDark] = useState(false);
// MutationObserverでダークモードの変更を監視
React.useEffect(() => {
const checkDarkMode = () => {
setIsDark(document.documentElement.classList.contains('dark-mode'));
};
checkDarkMode();
const observer = new MutationObserver(checkDarkMode);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class']
});
return () => observer.disconnect();
}, []);
const filteredArticles = filter === 'all'
? articles
: articles.filter(article => article.source === filter);
コードを書かない開発は、もはや「実験」ではなく「実用」になりました。
Claude Sonnet 4.5 は、アイデアを20分で形にする時代を実現しています。
次は、あなたの番です。
Discussion