Як уникнути розриву сторінки всередині рядка таблиці для wkhtmltopdf


81

Я створюю звіт у форматі PDF зі сторінки html з однією таблицею .

Я використовую wkhtmltopdf з цією метою.

коли pdf генерується, він ламається в будь-якому місці тегу tr .

Я хочу цього уникнути.

Відповіді:


152

Оновлення 17.09.2015: Перевірте версію, яку ви використовуєте: wkhtmltopdf 0.12.2.4, як кажуть, вирішує проблему (я не перевіряв) .


Це відома проблема у wkhtmltopdf. Алгоритм розбиття сторінок, використовуваний webkit (WK у WKhtmltopdf), насправді не працює добре для великих таблиць. Я пропоную розбити таблицю на менші фрагменти, які легше розділити на сторінки та багато використовувати css:

table, tr, td, th, tbody, thead, tfoot {
    page-break-inside: avoid !important;
}

Також подивіться на наступні проблеми wkhtmltopdf, вони мають цікаві коментарі, які обговорюють, наприклад, проблему розбиття таблиці. Існує рішення JS, яке програмно розбиває таблиці на 168, що може вам допомогти (хоча я його не використовую).

Оновлення 08.11.2013 Про це багато дискусій у випуску 168, зв’язаному вище. Хтось встиг скласти версію wkhtmltopdf, яка підтримує краще розбиття таблиць, але, на жаль, здається, що вона офіційно не випущена і може містити інші помилки. Я не знаю, як його отримати, і не знаю, як скомпілювати в Windows, але кожен, хто цікавиться, може перевірити, наприклад, коментар тут (див. Нове оновлення нижче).

Оновлення 24.02.2014 Ви будете раді почути, що у wkhtmltopdf 0,12 ця функція серед інших була значно вдосконалена. Однак почекайте 0.12.1 і ретельно протестуйте, перш ніж почати використовувати будь-яку нову версію, вона все ще трохи нестабільна, хоча нові хлопці, які працюють з антиалізацією, роблять чудову роботу (скелі Ашкульца)! Будьте в курсі wkhtmltopdf.org та github . Сайт коду Google застарів та повільно мігрує.


1
Спасибі за інформацію. Версія 0.12.1 вирішує проблему розриву сторінки.
Nidhi Sarvaiya

1
Зауважте, це рішення працює лише з останньою версією 0.12.1. Все, що було раніше, досі не працює.
Черін

4
Я боровся з цим пару днів. Виявилося, мій стіл був у div зі стилем display: inline-block. Змінив його на, blockі із змінами над цим все почало працювати!
Х'ю,

2
@Nenotlep дякую за вашу відповідь. так, я вже розмістив нове запитання з цього приводу: stackoverflow.com/q/36334330/3391783 - смішно, як все це, здавалося, працювало у версії 0.12.1-ish або 0.12.2-ish і знову зламалося в 0.12. 3-версії.
low_rents

2
@DjDacSaunders WKHTMLTOPDF - хакерство, а не чистий html -> pdf інструмент. Суть цього полягає в тому, щоб зробити дуже довгий документ у форматі сторінки. Той факт, що ми маємо якийсь контроль над цим, є чудовим. Якщо ви хочете, щоб це покращило, найкращим місцем для зв’язку є вихідна версія wkhtml, яка є або проектом QT, або, можливо, проектом WebKit. Я передбачаю, що ця річ ніколи не змінюється, оскільки це насправді не те, що WebKit мав робити при отриманні веб-сторінок як файли PDF: / Для повного контролю, можливо, спробуйте PrinceXML. (x) HTML - це не формат друку, і "рішення" цієї проблеми - це завжди хакі.
Джоел Пелтонен,

18

Це стара публікація, але оскільки я витрачав багато часу на спроби знайти належне рішення, я поміщу його тут, можливо, це комусь стане в нагоді.

Отже, з прочитаного - проблема

page-break-inside: avoid

полягає в тому, що це не працює. Але насправді, якщо ви встановите його на елемент, який має, display:blockвін працює, як очікувалося (як зазначалося десь у SO). так для простої структури таблиці css з

td div, th div{
    page-break-inside: avoid;
}

та структура таблиці

<table>
....
<tr>
    <td><div>some text</div></td>
    <td><div>more text</div></td>
</tr>
....
</table>

працюватиме як слід.

У мене був дещо складніший випадок із розмахом рядків, тому рішення зверху розбивало його на мир, що не було бажаним ефектом. Я вирішив це, використовуючи div для кожного рядка, що розгортається. Мій jquery js виконує всю роботу:

