The longfbox
package provides framed boxes that can be customized
using standard CSS attributes. It was written to support precise rendering
of Madoko documents in . Notable features are:
border-style=dashed
or border-top-left-radius=10pt
. Almost all of the CSS 2.0 attributes
with regard to borders, background, padding, and margins are supported.
picture
environment for drawing and does not depend on loading big packages
like tikz
or pstricks
, which makes running much
faster.
longbox
package to break boxes over multiple pages.
mdframed
or tcolorbox
, the
longfbox
package does not have more extensive features like frame
titles, middle lines, skins, etc. The focus of this package
is on rendering boxes well with full CSS support where every
corner and side can be styled separately with good looking transitions,
where we only depend on the standard picture
environment.
There are two ways to create a framed
box, the environment longfbox
and the command \lfbox
.
\lfbox
[〈options〉]{〈content〉}
The 〈options〉
are optional and specify CSS attributes. Just
like the regular \fbox
command, the \lfbox
command sets the content in a horizontal box and cannot break
the content over multiple lines (but it can contain other boxes
like a \parbox
or minipage
environment.). The default width
of an \lfbox
is the natural width of its content. This
corresponds to a CSS inline element.
Here is an \lfbox{inline} box, just like an \fbox{fbox}.
\begin
{longfbox}[〈options〉]〈content〉\end{longfbox}
The longfbox
environment sets the content in a long vertical
box and can break content over multiple columns or pages. The
default width is the current \linewidth
. This corresponds
to a CSS block element.
\begin{longfbox}
The \textsf{longfbox} can contain much
longer content and will by default be
as wide as the current line width.
\end{longfbox}
\newfboxstyle
{〈name〉}{〈options〉}
Defines a new style that can be used to specify commonly used options. For example, the package defines:
\newfboxstyle{tight}{padding=0pt,margin=0pt,baseline-skip=false}
The new style tight
can now be used to render a tight box:
Here is a \lfbox[tight]{tight} box.
The \lfbox
and longfbox
environment can replace many
commands in through the rich CSS interface.
In particular:
framed
, \framebox
, \fbox
: through the text-align
and
width
attributes.
minipage
, \parbox
: through the width
, text-align
,
vertical-align
and baseline
attributes.
\makebox
: through border-style=none
and the text-align
and
width
attributes.
\raisebox
: through the raise
attribute.
\colorbox
, \fcolorbox
: through the background-color
attribute.
\doublebox
, \ovalbox
: through the double
border style,
and the border-radius
attribute.
\shadowbox
: soon :-)
\fboxset
{〈options〉}
Options can be set for the current scope through this declaration. For example, to make all borders rounded and red by default, use:
\fboxset{rounded,border-color=red}%
Here is a \lfbox{rounded} box.
In the options you can specify standard CSS attributes to style
your boxes. Figure 1 shows the basic CSS attributes that
determine how a box is rendered. If you have used CSS boxes before
specifying a box in is straightforward. Here is
an example with an \lfbox
:
Here is a
\lfbox[
border-width=0.8pt,
border-left-color=red,
border-style=dotted,
padding={0.2ex,0.4ex}, %top&bottom, right&left
]{fancy} box.
Here is another example using the longfbox
environment:
\begin{longfbox}[
margin-right=6em,
padding=1.5em,
background-color=floralwhite,
background-clip=padding-box,
border-width=2pt,
border-radius=15pt,
border-top-left-radius=30pt,
border-left-width=8pt,
border-left-color=teal,
border-right-style=double,
]
A \textsf{longfbox} example. A longfbox can contain much
longer content and will by default be as
wide as the current line width.
\end{longfbox}
The border
options determine how the frame of the
box is rendered.
Each border can have an individual style:
border-style
=〈style sides〉
border-top-style
=〈style〉 (=solid)
border-right-style
=〈style〉 (=solid)
border-bottom-style
=〈style〉 (=solid)
border-left-style
=〈style〉 (=solid)
where all CSS styles are supported:
〈style〉
= none | hidden | solid | dotted | dashed | double
| inset | outset | groove | ridge
The 〈style sides〉
value can take 1 to 4 style arguments
just like in CSS:
〈attr sides〉
= 〈attr〉
| {〈top-bottom attr〉 , 〈left-right attr〉}
| {〈top-attr〉, 〈left-right attr〉, 〈bottom-attr〉}
| {〈top-attr〉, 〈right-attr〉, 〈bottom-attr〉, 〈left-attr〉}
Here are some examples of each CSS style:
\lfbox[border-style=solid]{solid},
\lfbox[border-style=dashed]{dashed},
\lfbox[border-style=dotted]{dotted},
\lfbox[border-style=double,border-width=2pt]{double},
\lfbox[border-style={solid,none,dashed,none}]{various}.
Note, for a dotted border, it is often nicer to use the dotted
style
(Section 3.7) since it makes the dots a bit larger, e.g.
Compare \lfbox[dotted]{dotted} versus \lfbox[border-style=dotted]{dotted}.
The final CSS styles darken sides of the border to give a 3D effect:
\lfbox[border-style=inset,border-color=red,border-width=3pt]{inset},
\lfbox[border-style=outset,border-color=red,border-width=3pt]{outset},
\lfbox[border-style=groove,border-color=teal,border-width=4pt]{\strut groove},
\lfbox[border-style=ridge,border-color=teal,border-width=4pt]{\strut ridge}.
The darkness can be controlled using the border-dark-mix
attribute (Section 3.1.3).
Beyond CSS, there are also styles for the border top and bottom when a box is broken over multiple pages (see Section 3.5):
border-break-style
=〈style break-sides〉
border-break-top-style
=〈style〉 (=none)
border-break-bottom-style
=〈style〉 (=none)
where 〈style break-sides〉
takes one or two arguments:
〈attr break-sides〉
=〈attr〉
| {〈break-top-attr〉, 〈break-bottom-attr〉}
See Figure 2 in Section 3.5 for more information.
border-width
=〈width sides〉
border-top-width
=〈dimen〉 (=\fboxrule)
border-right-width
=〈dimen〉 (=\fboxrule)
border-bottom-width
=〈dimen〉 (=\fboxrule)
border-left-width
=〈dimen〉 (=\fboxrule)
This sets the width of each border. By default the \fboxrule
width is used which
is normally 0.4pt
.
A \lfbox[border-width=3pt,border-left-color=red]{thick} border,
and
\lfbox[border-top-width=0pt,border-bottom-width=1pt]{varied}.
border-break-width
=〈width break-sides〉
border-break-top-width
=〈dimen〉 (=0pt)
border-break-bottom-width
=〈dimen〉 (=0pt)
These specify border width around page breaks. See Figure 2 in Section 3.5 for more information.
border-color
=〈color sides〉
border-top-color
=〈color〉 (=black)
border-right-color
=〈color〉 (=black)
border-bottom-color
=〈color〉 (=black)
border-left-color
=〈color〉 (=black)
Sets the color of each border.
〈color〉
= 〈color name〉
| 〈xcolor spec〉
| \#RRGGBB
| {}
Colors can be specified by a name (e.g. red
), and xcolor
package color
specification (e.g. red!60
), a direct HTML color (e.g. \#800080
) or as
an empty value. The empty value is used for transparency on backgrounds.
Strange
\lfbox[border-width=3pt,
border-top-color=red!50,
border-bottom-color=\#800080,
]{colors}.
\noindent\begin{longfbox}[border-style=none,
border-left-style=solid,
border-left-width=5pt,
border-color=blue,
padding-left=1ex,
]This is a definition
\end{longfbox}
Besides the regular CSS attributes, colors for borders around a page break are set as:
border-break-color
=〈color break-sides〉
border-break-top-color
=〈color〉 (=black)
border-break-bottom-color
=〈color〉 (=black)
See Section 3.5 for further information.
border-dark-mix
=〈color mix〉 (=!70!black)
The border-dark-mix
is used to make a color darker and is used for
the inset
, outset
, groove
and ridge
styles. This value is basically
appended to the main color of the border. The default takes 70% of the main
color and mixes in 30% black.
border-radius
=〈radius corners〉
border-top-left-radius
=〈radius〉 (=0pt)
border-top-right-radius
=〈radius〉 (=0pt)
border-bottom-left-radius
=〈radius〉 (=0pt)
border-bottom-right-radius
=〈radius〉 (=0pt)
The above attributes specify the corner radius to enable rounded corners.
〈radius〉
=〈dimen〉 | {〈x-radius〉,〈y-radius〉}
A radius value is either a dimension, or a separate x- and y-radius for elliptical borders. Here are some examples:
\lfbox[border-radius=0.5ex]{rounded},
\lfbox[border-radius=100ex, background-color=floralwhite]{\strut elliptical},
\lfbox[border-radius=0.5em,height=1em,width=1em,tight,
text-align=center,height-align=middle]{1}.
Here is an example of a longfbox
with an elliptical corner:
\begin{longfbox}[
border-radius=15pt,
border-width=2pt,
border-top-left-radius={50pt,25pt},
border-right-style=dashed,
border-left-style=double,
border-left-color=teal,
padding={1em,15pt},
width=0.6\linewidth,
]
\hobbit[7]
\end{longfbox}
Much care has been taken to ensure proper alignment and preservation
of the baseline. In our examples, we use the following definition where we enable
show-markers
so we can see the baseline and dimensions of the longbox:
\newcommand\alignbox[1]{%
\begin{longfbox}[width=2em,height=4.25em,show-markers,
baseline-skip=false,#1]
foo,\\ bar,\\ gnu.
\end{longfbox}%
}
baseline
= bottom | middle | top
The baseline attribute is not a CSS attribute, but we can use it to control the baseline of the content of a box. For example:
Aligning \alignbox{baseline=bottom},
\alignbox{baseline=middle},
\alignbox{baseline=top} done.
The vertical-align
property aligns a box:
vertical-align
= baseline | bottom | middle | top
| text-bottom | text-top | super | sub
The default baseline
attribute aligns the baseline
of the box with the baseline of the text.
The bottom
attribute aligns the bottom of the box with
the bottom of the text, middle
aligns the middle of the box
with the middle of the text, and top
aligns the top of the box
with the top of the text.
Here are the various attributes in action (compare this to the examples for different baselines):
Aligning \alignbox{vertical-align=bottom},
\alignbox{vertical-align=middle},
\alignbox{vertical-align=top} done.
Finally, the super
and sub
attributes align the
baseline of the box with the baseline of super- and sub-scripts:
$x^x_x$ \alignbox{vertical-align=super}, \alignbox{vertical-align=sub} $x^x_x$.
Unfortunately, in we cannot determine
the height or depth of the current text line easily so these
values are fixed at 0.7\baselineskip
and 0.3\baselineskip
.
The text-bottom
and text-top
are equal to bottom
and
top
for that reason.
raise
=〈dimen〉
In CSS it is also possible to assign a length to the
vertical-align
attribute. In we use the raise
attribute instead which raises an aligned box by the assigned value.
Aligning \alignbox{raise=1em}, \alignbox{raise=-1em},
done.
height-align
= top | middle | bottom
This is another non-CSS attribute (but probably one of the most desired :-)):
it specifies the vertical alignment of the content inside the box. This
attribute only has an effect for boxes where the height
is specified.
This attribute keeps the baseline unchanged and does not influence the
vertical alignment directly.
Aligning \alignbox{height-align=bottom},
\alignbox{height-align=middle},
\alignbox{height-align=top},
\alignbox{height-align=middle,baseline=top},
done.
text-align
= default | left | center | right | justify
Specifies the alignment of the content horizontally.
The default
is left
for a horizontal \lfbox
and justify
for a longfbox
environment.
Here is \lfbox[width=6em,text-align=center]{centered} text.
And vertical
\alignbox{text-align=center,baseline=middle,width=4em} too.
Just like with \makebox
we can use a narrow width to let
the text overlay to the left or right:
\lfbox[width=1.7em,text-align=right]{bummer, too long}.
background-color
=〈color〉 (={})
background-clip
=border-box | padding-box | content-box
Specifies the background color. The background-clip
attribute
determines if the background color spans all the way out to the
border (default), just the padding box, or only the content box
itself.
\newcommand\bgbox[2]{%
\lfbox[rounded,border-style=double,border-width=3pt,
border-color=teal,
background-color=#1,background-clip=#2]%
}
a\rlap{b}\bgbox{teal!30}{border-box}{foo},
a\rlap{b}\bgbox{teal!30}{padding-box}{foo},
a\rlap{b}\bgbox{teal!30}{content-box}{foo}.
background-padding-color
=〈color〉 (=\option{background-color})
background-border-color
=〈color〉 (=\option{background-color})
background-content-color
=〈color〉 (=\option{background-color})
Going beyond CSS, we can also specify the colors for the background at the border and padding separately.
A \lfbox[rounded,
background-color=teal!30,
background-padding-color=floralwhite,
background-border-color=gray!50,
border-style=double,border-width=3pt
]{too colorful} box.
padding
=〈padding sides〉
padding-top
=〈dimen〉 (=\fboxsep)
padding-right
=〈dimen〉 (=\fboxsep)
padding-bottom
=〈dimen〉 (=\fboxsep)
padding-left
=〈dimen〉 (=\fboxsep)
The padding is the space between the content and the border
of a box. By default the padding is equal to the \fboxsep
value.
margin
=〈margin sides〉
margin-top
=〈dimen〉 (=0pt)
margin-right
=〈dimen〉 (=0pt)
margin-bottom
=〈dimen〉 (=0pt)
margin-left
=〈dimen〉 (=0pt)
The margin is the transparent area outside the borders. In contrast
to the CSS attribute, the margins do not overlap. Please use
the standard \addvspace
command for adding overlapping top- and
bottom-margins.
\begin{longfbox}[width=6.8em]
Here is a longer paragraph with a
\lfbox[margin={1em,0.5em,1em},padding=1ex,show-markers]{box}
inside with margins.
\end{longfbox}
padding-break-top
=〈dimen〉 (=0.5em)
padding-break-bottom
=〈dimen〉 (=0.5em)
margin-break-top
=〈dimen〉 (=0pt)
margin-break-bottom
=〈dimen〉 (=0pt)
These attributes determine the margin and padding around a page break. By default, there is some padding set around a break such that the vertical borders of a box `stick out' a bit giving the reader a hint that the box continues at the next page (see Figure 2)
breakable
=〈bool〉 (=false)
When the option breakable
is present, a longfbox
environment
can be broken at page boundaries. All the borders, margins, padding,
etc. are preserved over the page break. Moreover, the border, padding,
and margin for each break at the top and bottom can be set
separately, as shown in in Figure 2.
extra-split
=〈dimen〉 (=1.5\baselineskip)
(Advanced) This option determines the minimal height of a box that is broken. If the height would be less the box is not broken and moved to the next page. This prevents for example to have just the top border and padding on one page followed by content on the next page.
breakat
={〈dimen1〉,…,〈dimenn〉}
(Advanced) This option lets you break a box manually at specific heights.
The breakable
option must be set for this to work. Usually a box is broken
to fit the space available on the page, but when breakat
is given, the box
breaks at 〈dimen1〉
. After the break, the first dimension is removed from
the list and the box is broken again at 〈dimen2〉
until only one element
(〈dimenn〉
) is left. After that the box is repeatedly broken at 〈dimenn〉
until all content is processed. For example, in Figure 2 we used
breakat={75pt}
to break the box at three 75pt
heights. Note that when a box
breaks, it chooses the largest height that is less than 75pt
where the content
can be broken nicely, i.e. a box never breaks in the middle of a line for example.
The breakat
can also be used to break a box in a multicols
environment.
height
=〈dimen〉
width
=〈dimen〉
Specifies the height
or width
of the inner content box, see
Figure 1. By default, the width of horizontal \lfbox
is the natural width of its content. In contrast, the default width
of a vertical longfbox
environment is the current \linewidth
.
The default height
is always the natural height of the content.
When the height
is fixed, you can use height-align
to align
the content in the available area.
outer-height
=〈dimen〉
outer-width
=〈dimen〉
For convenience, there are also these non-CSS attributes that
let you specify the width and height of the entire box including
the padding, border, and margins. Internally translated to
the height
or width
before processing the box.
tight
={padding=0pt,margin=0pt,padding-break=0pt}
rounded
={border-radius=1ex}
dotted
={border-width=0.8pt,border-style=dotted}
Some predefined convenient styles. tight
puts the box
tightly around the content. The rounded
style uses a border
radius that looks nice relative to the font size, and
dotted
uses a slightly larger border width which looks better
with dots.
A \lfbox[tight]{tight}, \lfbox[dotted]{dotted},
and \lfbox[rounded]{rounded} box.
render
=default | plain | picture
There are two ways to render a box border: using just plain
and the picture
environment.
The plain renderer just uses \hrule
etc. and can only
render simple boxes with solid
or dashed
styles without
rounded corners. The default
will pick the plain
renderer
if a box is simple, and use the picture
renderer otherwise.
This is mostly to make the rendering more efficient but there
should be no other difference.
insert-before
=〈value〉
insert-after
=〈value〉
These are hooks to insert content just before or after the content box.
A \lfbox[insert-before={``\bgroup\itshape},
insert-after={\/\egroup''}]{quoted}
box.
render-insert-before
=〈value〉
render-insert-after
=〈value〉
These are hooks to insert content just before or after the border-box is rendered.
\newcommand\makecircle{%
\setlength\unitlength{1pt}%
\begin{picture}(0,0)% make it occupy no space
\color{red}%
\put(0,0){\circle*{5}}%
\end{picture}%
}
\lfbox[render-insert-before=\makecircle]{funny}.
picture-insert-before
=〈value〉
picture-insert-after
=〈value〉
These insert content just before or after rendering the frame
in a picture
environment. In both case, the origin is
at the bottom-right corner. Here is an example where we cross-out
a box:
\newcommand\crossout{%
\color{red}\linethickness{1pt}\roundcap%
\moveto(0,0)
\lineto(\optionunit{/fbox/@border-box-width},
\optionunit{/fbox/@border-box-height})
\strokepath
}
This is
\lfbox[rounded,picture-insert-after=\crossout]{crossed out}.
plain-side-insert-before
=〈value〉
plain-side-insert-after
=〈value〉
picture-side-insert-before
=〈value〉
picture-side-insert-after
=〈value〉
These attributes insert content just before rendering a border side.
baseline-skip
=〈bool〉 (=true)
Usually, the library adds a small vertical skip in front of a
vertical longfbox
such that it content aligns to a \baselineskip
.
Similarly, it adds such skip just after the box. This generally makes text
align better, especially on a double column layout. Setting it to false
disables such vertical spacing.
show-markers
=〈bool〉
marker-color
=〈color〉 (=gray)
marker-width
=〈dimen〉 (=0.1pt)
If show-markers
is true
it will show the padding, baseline,
margin and border markers using marker-color
and marker-width
.
eject
=〈value〉 (={\protect\vfill\protect\eject})
After breaking a box, this command is issued which normally
ends the current page. The breakat
command sets this to
empty so no page break occurs in that case.
debug
=〈bool〉 (=false)
verbose
=〈bool〉 (=false)
Enable debug and verbose log messages.
The following attributes are used to render
dashes and dots for the dashed
and dotted
border styles.
border-dash
=〈dash sides〉
border-top-dash
=〈dimen〉 (=0.7ex)
border-right-dash
=〈dimen〉 (=0.7ex)
border-bottom-dash
=〈dimen〉 (=0.7ex)
border-left-dash
=〈dimen〉 (=0.7ex)
border-break-top-dash
=〈dimen〉 (=\option{border-top-dash})
border-break-bottom-dash
=〈dimen〉 (=\option{border-bottom-dash})
border-dashskip
=〈dashskip sides〉
border-top-dashskip
=〈dimen〉 (=0.7\option{border-top-dash})
border-right-dashskip
=〈dimen〉 (=0.7\option{border-right-dash})
border-bottom-dashskip
=〈dimen〉 (=0.7\option{border-bottom-dash})
border-left-dashskip
=〈dimen〉 (=0.7\option{border-left-dash})
border-break-top-dashskip
=〈dimen〉 (=\option{border-top-dashskip})
border-break-bottom-dashskip
=〈dimen〉 (=\option{border-bottom-dashskip})
border-dotskip
=〈dotskip sides〉
border-top-dotskip
=〈dimen〉 (=0.7\option{border-top-width})
border-right-dotskip
=〈dimen〉 (=0.7\option{border-right-width})
border-bottom-dotskip
=〈dimen〉 (=0.7\option{border-bottom-width})
border-left-dotskip
=〈dimen〉 (=0.7\option{border-left-width})
border-break-top-dotskip
=〈dimen〉 (=\option{border-top-dotskip})
border-break-bottom-dotskip
=〈dimen〉 (=\option{border-bottom-dotskip})