🍘

ブラウザPDF印刷 + CSS調整で改ページ指定等のメモ

2022/01/08に公開

概要:

ブラウザ印刷でPDF出力する場合で。CSSで印刷領域の指定や、
改ページ位置の指定の例となります。

  • 一般的なブラウザ仕様らしいので、CSS調整以外は不要で PDFレイアウト調整ができるそうでしたので
     試してみました。

  • 印刷時に、web画面の、共通ヘッダ、サイドバー、広告バナー等を対象外にして。
    主要コンテンツのみ印刷する調整ができそうでした。

  • 改ページは、カスタムタグのようなルール決めて、画面表示に div, hrタグ変換、クラス名指定後。
    CSS適用する手順としました

  • テストは、Next.js / SSGを、cloudflare.pages にデプロイ後、印刷テストしました。


構成

  • chrome : 96以上
  • CSS
  • next.js 12
  • node: 16
  • cloudflare.pages

参考


プリント範囲の設定

  • 下記の、青枠内を印刷する例です。(枠外は印刷しない)

印刷範囲設定、@media print

  • 印刷時のみ。ヘッダ部分、ボタン等を非表示

class= hidden_print を、@media print の条件で。非表示(display: none)

@media print {
    .hidden_print{
        display: none;
    }
}
  • pdf印刷すると、ヘッダ等が非表示になり。コンテンツ部分が出力できました。


改ページ:page-break-before

  • こちらは、自動で改行できません。
  • 手動でカスタムタグを定義し、画面表示時に、page-break-beforeを適用
.pdf_next_page {
    page-break-before: always;
}
  • カスタム定義(例) 下記を、改ページ位置に設定
:::nextpage
  • HRタグ等に、変換(next.js)
  • 上記の page-break-before が適用され印刷時のみ。改ページ処理
<hr class="pdf_next_page" />
  • 改ページのPDF出力例

手動で追加した改ページ位置で、ページ追加できました


  • 参考の詳細画面コード: next.js

https://gist.github.com/kuc-arc-f/190f7f36e8eb15a9fd88e1ac58184371

/src/pages/posts/[id].tsx

[id].tsx
/* pdf print css add */
import Head from 'next/head'
import React from 'react'
import Link from 'next/link';

import marked from  'marked'

import Layout from '../../components/layout'
import LibCommon from '../../libs/LibCommon'
import LibCms from '../../libs/LibCms'
//
export default function Page({ blog }) {
//console.log(blog)
  return (
    <Layout>
    <Head><title key="title">{blog.title}</title></Head>      
    <div className="container bg-light">
      <div className="hidden_print">
        <Link href="/home" >
          <a className="btn btn-light btnx-outline-orange mt-2">Back</a>
        </Link>
        <hr className="mt-2 mb-2" />
        <div className="show_head_wrap">
          <i className="bi bi-house-fill mx-2"></i>&nbsp;{blog.title}
        </div>
      </div>
      <div className="card shadow-sm my-2">
        <div className="card-body">
          <h1>{blog.title}</h1>
          Date: {blog.created_at}<br />
          Category : {blog.category.name }
        </div>
      </div>
      <div className="shadow-sm bg-white p-4 mt-2 mb-4">
        <div id="post_item" dangerouslySetInnerHTML={{__html: `${blog.content}`}}>
        </div>
      </div>                       
    </div>
    <style>{`
      div#post_item img{
        max-width : 100%;
        height : auto;
      }
      .show_head_wrap{ font-size: 1.4rem; }
      .pdf_next_page {
        page-break-before: always;
        background-color: green;
        border: none;        
      }
      @media print {
        .hidden_print{
          display: none;
        }
      }
      `}</style>      
  </Layout>
  )
}
//
export const getStaticPaths = async () => {
  const dt = LibCommon.formatDate( new Date(), "YYYY-MM-DD_hhmmss");
  const url = process.env.MY_JSON_URL+ '?' + dt
  const req = await fetch( url );
  const json = await req.json();  
  const items = json.items     
  const paths = []
  items.map((item, index) => {
    let row = { params: 
      { id: item.save_id } 
    }
    paths.push(row)
  })
//console.log(paths)
  return {
    paths: paths,
    fallback: false
  } 
};
export const getStaticProps = async context => {
  const id = context.params.id
//console.log(id)
  const dt = LibCommon.formatDate( new Date(), "YYYY-MM-DD_hhmmss");
  const url = process.env.MY_JSON_URL+ '?' + dt
  const req = await fetch( url );
  const json = await req.json();  
  let items = json.items 
  items = LibCommon.convert_items( items )
  let item  = LibCms.get_show_item( items, String(id) )
  item.content = marked(item.content)
  item = LibCms.get_post_itemOne(item , json.category_items)
//console.log(json.category_items )  
  return {
    props: { 
      blog: item,
    },
  }  
};

....

Discussion