$(window).load(function () {
    var sizes = {};
    $('#the_table tr:first th').each(function (a, td) {         
        var w = $(td).width();
        if (sizes.hasOwnProperty('' + a)) {
            if (sizes['' + a] < w)
                sizes['' + a] = w;
        }
        else {
            sizes['' + a] = w;
        }
    });

    var tableClone = $('#the_table').clone();
    $('#the_table').replaceWith('<div class="container"></div>');

    var curentDivTable;
    var cDiv = $('.container');
    tableClone.find('tr').each(function (i, ln) {
        var line = $(ln);
        if (line.hasClass('main_row')) {
            var div = $('<div class="new-section"><table><tbody>')
            currentDivTable = div.find('tbody');
            cDiv.append(div);               
        }
        currentDivTable.append(line);
    });
    //optional - maybe in % its better than px
    var sum = 0;
    $.each(sizes, function (a, b) {
        sum += b;
    });
    var widths = {};
    $.each(sizes, function (a, b) {
        var p = Math.ceil(b * 100 / sum);
        widths['' + a] = p + '%';
    });
    //setup
    $('.container table').each(function (a, tbl) {
        $(tbl).find('tr:first td, tr:first th').each(function (b, td) {
            $(td).width(widths['' + b]);
        });
        $(tbl).addClass('fixed');
    });
});

css:

div.new-section {
    page-break-inside: avoid;
}
.container, .new-section, .new-section table.fixed{
    width: 100%;
}

.new-section table.fixed{
    table-layout:fixed;
}

Я не знаю, чи все потрібно, і я не думаю, що це ідеально, але це робить свою справу. Випробувано лише на хромі


16

Оскільки 0,12 ця проблема вирішена, але іноді, коли таблиця занадто довга, щоб вмістити її на сторінці, wkhtmltopdf розбиває її на дві частини та повторює заголовки стовпців на новій сторінці, і ці заголовки стовпців з’являються накладеними на перший рядок.

Часове рішення цієї проблеми я знайшов у розділі проблем із github wkhtmltopdf: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

Просто додайте ці рядки до вашого перегляду css:

tr {
  page-break-inside: avoid; 
}

Це насправді допомагає. Дякую!! Не впевнений, чому це не поведінка за замовчуванням.
JosephK

6

Я копався у цих проблемах днями, і нарешті знайшов ідеальне рішення. Ви можете посилатися на цей проект phpwkhtmltopdf . Загляньте в каталог, articleі ви знайдете 3 рішення для 3 проблем. Коротше кажучи, кінцевим рішенням є додавання стилю css

thead {
    display: table-row-group;
}
tr {
    page-break-before: always;
    page-break-after: always;
    page-break-inside: avoid;
}
table {
    word-wrap: break-word;
}
table td {
    word-break: break-all;
}

Якщо ви китаець, сміливо перевіряйте цей сайт关于 wkhtmltopdf , 你 一定 想 知道 这些 Перевірте суть, якщо хочете суть для wkhtmltopdf


Це спрацювало для мене. Я використовую wkhtmltopdf 0.12.4 . Дякую!
Гюго


5

У моєму конкретному випадку чомусь жодна з попередніх відповідей не спрацювала для мене. Що в підсумку вдалося, насправді було поєднанням кількох речей.

  1. Я встановив (в Ubuntu 16.04) обгортку піктону Wkhtmltopdf з назвою pdfkit за допомогою pip3, а потім замість установки Wkhtmltopdf через apt-get встановив статичний двійковий файл (версія 0.12.3), дотримуючись наведеного нижче сценарію, взятого звідси

    #!/bin/sh
    
    sudo apt-get install -y openssl build-essential xorg libssl-dev
    wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    tar -xJf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    cd wkhtmltox
    sudo chown root:root bin/wkhtmltopdf
    sudo cp -r * /usr/
    
  2. Додав цей CSS (як запропоновано в одній із відповідей тут):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. А потім також додайте <thead>та <tbody>теги, як запропоновано і тут (без них таблиця все одно буде потворно розбиватися):

    <table>
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
            </tr>
        </thead>
    
        <tbody>
            <tr>
                <td>Value 1</td>
                <td>Value 2</td>
            </tr>
        </tbody>
    </table>
    

За допомогою цих модифікацій я тепер можу успішно використовувати шаблони Mako для генерації HTML-коду, а потім подавати його до Wkhtmltopdf і отримувати красиво розбитий на сторінки сторінки.


4

Я спробував усілякі маніпуляції зі своїми таблицями, але нічого, що я спробував, не могло зупинити розміщення розривів сторінок у середині рядка. У відчаї я спробував різні версії і виявив наступне:

Wkhtmltopdf 0.12.2.1: Погано

Wkhtmltopdf 0.12.3: Погано

Wkhtmltopdf 0.12.1: Добре

Моїм рішенням було перейти на версію 0.12.1, яка вирішила мої проблеми. Звичайно, вони могли бути частково пов’язані з тим, що вони не були супер OCD щодо мого html, але оскільки HTML формується всередині TinyMCE (користувачами), у мене насправді немає великого вибору.

Крім того, вкладені таблиці не працюють для мене в жодній версії.


для мене 0.12.1 не вирішує проблему, і це забирає ток
UnixAgain

2

Як використовувати розриви сторінок всередині pdf без break a tr?

Ось рішення, яке можна використовувати в будь-якому файлі html .....

Після запуску вашого tr ви повинні взяти div всередині tr і передати цей css div:

<tr>
      <div style="page-break-inside:avoid !important; page-break-after:auto !important; overflow: hidden; display:block !important; width:100% ">
     </tr>

2

Я стикався з тією ж проблемою, додавши після багатьох пробних помилок n, ця css вирішила проблему

