Search code examples
javascriptcssgoogle-chromeprintingpage-break

Page break workaround (javascript) for chrome


So, as known, this awesome CSS properties:

  table { page-break-inside:auto }
  tr    { page-break-inside:avoid; page-break-after:auto }
  thead { display:table-header-group }
  tfoot { display:table-footer-group }

Doesnt work on Chrome. So now comes the workaround. I have this table structure (please note JSP and EL syntax)

    <table class="table resultTable">
        <thead class="repeat">
            <tr class="head">
                <th>XPTO HEADER</th>
                <th>XPTO HEADER</th>
            </tr>
        </thead>
        <tbody>
            <c:forEach items="${items}" var="t" varStatus="loop">
                <tr>                        
                    <td class="money">${t.XPTO}</td>
                    <td class="money">${t.XPTO2}</td>
                </tr>
                <c:if test="${(loop.index + 1) % 20 == 0}">
                    <tr class="break-page">
                    </tr>                   
                </c:if>
            </c:forEach>                                        
        </tbody>
    </table>

Two things to notice: the class "repeat" on the thread and the empty tr with break-page class after 20 rows.

So, check this CSS:

    @media print {          
        .break-page {
             display: block; page-break-before: always;
        }
    }

And check this JS:

     var repeat = $('.repeat tr');

     $('.break-page').after(repeat.clone());

That's awesome :) This produces exactly what I want. Check how this first page:

enter image description here

And the second page, you can see that the header repeats, but, check out this huge white space:

enter image description here

So that's it. Can you guys help me get rid of that huge white space? Also I hope this helps if someone is having the same trouble as I am.

Thank you


Solution

  • All I did was: used div instead of table tag. Also I inserted a page-break after 20 rows for chrome. Created a javascript hack to add the header again.

    NOTE: this creates different pages and data layout for each browser. Chrome has 3 pages and the last one the table is kinda in the middle... And firefox has only two pages, that fits perfectly. That was the best I could do.

    HTML

                <div class="divTable">
                    <div class="divHeading">
                        <div class="divCell">${i18n.label.initialValue}</div>
                        <div class="divCell">${i18n.label.additions}</div>
                        <div class="divCell">${i18n.label.discounts}</div>
                        <div class="divCell">${i18n.label.finalValue}</div>
                    </div>
                    <c:forEach items="${detailedCashFlow.transactions}" var="t" varStatus="loop">
                            <div class="divCell money">${t.initialValue}</div>
                            <div class="divCell money">${t.totalAddition}</div>
                            <div class="divCell money">${t.totalDiscount}</div>
                            <div class="divCell money">${t.value}</div>
                        </div>
    
                        //THIS IS VERY IMPORTANT
                        <c:if test="${fn:length(detailedCashFlow.transactions) > (loop.index + 1 ) && (loop.index + 1) % 20 == 0}">
                            <div class="break-page"></div>
                        </c:if>
                    </c:forEach>                                        
                </div>
    

    CSS

                .divTable
                {
                    display: table;
                    width: 100%;
                    margin-top: 20px;
                }
                .divTitle
                {
                    display: table-caption;
                    text-align: center;
                    font-weight: bold;
                    font-size: larger;
                }
                .divHeading
                {
                    display: table-row;
                    font-weight: bold;
                    text-align: center; 
                }
                .divRow
                {
                    display: table-row;
                }
                .divCell
                {
                    display: table-cell;
                    border: solid;
                    border-width: thin;
                    padding-left: 5px;
                    padding-right: 5px;
                    text-align: center;         
                    font-size: 12px;
                }
                .divRow:nth-child(even){
                    background: #aad4ff !important;
                }
                .divRow:nth-child(odd){
                    background: #FFF !important;
                }
    
                @media print {                        
                    .divHeading { 
                        display:table-header-group;
                    }
    
                    .divRow
                    {
                        -webkit-column-break-inside: avoid;
                        webkit-page-break-inside:avoid; 
                        page-break-inside:avoid; page-break-after:auto;    
                    }
    
                    .break-page {
                        page-break-before: always;
                    }
                }
    

    JS HACK

         var is_chrome = window.chrome;
    
         if(is_chrome){
             var repeat = $('.divHeading');
    
             $('.break-page').after(repeat.clone());             
         }