🔥 Free Glide PDF Plugin - HTML2PDF

Hello,

First of all, thank you for this amazing tool! I’ve been using HTML2PDF to generate lesson plan documents for my educational platform, and it works perfectly on desktop devices. However, when the PDF is generated on mobile (especially in smaller screen resolutions, like in the Apple Books app), the text gets cut horizontally when transitioning between pages.

Here’s what happens:

  1. On desktop (when opened in a browser or a standard PDF reader), the page breaks are well-placed, and no words are cut between pages.

  2. On mobile, the first page transition works fine, but from page 2 to page 3 (or beyond), words are sliced in half horizontally, making the text unreadable.

What I have tried so far:

• Adjusting orphans and widows values.

• Using page-break-inside: avoid; and break-inside: avoid-page; for p, ul, ol, li, and key elements.

• Adding page-break-before: auto; and page-break-after: avoid;.

• Ensuring proper margins in the @page definition.

• Testing different zoom levels in HTML2PDF settings.

I suspect that the issue might be related to how the PDF engine renders the page breaks on mobile vs. desktop, but I’m not entirely sure how to fix it.

My current HTML template

(Below is my full HTML code, which works fine on desktop but causes issues on mobile.)

<html lang="pt-br">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Plano de Aula Gamificado</title>
    <link href="https://fonts.googleapis.com/css2?family=Comic+Neue:wght@400;700&display=swap" rel="stylesheet">
    
    <style>
        /* REGRAS GERAIS DE ESPAÇAMENTO */
        .marcador-secao, .destaque-titulo {
            margin: 6px 0 4px !important;
            padding-bottom: 2px;
        }

        .marcador-secao {
            font-size: 17px;
        }

        .destaque-titulo {
            font-size: 15px;
            padding-left: 22px;
        }

        .content {
            padding: 15px;
            line-height: 1.25;
        }

        .content p, .content ul, .content ol {
            margin: 3px 0 5px;
        }

        .content li {
            margin: 2px 0;
            padding-left: 5px;
        }

        @page {
            size: A4;
            margin: 35mm 40mm 45mm 40mm;
        }

        body {
            font-family: 'Comic Neue', cursive;
            margin: 0 auto;
            padding: 40px;
            max-width: 210mm;
            background: white;
            color: #333;
            line-height: 1.4;
            letter-spacing: 0.2px;
            overflow-wrap: break-word;
            word-break: keep-all;
        }

        .header {
            background: #9A68B3;
            color: white;
            padding: 18px 30px;
            margin: 0 0 25px 0;
            display: flex;
            align-items: center;
            gap: 20px;
            border-radius: 15px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }

        .selo-cabecalho {
            width: 80px;
            height: 80px;
            object-fit: contain;
            flex-shrink: 0;
            background: white;
            padding: 5px;
            border-radius: 10px;
        }

        .content {
            font-size: 14px;
            white-space: pre-wrap;
            word-wrap: break-word;
            margin: 0;
            padding: 25px;
            background: #fff9f9;
            border: 2px solid #eee;
            border-radius: 12px;
            page-break-inside: avoid;
        }

        .marcador-secao {
            font-size: 18px;
            color: #7B4F8D;
            margin: 15px 0 10px;
            padding-bottom: 3px;
            font-weight: 700;
        }

        .destaque-titulo {
            font-size: 16px;
            color: #7B4F8D;
            margin: 12px 0 8px;
            display: block;
            padding-left: 28px;
            position: relative;
            line-height: 1.3;
            font-weight: 700;
        }

        .destaque-titulo::before {
            content: "▹";
            position: absolute;
            left: 0;
            color: #9A68B3;
            font-size: 1.2em;
        }

        .numero-circulo {
            display: inline-block;
            margin: 0 6px 0 0;
            font-size: 1.3em;
            vertical-align: middle;
            font-weight: 700;
            color: #7B4F8D;
        }

        .footer {
            text-align: center;
            padding: 35px 0;
            margin-top: 40px;
        }

        .selo-rodape {
            width: 250px;
            height: auto;
            margin: 0 auto 12px;
            display: block;
        }

        .footer-texto {
            font-size: 12px;
            color: #666;
            margin: 0;
        }

        /* 🔥 PREVENÇÃO DE CORTES ENTRE PÁGINAS */
        .content, p, ul, ol, li, .marcador-secao, .destaque-titulo {
            page-break-inside: avoid;
            break-inside: avoid-page;
            page-break-before: auto;
            page-break-after: avoid;
            orphans: 5;
            widows: 5;
        }

        /* 🔥 SOLUÇÃO FINAL PARA EVITAR CORTES ENTRE PÁGINAS */
        p, ul, ol, li {
            page-break-inside: avoid;
            margin-bottom: 12px; /* 🔥 Garante espaçamento suficiente para não cortar o texto */
        }

        .content {
            padding-bottom: 60px !important; /* 🔥 Adiciona um espaço extra no final da página */
        }

        /* 🔥 AJUSTE ESPECÍFICO PARA CELULARES E TAMANHOS VARIADOS */
        @media print {
            .content {
                page-break-before: auto;
                page-break-after: always;
                padding-bottom: 70px; /* 🔥 Força um espaçamento seguro no final */
            }

            p, ul, ol, li {
                page-break-inside: avoid;
                margin-bottom: 15px;
            }

            .footer {
                position: fixed;
                bottom: 25px;
                left: 0;
                width: 100%;
                border-top: 2px solid #eee;
                background: white;
                padding-top: 10px;
            }
        }

    </style>
