Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to show same content in every page (same header/footer, by example) when exporting to pdf #806

Closed
Ciges opened this issue Feb 23, 2014 · 20 comments
Labels

Comments

@Ciges
Copy link

Ciges commented Feb 23, 2014

With Reveal.js there is no way of showing same content in every page (same header/footer, by example) when exporting to pdf. For solving it I have used some JQuery magic in my fork of Reveal.js in the following way:

What I want is that the following HTML be added in every page.

<div class="topbar">
    <h1 class="titulo">Title text</h1><image class="logo" src="images/logo_tegnix.png">
</div>

This works in the navigator if we place it before the <section> labels, but for showing it in every PDF page we must repeat the HTML fragment in every section.

So I used the JQuery code to avoid repeating:

  • if we want to get the PDF output (the URL contains ?print-pdf) insert automatically in every slide, after <section>
  • if shown in a navigator, insert only once after <div class="reveal">
var html_barra = '<div class="topbar"><h1 class="titulo">' + titulo + 
'</h1><image class="logo" src="images/logo_tegnix.png"></div>';
if ( window.location.search.match( /print-pdf/gi ) ) {
    $('section').append(html_barra);
}
else {
    $('div.reveal').append(html_barra);
}

Note that titulo is the variable name for title text.

You can see online demo, pdf export and download my fork from here.

@Ciges
Copy link
Author

Ciges commented Feb 23, 2014

I forgot to say I really love your work! I have written a post (in Spanish) in my blog here explaining what is Reveal.js, how to use it and what my fork is for.

@hakimel
Copy link
Owner

hakimel commented May 4, 2014

Thanks for sharing! I'm sure that will be useful to someone else when trying to add a fixed header/footer.

@devurandom
Copy link

Will this at some point be integrated into reveal.js?

@devurandom
Copy link

Complete example:

    <body>
        <style type="text/css">
            #header-left {
                position: absolute;
                top: 0%;
                left: 0%;
            }
            #header-right {
                position: absolute;
                top: 0%;
                right: 0%;
            }
            #footer-left {
                position: absolute;
                bottom: 0%;
                left: 0%;
            }
        </style>

        <div id="hidden" style="display:none;">
            <div id="header">
                <div id="header-left"></div>
                <div id="header-right"></div>
                <div id="footer-left"></div>
            </div>
        </div>

        <div class="reveal">
            <div class="slides"></div>
        </div>

        <script src="reveal.js/lib/js/head.min.js"></script>
        <script src="reveal.js/js/reveal.js"></script>

        <script>
            
        </script>

        <script src="jquery/jquery-2.1.3.min.js"></script>

        <script type="text/javascript">
            var header = $('#header').html();
            if ( window.location.search.match( /print-pdf/gi ) ) {
                $('.slides > section').prepend(header);
            }
            else {
                $('.slides').prepend(header);
            }
        </script>
    <body>

Note that I prepend to .slides and not .reveal for the screen version, as I want the text to be in the slide area, not outside.

Also note that I prepend to .slides > section instead of just section in the print version, as otherwise the header would appear twice on the initial slide of a 2D series (nested sections: <section><section>…</section></section>) and badly broken on all other slides.

Printing is still pretty broken with this code:

<section>
  The header will appear badly placed, square in the slide.
</section>
<section>
  <section>
    The header will appear fine here.
  </section>
  <section>
    It will not appear here at all.
  </section>
</section>

Still, this is a lot better than no headers at all, especially since I only need the horizontal slides in my printout (#1168).

@maxmeyer
Copy link

Hi, I added a link in the wiki to this issue at https://github.com/hakimel/reveal.js/wiki/Example-Presentations

@Leftium
Copy link

Leftium commented May 30, 2016

The methods documented in this issue don't work quite right anymore, so I have found a new method. The main change is adding the elements to the slide-background <div> (instead of section, slides, or reveal). This <div> is dynamically generated, so we must wait for the Reveal.js ready event. When printing there is a slight delay followed by unnecessary animation of the headers and footers moving into place, but all the headers/footers are rendered in the PDF as desired.

Pseudo-code:

  1. Style header/footer <div> so they are positioned as desired.
  2. Create hidden header/footer <div>
  3. On Reveal.js ready event, copy header/footer <div> into each .slide-background <div>

Code: this can be copy-pasted into the end of a reveal.js file (right before the end </body> tag):

<style type="text/css">
    /* 1. Style header/footer <div> so they are positioned as desired. */
    #header-left {
        position: absolute;
        top: 0%;
        left: 0%;
    }
    #header-right {
        position: absolute;
        top: 0%;
        right: 0%;
    }
    #footer-left {
        position: absolute;
        bottom: 0%;
        left: 0%;
    }
</style>

<!-- 2. Create hidden header/footer <div> -->
<div id="hidden" style="display:none;">
    <div id="header">
        <div id="header-left">HEADER-LEFT</div>
        <div id="header-right">HEADER-RIGHT</div>
        <div id="footer-left">FOOTER-LEFT</div>
    </div>
</div>

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script type="text/javascript">
    // 3. On Reveal.js ready event, copy header/footer <div> into each `.slide-background` <div>
    var header = $('#header').html();
    if ( window.location.search.match( /print-pdf/gi ) ) {
        Reveal.addEventListener( 'ready', function( event ) {
            $('.slide-background').append(header);
        });
    }
    else {
        $('div.reveal').append(header);
   }
</script>

@camerongreen
Copy link

I am in the middle of doing my first reveal slide. I appreciate @Leftium's work, but the lack of an exportable footer which won't break when reveal updates itself doesn't exactly inspire me with confidence.

@dxps
Copy link

dxps commented Jan 3, 2017

