Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like a vertical equivalent to \mbox{} that somehow takes a sequence of boxes and stacks them on top of each other.

I'd like the resulting width to be the width of the widest box, and I'd like it to have the following options:

  • either no vertical space between the boxes or standard inter-line spacing
  • left, right, or center alignment
  • the baseline of the resulting box goes through one of the following:

    • top: the baseline of the first box (like \vtop)
    • middle: in the middle of the box
    • bottom: the baseline of the last box (like \vbox)

For example:

surrounding text
\fbox{\stack[align=rt]{something}{something else}{foo}}
surrounding text

would produce:

                 +----------------+
surrounding text |      something | surrounding text
                 | something else |
                 |            foo |
                 +----------------+

Does something like this already exist? If not, does anyone have any pointers about how to make it?

Edit: I'm using LaTeX

share|improve this question

6 Answers 6

up vote 10 down vote accepted

The v0.8 of adjustbox from 2011/11/14 has now a \stackbox[<hor>][<vert>]{<content>} macro (and a matching stackbox environment and stack key). It accepts vertical and horizontal alignment and uses the varwidth package internally. To remove the usual skip between lines, you can use \baselineskip=0pt at the begin and \par at the end. I might add an option for this later.

\documentclass{article}

\usepackage{adjustbox}

\begin{document}

surrounding text
\fbox{\stackbox[r][t]{something\\something else\\foo}}
surrounding text

surrounding text
\fbox{\stackbox[l][b]{something\\something else\\foo}}
surrounding text

surrounding text
\adjustbox{stack=cc,fbox}{something\\something else\\foo}
surrounding text

% No interline skip:
surrounding text
\fbox{\stackbox[c][b]{\baselineskip=0pt something\\something else\\foo\par}}
surrounding text

\end{document}

Result

share|improve this answer
    
as Leo Liu already pointed out it is a simple tabular –  Herbert Nov 17 '11 at 8:28
4  
@Herbert: My first implementation try was using a tabular. However, like all other box macros of adjustbox the content is read as a real box to allow verbatim etc. This is actually quit difficult to do with an implicit tabular, so I went with varwidth. I also wanted to point out that there is a package which has a macro for this. –  Martin Scharrer Nov 17 '11 at 8:33
    
Thank you! I like having something already written and debugged. :) Speaking of bugs, \offinterlineskip doesn't quite work with the macro variant (but the environment version works fine): \setlength{\fboxsep}{-\fboxrule}\stackbox[r][t]{\offinterlineskip\fbox{somethin‌​g}\\\fbox{somethingelse}\\\fbox{foo}} –  Richard Hansen Nov 17 '11 at 18:16
    
@RichardHansen: You need to add a \par at the very end to make it work. I might add it in the macro definition in the next package version. –  Martin Scharrer Nov 18 '11 at 8:22
1  
@Mohan: stackbox uses paragraph mode for the contents, which leads to the limitation to \linewidth. –  Martin Scharrer Dec 10 '12 at 21:00

It is strange no one has mentioned tabular:

\documentclass{article}
\usepackage{array}
\begin{document}
before
\begin{tabular}[t]{|c|}\firsthline
foo\\bar\\baz\\\lasthline
\end{tabular}
after

before
\begin{tabular}[b]{|c|}\firsthline
foo\\bar\\baz\\\lasthline
\end{tabular}
after
\end{document}

enter image description here

You can easily define a new command for short.

And there are indeed quite a lot of tool packages for tabulars to help you to get what you want.

share|improve this answer
    
Is it possible to control inter-row spacing with tabular (so that each box is stacked on top of each other with no vertical gaps)? –  Richard Hansen Nov 17 '11 at 4:47
    
@RichardHansen: Yes, of course. The factor \arraystretch is for this. And you can use makecell package to modify the gape of the tabular lines. –  Leo Liu Nov 17 '11 at 4:49
    
Ah yes, \renewcommand{\arraystretch}{0} eliminated all vertical space between the rows. Excellent! –  Richard Hansen Nov 17 '11 at 5:10
    
What are the pros and cons of using tabular vs. the varwidth approach? Is one better than the other with respect to compatibility (with other LaTeX commands or packages)? –  Richard Hansen Nov 17 '11 at 6:21
    
@Richard: Well, you know a varwidth is a minipage with variable width, in fact origin \parbox or minipage is enough in most cases. A tabular is actually more complex and more powerful than a minipage box: alignment, spacing, frames, etc. –  Leo Liu Nov 17 '11 at 6:30

