Как избежать разрыва страницы внутри строки таблицы для 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 и тщательно протестируйте, прежде чем начинать использовать любую новую версию, она все еще немного нестабильна, хотя новые ребята, работающие с antialize, делают отличную работу (ашкулз качается)! Следите за обновлениями на wkhtmltopdf.org и github . Сайт с кодом Google устарел и медленно переносится.


1
Спасибо за информацию. Версия 0.12.1 решает проблему разрыва страницы.
Нидхи Сарвайя

1
Обратите внимание, что это решение работает только с последней версией 0.12.1. Все, что было раньше, по-прежнему не работает.
Cerin

4
Я боролся с этим пару дней. Оказалось, что моя таблица была в div со стилем display: inline-block. Поменял на blockи с изменениями выше все заработало!
Хью

2
@Nenotlep спасибо за ваш ответ. да, я уже опубликовал новый вопрос по этому поводу: stackoverflow.com/q/36334330/3391783 - забавно, как все это работало в версиях 0.12.1 или 0.12.2 и снова не работает в 0.12. 3 версии.
low_rents 01

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>

будет работать как положено.

У меня был более сложный случай с rowspans, поэтому решение сверху разбивало его на части, что было нежелательным эффектом. Я решил это, используя 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 разбивает ее на две части и повторяет заголовки столбцов на новой странице, и эти заголовки столбцов появляются наложенными на первую строку.

Я нашел временное решение этой проблемы в разделе wkhtmltopdf github issues: 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 . Благодаря!
Hugo


5

В моем конкретном случае по какой-то причине ни один из предыдущих ответов у меня не работал. В итоге сработало сочетание нескольких вещей.

  1. Я установил (в Ubuntu 16.04) оболочку python 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 и получить красиво разбитый на страницы PDF.


4

Я пробовал всевозможные манипуляции со своими таблицами, но ничто из того, что я пробовал, не могло помешать размещению разрывов страниц в середине строки. В отчаянии я пробовал разные версии и обнаружил следующее:

Wkhtmltopdf 0.12.2.1: Плохо

Wkhtmltopdf 0.12.3: Плохо

Wkhtmltopdf 0.12.1: Хорошо

Мое решение состояло в том, чтобы перейти на версию 0.12.1, что решило мои проблемы. Конечно, это могло быть отчасти из-за того, что мой html не был супер-ОКР, но поскольку HTML создается внутри TinyMCE (пользователями), у меня действительно нет особого выбора.

Также вложенные таблицы у меня не работают ни в одной версии.


для меня 0.12.1 не решает проблему, а убирает все
UnixAgain

2

Как использовать разрывы страниц внутри PDF без разрыва 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

Я столкнулся с той же проблемой, добавленной после множества пробных ошибок, этот 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

Для тех, у кого все еще есть проблемы с этим, нужно помнить, что таблица должна быть прямым потомком body , иначе css не будет работать (по крайней мере, так случилось со мной).


для меня это было не так - я могу подтвердить, что даже вложенные таблицы соблюдают разрывы страниц ... проблема для меня была больше в mac os и ubuntu ...
Петров

У меня была аналогичная проблема: моя таблица находилась в div с display: table-cell;application. Создание этих стилей @media only screenисправило разрывы страниц. Если вы не можете заставить работать разрывы страниц, попробуйте разделять и властвовать, поэтапно удаляя половину CSS и проверяя, работает ли он.
Leslie Viljoen

1

Я нашел это нелепое решение, но оно мне очень понравилось :)

Я просто поместил очень длинный столбец rowspan, как этот

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

и тогда стол не сломается.


1

Другой вариант: поместите каждый trпо отдельности, tbodyа затем примените правила css peage break к файлу tbody. Таблицы поддерживают несколько tbodys.

Немного дополнительной разметки, но у меня работает прилично.


Я попробовал это на группе элементов tr - заключив их в отдельные элементы tbody - чтобы попытаться сохранить вместе определенные группы строк. Никакого эффекта. Выполнение этого метода без «разрыва страницы внутрь: избежать;» на элементе «tr» снова вызвала возврат к печати данных поверх заголовков страниц (поведение «по умолчанию»).
JosephK

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

Спасибо, но только что попробовал. Он все еще разрывает страницы в середине моих групп строк таблицы. Я также попытался добавить класс к tbody и css к классу с «избегайте» - без эффекта. Хотел бы я знать, что это на самом деле «делает» с правилом css - может быть, каким-то образом заставить его думать, что группа trs на самом деле «один ряд» - но поскольку создание tr 2x + высотой также нарушает его, я предполагаю не. Может быть, через 10 лет кто-то создаст удобное решение из HTML в PDF, но я думаю, что вместо этого они ждут прямой нейронной передачи данных.
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.