Опубликован: 07.02.2007 | Доступ: свободный | Студентов: 4014 / 1341 | Оценка: 4.56 / 3.95 | Длительность: 23:09:00
Специальности: Художник
Лекция 8:

Блоки и клей

Клей

Выше мы рассмотрели команды \hfil и \hfill, которые действуют подобно вставленным в строку пружинам. Можно вставлять в строку пружины с самыми разнообразными свойствами, указав LaTeX'овской команде \hspace аргумент, содержащий plus- или minus-компоненту (в разд.3.9.4 мы упоминали об этой возможности, но в тот момент у нас еще не было серьезных примеров). Именно, если вы скажете

\hspace{"$x$ plus $y$ minus $z$"}

где x, y и z - длины, то вставите в текст пружину, которая в свободном состоянии имеет длину x, может увеличивать свою длину на y и уменьшать свою длину на z (в отличие от пружин, встречающихся в жизни, может выполняться неравенство x<z, и, того пуще, длины y и z могут быть отрицательными, но мы не будем объяснять, как TeX поведет себя в столь странной ситуации)3Если мы заставим такую пружину растянуться или сжаться больше, чем сказано, то получим сообщение "Underfull \hbox " или "Overfull \hbox "; см.\ ниже. Здесь plus и minus - это, как мы помним, очередные ключевые слова TeX'а, наподобие to, width и height. Если мы создаем блок естественной ширины, то команда \hspace с таким аргументом создаст пробел размером x ; если же мы в команде \hbox попросим TeX создать блок, ширина которого отличается от естественной, то для достижения требуемой ширины размеры пробелов будут изменяться. В TeXнической терминологии эти "пружины" называются клеем (Дональд Кнут отмечает, что название "клей" неудачно, но менять его поздно, поскольку оно, по его словам, "уже прилипло"). Длины y и z, указанные после ключевых слов plus и minus, называются plus- и minus- компонентами клея. Длина x называется естественным размером клея. С этой точки зрения команда \hfil также помещает в строку клей - с бесконечной растяжимостью и нулевым естественным размером.

Опишем более точно, как именно растягивается или сжимается клей при выполнении команды \hbox to ... Для простоты предположим дополнительно, что plus- и minus- компоненты клея всюду неотрицательны и что в строке отсутствует клей с бесконечной растяжимостью или сжимаемостью (в частности, в строке нет \hfil 'ов или \hfill 'ов; про клей с бесконечной сжимаемостью речь пойдет ниже). В этом случае TeX вычисляет "естественную ширину" блока, складывающуюся из ширин составляющих его элементов и естественных размеров клея, и сравнивает ее с требуемой шириной блока, указанной в команде \hbox после ключевого слова to. Если эти две ширины совпали, то все пробелы будут иметь естественный размер. Если требуемая ширина больше естественной, то TeX вычисляет, насколько больше, после чего "разверстывает" эту добавку между всеми пробелами пропорционально величинам plus - компонент клея в этих пробелах.

Вот пример. Предположим, мы создаем блок с помощью команды

\hbox to $a$ {А\hspace{0pt plus 2em}%
Б\hspace{1cm plus 1em minus 2mm}В}

где величина a на 13 мм больше суммы ширин букв А, Б и В, то пробел между А и Б будет равен 2\,\rm мм, а пробел между Б и В - 11\,\rm мм, поскольку plus - компонента клея между А и Б в два раза больше, чем plus - компонента клея между Б и В (и никакого другого клея в строке нет, так что ничего более растянуть нельзя). Если требуемая ширина меньше естественной, то уменьшение длины также распределяется между всеми элементами клея пропорционально величинам их minus-компонент. Если продолжить аналогию между TeX'овским клеем и пружинами, то можно сказать, что жесткость пружины при растяжении обратно пропорциональна величине plus-компоненты.

В приведенном примере оба пробела в блоке были созданы вручную командой \hspace ; если же в аргументе команды \hbox присутствуют пробелы, то следует учесть, что эти пробелы также, как мы объясняли ранее, обладают растяжимостью и сжимаемостью, которая также берется в расчет.

В случае, когда пробелы надо растягивать и требуемое растяжение блока больше, чем сумма plus - компонент всех элементов клея, на экран и в log -файл выдается знакомое вам сообщение Underfull \hbox ; если пробелы надо уменьшать и величина, на которую надо уменьшить ширину блока, меньше, чем сумма minus - компонент всех элементов клея, то выдается не менее знакомое сообщение Overfull \hbox.

Все сказанное относилось к случаю, когда бесконечно растяжимого клея в аргументе команды \hbox нет. Если же таковой присутствует (например, есть команда \hfil ) и пробелы надо растягивать, то растяжимость клея с конечными значениями plus -компонент утрачивается: соответствующие интервалы будут иметь естественный размер (что бы ни было написано в аргументе команды \hspace после plus), а все растяжения будут происходить только за счет команд \hfil. При этом сообщение об Underfull'е выдаваться не будет, как бы ни растянулись пробелы. Аналогично, если пробелы надо ужимать и присутствует клей с бесконечной сжимаемостью, все уменьшения пробелов произойдут только за его счет и никогда не будет выдано сообщения об Overfull'е.

