Clear rowcolor at midrule
You can clear colors with \hiderowcolors:
\documentclass{article}
\usepackage{etoolbox}
\usepackage[table]{xcolor}
\usepackage{booktabs}
\colorlet{text}{black}
\colorlet{page}{white}
\renewcommand{\toprule}{%
\showrowcolors\arrayrulecolor{text}\specialrule{\heavyrulewidth}{\abovetopsep}{0pt}%
\arrayrulecolor{tableheadcolor}\specialrule{\belowrulesep}{0pt}{0pt}%
\arrayrulecolor{text}}%
\colorlet{tableheadcolor}{orange!30!page}
\apptocmd\midrule{\hiderowcolors}{}{\fail}
\rowcolors{1}{tableheadcolor}{tableheadcolor}
\begin{document}
\pagecolor{blue!10}
\begin{tabular}{lll}
& & \\
\toprule
a & b & \\
\midrule
1 & 2 & \\
\midrule
4 & 5 & \\
\midrule
7 & 8 &
\end{tabular}
\quad
\begin{tabular}{lll}
\toprule
a & b & \\
\midrule
1 & 2 & \\
\midrule
4 & 5 & \\
% \meaning\\ & & \\
\midrule
7 & 8 &
\end{tabular}
\end{document}
The reason for your off-by-one row colouring is that when your modified \midrule
sets your tabularTitleRow
boolean flag to false, it is already too late: the preceding \\
command has already put the \rowcolor
call that sets the row color for header rows. Moreover, your way of modifying \@xarraycr
is nasty, because it prevents the \\[〈dimen〉]
syntax from working inside a tabular
or array
. So, it's better not to redefine \@xarraycr
if possible (as done below).
Based on Ulrike Fischer's idea about using \hiderowcolors
, here is a way to get the space above the \midrule
coloured in the proper colour for the table header (but see below for a more elaborate solution based on this technique):
\documentclass{article}
\usepackage{etoolbox}
\usepackage[table]{xcolor}
\usepackage{ctable} % or booktabs
\colorlet{text}{black}
\colorlet{page}{white}
\colorlet{tableheadcolor}{orange!30!page}
% Use of \showrowcolors and \hiderowcolors is an idea from Ulrike
% Fischer's answer here: <https://tex.stackexchange.com/a/494954/73317>
\renewcommand{\toprule}{%
\showrowcolors
\arrayrulecolor{text}\specialrule{\heavyrulewidth}{\abovetopsep}{0pt}%
\arrayrulecolor{tableheadcolor}\specialrule{\belowrulesep}{0pt}{0pt}%
\arrayrulecolor{text}%
\rowcolor{tableheadcolor}%
}
\apptocmd\midrule{\hiderowcolors}{}{\FAILED}
\makeatletter
\let\@BTrule@ORI=\@BTrule
\let\my@BTrule=\@BTrule
% Modified version of \@BTrule that doesn't do \vskip\@aboverulesep, for use
% when the corresponding vertical space should be coloured.
\patchcmd{\my@BTrule}{%
\ifnum\@lastruleclass=\z@\vskip\@aboverulesep\else
}{%
\ifnum\@lastruleclass=\z@\else
}{}{\FAILED}
\newcommand*{\myendtablehead}{%
\\[\aboverulesep] % this colours the additional space with the current row
% color
\noalign{\global\let\@BTrule\my@BTrule}% temporarily modify \@BTrule
\midrule
\noalign{\global\let\@BTrule\@BTrule@ORI}% restore it
}
\makeatother
\rowcolors{1}{tableheadcolor}{tableheadcolor}
\begin{document}
\pagecolor{blue!10}
\begin{tabular}{ll}
\toprule
a & b \\
d & e \myendtablehead
1 & 2 \\
4 & 5 \\
7 & 8 \\
\bottomrule
\end{tabular}
\end{document}
Here is a solution that allows you to write the \\
before \midrule
, as usual, without needing to explicitly call \myendtablehead
. Note that for \midrule
to be recognized by the modified \@arraycr
, it must immediately follow the \\
command (well, there may be space tokens between them, but nothing else).
Since the \rowcolors
command respects grouping, we define a coloredtableheaders
environment inside which alignments are colored according to this scheme. Outside this environment, \toprule
, \midrule
and \@arraycr
have their usual meaning. Any \rowcolors
command used outside the coloredtableheaders
environment is independent of what we do inside, and should behave as usual.
\documentclass{article}
\usepackage{etoolbox}
\usepackage[table]{xcolor}
\usepackage{booktabs} % or ctable
\colorlet{text}{black}
\colorlet{page}{white}
\colorlet{tableheadcolor}{orange!30!page}
\makeatletter
% The use of \showrowcolors and \hiderowcolors is an idea from Ulrike
% Fischer's answer here: <https://tex.stackexchange.com/a/494954/73317>
\newcommand*{\my@coloredtoprule}{%
\showrowcolors
\arrayrulecolor{text}\specialrule{\heavyrulewidth}{\abovetopsep}{0pt}%
\arrayrulecolor{tableheadcolor}\specialrule{\belowrulesep}{0pt}{0pt}%
\arrayrulecolor{text}%
\rowcolor{tableheadcolor}%
}
\let\my@coloredmidrule\midrule
\apptocmd\my@coloredmidrule{\hiderowcolors}{}{\FAILED}
\let\@BTrule@ORI=\@BTrule
\let\my@BTrule=\@BTrule
% Modified version of \@BTrule that doesn't do \vskip\@aboverulesep, for use
% when the corresponding vertical space should be coloured.
\patchcmd{\my@BTrule}{%
\ifnum\@lastruleclass=\z@\vskip\@aboverulesep\else
}{%
\ifnum\@lastruleclass=\z@\else
}{}{\FAILED}
\let\@arraycrORI=\@arraycr
% The “master counter” hackery is explained in the TeXbook appendix D (Dirty
% Tricks), pp. 385-386. It is also mentioned in the array.sty implementation
% notes concerning \@arraycr.
\newcommand*{\my@colored@arraycr}{%
% Increase the master counter. This is needed to prevent TeX from
% prematurely finishing the alignment entry in case \\ was followed by '&'
% (when the \futurelet from \@ifnextchar causes TeX to read a '&', this
% finishes the entry unless the master counter has a different value than it
% had when the entry was started).
\relax\iffalse{\fi\ifnum 0=`}\fi
% Each of the two branches takes care of decreasing the master counter.
\@ifnextchar\midrule
{\@firstoftwo{\my@endtablehead}}% gobble the following \midrule
{\my@closebrace@and@arraycrORI}%
}
\newcommand*{\my@endtablehead}{%
\ifnum 0=`{}\fi % the second brace decreases the master counter
\@arraycrORI[\aboverulesep]% this colours the additional space with the
% current row color
\noalign{\global\let\@BTrule\my@BTrule}% temporarily modify \@BTrule
\midrule
\noalign{\global\let\@BTrule\@BTrule@ORI}% restore it
}
\newcommand*{\my@closebrace@and@arraycrORI}{%
\ifnum 0=`{}\fi % the second brace decreases the master counter
\@arraycrORI
}
\newenvironment{coloredtableheaders}{%
\let\toprule\my@coloredtoprule
\let\midrule\my@coloredmidrule
\let\@arraycr\my@colored@arraycr
\rowcolors{1}{tableheadcolor}{tableheadcolor}%
\ignorespaces
}{%
\unskip\ignorespacesafterend
}
\makeatother
\begin{document}
\pagecolor{blue!10}
No colored header in the following \verb|tabular|:\quad
\begin{tabular}{l}
a \\
b \\
c
\end{tabular}
\bigskip
\begin{coloredtableheaders}
\begin{tabular}{ll}
\toprule
a & b \\
d & e \\
\midrule
1 & 2 \\
4 & 5 \\
7 & 8 \\
\bottomrule
\end{tabular}
\vspace{4ex}
\begin{tabular}{>{\hspace{3pt}\normalsize}l>{\hspace{5pt}}*{3}{p{7.9em}}}
\toprule
Category & \multicolumn{3}{l}{\normalsize Packages} \\
\midrule
General & etb & xpt & sil \\
& tts & ttc & frm \\
\bottomrule
\end{tabular}
\end{coloredtableheaders}
\vspace{4ex}
No colored header in the following \verb|tabular|:\quad
\begin{tabular}{lr}
Foo & 1\\
Bar & 2\\
And baz & 3
\end{tabular}
\end{document}
Using \cline
in the colored header
As documented in the colortbl
manual:
Lines produced by
\cline
are coloured if you use\arrayrulecolor
but you may not notice as they are covered up by any colour pannels in the following row. This is a ‘feature’ of\cline
. If using this package you would probably [be] better using the-
rule type in a\hhline
argument, rather than\cline
.
Example using the above code and the hhline
package:
\begin{tabular}{lll}
\toprule
a & \multicolumn{2}{c}{b} \\
% \cline{2-3} % problem: covered by the next colored row
% \hhline provides a viable alternative:
\hhline{>{\arrayrulecolor{tableheadcolor}}->{\arrayrulecolor{black}}--}
& c & d\\ \midrule
e & f & g \\ \bottomrule
\end{tabular}