tr {
    display: inline-table;
}


1

Відповіді вище мені не спрацювали. Мені довелося спеціально вимкнути параметр масштабування мого конфігураційного pdfkit.

PDFKit.configure do |config|

  config.default_options = {
    print_media_type: false,
    page_size: "A4",
    encoding: "UTF-8",
    ## Make sure the zoom option is not enabled!
    ## zoom: '1.3',
    disable_smart_shrinking: false,
    footer_right: "Page [page] of [toPage]"
  }

end

1

Для тих, хто все ще має проблеми з цим, слід пам’ятати одне, що таблиця повинна бути безпосередньою дитиною тіла , інакше css не буде працювати (принаймні, це сталося зі мною).


це не було для мене - я можу підтвердити, що навіть вкладені таблиці дотримувались розривів сторінок ... проблема для мене була більше mac os vs ubuntu ...
Петров

У мене була подібна проблема: моя таблиця знаходилася в div з display: table-cell;застосованим. Вирішення цих стилів @media only screenвиправило розриви сторінок. Якщо вам не вдається змусити працювати розриви сторінок, спробуйте розділити і завоювати, видаляючи поетапно половину CSS і перевіряючи, чи це працює.
Leslie Viljoen

1

Я знайшов це смішне рішення, але воно мені дуже добре вдалось :)

Я просто поставив такий довгий стовпець з розмахом рядків, як цей

<td rowspan="XXX TOTAL ROWS" style="width:0px"></td>

і тоді стіл не розбився б.


1

Інший варіант: розмістіть кожен trу своєму, tbodyа потім застосуйте правила css peage break css до tbody. Таблиці підтримують кількаtbody s.

Трохи додаткової розмітки, але для мене працює гідно.


Я спробував це на групі елементів tr - обертаючи їх в окремі елементи tbody - щоб спробувати зберегти певні групи рядків разом. Це не мало ефекту. Виконання цього методу без "прориву сторінки: уникайте;" на елементі "tr" знову призвело до повернення даних до верхньої частини заголовків сторінки (поведінка "за замовчуванням").
JosephK

Так, зараз я застосовую одне і те ж правило "page-break-inside: уникати" і до tbody, і до tr, і до td: "tbody, tbody> tr, tbody> tr> td, tbody> tr> th {break-inside: уникати;} ", що, здається, працює в більшості ситуацій.
Трой Морехаус,

Спасибі, але просто спробував це. Це все ще розбиває сторінки в середині моїх груп tbody рядків таблиць. Я також спробував додати клас до tbody, і css для класу з "уникати" - ніякого ефекту. Мені б хотілося, щоб я знав, що це насправді "робить" з правилом css - можливо, якимось чином можна змусити його думати, що група trs насправді є "одним рядком" - але оскільки виготовлення tr 2x + tall також це порушує, я здогадуюсь ні. Можливо, хтось зробить придатне рішення HTML у PDF ще через 10 років, але я думаю, що вони чекають прямої нейронної передачі даних.
JosephK

1

Я вирішив проблему, використовуючи комбінацію деяких запропонованих рішень.

Я загорнув свою таблицю в div і визначив наступний CSS.

.wrapping-div {
        display: block;
        page-break-inside: avoid !important;
    }

.wrapping-div table, .wrapping-div tbody, .wrapping-div tr, .wrapping-div td, .wrapping-div th {
        page-break-inside: avoid !important;
    }

Структуру таблиці після закінчення було визначено як такий приклад:

<div class="wrapping-div">
 <table>
  <tbody>
   <tr>
    <th>
      header
    </th>
    <td>
      content
    </td>
   </tr>
  </tbody>
 </table>
</div>

Мені не потрібно було створювати div у тегах td або th.

Важливі речі, які я помітив, намагаючись вирішити проблему:

  • Тіло має бути включене в таблицю
  • У div має бути display: block
  • Коли таблиця не вміщується на сторінці, вона автоматично перемістить всю таблицю на наступну сторінку (я не пробував цю з величезними таблицями)
  • Якщо ви видалите з CSS лише селектор ".wrapping-div table" , це дозволить розділити таблицю на дві сторінки, але візуалізуватиме її правильно, не порушуючи одну клітинку на двох сторінках (це як поведінка за замовчуванням у Word )

Сподіваюся, це допоможе.



1

Щоб уникнути розриву сторінки, ми можемо використовувати опцію уникати розриву сторінки css.

tr { page-break-inside: avoid; }

Розбийте будь-який вміст (Зображення / Текст) і покажіть його на наступній сторінці

.sample-image { page-break-before: always; }

0

У вас є голова столу? а тіло столу?

<table>
<tbody>
<tr><th>Name</th><th>Value</th></tr>
<tr><td>url</td><td>stackoverflow.com</td></tr>
<tr><td>ip</td><td>123.123.123.123</td></tr>
</tbody>
</table>

Це правильне форматування таблиці, в той час як більшість браузерів не хвилюються, перетворювачі, як той, про який ви згадали, можуть, якщо ваші відсутні <tbody>або <th>теги я пропоную спробувати додати їх першими.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.