The $\mbox{\lfbox[rounded]{longfbox}}${math-needpdf=true} package
Author: Daan Leijen

The package
Breakable boxes with standard CSS attributes.

Daan Leijen 2015-12-05

## 1.Introduction

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:

- Specify the boxes using standard CSS attributes like `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.
- Fast and portable: only uses the standard `picture` environment for drawing and does not depend on loading big packages like `tikz` or `pstricks`, which makes running much faster.
- Supports breakable boxes that span multiple columns or pages. This package builds on the `longbox` package to break boxes over multiple pages.
- Much care has been put in precise rendering with proper baseline alignment and no spurious extra whitespace.
- In contrast to larger packages like `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.

## 2.Overview

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.

## 3.Styling with CSS

Figure 1. Attributes of the `longfbox` are modeled after the corresponding CSS attributes. Borders are drawn using the standard `picture` environment.

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}

### 3.1.Borders

The `border` options determine how the frame of the box is rendered.

#### 3.1.1.Border style

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.

#### 3.1.2.Border width

​`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.

#### 3.1.3.Border color

​`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.

#### 3.1.4.Border corner radius

​`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}

### 3.2.Alignment

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}.

### 3.3.Background

​`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.

### 3.4.Padding and margins

​`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)

### 3.5.Breaking content

Figure 2. A box that has been broken in three parts. The border style and the padding and margin of each break can be set separately. Use the `breakable` option to make boxes breakable over page boundaries. In the above example we also used the `breakat={75pt}` option to break at specific heights, and the `background-clip=content-box` to limit the background color to the content only.
​`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.

### 3.6.Height and width

​`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.

### 3.7.Predefined styles

​`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.

## 4.Advanced topics

### 4.1.Hooks and rendering

​`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.

### 4.2.Internal attributes

​`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.

### 4.3.Customizing border dashes and dots

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})`
Created with Madoko.net.