Proper vertical spacing and pagebreaks in custom environment

I would like to design a simple environment which displays examples. This is what I got so far:

\documentclass{article}
\usepackage{xcolor}
\usepackage{parskip}
\usepackage{lipsum}

\makeatletter
\newcounter{example}
\newenvironment{example}[1][]{%
\refstepcounter{example}%
\textbf{Example~\theexample{}}~{\color{gray}\filltoend}% number and line
\nopagebreak% is this the right place?
\par% should I call other vertical spacing commands so I can use the plus/minus syntax?
\par\itshape\ignorespaces%
}{%
\\% it would be nice to keep this together with contents
{\color{gray}\null\filltoend\null}
}

\makeatother

\begin{document}
\lipsum[1-4]
\begin{example}[My example]
\lipsum[5]
\end{example}
\end{document}


This is simple and kind of ok.

How can I specify that I want some non-strechable vertical space between the example's number and line, heading and text? How do I discourage LaTeX from putting page breaks between the header components?

In other words: I would like to keep the Example # ---, heading, and start of inner paragraph together, on the same page and without too large spacing between them.

-
You can put any vertical space right after \par in your code. I would also put that \nopagebreak after \par and before the vertical space, but it is probably OK where it is. –  Dan Feb 11 at 20:18

If you are willing to use an additional package, I'd suggest you to use tcolorbox. This offers you endless customization possibilities and offers you mechanisms to solve the issues you mention (no page breaks in the title, minimum 5 lines before a page break, automatic handling of the optional argument, easily customization of spacing betwee the various elements).

Here's a little example emulating your environment:

\documentclass{article}
\usepackage[a5paper]{geometry}% just for the example
\usepackage{lipsum}
\usepackage{tcolorbox}
\tcbuselibrary{most}

\tcbset{mybox/.style={
before={\par\vskip3ex\noindent},
after={\par\vskip1.5ex}}}

\newtcolorbox[auto counter=example]{example}[1][]{
breakable,
mybox,
notitle after break,
lines before break=5,
enhanced,
colback=white,
colframe=white,
coltitle=black,
fonttitle=\bfseries,
arc=0pt,
outer arc=0pt,
leftrule=0pt,
rightrule=0pt,
left=0pt,
right=0pt,
boxsep=0pt,
toptitle=.5\baselineskip,
bottomtitle=-.1\baselineskip,
title=#1,
enlarge top by=4ex,
overlay unbroken={
\node[fill=white,anchor=west,font=\bfseries,inner xsep=0pt]
at (frame.north west) (title) {Example~\thetcbcounter\enspace};
\draw[thick] (title.east|-frame.north east) -- (frame.north east);
\draw[thick] (frame.south west) -- (frame.south east);
},
overlay first={
\node[fill=white,anchor=west,font=\bfseries,inner xsep=0pt]
at (frame.north west) (title) {Example~\thetcbcounter\enspace};
\draw[thick] (title.east|-frame.north east) -- (frame.north east);
},
overlay last={
\draw[thick] (frame.south west) -- (frame.south east);
},
}

\begin{document}
\lipsum[5]
\begin{example}[My example]
\lipsum[5]
\end{example}
\lipsum[5]
\begin{example}
\lipsum[1-3]
\end{example}
\lipsum[5]

\end{document}


-
This package seems powerful indeed but looked like an overkill for my simple purposes. Plus, I really wanted to learn how it should be done. –  Bordaigorl Feb 12 at 19:42

The heading is now actually part of the first line of text, so it cannot be separated.

\documentclass{article}
\usepackage{xcolor}
\usepackage{parskip}

\newlength{\test}

