タイトル: HTMLへの埋め込み
SEOタイトル: HTML に JavaScript を埋め込む完全ガイド
| この記事の要点 |
|
JavaScript を HTML に埋め込む 3 つの方法
1. インライン (script タグ内に直接記述)
<!DOCTYPE html>
<html>
<head>
<title>Sample</title>
</head>
<body>
<h1 id="title">Hello</h1>
<script>
// ここに JavaScript を直接書く
document.getElementById('title').textContent = 'Hello, World!';
console.log('inline script executed');
</script>
</body>
</html>
2. 外部ファイル (推奨)
<!-- 同じディレクトリの app.js を読み込み -->
<script src="app.js"></script>
<!-- 絶対パス -->
<script src="/js/app.js"></script>
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<!-- 整合性ハッシュ + crossorigin(推奨セキュリティ設定) -->
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
3. インライン属性 (非推奨)
<!-- ❌ 非推奨(XSS リスク、CSP 違反、保守性低い) -->
<button onclick="alert('clicked')">Click</button>
<!-- ✅ addEventListener 推奨 -->
<button id="btn">Click</button>
<script>
document.getElementById('btn').addEventListener('click', () => {
alert('clicked');
});
</script>
script タグの属性 (defer / async / type)
| 属性 | ダウンロード | 実行タイミング | 順序 | 用途 |
|---|---|---|---|---|
| なし | 同期、HTML パース停止 | 即時 | HTML 内記述順 | 互換性、最終手段 |
defer | 非同期 | HTML パース完了後、DOMContentLoaded 前 | HTML 内記述順 | ★通常のアプリスクリプト |
async | 非同期 | ダウンロード完了次第 | 不定 | 独立した解析タグ等 |
type="module" | 非同期 | defer 相当 | 記述順 | ES Modules |
<!DOCTYPE html>
<html>
<head>
<!-- ★推奨: head に defer 付きで読み込み -->
<script src="app.js" defer></script>
<!-- 独立した広告/解析: async -->
<script src="https://www.googletagmanager.com/gtag/js?id=GA_ID" async></script>
<!-- ES Modules: 自動で defer 動作 -->
<script src="main.js" type="module"></script>
<!-- 旧ブラウザフォールバック: module 非対応で読まれる -->
<script src="main-legacy.js" nomodule></script>
</head>
<body>
<!-- body 末尾配置でも defer/async 不要だが、defer のほうが体感速い -->
</body>
</html>
ES Modules
<!-- index.html -->
<script type="module" src="main.js"></script>// main.js
import { greet } from './utils.js'; // 拡張子必須
greet('World');
// utils.js
export function greet(name) {
console.log(`Hello, ${name}`);
}
module は CORS / MIME (application/javascript) / 厳格モードが強制されるため、HTTP サーバ経由でアクセスする必要があります(file:// 直接開きは不可)。
DOM 操作の基本
<div id="app">Hello</div>
<ul class="list">
<li>A</li>
<li>B</li>
</ul>
<script>
// 要素取得
const app = document.getElementById('app');
const items = document.querySelectorAll('.list li');
const first = document.querySelector('.list li:first-child');
// テキスト書き換え
app.textContent = 'World';
// HTML として埋め込み(XSS 注意)
app.innerHTML = '<strong>Bold</strong>';
// 属性
app.setAttribute('data-id', '42');
app.dataset.id = '42';
// クラス
app.classList.add('active');
app.classList.toggle('hidden');
// スタイル
app.style.color = 'red';
// イベント
app.addEventListener('click', (e) => {
console.log('clicked', e.target);
});
// 子要素追加
const li = document.createElement('li');
li.textContent = 'C';
document.querySelector('.list').appendChild(li);
</script>
innerText / textContent / innerHTML の違い
| プロパティ | HTML タグ | 非表示要素 | パフォーマンス | XSS |
|---|---|---|---|---|
textContent | 取得・設定とも文字列扱い(エスケープ済) | 含む | ★高速 | 安全 |
innerText | 表示テキストのみ | 含まない | 遅い(レイアウト必要) | 安全 |
innerHTML | HTML として解釈 | 含む | 遅い(パース必要) | ★危険 |
XSS (クロスサイトスクリプティング) 対策
// ❌ 危険: ユーザー入力を innerHTML に直接
const userInput = '
';
element.innerHTML = userInput; // → スクリプト実行される
// ✅ textContent で文字列扱い
element.textContent = userInput; // → "
"']/g, m => ({
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
}[m]));
}
element.innerHTML = escapeHtml(userInput);
DOMContentLoaded と load イベント
| イベント | 発火タイミング | 用途 |
|---|---|---|
DOMContentLoaded | HTML パース + defer スクリプト完了時 | ★ DOM 操作開始 |
load | 画像/CSS/iframe 含め全リソース完了 | サイズ計算等、画像確認 |
document.addEventListener('DOMContentLoaded', () => {
// ここから安全に DOM 操作可能
init();
});
window.addEventListener('load', () => {
// 画像 size などの最終確認
});
// 既に発火済みかチェック
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init(); // 既に発火後なら即実行
}
FAQ
Q: defer と body 末尾配置、どちらが良い?
A: 機能的にはほぼ同じですが、defer + head 配置のほうが「ダウンロードが HTML パースと並行して始まる」ぶん体感が速くなります。
Q: document.write は?
A: 非推奨。HTML パース後に呼ぶとページ全体を破壊します。広告タグ等の互換目的以外は使わないこと。
Q: jQuery の $(function(){}) と DOMContentLoaded の違いは?
A: 同じです。jQuery 内部でも DOMContentLoaded を待つ実装になっています。