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


Я генерации отчетов в формате PDF из HTML-страницы одной таблице.

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

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

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

17 59

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 устарел и медленно мигрирует.

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

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

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, поэтому решение сверху нарушало его до мира, что не было желаемым эффектом. Я решил это с помощью divs для каждого набора строк в строке. Мой 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 issues: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

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

tr {
  page-break-inside: avoid; 
}

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

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

  1. я установил (в Ubuntu 16.04) оболочка wkhtmltopdf python называется 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>
    

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

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

Wkhtmltopdf 0.12.2.1: Плохо

Wkhtmltopdf 0.12.3: Плохо

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

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

Если вы китаец, не стесняйтесь проверить этот сайт关于wkhtmltopdf,你一定想知道这些 Проверьте суть, если вы хотите 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.

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

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

Я надеюсь, что это помогает.

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