'With html2pdf in generated pdf as all css styles are lost

In my laravel 5.7 / bootstrap 4.4 app I use spatie/browsershot 3.37 and spipu/html2pdf 5.2 to generate pdf file and for my generated pdf file want I set layout with 100% height and footer and header like here: https://jsfiddle.net/MadLittleMods/LmYay/

But imported block of code which looks ok on my blade page in browser is invalid in generated pdf : as all css styles are lost.

by clicking on “To pdf file” content of the page is rendered into pdf file:

Browsershot::html(htmlspecialchars_decode($pdf_content))
           ->showBackground()
           ->save($save_to_file);

if($hidden_action== 'upload') {
    \Response::download($save_to_file, $filename_to_save, array('Content-Type: application/octet-stream', 'Content-Length: pdf'));
    return response()->download($save_to_file, $filename_to_save)->deleteFileAfterSend(true);
}

in my blade file:

@extends($current_admin_template.'.layouts.backend')


@section('content')

    @inject('viewFuncs', 'App\library\viewFuncs')

    <div id="page-wrapper" class="card">


  // THIS PART LOOKS OK IN BROWSER BUT IN GENERATED PDF INVALID AS ALL CSS CLASSES ARE LOST
        <div class="flexbox-parent" id="div_invoice_content" style="display: flex;">
            <input type="hidden" id="hidden_invoice_no" name="hidden_invoice_no" value="{{$invoice_no}}">
            <input type="hidden" id="hidden_invoice_id" name="hidden_invoice_id" value="{{$invoice_id}}">

            <div class="flexbox-item header">
                Header $invoice_no::{{$invoice_no}}<br>
                $invoice_id::{{$invoice_id}}
            </div>

            <div class="flexbox-item fill-area content flexbox-item-grow">
                <div class="fill-area-content flexbox-item-grow">
                    Content
                    <br /><br />
                    Emulates height 100% with a horizontal flexbox with stretch
                    <br /><br />
                    This box with a border should fill the blue area except for the padding (just to show the middle flexbox item).
                </div>
            </div>

            <div class="flexbox-item footer">
                Footer
            </div>
        </div>


        <form method="POST" action="{{ url('/admin/generate-pdf-by-content') }}" accept-charset="UTF-8" id="form_print_to_pdf_content"
              name="form_print_to_pdf_content"
              enctype="multipart/form-data">
            {!! csrf_field() !!}

            <div class="form-row m-3">
            ...
            FORM CONTENT
            ...
            

            </div>
        </section> <!-- class="card-body" -->

    </div>
    <!-- /.page-wrapper page Content : invoice edit -->


@endsection



{{--@section('head')--}}
{{--@push('scripts')--}}
    <style  lang="css">
        .flexbox-parent
        {
            height: 842pt !important;
            width: 595pt !important;

            display: flex;
            flex-direction: column;

            justify-content: flex-start; /* align items in Main Axis */
            align-items: stretch; /* align items in Cross Axis */
            align-content: stretch; /* Extra space in Cross Axis */

            background: rgba(255, 255, 255, .1);
        }

        .flexbox-item
        {
            padding: 8px;
        }
        .flexbox-item-grow
        {
            flex: 1; /* same as flex: 1 1 auto; */
        }

        .flexbox-item.header
        {
            background: rgba(255, 0, 0, .1);
        }
        .flexbox-item.footer
        {
            background: rgba(0, 255, 0, .1);
        }
        .flexbox-item.content
        {
            background: rgba(0, 0, 255, .1);
        }

        .fill-area
        {
            display: flex;
            flex-direction: row;

            justify-content: flex-start; /* align items in Main Axis */
            align-items: stretch; /* align items in Cross Axis */
            align-content: stretch; /* Extra space in Cross Axis */

        }
        .fill-area-content
        {
            background: rgba(0, 0, 0, .3);
            border: 1px solid #000000;

            /* Needed for when the area gets squished too far and there is content that can't be displayed */
            overflow: auto;
        }
    </style>
{{--@endpush--}}

{{--@endsection--}}




@section('scripts')


    <link rel="stylesheet" href="{{ asset('/css/gijgo.min.css') }}" type="text/css">

    <script src="{{ asset('js/AutoNumeric/[email protected]') }}"></script>
    ...

@endsection

        

I tried to put <style block in several places of the page, but in all cases in generated pdf as all css styles are lost

Which is valid way to use css classes in the generated file?

MODIFIED BLOCK 1: I created file public/css/flb_layout.css with all flexbox classes definitions and in my blade file I added asset to this css file:

@section('scripts')


    <link rel="stylesheet" href="{{ asset('/css/gijgo.min.css') }}" type="text/css">
    <link rel="stylesheet" href="{{ asset('/css/flb_layout.css') }}" type="text/css">
    ...
    

and checking source of generated html file I see link to flb_layout.css file:

</footer>
<link rel="stylesheet" href="http://local-boxbooking2.com/css/gijgo.min.css" type="text/css">
<link rel="stylesheet" href="http://local-boxbooking2.com/css/flb_layout.css" type="text/css">

where http://local-boxbooking2.com - is hosting of my local app.

and as result in my browser I see that flexbox layout is rendered ok, but generating pdf file I see plain html without flexbox classes definitions applied. Which way is valid ?

MODIFIED BLOCK 2:

I found a hint:

The asset function generates a URL for an asset using the current scheme of the request (HTTP or HTTPS)

The library you're using launches a puppeteer instance in the background to capture the PDF.

Instead of generating a URL, try generating an absolute path to the file on your machine: (obviously you can leave out the mix helper if you do not use Laravel Mix)

> <link rel="stylesheet" href="{{
> public_path(mix('/path/to/styles.css')) }}" />

So in my blade form I chanhed refering to my css :

<link rel="stylesheet" href="{{ public_path('/css/flb_layout.css') }}">

As result my css classes are not rendered in the page of the browser. In generated pdf file my css classes are not rendered too.

In my project I use webpack.mix.js with definitions:

const mix = require('laravel-mix');


let current_admin_template= 'Backend';
mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/' + current_admin_template + '/backend.scss', 'public/css/' + current_admin_template)
    .sass('resources/sass/' + current_admin_template + '/style_lg.scss', 'public/css/' + current_admin_template)
    .sass('resources/sass/' + current_admin_template + '/style_md.scss', 'public/css/' + current_admin_template)
    .sass('resources/sass/' + current_admin_template + '/style_sm.scss', 'public/css/' + current_admin_template)
    .sass('resources/sass/' + current_admin_template + '/style_xs_320.scss', 'public/css/' + current_admin_template)
    .sass('resources/sass/' + current_admin_template + '/style_xs_480.scss', 'public/css/' + current_admin_template)
    .sass('resources/sass/' + current_admin_template + '/style_xs_600.scss', 'public/css/' + current_admin_template)
    .sass('resources/sass/debug.scss',  'public/css' )
;

Can it be used anyway?

Thanks!



Solution 1:[1]

I failed to add css classes to spipu/html2pdf and had to move into https://github.com/spatie/browsershot with style definition :

Browsershot::url('https://example.com')
    ->setOption('addStyleTag', json_encode(['content' => 'body{ font-size: 14px; }']))
    ->save($pathToImage);

which works ok for me...

Solution 2:[2]

It does not work like that in pdf Parser plugin.. give all css inline. NOTE: no files can be read directly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Petro Gromovo
Solution 2