</head>
<body>
    <div class="header">
        <img class="selo-cabecalho" 
             src="https://storage.googleapis.com/glide-prod.appspot.com/uploads-v2/KCKF17djPbrmtUu4oHir/pub/Jc8C9I8vVo49njQNY6Wn.png" 
             alt="Selo Educacional">
        <span style="font-weight: 700; font-size: 18px;">TITULO</span>
    </div>
    
    <pre class="content" id="content">

{CONTEUDO}

</pre>

<div class="footer">
    <img class="selo-rodape" 
         src="https://storage.googleapis.com/glide-prod.appspot.com/uploads-v2/KCKF17djPbrmtUu4oHir/pub/wqHlzJQHbWiY6eS3G5w5.png" 
         alt="Certificação">
    <p class="footer-texto">
        Gerado pelo Jogabilizador, mas com aquele toque especial do professor <b>PROF</b>, porque quem ensina sabe o que faz diferença!  
        <br>
        <span id="data-geracao"><b>DATA</b></span>
    </p>
</div>

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            setTimeout(function() {
                const content = document.getElementById('content');
                const emojiMap = {
                    '1️⃣':'①','2️⃣':'②','3️⃣':'③',
                    '4️⃣':'④','5️⃣':'⑤','6️⃣':'⑥',
                    '7️⃣':'⑦','8️⃣':'⑧','9️⃣':'⑨',
                    '0️⃣':'⓪'
                };

                let newContent = content.innerHTML
                    .replace(/(\d{0,2}️⃣)/g, (match) => {
                        const numero = emojiMap[match] || match;
                        return `<span class="numero-circulo">${numero}</span>`;
                    })
                    .replace(/(📌 Avaliação:)/g, '<span class="destaque-titulo">$1</span>')
                    .replace(/(📌 Referências:)/g, '<span class="destaque-titulo">$1</span>')
                    .replace(/(🏆|📊|💡|🔎|⚠️|📦|👤|🎮|📢|📝) ([^\n]+)/g, '<span class="destaque-titulo">$1 $2</span>')
                    .replace(/(•\s+)/g, '<span style="margin-right:8px">$1</span>')
                    .replace(/⸻/g, '');

                content.innerHTML = newContent;
            }, 500);
        });
    </script>
