TransWikia.com

Breadcrumb hyperlink header

TeX - LaTeX Asked by Scott Wilton on December 10, 2020

I wish to put breadcrumb navigation with hyperlinks into the header of each page. Clicking on each part, chapter, section will take you to the beginning of that part/chapter/section.

I’m already using hyperref to link the ToC.

2 Answers

How about automatically inserting a label at each part/chapter/section? Note this solution (modeled after How to get the section title by section number?) requires you to use part/chapter/section at least once each.


EDIT 3: Still WIP, but trying to generalize by keeping the breadcrumb as data in a sequence first, separating content from presentation. This basic tracking will enable more extensible functionality and different faces for the breadcrumbs. Those interested: keep checking GitHub for more information. (The stack code is not shown here, but can be browsed here.)


EDIT 2: Still WIP, but moved over to LaTeX3 syntax with egreg's help. Working on the previous. Bleeding edge on GitHub.


EDIT: Still a WIP, but now the breadcrumbs are variable-length per the comments. Still working on reversing the order of preference for chapterpage, sectionpage, etc, by digging through the fancyhdr sources. I'd also like the current section at page-begin to be part of the breadcrumb, unless page-begin is a section header.

bredcrmb.sty

% GOAL: introduce a pagestyle "breadcrumb" that will place the breadcrumb as a header.
RequirePackage{xparse}
RequirePackage{everypage
RequirePackage{atbegshi}
RequirePackage{fancyhdr}

letmyhookAtBeginShipout % playing with the two to see if I can get the desired output

% All credit to egreg for the following generalization: (#122823)
% My only additions were the booleans and related stuff.
ExplSyntaxOn
% Macro to insert labels at the end of other macros
NewDocumentCommand{labelize}{mm}
{
  breadcrumbs_labelize:Nn #1 { #2 }
}
myhook{pagestyle{breadcrumb}}
cs_new_protected:Npn breadcrumbs_labelize:Nn #1 #2 {
  % LaTeX3-ify
  bool_new:c { g_breadcrumbs_in_#2 }
  myhook{
    bool_gset_false:c { g_breadcrumbs_in_#2 }
  }

  cs_set_eq:cN { original_ cs_to_str:N #1 } #1
  RenewDocumentCommand #1 { som }
  {
    % Put page style stuff here
    bool_gset_true:c { g_breadcrumbs_in_#2 }
    thispagestyle{#2:style}
    IfBooleanTF{##1}
    {
      use:c { original_ cs_to_str:N #1 }*{##3}
    }
    {
      IfNoValueTF{##2}
      {
        use:c { original_ cs_to_str:N #1 } {##3}
      }
      {
        use:c { original_ cs_to_str:N #1 } [##2]{##3}
      }
      label{#2: use:c{thecs_to_str:N #1} }%
    }
  }
}
% Much nicer syntax.  Thanks, egreg!
labelize {part}    {breadcrumb:part}
labelize {chapter} {breadcrumb:chapter}
labelize {section} {breadcrumb:section}

fancypagestyle{breadcrumb:part:style}{
  fancyhf{}
}
fancypagestyle{breadcrumb:chapter:style}{
  fancyhf{}
  chead{
    nameref{breadcrumb:part:thepart}
  }
}
fancypagestyle{breadcrumb:section:style}{
  fancyhf{}
  chead{
    nameref{breadcrumb:part:thepart}~$rightarrow$~
    nameref{breadcrumb:chapter:thechapter}
  }
}
fancypagestyle{breadcrumb}{
  fancyhf{}
  chead{
    nameref{breadcrumb:part:thepart}~$rightarrow$~
    nameref{breadcrumb:chapter:thechapter}~$rightarrow$~
    nameref{breadcrumb:section:thesection}
  }
}
ExplSyntaxOff

test.tex

documentclass{memoir}

letfootruleskiprelax

usepackage{bredcrmb} % Moved code to style file
usepackage{fancyhdr}
usepackage[colorlinks]{hyperref}

pagestyle{breadcrumb}

usepackage{mwe}
begin{document}

part{Part the First}
chapter{Chapter Primo}
section{Section A}
lipsum
section{Section B}
lipsum
chapter{Chapter Secundo}
section{Section A}
lipsum
section{Section B}
lipsum
part{Part the Second}
chapter{Chapter Primo}
section{Section A}
lipsum
section{Section B}
lipsum
chapter{Chapter Secundo}
section{Section A}
lipsum
section{Section B}
lipsum

end{document}

enter image description here

Correct answer by Sean Allred on December 10, 2020

The following example uses the fact that the anchors for the section commands are set and known before the header line is build. That means with careful timing it is possible to avoid the referencing system with a second LaTeX run.

The example uses class book, where chaptermark, sectionmark and subsectionmark are redefined to include hyperlink with the current anchor @currentHref, which is defined quite right before either via refstepcounter or phantomsection for unnumbered section commands. Some patching is needed to insert partmark or to support starred section commands or commands. Also commands like tableofcontents, which uses @markboth, needs to be patched to get chaptermark.

The section titles in the example are taken from the start of the user manual of pgf to get a closer real document feeling.

documentclass{book}

usepackage[T1]{fontenc}
usepackage{lmodern}
usepackage{ragged2e}

usepackage{etoolbox}

usepackage{fancyhdr}
pagestyle{fancy}
fancyfoot{}
fancyhead{}
cfoot{thepage}
lhead{%
  RaggedRight
%  HeaderFont
  hypersetup{linkcolor=blue}%
  rightmark
}

newcommand*{HeaderFont}{%
  usefont{T1}{qhv}{c}{n}%
  small
}
makeatletter

DeclareRobustCommand*{BreadSep}{%
  ,textbf{guilsinglright}hspace{0pt},%
}
newcountbreadnav@level
breadnav@level=0 %

newcommand*{breadnav@starmark}[2]{%
  begingroup
    c@secnumdepth=-9 %
    #1{#2}%
  endgroup
}

patchcmd{@part}{markboth}{%
  partmark{#1}@gobbletwo
}{}{}
patchcmd{@spart}{normalfont}{%
  breadnav@starmarkpartmark{#1}%
  normalfont
}{}{}
newcommand*{partmark}[1]{%
  protected@xdefCurrentPart{%
    protecthyperlink{@currentHref}{%
      ifnumvalue{secnumdepth}>-2 %
        thepart@~%
      fi
      #1%
    }%
  }%
  markright{%
    CurrentPart
  }%
}
newcommand*{CurrentPart}{}

patchcmd{@schapterhead}{normalfont}{%
  breadnav@starmarkchaptermark{#1}%
  normalfont
}{}{}
patchcmd{tableofcontents}{@mkboth}{%
  breadnav@starmarkchaptermark{contentsname}%
  @gobbletwo
}
renewcommand*{chaptermark}[1]{%
  protected@xdefCurrentChapter{%
    protecthyperlink{@currentHref}{%
      ifnumvalue{secnumdepth}>-1 %
        if@mainmatter
          %@chapapp~
          thechapter.@~%
        fi
      fi
      #1%
    }%
  }%
  markright{%
    ifxCurrentPart@empty
    else
      CurrentPartBreadSep
    fi
    CurrentChapter  
  }%
}
newcommand*{CurrentChapter}{}

patchcmd{@startsection}{@ifstar}{%
  edefCurrentSectionType{#1}%
  @ifstar
}{%
  patchcmd{@ssect}{@tempskipa}{%
    expandafterbreadnav@starmark
    csnameCurrentSectionType markendcsname{#5}%
    @tempskipa
  }{}{}%
}{}
renewcommand*{sectionmark}[1]{%
  protected@xdefCurrentSection{%
    protecthyperlink{%
      @currentHref
    }{%
      ifnumvalue{secnumdepth}>0 %
        thesection.@~%
      fi
      #1%
    }%
  }%
  markright{%
    ifxCurrentPart@empty
    else
      CurrentPartBreadSep
    fi
    ifxCurrentChapter@empty
    else
      CurrentChapterBreadSep
    fi
    CurrentSection
  }%
}
newcommand*{CurrentSection}{}

renewcommand*{subsectionmark}[1]{%
  protected@xdefCurrentSubsection{%
    protecthyperlink{@currentHref}{%
      ifnumvalue{secnumdepth}>1 %
        thesubsection.@~%
      fi
      #1%
    }%
  }%
  markright{%
    ifxCurrentPart@empty
    else
      CurrentPartBreadSep
    fi
    ifxCurrentChapter@empty
    else
      CurrentChapterBreadSep
    fi
    ifxCurrentSection@empty
    else
      CurrentSectionBreadSep
    fi
    CurrentSubsection
  }%
}
newcommand*{CurrentSubsection}{}

letps@plainps@fancy
makeatother

usepackage[colorlinks]{hyperref}
usepackage{bookmark}
bookmarksetup{numbered,open}

usepackage{lipsum}

addtolength{textheight}{headheight}
setlength{headheight}{21pt}
addtolength{textheight}{-headheight}

begin{document}
title{Test document}
author{Me}
date{today}
maketitle
tableofcontents
chapter{Introduction}
lipsum
section{Structure of the System}
lipsum
section{Comparison with Other Graphics Packages}
lipsum
section{Utility Packages}
lipsum
section{How to Read This Manual}
lipsum
section{Authors and Acknowledgements}
lipsum
section{Getting Help}
lipsum
part{Tutorials and Guidelines}
chapter{Tutorial: A Picture for Karl's Students}
lipsum
section{Problem Statement}
lipsum
section{Setting up the Environment}
lipsum
subsection{Setting up the Environment in LaTeX}
lipsum
subsection{Setting up the Environment in Plain TeX}
lipsum
subsection{Setting up the Environment in ConTeX t}
lipsum
section{Straigt Path Construction}
lipsum
section{Curved Path Construction}
lipsum
section{Circle Path Construction}
lipsum
section{Rectangle Path Construction}
lipsum
end{document}

Result, page 8:

Result

and page 25:

Result

Discussion

IMHO the main problem is that breadcrumb headers take a lot of space as seen in the second shapshot, where the header already needs three lines.

The place can be reduced by:

  • Using a shorter separation symbol, the example uses guilsinglright instead of the larger rightarrow.

  • Smaller font sizes (small or footnotesize).

  • Condensed font. Unfortunately these are not often available for the wanted font family.

The following snapshots show the result for the condensed font of Tex Gyre Hermes in size small if HeaderFont is enabled in lhead. This reduces the three lines to two of the second screen shot above:

Result

Variant

Even more clearly arranged looks the navigation path if the levels are shown in separate lines with indentation. This can be achieved by the following definition of BreadSep (that does not support overlong titles that needs more than one line):

DeclareRobustCommand*{BreadSep}{%
  %
  advancebreadnav@level by 1 %
  hspace*{breadnav@leveldimexpr1emrelax}%
  textbf{guilsinglright},%
}

Screen shot with this definition and using small as HeaderFont:

Result

However, this needs as much lines as supported section levels.

It would be nice if smaller headers could give the unneeded space back to the text body. But the page is build before the header and its free space is known. Remember the header size in a label raises the problem that the header can change if the page material is rearranged. Similar to package varioref this can cause documents that never stabilizes.

Answered by Heiko Oberdiek on December 10, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP