[Tex/LaTex] How to make enumerate items align at left margin

#enumerateenumitemhorizontal alignmentlistsparalist

I would like to have my lists to have no indent for the top level, i.e. having the same left margin as the surrounding paragraph, with just enough space for the widest label to fit:

Paragraph text
 1. Item
 2. Item
 3. Item
 ...
10. Item
Paragraph text

I already do something similar for itemize and description, using the enumitem package:

\usepackage{enumitem}
\setlist[itemize]{leftmargin=*}
\setlist[description]{leftmargin=*}

But apparently enumerate has some issues determining the width of its labels. It starts with a shaky assumption, which pushes small labels too far to the right, and extends beyond the left margin if the enumeration gets big enough (I know the 10000 value is ridiculous, it's just to make my point obvious):

\documentclass[twocolumn]{scrbook}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\newcommand{\justsometext}{Just enough text to make the line break so we get to see a second line.}

\begin{document}

\justsometext

\begin{enumerate}
\item \justsometext
\begin{enumerate}
\item Nested. \justsometext
\end{enumerate}
\item \justsometext
\addtocounter{enumi}{9997}
\item \justsometext
\end{enumerate}

\justsometext

\end{document}

The enumitem package gives me half of a way around it, but it requires me to state the widest label

\usepackage{enumitem}
\setlist[enumerate]{leftmargin=*}

% ...

\begin{enumerate}[widest=10000]
% ...

However, isn't there some way to make enumerate detect the width of its widest label automatically, instead of having to set it for each individual list? I feel like there must be some way, I just couldn't figure out how from the enumitem doc…

(I tried the paralist package with option alwaysadjust, as well as compactenum from the same package; both are worse than what I got from enumitem: assuming some label width first – pushing the "1." and "2." from the left margin – then ruining the alignment completely when the 10000 label pushes its item to the right…)

Best Answer

Here is a way to do it using references, and consequently at least two compilations. It requires using labelwidth rather than widest. First, some background...

The obvious motivation behind itemize and description providing solutions to this without problem is because the former (itemize) uses a single-element (symbol) to denote list items, all of which have the same width (by default). Overriding this default to anything other than a single-element (symbol) will have misaligned items, or item labels protruding margin lines:

\begin{itemize}
  \item An item
  \item[qwerty] An item
  \item An item
\end{itemize}

This is due to the left-aligned nature of the itemized bullets. Another motivation is because lists are typeset "on the fly" and even allow for page breaks between items. So, in order to know the widest item at the start, the entire enumerate environment body would have to be read in memory/parsed before determining the widest, and then typeset - not the case by default. The latter (description) works because it uses a right-aligned approach to typesetting the itemized bullets and has a paragraph-style typesetting of the label and item contents by default.

The solution using enumerate requires setting the following enumitem options for a list:

  • labelindent=0pt: to have a flush left margin;
  • labelwidth=\widthof{\ref{last-item}}: this requires the calc package that measures the width of \ref{last-item} where last-item is a label set for the last item in your list;
  • label=\arabic*.: labels will be arabic, followed by a period .;
  • itemindent=1em: separation/space between label and item; and
  • leftmargin=!: automatically calculate what the leftmargin should be based on the provided parameters above (this is new to version 3.0 of enumitem).

Here is a minimal example highlighting the result:

\documentclass{article}
\usepackage{enumitem}% http://ctan.org/pkg/enumitem
\usepackage{calc}% http://ctan.org/pkg/calc
\begin{document}
\noindent Just enough text to make the line break so we get to see a second line.
\begin{enumerate}[labelindent=0pt,labelwidth=\widthof{\ref{last-item}},label=\arabic*.,itemindent=1em,leftmargin=!]
  \item An item
  \item An item
  \item An item \addtocounter{enumi}{9997}
  \item An item \label{last-item}
\end{enumerate}
Just enough text to make the line break so we get to see a second line.
\end{document}

Dynamically-aligned enumerate label

Related Question