frameset タグを使用したページを Chrome や Edge で印刷しようとすると、意図しない余白が入り、コンテンツが縮小されてしまう問題が発生します。
この記事では、この問題の原因と具体的な解決方法を解説します。さらに、frameset から iframe への移行手順、CSS Grid / Flexbox による現代的な代替レイアウト、HTML5 での非推奨状況まで、実務で必要になるパターンを網羅します。
この記事でわかること
- frameset / frame タグとは何か(レガシー HTML 要素の基礎知識)
- Chrome / Edge で印刷時に余白が入る原因
- CSS
@media print や JavaScript による対処法
- frameset から iframe への移行手順
- CSS Grid / Flexbox を使った現代的な代替レイアウト
- HTML5 での非推奨状況と実務での対処パターン
frameset / frame タグとは
まず、frameset と frame タグについて整理しておきましょう。
<frameset> は、ブラウザウィンドウを複数の領域(フレーム)に分割し、それぞれに別の HTML ファイルを表示するための HTML 要素です。<body> の代わりに使用され、<frame> タグで各領域に表示するページを指定します。
frameset の基本構文(HTML 4.01)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">
<html>
<head>
<title>フレームレイアウトのページ</title>
</head>
<frameset rows="100px,*">
<frame src="header.html" name="header">
<frameset cols="200px,*">
<frame src="sidebar.html" name="sidebar">
<frame src="main.html" name="main">
</frameset>
</frameset>
</html>
この例では、画面を上部のヘッダー(100px)と下部に分割し、下部をさらに左のサイドバー(200px)と右のメインコンテンツに分割しています。
frameset で使える主な属性
| 属性 |
対象 |
説明 |
例 |
rows |
frameset |
水平方向にフレームを分割 |
"100px,*" |
cols |
frameset |
垂直方向にフレームを分割 |
"200px,*" |
src |
frame |
フレームに表示するURL |
"page.html" |
name |
frame |
フレームの名前(target先として利用) |
"main" |
noresize |
frame |
フレームのリサイズを禁止 |
noresize |
scrolling |
frame |
スクロールバーの表示制御 |
"auto" / "no" |
frameborder |
frame |
フレーム間の境界線 |
"0" / "1" |
Chrome / Edge で印刷時に余白が入る原因
frameset を使用したページを Chrome や Edge で印刷しようとすると、各フレームの間に大きな余白が挿入され、本来のレイアウトが大きく崩れてしまいます。
ブラウザごとの対応状況
この問題はブラウザのレンダリングエンジンに起因しています。
| ブラウザ |
エンジン |
frameset 印刷 |
備考 |
| Internet Explorer |
Trident |
対応 |
各フレームを個別に印刷可能 |
| Firefox |
Gecko |
対応 |
フレーム選択→印刷が可能 |
| Chrome |
Blink |
非対応 |
余白が入り、レイアウトが崩れる |
| Edge |
Blink |
非対応 |
Chrome と同じエンジンのため同様 |
| Safari |
WebKit |
一部対応 |
表示はされるが崩れる場合がある |
技術的な原因
Chrome / Edge(Blink エンジン)では、frameset の印刷処理において以下の問題が発生します。
原因:Blink エンジンは frameset を印刷する際、各 frame を独立したページとして扱います。フレーム同士の位置関係やサイズ比率が正しく再現されず、各フレームの間にページマージン相当の余白が挿入されてしまいます。
具体的には、以下のような現象が起こります。
- 各フレームが別々のブロック要素として印刷される
- フレーム間にブラウザのデフォルト印刷マージンが挿入される
rows / cols で指定したサイズ比率が無視される
- 結果として、コンテンツが縮小されて表示される
そもそも frameset と frame は HTML5 で廃止された要素であり、Chrome / Edge がこれらの印刷を積極的にサポートしていないことも一因です。
解決方法1:CSS @media print で印刷用スタイルを適用する
もっとも手軽な対処法は、@media print を使って印刷時のスタイルを調整することです。ただし、frameset 自体の構造上の制限があるため、完全な解決にはならない場合があります。
各フレーム内の HTML に印刷用 CSS を追加
frameset に直接 CSS を適用することはできないため、各 frame が読み込む HTML ファイルに印刷用のスタイルを記述します。
各フレームの HTML に追加する印刷用 CSS
<style>
@media print {
/* 印刷時のマージンとパディングをリセット */
body {
margin: 0;
padding: 0;
}
/* 不要な要素を非表示(ナビゲーション等) */
.no-print {
display: none !important;
}
/* 背景色を印刷に含める */
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
</style>
注意:この方法は各フレーム内部の余白は制御できますが、フレーム間の余白(Blink エンジンが挿入するもの)は解消できません。根本的な解決には、後述する iframe への移行やレイアウト変更が必要です。
@page ルールで印刷ページ設定を調整
@page ルールを併用すると、印刷時のページマージンも制御できます。
@page ルールの追加
@media print {
@page {
margin: 5mm; /* ページ余白を最小限に */
size: A4; /* 用紙サイズを指定 */
}
body {
margin: 0;
padding: 0;
font-size: 12pt; /* 印刷用フォントサイズ */
}
}
解決方法2:JavaScript で印刷用コンテンツを生成する
JavaScript を使って、印刷時にすべてのフレームの内容を1つのページにまとめて出力する方法です。これなら frameset の構造を変更せずに、正常な印刷結果を得ることができます。
JavaScript による印刷用コンテンツ生成
function printAllFrames() {
// 新しいウィンドウを開く
var printWindow = window.open('', '_blank');
var content = '<html><head><title>印刷</title>';
// 印刷用スタイルを追加
content += '<style>';
content += 'body { margin: 0; padding: 20px; }';
content += '.frame-section { margin-bottom: 20px; page-break-inside: avoid; }';
content += '</style>';
content += '</head><body>';
// 各フレームの内容を取得して結合
var frames = window.frames;
for (var i = 0; i < frames.length; i++) {
try {
var frameBody = frames[i].document.body.innerHTML;
content += '<div class="frame-section">' + frameBody + '</div>';
} catch(e) {
content += '<p>フレーム ' + i + ' の内容を取得できませんでした</p>';
}
}
content += '</body></html>';
// 新しいウィンドウに書き出して印刷
printWindow.document.write(content);
printWindow.document.close();
printWindow.print();
}
この関数をボタンに紐づけて使用します。
印刷ボタンの設置例
<button onclick="printAllFrames()">全フレームを印刷</button>
ポイント:この方法は frameset の構造を変更せずに印刷問題を解決できるため、すぐに対処が必要な場合に有効です。ただし、クロスオリジンのフレーム(外部サイトの URL を読み込んでいるフレーム)の内容は取得できないため、その場合はエラーハンドリングが必要です。
特定のフレームだけを印刷する
メインコンテンツのフレームだけを印刷したい場合は、window.frames で特定のフレームを指定します。
特定フレームの印刷
function printFrame(frameName) {
var frame = window.frames[frameName];
if (frame) {
frame.focus();
frame.print();
}
}
// 使い方:name属性で指定したフレーム名を渡す
printFrame('main');
解決方法3:frameset を iframe に変更する
frameset を iframe に置き換えることで、Chrome / Edge でも正常に印刷できるようになります。iframe は HTML5 でもサポートされている要素であり、もっとも現実的な移行先です。
変更前(frameset)
変更前:frameset を使用したレイアウト
<frameset rows="80px,*">
<frame src="header.html" name="header" scrolling="no" noresize>
<frameset cols="200px,*">
<frame src="sidebar.html" name="sidebar">
<frame src="main.html" name="main">
</frameset>
</frameset>
変更後(iframe + CSS)
変更後:iframe + CSS によるレイアウト
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ページタイトル</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; overflow: hidden; }
.header-frame {
width: 100%;
height: 80px;
border: none;
}
.content-wrapper {
display: flex;
height: calc(100% - 80px);
}
.sidebar-frame {
width: 200px;
height: 100%;
border: none;
}
.main-frame {
flex: 1;
height: 100%;
border: none;
}
</style>
</head>
<body>
<iframe src="header.html" class="header-frame"></iframe>
<div class="content-wrapper">
<iframe src="sidebar.html" class="sidebar-frame"></iframe>
<iframe src="main.html" class="main-frame"></iframe>
</div>
</body>
</html>
frameset と iframe の属性対応表
移行時に各属性をどう置き換えるか、対応を確認しておきましょう。
| frameset / frame の属性 |
iframe での代替 |
補足 |
rows / cols |
CSS width / height |
Flexbox や Grid で柔軟にレイアウト可能 |
src |
src |
そのまま使用可能 |
name |
name |
target 指定に引き続き利用可能 |
noresize |
CSS resize: none |
iframe はデフォルトでリサイズ不可 |
scrolling |
CSS overflow |
scrolling 属性は HTML5 で非推奨 |
frameborder |
CSS border |
frameborder 属性は HTML5 で非推奨 |
解決方法4:CSS Grid / Flexbox で完全に置き換える
もっとも推奨される方法は、frameset / iframe を使わず、CSS Grid や Flexbox でレイアウトを再構築することです。別々の HTML ファイルを読み込む必要がなくなり、SEO やアクセシビリティの面でも大幅に改善されます。
CSS Grid による再構築
CSS Grid によるフレームレイアウトの再現
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ページタイトル</title>
<style>
body {
margin: 0;
display: grid;
grid-template-rows: 80px 1fr;
grid-template-columns: 200px 1fr;
grid-template-areas:
"header header"
"sidebar main";
height: 100vh;
}
.header { grid-area: header; background: #f8f9fa; }
.sidebar { grid-area: sidebar; background: #e9ecef; overflow-y: auto; }
.main { grid-area: main; overflow-y: auto; padding: 20px; }
/* レスポンシブ対応 */
@media (max-width: 768px) {
body {
grid-template-rows: 60px auto 1fr;
grid-template-columns: 1fr;
grid-template-areas:
"header"
"sidebar"
"main";
}
.sidebar { max-height: 200px; }
}
/* 印刷用スタイル */
@media print {
body {
display: block;
height: auto;
}
.sidebar { display: none; }
.main { overflow: visible; }
}
</style>
</head>
<body>
<header class="header">ヘッダー</header>
<nav class="sidebar">サイドバー</nav>
<main class="main">メインコンテンツ</main>
</body>
</html>
ポイント:CSS Grid を使えば、frameset の rows / cols と同等のレイアウトを、より柔軟に実現できます。さらに @media クエリによるレスポンシブ対応や、@media print による印刷最適化も簡単に追加できます。
Flexbox による再構築
Flexbox を使ったレイアウトの例を見る
<style>
body {
margin: 0;
display: flex;
flex-direction: column;
height: 100vh;
}
.header {
height: 80px;
flex-shrink: 0;
background: #f8f9fa;
}
.content-wrapper {
display: flex;
flex: 1;
overflow: hidden;
}
.sidebar {
width: 200px;
flex-shrink: 0;
background: #e9ecef;
overflow-y: auto;
}
.main {
flex: 1;
overflow-y: auto;
padding: 20px;
}
</style>
<header class="header">ヘッダー</header>
<div class="content-wrapper">
<nav class="sidebar">サイドバー</nav>
<main class="main">メインコンテンツ</main>
</div>
frameset / frame / iframe の違いと使い分け
3つの要素の違いを改めて整理しておきましょう。
| 項目 |
frameset + frame |
iframe |
CSS Grid / Flexbox |
| HTML5 対応 |
廃止 |
対応 |
対応 |
| Chrome 印刷 |
問題あり |
正常 |
正常 |
| SEO |
不利 |
要注意 |
有利 |
| アクセシビリティ |
不利 |
要注意 |
有利 |
| レスポンシブ |
不可 |
制限あり |
容易 |
| 別ファイル読み込み |
対応 |
対応 |
不可 |
| 移行コスト |
− |
低い |
高い |
移行方針の選び方
- すぐに印刷問題だけ直したい → JavaScript による印刷用コンテンツ生成(解決方法2)
- 最小限の修正で対応したい → iframe への置き換え(解決方法3)
- 将来的な保守性も考慮したい → CSS Grid / Flexbox でフルリニューアル(解決方法4)
HTML5 での非推奨状況と背景
frameset、frame、noframes は HTML5 で正式に廃止されました。W3C の HTML5 仕様から完全に削除されており、使用すべきではない要素として扱われています。
廃止された理由
| 問題点 |
詳細 |
| SEO への悪影響 |
検索エンジンがフレーム内の個別ページを正しくインデックスできない。検索結果からフレーム単体のページに直接アクセスされると、ナビゲーションなしの不完全なページが表示される。 |
| アクセシビリティ |
スクリーンリーダーがフレーム間のナビゲーションを正しく処理できない。キーボード操作でのフレーム間移動が困難。 |
| ブックマーク・共有 |
フレーム内のページを個別にブックマークしたり URL を共有したりできない。アドレスバーには常に frameset の URL が表示される。 |
| 印刷の問題 |
本記事で解説しているとおり、モダンブラウザでの印刷に対応していない。 |
| モバイル非対応 |
レスポンシブデザインに対応できない。スマートフォンでの表示が極めて困難。 |
| セキュリティ |
クリックジャッキング攻撃に利用される可能性がある。 |
HTML のバージョンとフレーム関連要素の対応
| HTML バージョン |
frameset |
frame |
iframe |
備考 |
| HTML 4.01 Frameset |
対応 |
対応 |
対応 |
Frameset DTD が必要 |
| XHTML 1.0 Frameset |
対応 |
対応 |
対応 |
Frameset DTD が必要 |
| HTML5 |
廃止 |
廃止 |
対応 |
iframe のみサポート |
| HTML Living Standard |
廃止 |
廃止 |
対応 |
WHATWG 仕様 |
実務での対処パターンまとめ
レガシーシステムで frameset が使われている場合の、実務での対処パターンをまとめます。
パターン1:応急処置(JavaScript 印刷)
状況:すぐに印刷できるようにしたいが、HTMLの構造は変更できない
印刷ボタンを追加するだけの応急処置
/* メインフレームの HTML に追加 */
<button onclick="window.parent.frames['main'].focus(); window.parent.frames['main'].print();"
class="no-print">
このページを印刷
</button>
<style>
@media print {
.no-print { display: none; }
}
</style>
パターン2:段階的移行(iframe 置換)
状況:ページ構造を変更できるが、各フレームの HTML ファイルはそのまま使いたい
frameset → iframe 置換の手順
手順1. DOCTYPE を HTML5 に変更
手順2. <frameset> を <body> に変更
手順3. <frame> を <iframe> に変更
手順4. rows/cols を CSS width/height に変換
手順5. target による遷移リンクを確認・修正
手順6. 印刷テストを実施
パターン3:フルリニューアル(CSS レイアウト)
状況:サイト全体をモダンな構成に作り直す余裕がある
移行チェックリスト
[ ] 各フレームの HTML を1つのページに統合
[ ] CSS Grid または Flexbox でレイアウト再構築
[ ] ナビゲーション(target 属性)をルーティングに置換
[ ] レスポンシブデザインの実装
[ ] 印刷用スタイル(@media print)の追加
[ ] SEO 対策(meta タグ、構造化データ)
[ ] アクセシビリティ対応(ARIA 属性、キーボードナビゲーション)
[ ] 全ブラウザでの表示・印刷テスト
パターン4:スクリーンショットで印刷(最も手軽)
構造を一切変更できない場合、もっとも手軽で確実な方法はスクリーンショットを印刷することです。
- Windows:
Win + Shift + S(Snipping Tool)で画面をキャプチャ
- Chrome 拡張:「Full Page Screen Capture」等で全画面キャプチャ
- 開発者ツール:DevTools →
Ctrl + Shift + P → 「Capture full size screenshot」
キャプチャした画像をそのまま印刷すれば、余白の問題は発生しません。
ポイント:Chrome の DevTools を使ったスクリーンショットは、画面に表示されていないスクロール領域も含めてキャプチャできるため、長いページでも全体を1枚の画像にできます。
iframe を使う場合の印刷用 CSS
iframe に移行した場合でも、印刷時にはいくつかの調整が必要です。
iframe レイアウトの印刷用 CSS
/* 親ページ(iframe を配置しているページ)の印刷スタイル */
@media print {
/* ヘッダーやサイドバーの iframe を非表示にし、メインだけ印刷 */
.header-frame,
.sidebar-frame {
display: none;
}
/* メインの iframe を全幅にする */
.main-frame {
width: 100%;
height: auto;
min-height: 100vh;
border: none;
}
/* Flexbox/Grid レイアウトを印刷用にリセット */
.content-wrapper {
display: block;
}
}
注意:iframe 内のコンテンツの印刷は、親ページの CSS からは制御できません。iframe 内の HTML にも別途 @media print のスタイルを記述する必要があります。
まとめ
frameset タグを使用したページを Chrome や Edge で印刷すると余白が入る問題の原因と解決方法を解説しました。
| 解決方法 |
対応範囲 |
修正コスト |
推奨度 |
| CSS @media print |
フレーム内部の余白のみ |
低 |
限定的 |
| JavaScript 印刷 |
印刷問題全体 |
低 |
応急処置として有効 |
| iframe 置換 |
印刷問題 + HTML5 準拠 |
中 |
推奨 |
| CSS Grid / Flexbox |
全問題を根本解決 |
高 |
最も推奨 |
| スクリーンショット |
印刷のみ |
なし |
緊急時に有効 |
frameset は HTML5 で廃止された要素であり、今後ブラウザのサポートがさらに縮小される可能性があります。レガシーシステムで frameset を使用している場合は、可能な限り iframe や CSS Grid / Flexbox への移行を検討してください。
まずは iframe への置き換えで印刷問題を解消し、その後余裕のあるタイミングで CSS Grid / Flexbox による完全な再構築を行う、という段階的なアプローチがもっとも現実的です。