</body>
</html>
type or paste code here

My HTML2PDF settings in Glide

Format: A4

Zoom: 0.95

Orientation: Portrait

Margin: 35px

Break page before: (Custom)

Break page after: (Custom)

Don’t break page on: .content, p, ul, ol, li, span, strong, em, b, iÂ

Fidelity: High

Data Source Example

(I’m using GlideApps as my data source. Below is an example of how the structured data looks before being inserted into the HTML template.)


📌 Tema: Artes Visuais

📌 Unidade Temática: Artes visuais

📌 Habilidade BNCC: (EF15AR01) Identificar e apreciar formas distintas das artes visuais tradicionais e contemporâneas, cultivando a percepção, o imaginário, a capacidade de simbolizar e o repertório imagético.

📌 Objetivos:
- Desenvolver a capacidade dos alunos de identificar diferentes formas de artes visuais.
- Incentivar a apreciação das obras de arte contemporâneas e tradicionais.
- Estimular a criatividade e a expressão individual através da criação artística.

📌 Conteúdo:
- Tipos de artes visuais (pintura, escultura, fotografia, etc.)
- Elementos básicos da arte (cor, forma, linha, textura).
- A importância do contexto na apreciação da arte.

📌 Duração: 1 aula

📦 Materiais Sugeridos:
• Papel em branco
• Lápis coloridos ou canetinhas
• Acesso a imagens impressas ou projetadas de diferentes obras de arte (tradicionais e contemporâneas)
• Fichas para anotações
• Quadro branco ou flip chart para anotações coletivas

⸻

📝 Metodologia

1️⃣ Preparação:
- Organize os alunos em uma roda para uma introdução sobre o que são artes visuais. Pergunte se conhecem algum artista famoso ou alguma obra que gostem. 
- Apresente brevemente algumas características das artes visuais.

2️⃣ Execução Inicial:
- Mostre algumas imagens de obras de arte (pode ser um slideshow projetado ou impresso). Pergunte aos alunos o que eles veem nas imagens e como se sentem ao olhar para elas. 
- Explique que cada um fará sua própria interpretação artística sobre uma dessas obras.

3️⃣ Desenvolvimento:
- Cada aluno escolherá uma obra para reinterpretar em seu papel. Eles têm 30 minutos para criar sua própria versão inspirada na obra escolhida.
- Após esse tempo, cada aluno deve apresentar sua criação ao grupo em 1 minuto, explicando suas escolhas artísticas (cores usadas, formas etc.).
  
4️⃣ Interações e Dinâmica:
- Os alunos podem dar feedback uns aos outros após as apresentações. Estimule um diálogo respeitoso onde possam compartilhar o que mais gostaram nas criações dos colegas.
  
5️⃣ Encerramento e Avaliação:
- Finalize a aula com uma reflexão coletiva sobre o que aprenderam sobre as artes visuais. Pergunte como se sentiram ao criar suas próprias interpretações.
  
⸻

👤 Perfis de Alunos e Como São Atendidos:
• Explorador: Os exploradores podem investigar diferentes estilos artísticos através das obras apresentadas. Eles apreciarão a liberdade criativa na hora da criação.
• Conquistador: Os conquistadores serão motivados pela possibilidade de apresentar suas criações ao grupo e receber reconhecimento por seu trabalho artístico.
• Socializador: A atividade incentiva interações entre os alunos durante as apresentações e feedbacks, promovendo um ambiente colaborativo.
• Competidor: Para os competidores, pode-se criar um "voto popular" ao final das apresentações onde todos votam na obra que mais gostaram (sem votar na própria).

⸻

🎮 Conexão com Gamificação:
• Dinâmica: A dinâmica escolhida é baseada nas restrições criativas que desafiam os alunos a reinterpretar obras conhecidas dentro do seu próprio estilo pessoal.
• Mecânica: O estado de vitória é alcançado quando os alunos conseguem expressar suas interpretações artísticas com confiança durante as apresentações.
• Componentes: Os níveis são representados pelas etapas da atividade - pesquisa visual, criação artística e apresentação; os pontos podem ser dados pelo feedback positivo recebido dos colegas.