This is an old question but it has a very easy decomplexified answer, which I offer here for completeness. Use \valign from TeX.

Then it becomes a two liner:

\documentclass{article}
\begin{document}
Before text \lower 30pt\hbox{\valign{&\hbox to 1cm{\fbox{#}\hfil}\vfill\cr
one& two& three& four& five& six\cr}} after text.
\end{document}

TeX commands are available in (La)TeX, and these are the commands that LaTeX uses to build its own macros. I have used \fbox from LaTeX, but is as easy to define a boxit command using TeX. (Please also see the alternative solution by morbusg in the comments, using ooalign).

enter image description here

share|improve this answer
    
Maybe even Before text \oalign{one\cr two\cr three\cr four\cr} after text.? –  morbusg Dec 10 '11 at 13:14
    
@morbusg -- Thanks I forgot about this! Even simpler. I don't know why people don't use basic TeX more. –  Yiannis Lazarides Dec 10 '11 at 13:17

Here is an option that uses the keyval package for setting the keys, the varwidth package for setting the text block, the setspace package for line height adjustment and xifthen for conditioning.

enter image description here

\documentclass{article}
\usepackage{setspace}% http://ctan.org/pkg/setspace
\usepackage{varwidth}% http://ctan.org/pkg/varwidth
\usepackage{keyval}% http://ctan.org/pkg/keyval
\usepackage{xifthen}% http://ctan.org/pkg/xifthen
\makeatletter
\newcommand{\stack}[2][,]{%
  \setkeys{stack}{#1}% Set keys
  \begin{varwidth}[\stack@valign]{\textwidth}\stack@spacing\stack@halign#2\end{varwidth}%
}
% ========= KEY DEFINITIONS =========
\define@key{stack}{halign}{% horizontal alignment
  \ifthenelse{\equal{#1}{r}}{\def\stack@halign{\raggedleft}}{% right-aligned
  \ifthenelse{\equal{#1}{c}}{\def\stack@halign{\centering}}{% centered
  \ifthenelse{\equal{#1}{l}}{\def\stack@halign{\raggedright}}{% left-aligned
  }}}% Otherwise, justified
}
\define@key{stack}{valign}{% vertical alignment
  \ifthenelse{\equal{#1}{m}}{\def\stack@valign{m}}{% middle-aligned
  \ifthenelse{\equal{#1}{b}}{\def\stack@valign{b}}{% bottom-aligned
    \def\stack@valign{t}}}% top-aligned
}
\define@key{stack}{spacing}{\def\stack@spacing{#1}}% spacing
\makeatother
% ========= KEY DEFAULTS =========
\setkeys{stack}{halign=l,valign=t,spacing=\setstretch{1}}%

\begin{document}
surrounding text
\fbox{\stack[valign=m]{something\par something else\par foo}}%
surrounding text

surrounding text
\fbox{\stack[valign=b,halign=l]{something\par something else\par foo}}%
surrounding text

surrounding text
\fbox{\stack[valign=t,halign=r]{something\par something else\par foo}}%
surrounding text

surrounding text
\fbox{\stack[valign=m,halign=c]{something\par something else\par foo}}%
surrounding text

surrounding text
\fbox{\stack[valign=t,spacing=\doublespacing]{something\par something else\par foo}}%
surrounding text

surrounding text
\fbox{\stack[valign=b,halign=c,spacing=\onehalfspacing]{something\par something else\par foo}}%
surrounding text
\end{document}

The following key-value pairs are defined:

  • valign: Adjusts the vertical alignment; possible options are top (default), middle and bottom. Anything else specified defaults to top.
  • halign: Adjusts the horizontal alignment; possible options are left or \raggedright (default), center or \centering, and right or \raggedleft. Anything else defaults to justified text.
  • spacing: Provides an additional formatting hook. With the setspace package loaded, one could use \doublespacing or \setstretch{2}, say. Turning off the inter-line skip is done using spacing=\offinterlineskip or spacing={\baselineskip=0pt}.

Note @barbarabeeton's comment regarding \offinterlineskip:

\offinterlineskip has the danger that if some lines contain no ascenders or no descenders, the baselines can become very irregular. Very ugly and undesirable. use \strut, or less intrusive, $\mathstrut$ (since it doesn't include leading), to even them out if you must use this option.

share|improve this answer
    
Another good answer! I have the same question: How would I turn off inter-line spacing? Thanks! –  Richard Hansen Nov 17 '11 at 4:21
    
I think I figured it out: spacing=\offinterlineskip seems to do it. –  Richard Hansen Nov 17 '11 at 4:31
1  
\offinterlineskip has the danger that if some lines contain no ascenders or no descenders, the baselines can become very irregular. very ugly and undesirable. use \strut, or less intrusive, $\mathstrut$ (since it doesn't include leading), to even them out if you must use this option. –  barbara beeton Nov 17 '11 at 15:50
    
Sometimes I intentionally want the baselines to be irregular. Not often, but often enough that I'd like it to be an option. –  Richard Hansen Nov 17 '11 at 21:20
    
@RichardHansen: Agreed, this is down to personal preference and the application of the provided solution (not always included in the original question), and therefore very subjective at times. –  Werner Nov 17 '11 at 21:22

Basic Solution:

You can use a node with tikz. Below I have defined a macro that accepts an optional alignment as either top, middle, or bottom alogn with 3 parameters for the various text fields. You can easily extend this to handle more.

\MyVBox[top|middle|bottom]{text1}{text2}{text3}

Using just these basic alignment positions you get:

enter image description here

Fancy Options:

But, since this is using \tikz you can also get fancier and adjust the alignment to center, left, add a fill, specify a color for the lines, use a dashed line, etc, etc:

enter image description here

Further Enhancements:

In this solution I resorted to magic numbers for yshift that had to be tweaked to get the top and middle alignment options to work properly. However if the vertical size of the bounding box changes by adjusting the inner sep or the line thickness, this will need to be tweaked. I attempted to use the use as bounding box option as well as adjust those parameters automatically but was not able to get it to work as I expected.

Code:

\documentclass[border=5pt]{standalone}
\usepackage{tikz}

\tikzset{top/.style={baseline={([yshift=-2.44ex]current bounding box.north)}}}
\tikzset{middle/.style={baseline={([yshift=-0.80ex]current bounding box.west)}}}
\tikzset{bottom/.style={baseline=(X.base)}}

\newcommand{\MyVBox}[4][middle, align=right]{\tikz [#1] \node [draw=black, align=right, #1] (X) {#2 \\ #3 \\ #4};}%
\begin{document}
surrounding text
    \MyVBox[top]{something}{something else}{foo}
surrounding text

surrounding text
    \MyVBox[middle]{something}{something else}{foo}
surrounding text

surrounding text
    \MyVBox[bottom]{something}{something else}{foo}
surrounding text

\bigskip\hrule\bigskip
surrounding text
    \MyVBox[middle,align=center,draw=blue,fill=yellow]{something}{longer something else}{foo}
surrounding text

surrounding text
    \MyVBox[middle,align=left,draw=red,fill=green, dashed]{something}{even longer something else}{foo}
surrounding text
\end{document}
share|improve this answer
    
Thank you for the answer! Do you know how I might turn off the inter-line space? –  Richard Hansen Nov 17 '11 at 4:13
1  
It seems like tikz is powerful enough that it should be possible to specify which line's baseline the entire box's baseline should go through. I wonder how hard it would be to tweak the macro to make it possible to specify a line number to use as the baseline? For example, baseline=1 would be the same as giving the top option, baseline=2 would align to the second line's baseline, baseline=-1 would be the same as bottom, baseline=-2 would select the baseline of the second-to-last line as the box's baseline, etc. –  Richard Hansen Nov 17 '11 at 4:40
    
I believe the the inter-line spacing is the normal spacing between lines in a paragraph, so adjusting that should do the job. Yeah, I agree that tikz can probably do that, I just am not that much of an expert to be able to do it without much work. You can post a follow up question about that and am pretty sure you'll get a great solution. –  Peter Grill Nov 17 '11 at 15:19

This is a ConTeXt solution:

\starttext
surrounding text
\inframed [align=left, location=top]
  {something\\something else\\foo}
surrounding text
\stoptext

the result looks like this: result

left, right, or center alignment

Use the align key: left, middle, or right.

The baseline position is controlled by the location key. Set it to either top, bottom, middle. The baseline distance can be controlled using something like

\inframed [
  align=left,
  location=top,
  top={\setupinterlinespace[18pt]}]
  {something\\something else\\foo}

You can remove the frame with frame=off. There are many more options to tweak look here or here for more information.

share|improve this answer
    
Sorry, I forgot to mention that I'm using LaTeX. –  Richard Hansen Nov 17 '11 at 4:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.