The explanation lies in the fact that \marginpar
causes the output routine to be invoked and the page-so-far to be subsequently sent back to the page builder; the latter then inserts again the \topskip
glue, which, at this time, has resumed its default value (10 points in your example). You can check that the same thing happens, for instance, on any page that contains a float, since floats invoke the output routine in a similar fashion.
These claims can be verified by asking TeX to show the lists it’s working on, as in the following test code:
\documentclass{report}
\showboxbreadth = 1000
\showboxdepth = 10
% \tracingonline = 1
\begin{document}
\begingroup
\setlength{\topskip}{0pt}
\vspace*{8pt}
\endgroup
I'm supposed to be 8 points below the top.
Another paragraph.
% \showlists
\clearpage
\begingroup
\setlength{\topskip}{0pt}
\vspace*{8pt}
\endgroup
I'm supposed to be 8 points below the top.
Another paragraph.\marginpar{And then there's a note.}\showlists
\showlists
\end{document}
This is the trace produced by the first (uncommented) \showlists
, taken from the transcript file:
### horizontal mode entered at line 26
\hbox(0.0+0.0)x15.0
\OT1/cmr/m/n/10 A
\OT1/cmr/m/n/10 n
\OT1/cmr/m/n/10 o
\OT1/cmr/m/n/10 t
\OT1/cmr/m/n/10 h
\OT1/cmr/m/n/10 e
\OT1/cmr/m/n/10 r
\glue 3.33333 plus 1.66666 minus 1.11111
\OT1/cmr/m/n/10 p
\OT1/cmr/m/n/10 a
\OT1/cmr/m/n/10 r
\OT1/cmr/m/n/10 a
\OT1/cmr/m/n/10 g
\OT1/cmr/m/n/10 r
\OT1/cmr/m/n/10 a
\OT1/cmr/m/n/10 p
\OT1/cmr/m/n/10 h
\OT1/cmr/m/n/10 .
\vadjust
.\penalty -10004
.\vbox(0.0+0.0)x0.0
.\penalty -10002
spacefactor 3000
### vertical mode entered at line 0
### current page:
\write-{}
\glue(\topskip) 0.0
\rule(0.0+0.0)x*
\penalty 10000
\glue 8.0
\glue 0.0
\glue(\parskip) 0.0 plus 1.0
\glue(\baselineskip) 5.05556
\hbox(6.94444+1.94444)x345.0, glue set 141.77744fil
.\hbox(0.0+0.0)x15.0
.\OT1/cmr/m/n/10 I
.\OT1/cmr/m/n/10 '
.\OT1/cmr/m/n/10 m
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 s
.\OT1/cmr/m/n/10 u
.\OT1/cmr/m/n/10 p
.\OT1/cmr/m/n/10 p
.\kern0.27779
.\OT1/cmr/m/n/10 o
.\OT1/cmr/m/n/10 s
.\OT1/cmr/m/n/10 e
.\OT1/cmr/m/n/10 d
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 o
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 b
.\kern0.27779
.\OT1/cmr/m/n/10 e
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 8
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 p
.\kern0.27779
.\OT1/cmr/m/n/10 o
.\OT1/cmr/m/n/10 i
.\OT1/cmr/m/n/10 n
.\kern-0.27779
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 s
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 b
.\kern0.27779
.\OT1/cmr/m/n/10 e
.\OT1/cmr/m/n/10 l
.\OT1/cmr/m/n/10 o
.\kern-0.27779
.\OT1/cmr/m/n/10 w
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 h
.\OT1/cmr/m/n/10 e
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 o
.\OT1/cmr/m/n/10 p
.\OT1/cmr/m/n/10 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\glue(\parskip) 0.0 plus 1.0
total height 21.94444 plus 2.0
goal height 550.0
prevdepth 1.94444
You can see, in the section that begins with
### vertical mode entered at line 0
### current page:
that the \topskip
glue that had originally been inserted, before the call to the output routine triggered by \marginpar
, was indeed
\glue(\topskip) 0.0
By the way, in the section headed
### horizontal mode entered at line 26
you can see how the \marginpar
commands triggers that call: it inserts
\vadjust
.\penalty -10004
.\vbox(0.0+0.0)x0.0
.\penalty -10002
in the horizontal list of the paragraph being formed. When the paragraph terminates, it is broken into lines, and the contents of \vadjust
are inserted in the main vertical list under the line on which the \marginpar
winds up: this will call the output routine (actually, twice) as the two \penalty
nodes are subsequently moved from the “recent contributions” to the “current page”.
On the contrary, the result of the second (uncommented) \showlists
is the following:
### vertical mode entered at line 0
### current page:
\write-{}
\glue(\topskip) 10.0
\rule(0.0+0.0)x*
\penalty 10000
\glue 8.0
\glue 0.0
\glue(\parskip) 0.0 plus 1.0
\glue(\baselineskip) 5.05556
\hbox(6.94444+1.94444)x345.0, glue set 141.77744fil
.\hbox(0.0+0.0)x15.0
.\OT1/cmr/m/n/10 I
.\OT1/cmr/m/n/10 '
.\OT1/cmr/m/n/10 m
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 s
.\OT1/cmr/m/n/10 u
.\OT1/cmr/m/n/10 p
.\OT1/cmr/m/n/10 p
.\kern0.27779
.\OT1/cmr/m/n/10 o
.\OT1/cmr/m/n/10 s
.\OT1/cmr/m/n/10 e
.\OT1/cmr/m/n/10 d
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 o
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 b
.\kern0.27779
.\OT1/cmr/m/n/10 e
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 8
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 p
.\kern0.27779
.\OT1/cmr/m/n/10 o
.\OT1/cmr/m/n/10 i
.\OT1/cmr/m/n/10 n
.\kern-0.27779
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 s
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 b
.\kern0.27779
.\OT1/cmr/m/n/10 e
.\OT1/cmr/m/n/10 l
.\OT1/cmr/m/n/10 o
.\kern-0.27779
.\OT1/cmr/m/n/10 w
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 h
.\OT1/cmr/m/n/10 e
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 o
.\OT1/cmr/m/n/10 p
.\OT1/cmr/m/n/10 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\glue(\parskip) 0.0 plus 1.0
\glue(\baselineskip) 3.11111
\hbox(6.94444+1.94444)x345.0, glue set 243.52757fil
.\hbox(0.0+0.0)x15.0
.\OT1/cmr/m/n/10 A
.\OT1/cmr/m/n/10 n
.\OT1/cmr/m/n/10 o
.\OT1/cmr/m/n/10 t
.\OT1/cmr/m/n/10 h
.\OT1/cmr/m/n/10 e
.\OT1/cmr/m/n/10 r
.\glue 3.33333 plus 1.66666 minus 1.11111
.\OT1/cmr/m/n/10 p
.\OT1/cmr/m/n/10 a
.\OT1/cmr/m/n/10 r
.\OT1/cmr/m/n/10 a
.\OT1/cmr/m/n/10 g
.\OT1/cmr/m/n/10 r
.\OT1/cmr/m/n/10 a
.\OT1/cmr/m/n/10 p
.\OT1/cmr/m/n/10 h
.\OT1/cmr/m/n/10 .
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
\kern -1.94444
\hbox(0.0+0.0)x345.0, glue set - 76.0fil
.\glue 345.0
.\glue 11.0
.\vbox(0.0+0.0)x65.0
..\glue -6.94444
..\vbox(6.94444+12.0)x65.0
...\hbox(6.94444+0.0)x65.0, glue set 14.1667
....\hbox(0.0+0.0)x0.0
....\OT1/cmr/m/n/10 A
....\OT1/cmr/m/n/10 n
....\OT1/cmr/m/n/10 d
....\glue 3.33333 plus 1.66666 minus 1.11111
....\OT1/cmr/m/n/10 t
....\OT1/cmr/m/n/10 h
....\OT1/cmr/m/n/10 e
....\OT1/cmr/m/n/10 n
....\glue(\rightskip) 0.0
...\penalty 300
...\glue(\baselineskip) 5.05556
...\hbox(6.94444+0.0)x65.0, glue set 2.69435fil
....\OT1/cmr/m/n/10 t
....\OT1/cmr/m/n/10 h
....\OT1/cmr/m/n/10 e
....\OT1/cmr/m/n/10 r
....\OT1/cmr/m/n/10 e
....\OT1/cmr/m/n/10 '
....\OT1/cmr/m/n/10 s
....\glue 3.33333 plus 1.66666 minus 1.11111
....\OT1/cmr/m/n/10 a
....\glue 3.33333 plus 1.66666 minus 1.11111
....\OT1/cmr/m/n/10 n
....\OT1/cmr/m/n/10 o
....\OT1/cmr/m/n/10 t
....\OT1/cmr/m/n/10 e
....\OT1/cmr/m/n/10 .
....\penalty 10000
....\glue(\parfillskip) 0.0 plus 1.0fil
....\glue(\rightskip) 0.0
.\glue 0.0 plus 1.0fil minus 1.0fil
\hbox(0.0+1.94444)x0.0
.\rule(0.0+1.94444)x0.0
\penalty 0
\penalty 10000
total height 42.0 plus 2.0
goal height 550.0
prevdepth 1.94444, prevgraf 1 line
As you can see, the \topskip
glue has been re-inserted, with its default value of 10.0
points, for the reason explained formerly.
It should be noted that the above transcripts also show that the normal interline glue is inserted between the \vspace*
command and the “I’m supposed to be…” boxes: this means that neither of them has its upper edge running at 8 points from the top of the textblock. You should precede them with \nointerlineskip
.