@Leftium, Thank you for sharing! I just used your approach and the result looks just right. 👍
@camerongreen, Did you manage to find another way?

@handsomeyang
Copy link

Check out my example https://github.com/handsomeyang/reveal.js

@starlinq
Copy link

Another example is here

@sboisen
Copy link

sboisen commented Apr 10, 2019

For others who wind up here and are interested in @Leftium's solution: if you're using Markdown as input with pandoc for conversion, you can put this additional code in a separate file like footer.html and then include it when generating the HTML with --include-after-body="footer.html".

@antaldaniel
Copy link

@sboisen, can you point to an example to such a 'footer.html'. I cannot make it work.

@sboisen
Copy link

sboisen commented Sep 23, 2019

@antaldaniel Attached is an example i used to include a logo in the footer (renamed to .txt so Git will let me upload it).
tmp-footer.html.txt

@antaldaniel
Copy link

Well, thank you very much...! I read this solution, I was just wondering how to do this when I am rendering from RStudio all the slides.

title: "Habits"
output:
html_document:
includes:
in_header: header.html
before_body: doc_prefix.html
after_body: doc_suffix.html

The first part can go to a style.css that I can add to the yaml, that is clear. I am wondering where to put the html bits, in_header or before_body?

@sboisen
Copy link

sboisen commented Sep 23, 2019

I don't know about RStudio. In my case, i'm rendering via shell script using a pandoc command line like this:

pandoc -t revealjs --standalone --self-contained -o bibletechslides-shared.html bibletechslides.md -V revealjs-url=/Users/sboisen/local/reveal.js --slide-level=2 --css slides.css --include-after-body="footer.html"

I'm pretty sure the --include-after-body parameter is specific to pandoc.

@demlak
Copy link

demlak commented Nov 4, 2019

The methods documented in this issue don't work quite right anymore, so I have found a new method. The main change is adding the elements to the slide-background

(instead of section, slides, or reveal). This
is dynamically generated, so we must wait for the Reveal.js ready event. When printing there is a slight delay followed by unnecessary animation of the headers and footers moving into place, but all the headers/footers are rendered in the PDF as desired.

Pseudo-code:

1. Style header/footer <div> so they are positioned as desired.

2. Create hidden header/footer <div>

3. On Reveal.js ready event, copy header/footer <div> into each `.slide-background` <div>

Code: this can be copy-pasted into the end of a reveal.js file (right before the end tag):

<style type="text/css">
    /* 1. Style header/footer <div> so they are positioned as desired. */
    #header-left {
        position: absolute;
        top: 0%;
        left: 0%;
    }
    #header-right {
        position: absolute;
        top: 0%;
        right: 0%;
    }
    #footer-left {
        position: absolute;
        bottom: 0%;
        left: 0%;
    }
</style>

<!-- 2. Create hidden header/footer <div> -->
<div id="hidden" style="display:none;">
    <div id="header">
        <div id="header-left">HEADER-LEFT</div>
        <div id="header-right">HEADER-RIGHT</div>
        <div id="footer-left">FOOTER-LEFT</div>
    </div>
</div>

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script type="text/javascript">
    // 3. On Reveal.js ready event, copy header/footer <div> into each `.slide-background` <div>
    var header = $('#header').html();
    if ( window.location.search.match( /print-pdf/gi ) ) {
        Reveal.addEventListener( 'ready', function( event ) {
            $('.slide-background').append(header);
        });
    }
    else {
        $('div.reveal').append(header);
   }
</script>

Very nice.. thx a lot..
any idea/solution for hiding it on the first slide?

@mousaalsheikh
Copy link

try Kinzi Print Jquery Plugin, it's great and you can print header/footer on every page

http://kinziprint.com/

@peter-kehl
Copy link
Contributor

To save effort for anyone who uses disableLayout: true when calling Reveal.initialize(...): Neither of the above methods work (at least no with current Reveal.js) with disableLayout: true.

Neither $('.slides').prepend(header); nor $('div.reveal').append(header); work with disabled default layout (in a browser - or non-PDF - and chances are that the related PDF method doesn't work either). $('.slide-background').append(header); doesn't help either (at least not in a browser, non-PDF).

(I do understand that the main topic is for PDF and for default layout.)

@hakimel
Copy link
Owner

hakimel commented Oct 17, 2022

Here's one way you could add a header to each PDF page

const header = document.createElement('header');
header.textContent = 'My custom header'
Object.assign( header.style, {
  position: 'absolute',
  top: '0',
  left: '0',
  width: '100%',
  height: '40px',
  background: '#fff',
  color: '#000'
} );

Reveal.on('pdf-ready', () => {
  document.querySelectorAll('.pdf-page').forEach(page => {
    page.appendChild(header.cloneNode(true));
  });
})

The header uses position absolute and could overlap with content depending on your slide layout. If it does, you can add spacing around the slide using Reveal.configure({margin: 0.1})

@libralibra
Copy link

Here's one way you could add a header to each PDF page

const header = document.createElement('header');
header.textContent = 'My custom header'
Object.assign( header.style, {
  position: 'absolute',
  top: '0',
  left: '0',
  width: '100%',
  height: '40px',
  background: '#fff',
  color: '#000'
} );

Reveal.on('pdf-ready', () => {
  document.querySelectorAll('.pdf-page').forEach(page => {
    page.appendChild(header.cloneNode(true));
  });
})

The header uses position absolute and could overlap with content depending on your slide layout. If it does, you can add spacing around the slide using Reveal.configure({margin: 0.1})

Very nice! I tried this approach and it did copy the header to each page while adding ?print-pdf to the URL. However, this didn't work in the pdf file generated by CTRL+P after previewing the PDF version of the slides. So I assume in the printed pdf file the header won't be there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests