Как избежать разрыва страницы внутри строки таблицы для wkhtmltopdf

я генерирую pdf-отчет с html-страницы с одной таблице.

Я использую wkhtmltopdf для этой цели.

когда pdf генерируется это разрывы в любом месте тега tr.

Я хочу избежать этого .

17 ответов


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, делают отличную работу (ashkulz rocks)! Держите в курсеwkhtmltopdf.org и github. Сайт google Code устарел и медленно мигрирует.


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

Итак, из того что я читал, проблема с

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>

будет работать, как ожидаемый.

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

Я не знаю, нужно ли все, и я не думаю, что это идеально, но он делает свою работу. Протестировано только на chrome


начиная с 0.12 эта проблема решена, но иногда, когда таблица слишком длинная, чтобы поместиться на странице, wkhtmltopdf разбивает ее на две части и повторяет заголовки столбцов на новой странице, и эти заголовки столбцов появляются наложенными на первую строку.

Я нашел временное решение этой проблемы в разделе проблем wkhtmltopdf github: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

просто добавьте эти строки в представление css:

tr {
  page-break-inside: avoid; 
}

Я обнаружил, что wkhtmltopdf 0.12.2.1 и далее исправил эту проблему.


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

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

    #!/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>
    

С этими изменениями теперь я могу успешно использовать шаблоны Мако чтобы создать HTML, а затем передать это Wkhtmltopdf и получите красиво разбитый на страницы PDF:)


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

Wkhtmltopdf 0.12.2.1: Bad

Wkhtmltopdf 0.12.3: Bad

Wkhtmltopdf 0.12.1: Хорошее

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

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


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

- у вас есть стол? а тело стола?

<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> теги я предлагаю вам сначала попробовать добавить их.


с добавлением к тому, что говорит Nanotelep, вот рабочая реализация ручного алгоритма разбиения страниц таблицы. https://github.com/AAverin/JSUtils/tree/master/wkhtmltopdfTableSplitHack


ответы выше не сработали для меня. Мне пришлось специально отключить опцию масштабирования моей конфигурации 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

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


Я нашел это нелепое решение, но это сработало очень хорошо для меня :)

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

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

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


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

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


я столкнулся с той же проблемой добавить после многих пробных ошибок n этот css решил проблему

tr { display: inline-table; }


я копался в этих проблемах в течение нескольких дней и, наконец, нашел идеальное решение. Вы можете ссылаться на этот проект 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;
}

Если вы китаец, не стесняйтесь проверить этот сайтkhwkhtmltopdf ,一一 Проверьте суть, если вы хотите gist для wkhtmltopdf


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

я завернул свою таблицу в 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.

важные вещи, которые я заметил, пытаясь решить проблему:

  • в элемента tbody должны быть включены в таблица
  • div должен иметь дисплей: блок
  • когда таблица не помещается на странице, она автоматически перемещает всю таблицу на следующую страницу (Я не пробовал это с огромными таблицами)
  • если вы удалите только ".обертывание-див стол" селектор из CSS, он позволит разделить таблицу на две страницы, но будет отображать ее правильно, не разбивая одну ячейку на две страницы (это похоже на поведение по умолчанию на Слово)

надеюсь, это поможет.


Я много боролся с проблемой, используя последние h4cc / wkhtmltopdf-amd64 версия 0.12.4 и, наконец, заставил его работать, понизив версию пакета до 0.12.3!