【HTML】framesetタグの印刷で余白が入る原因と解決方法|Chrome・Edge対応・iframe移行・CSS Grid代替

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 タグとは

まず、framesetframe タグについて整理しておきましょう。

<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 で指定したサイズ比率が無視される
  • 結果として、コンテンツが縮小されて表示される

そもそも framesetframeHTML5 で廃止された要素であり、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 に変更する

framesetiframe に置き換えることで、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 を使えば、framesetrows / 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 での非推奨状況と背景

framesetframenoframesHTML5 で正式に廃止されました。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:スクリーンショットで印刷(最も手軽)

構造を一切変更できない場合、もっとも手軽で確実な方法はスクリーンショットを印刷することです。

  • WindowsWin + 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 による完全な再構築を行う、という段階的なアプローチがもっとも現実的です。