⸻

📊 Avaliação:
• Forma de Avaliação: Apresentação oral da obra criada e participação no feedback coletivo.
• Critérios Avaliados: Criatividade na interpretação artística, clareza na apresentação oral e respeito nas interações durante o feedback.
• Ferramentas de Avaliação: Observação direta do professor durante as atividades; fichas rápidas com notas para cada apresentação feitas pelos colegas.

⸻

💡 Sugestões:
✅ Mantenha um ambiente acolhedor onde todos se sintam à vontade para expressar suas opiniões sobre as obras dos outros.
✅ Para atender diferentes perfis ainda mais eficazmente, considere permitir variações nos materiais usados na criação artística (ex.: colagem).
✅ Uma possível extensão seria criar uma exposição das obras produzidas pelos alunos em um espaço comum da escola após várias aulas.

⸻

🔎 Fontes de Pesquisa:
• Autores recomendados: “A História da Arte” por E.H. Gombrich; “O Livro das Artes” por J.M.C. Ferreira.
• Vídeos e documentários: Canal "História da Arte" no YouTube; documentário “O Mundo das Artes” disponível no canal BBC Arts no YouTube.
• Plataformas de ensino: Portal do MEC (https://www.gov.br/mec/pt-br); Khan Academy - Seção sobre História da Arte (https://pt.khanacademy.org/humanities/art-history).
type or paste code here

Help Needed

• Do you have any suggestions on how to force the content to avoid being sliced horizontally between pages, especially on mobile devices?

• Would changing the @page settings help?

• Is there a known issue with how HTML2PDF handles mobile page rendering?

• Here are two PDF examples showing the issue:

PDF generated on desktop (correct page breaks): [https://drive.google.com/file/d/1uYNExB08MpSI9WYH_hF51z35Ra_15oG7/view?usp=sharing]

PDF generated on mobile (text cut between pages): [https://drive.google.com/file/d/1uc1nNrR3Dxq1W0LTY6BhqYGtrXrI4M5u/view?usp=sharing]

Any guidance would be greatly appreciated!

Thanks in advance for your support!

Best regards,
Anderson Baumgartner

Let me know if I can help with anything @SageCat :slight_smile:

As always, thanks for tagging @ThinhDinh!

2 Likes

Thanks. @ThinhDinh pointed me towards JSON and I’ve worked out how to create a JSON column in my CATS table that contains the relevant data from the MEDICAL table… Yay! Now I’m just trying to work out how to get that information to display in HTML. I’m getting there slowly, but I’m heading in the right direction (I think). It might be 2-3 months before we have the money to pay for Maker level so I’d really like to nut this out so that we have a basic report in the meantime.
:grinning_cat:

Hi there. thank you so much for your help.the plugin works perfectly fine but there is one issue. since we are using glide free plan we can;t have a web-embed component , instead we have to use a button as this is the only alternative. but it seems every time we click the button when it tries to direct us to the url we get a blank page and we need to refresh it manually before the report with the download option appears.this has to be done every time. can you help us to fix this issue and maybe update the code so we don’t need to refresh the page manually everytime.I have tried several changes in the code but nth seems to fix the issue.

Question @Loqode. So I was using Version 1 of HTML2PDF no worries until I ran into the issue where there is too much data being passed in the URL. Because my data that I’m using to generate the PDF is dynamic and I’m building a report, this means the data could be any length which, in turn, can make the URL too long.

Before I go down the path of using V2 HTML2PDF - assuming I can get it working under the Free plan and I’m hoping I can by using a button - I wonder if it will encounter the same issue, that being that the URL may end up too long to pass to the browser?

Thanks in advance.