Если в аргументе команды \hbox присутствуют команды \hfil и \hfill совместно, то при необходимости растягивать пробелы учитывается только \hfill, в то время как "в бесконечное число раз менее растяжимый" \hfil в расчет не берется (не говоря уж о клее с конечной растяжимостью):

\hbox to 4cm{\hfil Блоки и клей\hfil}\\
\hbox to 4cm{\hfil Блоки и клей\hfill}\\
\hbox to 4cm{\hfill Блоки и клей\hfill}
\hbox to 4cm
{\hfil Блоки и клей\hfil}
\hbox to 4cm
{\hfil Блоки и клей\hfill}
\hbox to 4cm
{\hfill Блоки и клей\hfill}

Ранее мы упоминали о том, что в аргументе команды \vspace может (вместо длины с plus- и/или minus-компонентой) стоять команда \fill (возможно, с коэффициентом). Как мы теперь понимаем, \vspace с таким аргументом также задает бесконечно растяжимый клей. Точнее говоря, \vspace{\fill} действует так же, как \hfill, в то время как команда \vspace{0.3\fill} задает клей, растяжимость которого составляет 30% от растяжимости \hfill (тем не менее, этот клей также "бесконечно растяжим" в том отношении, что его присутствие отменяет растяжимость \hfil 'ов и клея с конечными plus - компонентами).

Бесконечно сжимаемые интервалы

Мы уже два раза упомянули про клей с бесконечной сжимаемостью. Настало время объяснить, какими командами его создавать. Из многих способов укажем один, наиболее часто встречающийся. Команда \hss вставляет в строку клей, естественный размер которого равен нулю, и который при этом обладает бесконечной растяжимостью (подобно \hfil ) и бесконечной сжимаемостью. Типичное применение такого "бесконечно сжимаемого" клея — создавать блоки, ширина которых меньше реального размера текста, или блоки с наложением текстов. В самом деле, посмотрите на такой пример:

\hbox to 50pt {Кот\hss Пес}\\
\hbox{Кот\hss Пес}\\
\hbox to 30pt {Кот\hss Пес}\\
\hbox to 15pt {Кот\hss Пес}\\
\hbox to 0pt {Кот\hss Пес}
\hbox to 50pt {Кот\hss Пес}
\hbox{Кот\hss Пес}
\hbox to 30pt {Кот\hss Пес}
\hbox to 15pt {Кот\hss Пес}
\hbox to 0pt {Кот\hss Пес}

Если мы просим сделать ширину блока больше естественной, команда \hss действует так же, как и \hfil ; когда мы создаем блок с естественной шириной, слова "Кот" и " Пес" стоят вплотную друг к другу (естественная ширина клея, созданного \hss, равна нулю). Интересные вещи начинаются, когда мы просим, чтобы ширина была 30\,\rm pt (что меньше естественной). Интервал между словами при этом приходится уменьшить; поскольку его естественный размер равен нулю, то после уменьшения интервал становится отрицательным, т. е. слово " пес" сдвигается влево (накладываясь на слово "Кот"), причем сдвигается так, чтобы ширина блока (т. е. расстояние от начала слова "Кот" до конца слова "Пес") равнялась требуемым 30\,\rm pt. Когда же мы наконец просим, чтобы ширина блока равнялась нулю, слову "Пес" приходится сдвинуться влево настолько, чтобы расстояние от его конца до начала слова "Кот" равнялось нулю - иными словами, кот и пес меняются местами! Заметим, кстати, что точка отсчета всех наших блоков совпадает с точкой отсчета буквы К из слова "Кот".

Еще один пример использования \hss: как создать блок, точка отсчета которого будет находиться в правом, а не левом конце текста (мы столкнулись с этой проблемой в "Псевдорисунки" )? Ответ: надо сказать

\hbox to 0pt{\hss текст}

и все будет в порядке. В самом деле, \текст имеет ширину, отличную от нуля; чтобы блок имел в итоге нулевую ширину, приходится "уменьшать" тот интервал, где стоит \hss ; так как интервал уже нулевой, то это уменьшение сводится к тому, что текст сдвигается влево до тех пор, пока расстояние между его концом и точкой отсчета не станет равным нулю - а это и означает, что правый конец текста стал его точкой отсчета. В "Псевдорисунки" мы сказали, что эта проблема решается с помощью TeX'овской команды \llap, а теперь мы видим, как ее можно определить:

\newcommand{\llap}[1]{\hbox to 0pt{\hss #1}}

Кстати говоря, именно так она и определяется.

А если сказать

\hbox to 0pt{текст \hss}

то что, спрашивается, будет? Ответ: на сей раз будет уменьшаться интервал после текста; стало быть, сам текст никуда не сдвинется, но после него будет сделан такой "отрицательный пробел", чтобы суммарная ширина равнялась нулю. Иными словами, TeX будет просто считать, что ширина блока равняется нулю - мы обманули TeX, убедив его, что наш текст не занимает места по горизонтали! Для такого обмана (к нему приходится прибегать нередко) предусмотрена специальная TeX'овская команда \rlap, определяемая так:

\newcommand{\rlap}[1]{\hbox to 0pt{#1\hss}}

Все это также напоминает ситуацию с командой \lefteqn — и напоминает не случайно, поскольку эта команда определяется фактически так:

\newcommand{\lefteqn}[1]{\rlap{$\displaystyle #1$\hss}}
Нина Казачек
Нина Казачек
Василий Майоров
Василий Майоров