\newcounter{example}
\newenvironment{example}[1][]{%
\refstepcounter{example}%
\vspace{0.5\baselineskip}\par\noindent%
\raisebox{\baselineskip}{\parbox[b]{\linewidth}%
{\textbf{Example~\theexample{}}~{\color{gray}\filltoend}% number and line
\settowidth{\test}{#1}\ifdim\test>0pt% test for optional argument
\hspace{-\linewidth}}\hspace{\parindent}%start of text
}{%
\hfill% the following acts as a strut at the end of the line
{\hspace{-\linewidth}\color{gray}\rule[-.5\baselineskip]{\linewidth}{.4pt}}
\par
}

\begin{document}
last line.

\begin{example}[My example]% adds a space if not commented
Fusce mauris. Vestibulum luctus nibh at lectus. Sed bibendum, nulla a faucibus
semper, leo velit ultricies tellus, ac venenatis arcu wisi vel nisl. Vestibulum diam.
Aliquam pellentesque, augue quis sagittis posuere, turpis lacus congue quam,
in hendrerit risus eros eget felis. Maecenas eget erat in sapien mattis porttitor.
Vestibulum porttitor. Nulla facilisi. Sed a turpis eu lacus commodo facilisis.
Morbi fringilla, wisi in dignissim interdum, justo lectus sagittis dui, et vehicula
libero dui cursus dui. Mauris tempor ligula sed lacus. Duis cursus enim ut
augue. Cras ac magna. Cras nulla. Nulla egestas. Curabitur a leo. Quisque
egestas wisi eget nunc. Nam feugiat lacus vel est. Curabitur consectetuer.
\end{example}

New paragraph.
\end{document}


To get the end of the environment to work I had to use actual text instead of \lipsum, which must include a \par at the end of each paragraph.

-
This is not what I need since I want to allow pagebreaks in between paragraphs of the content section, but avoiding too much spacing or page breaks between the heading and the contents. I found a solution, I'll post it tomorrow –  Bordaigorl Feb 11 at 23:40
Okay, I changed to a completely different approach. –  John Kormylo Feb 12 at 2:24
Isn't this fiddling with negative spaces really fragile? Wouldn't it be better to use skips with custom stretchability, \addtovspace and \unskip or similar commands? –  Bordaigorl Feb 12 at 20:01
For removing the bottom margin from \lipsum, sure. But then no one is going to use \lipsum for anything but a test (and hopefully not even then). This is the first time I tried the \rule\vspace combo and it tested well. It sure works better than \pagebreak[3]! –  John Kormylo Feb 12 at 22:26
Penalties are how TeX works internally, so are probably more robust, if obscure. My approach was based on struts. –  John Kormylo Mar 3 at 15:14

I came up with my own solution and I am sharing it here since it might be useful to others.

Using tcolorbox, mdframed and similar packages is an option but first, I wanted to know how to do proper spacing, second the lines will not necessarily be in my final design, third they seemed an overkill (they use tikz) for what I needed.

So, I had a look at this question Environment with first paragraph in bold and no pagebreaks and realised that the way to go is setting penalties and widow/orphan values. So, in order to have a paragraph break that discourages page breaks and keeps the text together you can define something like:

\newcommand{\nbpar}{\widowpenalty=10000 \@@par\penalty10000}


then my environment can be rewritten as

\newenvironment{example}[1][]{%
\def\@extitle@{#1}%
\refstepcounter{example}%
\par\smallskip%
{\parskip=0.5\baselineskip \advance\parskip by 0pt plus 0pt%
\textbf{Example~\theexample{}}~{\color{gray}\filltoend}%
\ifx\@extitle@\@empty\relax\else\nbpar\textbf{#1}\fi\nbpar\mbox{}}%
\itshape\ignorespaces}%
{\nbpar{\color{gray}\filltoend\mbox{}}}


there I also redefined (in a group) \parskip so I can control how stretchable the space in the heading block is.

Now, since I did not really like how it looked, I settled for a simpler but yet, I think, nice way of setting apart the example from the rest of the content: bold heading, and an ornament at the end; using \nbpar as above to handle spacing.

\usepackage{adforn}