Глава 12. Динамическое позиционирование



Каскадные таблицы стилей (Cascading Style Sheets, CSS) позволяют определить точное положение HTML-элементов. Динамическое позиционирование использует объектную модель для доступа и манипулирования положением элементов в документе с помощью объектной модели CSS.

Возможность точного позиционирования элементов с помощью HTML впервые появилась в Internet Explorer 3.0 посредством элемента HTML Layout. Элемент HTML Layout был разработан как элемент ActiveX, который интерпретировал раннюю версию синтаксиса позиционирования CSS. Элемент ActiveX был внедрен в браузер временно на период доработки синтаксиса позиционирования консорциумом W3C (World Wide Web Consortium). В конце 1996 года синтаксис был одобрен в рабочем проекте консорциума "CSS Positioning (CSS-P)" ("Позиционирование CSS (CSS-P)"). Скотт Фурман, представитель компании Netscape, и автор этой книги в качестве представителя компании Microsoft, совместно выполнили данный проект. Браузеры Internet Explorer 4.0 и Netscape Navigator 4.0 поддерживают рабочий проект CSS-P для позиционирования элементов, так что страницы, созданные с использованием CSS-P, практически одинаково отображаются в обоих браузерах. Однако существует ряд мелких отличий между браузерами, касающихся точного воспроизведения размера и положения элемента.

Рабочий проект CSS-P устанавливает синтаксис CSS для определения исходного положения элементов на странице. Этот проект не устанавливает модель сценариев. Объектная модель, представленная в Netscape Navigator 4.0 для перемещения позиционированных элементов отличается от модели, представленной в Internet Explorer 4.0. Модель Netscape Navigator предоставляет только часть функциональных возможностей, доступных в Internet Explorer.

Рабочий проект CSS-P определяет три типа позиционирования: статическое, абсолютное и относительное. Статическое позиционирование используется по умолчанию и соответствует традиционному способу размещения HTML-документов. При использовании абсолютного позиционирования элемент изымается из нормального потока документа и размещается в соответствии с родительской системой координат. Абсолютно позиционированный элемент не оказывает влияния на окружающие его элементы в документе. При использовании относительного позиционирования элемент находится в потоке документа и размещается относительно его нормального положения в потоке. При изменении размера документа элемент, позиционированный относительно, может перемещаться и изменять свою форму в результате переформатирования документа. Абсолютно и относительно позиционированные элементы создают системы координат для позиционирования возможных дочерних элементов.

В данной главе представлены свойства CSS-P и модель сценариев для управления местоположением элементов и рассмотрены следующие темы:



Позиционирование CSS

Рабочий проект CSS-P определяет расширения таблиц стилей для обеспечения дополнительных возможностей управления HTML-элементами. Абсолютное и относительное позиционирование позволяет Web-разработчику точно управлять положением и размером элемента, а также проводить наложение элементов. Совместное использование этих нововведений вместе с программированием сценариев позволяет осуществлять анимацию элемента. В данном разделе представлено краткое введение в методы использования новых возможностей позиционирования CSS.



Свойства позиционирования CSS

Рабочий проект CSS-P определяет новые свойства CSS, которые поддерживаются браузерами Internet Explorer 4.0 и Netscape Navigator 4.0. В табл. 12.1 перечислены данные свойства. Значения по умолчанию для каждого свойства выделено полужирным начертанием.

Таблица 12.1. Свойства позиционирования CSS


Свойство Допустимые величины Область применения Описание

position static | absolute | relative Все элементы Определяет, будет ли элемент помещен в поток (статическое позиционирование), относительно его нормального положения в потоке (относительное позиционирование) или за пределами потока (абсолютное позиционирование)
top, left auto | <length> | <percentage> Все элементы со значением атрибута position, равным значению absolute или relative Определяет верхнее и левое положения элемента относительно его родительского контекста воспроизведения
width, height auto | <length> | <percentage> Все элементы блока, заменяемые элементы (например, элементы IMG и внутренние элементы управления) и элементы со значением атрибута position равным absolute Определяет ширину и высоту элемента. Процентные значения установлены относительно родительского контекста воспроизведения
clip auto| rect (top right bottom left) Все элементы со значением атрибута position равным absolute или relative Определяет область вырезки элемента
z-index auto | number Все элементы со значением атрибута position равным absolute или relative Определяет положение элемента, на который накладываются Другие элементы или который накладывается на другие элементы
visibility inherit | visible | hidden Все элементы Определяет область видимости элемента. Спрятанный элемент не удаляется из потока документа
overflow visible | hidden | auto | scroll Все элементы со значением атрибута position равным absolute, все элементы блоков Определяет отображение полос прокрутки, если содержание документа не помещается в элементе



Позиционируемые элементы

Традиционно, большинство элементов в HMTL позиционируются относительно предыдущих элементов в потоке документа. Исключением из этого правила является возможность выравнивать изображения и другие объекты и обтекать их текстом. Позиционирование CSS позволяет позиционировать элементы в отдельной рамке отдельно от потока документа или за пределами их обычного положения в документе. Позиционирование CSS допускает наложение элементов и предоставляет Web-разработчикам большие возможности управления размещением элементов по сравнению с доступными ранее.

Как упоминалось выше, свойство CSS position может принимать одно из трех значений: static (статическое), absolute (абсолютное) или relative (относительное). Статическое позиционирование по умолчанию не оказывает влияния на традиционную схему размещения HTML-документа.

Относительное позиционирование используется для смещения документа за пределы его нормального положения в потоке документа. Установка значения relative для элемента position не изменяет размещение элемента, но если вы также установили значение свойства top или left, то элемент смещается от своего нормального положения в потоке. В тексте на рис. 12.1 одно слово сдвинуто на 10 пикселов по горизонтальной и вертикальной осям. Обратите внимание, что остальная часть документа расположена так, как будто данное слово не было сдвинуто. Относительное позиционирование особенно полезно при создании анимированных элементов, таких как изображения, рядом с их нормальными положениями в документе.

Рис. 12.1. Элемент, позиционированный относительно

Абсолютное позиционирование используется для определения фиксированного положения элемента за пределами потока документа. В тексте на Рис. 12.2 одно слово позиционировано в верхнем левом углу окна браузера. Обратите внимание на отсутствие интервала.

Рис. 12.2. Абсолютно позиционированный документ

Поскольку абсолютно позиционированные элементы размещаются за пределами потока, то положение элемента внутри источника документа становится несущественно. Элемент должен быть помещен в источнике в том положении, которое обеспечит приемлемый результат в браузерах низкого уровня. Такие браузеры не поддерживают новых возможностей позиционирования и поэтому располагают изображение в потоке документа.

В браузере Internet Explorer 4.0 все элементы в теле документа поддерживают статическое и динамическое позиционирование. Однако абсолютное позиционирование поддерживают только те элементы, которые перечислены ниже:

Для абсолютного позиционирования текста следует использовать элемент Span или DIV. Элементы Span и DIV взаимозаменяемы, но при выборе одного из них следует учесть предполагаемый внешний вид элемента в браузере низкого уровня. Если разрыв требуется и до и после текста, то следует использовать элемент DIV. Если текст может находиться в параграфе, то следует использовать элемент Span. Отображение документа всегда следует проверять на всех платформах, которые будут использованы для его просмотра, для гарантии его адекватного отображения.



Определение системы координат

Каждый элемент, который позиционирован абсолютно или относительно, должен быть позиционирован относительно другого элемента или положения в документе. Точка, относительно которой сдвинут документ, называется корнем (root) системы координат элемента. По умолчанию, местоположение корня относительно позиционированных элементов определяется на основе его местоположения в потоке документа. Поэтому если документ переформатируется, то корень системы координат, а также дочерние элементы внутри данной системы координат будут смещены.

Абсолютно позиционированные элементы размещаются относительно системы координат, в которой находится элемент. Верхний левый угол документа определяет систему координат по умолчанию для абсолютно позиционированных элементов. Независимо от того, позиционирован элемент относительно или абсолютно, новая система координат определена для всех находящихся в нем элементов.


Свойства размера и положения

Если элемент позиционирован абсолютно или относительно, его свойства top и left определяют смещение элемента от верхнего левого угла системы координат. Свойства width и height определяют физическую ширину и высоту элемента при его воспроизведении на экране. Если вы используете относительные размеры, то свойства width и height интерпретируются относительно размера элемента, определяющего систему координат. Свойства top, left, width и height могут быть определены в процентном отношении или других единицах (например, точках, пикселах и em), определенных CSS. На рис. 12.3 показаны свойства top, left, width и height двух вложенных элементов DIV.

TOP1 - свойство первого элемента DIV top=50 (пикселов)
LEFT1 - свойство первого элемента DIV left=50 (пикселов)
ТОР2 - свойство вложенного элемента DIV top=100 (пикселов)
LEFT2 - свойство вложенного элемента DIV left=40 (пикселов)

Рис. 12.3. Вложенные системы координат


Автоматическая установка размера

Для свойств top и left значение по умолчанию, равное auto, является нормальным положением элемента в потоке. Когда значения свойств top и left равны auto, то относительно позиционированный элемент отображается так же, как и статический элемент, а абсолютно позиционированный элемент изображается за пределами потока, но связан с положением, которое бы он занимал, будучи статическим элементом. Если свойства width и height опущены, то размер элемента устанавливается автоматически на основе его содержания.


Свойство visibility

По умолчанию элемент видим, если отображается его родительский элемент. Например, скрытие элемента Body путем установки значения hidden для свойства visibility прячет все содержание документа. Вы можете изменить данное поведение путем явной установки значений hidden или visible для свойства visibility вместо установленного по умолчанию inherit. Если значение свойства visibility установлено явно, то элемент не учитывает любые наследованные значения и будет, соответственно, отображен или скрыт.


Свойство z-index

Свойство z-index определяет графический z-порядок, или перекрытие элементов по отношению к другим элементам. Каждая координатная система определяет новое z-пространство для воспроизводимых элементов, таким образом обеспечивая иерархический z-порядок. Например, если элемент DIV абсолютно позиционирован поверх тела документа, то содержание элемента DIV не может появиться в теле документа после текста. Все элементы внутри элемента DIV могут быть только позиционированы в системе координат элемента DIV.

По умолчанию все элементы, определяющие систему координат, включая элемент Body, позиционированы со значением z-index, равным 0. Другие элементы могут быть позиционированы после текста путем установки отрицательного значения z-index. Для элементов, значения z-index которых не установлены, значения z-index неявно назначаются в соответствии с их положением в исходном документе. Поэтому элемент, который помещен в данный документ позже, помещается до всех элементов, позиционированных ранее.



Области вырезки

Каждый абсолютно позиционированный элемент имеет связанную с ним область вырезки, назначение которой заключается в определении части документа, доступной для отображения элемента и его содержания. Все, что находится за пределами данной области, отбрасывается и не отображается документом.

Представим себе непрозрачный лист бумаги, который закрывает физическую область абсолютно позиционированного элемента. В данном листе бумаги имеется прямоугольный вырез, определяющий видимую область элемента. Все, что не помещается в данном вырезе, отбрасывается и становится невидимым.

На рис. 12.4 показано использование областей вырезки. В верхней части рисунка показана страница без вырезки. Больший по размеру прямоугольник представляет собой элемент DIV. Меньший прямоугольник находится внутри элемента DIV, но абсолютно позиционирован за пределами элемента DIV. В нижней части рисунка показан тот же документ после выполнения вырезки.

Рис. 12.4. Элемент DIV с частью содержания за его пределами без вырезки (сверху) и с прямоугольной вырезкой (снизу)

Значение по умолчанию для свойства clip равно auto, что обусловливает отсутствие вырезки документа. Вы можете установить значение свойства clip равным прямоугольному вырезу:


clip:rect(top right bottom left) 

Установки top, right, bottom и left определяют прямоугольник вырезки по отношению к абсолютно позиционированному верхнему левому углу элемента. Любой из данных четырех параметров может быть установлен равным любой длине CSS или значению auto для запрещения вырезки в этом направлении. Если свойства top и left равны отрицательным значениям, то элементы сверху и слева от абсолютно позиционированного элемента могут быть включены в область вырезки.



Свойство overflow

Свойство overflow управляет обработкой содержания, которое выходит за пределы физического размера элемента. Свойство overflow принимает одно из четырех значений: visible, hidden, auto и scroll. Если значение overflow равно visible, то будет отображаться все содержание документа, даже содержание за пределами установленной высоты (height) и ширины (width) элемента. Если значение overflow равно hidden, то будет отображаться только содержимое внутри области элемента, определенной значениями свойств height и width. Содержание элемента за пределами установленных границ отображаться не будет.

Значения auto и scroll используются для добавления полос прокрутки, если содержание превышает область, ограниченную значениями height и width. Полосы прокрутки могут быть добавлены в любой абсолютно позиционированный элемент, в элементы DIV с определенной высотой и любой элемент который поддерживает свойство float каскадных таблиц стилей CSS. Если значение параметра overflow равно scroll, то всегда будут отображены полосы прокрутки. Если значение равно auto, то полосы прокрутки будут отображаться только при необходимости.

Приведенный ниже документ демонстрирует создание маркера полосы прокрутки:

<HTML>
   <HEAD>
      <TITLE> Маркер полосы прокрутки </TITLE>
   </HEAD>
   <BODY>
      <DIV STYLE="overflow:scroll; float:left;
            width:120pt; height:120pt">
         <H1>Scrolling Sidebar</H1>
         <P>This text appears in a scrolling window that is floating
            to the left of the main contents.</P>
      </DIV>
      <P>These contents appear to the right of the scrolling DIV
         element.
   </BODY>
</HTML>

Данный документ показан на рис. 12.5.

Рис. 12.5. Документ с маркером полосы прокрутки

Если для элемента определены полосы прокрутки, то они автоматически расширяются для включения абсолютно позиционированных дочерних элементов. Данное расширение гарантирует, что пользователю будут доступны все абсолютно позиционированные дочерние элементы. Вы можете создать полностью доступные формы и сложные схемы размещения. Исключение в данном случае составляет любой элемент, который позиционирован отрицательно. Полосы прокрутки никогда не используются в пространстве отрицательных координат.

Если полосы прокрутки отображаются с помощью свойства overflow, то вырезка не влияет на абсолютно позиционированные дочерние элементы.

Пользователь может, тем не менее, прокручивать их, и они будут доступны. Напротив, если область вырезки не включает в себя целиком весь элемент с полосами прокрутки, то он будет усечен. Данное правило проиллюстрировано на рис. 12.6. Снизу абсолютно позиционированный элемент не виден, поскольку он находится внутри элемента DIV с полосами прокрутки.

Рис. 12.6. Слева изображен экран с областью вырезки и без полос прокрутки. Справа - тот же элемент с полосами прокрутки

Примечание: Относительно позиционированные элементы не влияют на полосу прокрутки. При расчете полосы прокрутки учитывается только исходное пространство элемента в потоке, поскольку местоположение относительно позиционированного элемента в документе является его положением в потоке, а смещение просто определяет точку вывода элемента. Более того, относительно позиционированные элементы наиболее часто используются для анимации. Включение данных элементов в расчет полосы прокрутки будет влиять на анимацию. Например, надо обеспечить прокручивание текста за пределы правого края экрана. Отсутствует полоса прокрутки, которая позволит пользователю прокручивать текст обратно в область просмотра.



Программирование позиционирования CSS

Любой стандартный элемент с абсолютным или относительным позиционированием может быть динамически перемещен, а его размер может быть изменен с помощью сценария. Данный метод позволяет осуществлять анимацию позиционированных элементов путем изменения положения, изменения размера и динамического изменения области вырезки элемента. Манипулирование положением элемента и областью вырезки осуществляется посредством объектных моделей таблицы стилей.

Свойство position CSS в браузере Internet Explorer 4.0 допускает только чтение. Для перемещения с помощью сценария элемент при создании должен быть позиционирован или относительно или абсолютно, независимо от того, был ли он создан из исходного кода или вставлен посредством динамического содержания, что описывается в главе 13. Данное правило справедливо, даже если таблица стилей модифицируется с помощью объектной модели CSS после воспроизведения элемента.



Свойства позиционирования CSS

Каждое свойство размера или положения CSS представлено набором свойств, которые делают более удобным доступ к нему и манипулирование его размером и положением. Подобно другим свойствам CSS свойства top, left, width и height представлены посредством свойства style элемента. Данные свойства являются строками и возвращают значения в определенных единицах. Например, элемент со значением top равным 20 пунктов возвращает 20pt.

Манипулирование данной строкой может быть очень сложным, особенно если код пытается изменить положение элемента на экране. Поэтому кроме свойств со строковыми значениями, представлены свойства: posTop, posLeft, posWidth и posHeight. Если значение top является строкой 20pt, то значение posTop равно числу 20. Числовым значением можно манипулировать непосредственно.

Поскольку основной единицей измерения в объектной модели динамического HTML является пиксел, то представлены четыре дополнительных свойства, которые возвращают значения размера и положения, преобразованные в пикселы: pixelTop, pixelLeft, pixelWidth и pixelHeight. Установка значения одного из свойств вызывает преобразование значения в исходно определенные единицы, когда оно представляется посредством значения pos* и свойств со строковыми значениями.

Эти двенадцать свойств таблиц стилей определяются при анализе документа. В разделе данной главы "Контекст воспроизведения" описываются свойства для доступа к размеру и положению отображаемого элемента, позволяющие создавать совершенно индивидуальную схему размещения элементов, в которой сценарий управляет воспроизведением всего документа.



Абсолютное позиционирование

Приведенные ниже примеры демонстрируют манипулирование абсолютно позиционированными элементами. Абсолютно позиционированные элементы используются для активизации операций перемещения с помощью мыши для размещения элементов в определенных точках на экране.


Статический логотип

Используя свойство CSS background, можно установить положение фонового изображения для создания статического логотипа, который не будет прокручиваться вместе с окном. Приведенный ниже код закрепляет изображение в нижнем правом углу окна клиента:


BODY {background:URL(logo.gif) fixed bottom right no-repeat} 

Используя только CSS, нельзя фиксировать местоположение элементов так, чтобы они не прокручивались вместе с окном, кроме фоновых изображений. Однако этого можно достичь, используя абсолютное позиционирование и простой сценарий. Следующий пример создает статический текст, который всегда находится в фиксированном положении относительно верхнего левого угла текущего окна. Для того чтобы перемещать элемент при прокручивании документа, код, позиционирующий текст, отслеживает события onscroll.

Текстовый логотип в данном примере подобен телевизионному логотипу, который иногда появляется во время телевизионных передач. Логотип отображается постоянно, но код можно легко изменить, чтобы логотип появлялся и исчезал на экране с определенной периодичностью, с помощью таймера попеременно устанавливая для свойства display значения none или block. (Если в таблице глобальных стилей для свойства display элемента установлено значение none, то сценарий не может заменить это значение на пустую строку для отображения элемента, а должен явно установить для свойства display значение block или inline, соответствующее данному элементу).

Приведенный ниже код является простейшей реализацией текстового логотипа. Он помещает логотип в верхний левый угол экрана, для чего требуется только отслеживать события scroll и не надо вычислять положение логотипа. Для отображения логотипа в любом из других углов следует также отслеживать событие onresize. Когда пользователь изменяет размер страницы, положение логотипа должно быть снова рассчитано на основе нового размера окна, также следует учесть ширину и высоту самого элемента.

<HTML>
   <HEAD>
      <TITLE> Статический логотип </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function resetLogo() {
            document.all.Logo.style.posTop = document.body.scrollTop;
            document.all.Logo.style.posLeft =
               document.body.scrollLeft;
         }
      </SCRIPT>
   </HEAD>
   <BODY ONSCROLL="resetLogo()">
      <DIV ID="Logo" SRC="logo.gif"
            STYLE="position:absolute; z-index:-1; top:0px; left:0px;
               color:gray">
         Inside DHTML
      </DIV>
      <P>Add HTML document here.</P>
   </BODY>
</HTML>

Логотип лучше смотрится с ярким текстом. В противном случае он может затенять содержание страницы. Логотип может быть помещен за содержанием или вверху над содержанием документа путем установки следующих значений свойства z-index.

Логотип может находиться за другими элементами ниже в зависимости от значения свойства z-index других элементов.


Прыгающий мяч

Этот пример иллюстрирует взаимоотношения между свойствами положения и размером окна. Приведенный ниже код является расширением примера со статическим логотипом. Изображение перемещается по экрану и выпрыгивает за границы экрана:

<HTML>
   <HEAD>
      <TITLE> Прыгающий мяч </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         var x = 0;
         var y = 0;
         var offsetx = 4;
         var offsety = 4;

         function bounceIt() {
            var el = document.all.bounce;
            x += offsetx;
            y += offsety;
            if ((x + el.offsetWidth >= document.body.clientWidth +
                     document.body.scrollLeft) ||
                  (x <= document.body.scrollLeft)) {
               offsetx = -offsetx;
               if (x <= document.body.scrollLeft)
                  x = document.body.scrollLeft;
               else
                  x = document.body.clientWidth - el.offsetWidth +
                     document.body.scrollLeft;
            }
            if ((y + el.offsetWidth >= document.body.clientHeight +
                     document.body.scrollTop) ||
                  (y <= document.body.scrollTop)) {
               offsety = -offsety;
               if (y <= document.body.scrollTop)
                  y = document.body.scrollTop;
               else
                  y = document.body.clientHeight - el.offsetHeight +
                     document.body.scrollTop;
            }
            el.style.posLeft = x;
            el.style.posTop = y;
         }
      </SCRIPT>
   </HEAD>
   <BODY ONLOAD="window.tm = setInterval('bounceIt()', 10);"
         ONUNLOAD="clearInterval(window.tm);">
      <IMG SRC="ball.gif" ID="bounce"
         STYLE="position:absolute; top:0; left:0; z-index:-1">
      <H1>Bouncing Ball</H1>
      <P>The ball bounces around and around under the text.</P>
      <P>This page works even if you resize
         or scroll the window.</P>
      <P>This page takes advantage of:
      <UL>
         <LI>Absolute positioning
         <LI>Moving elements based on the timer
         <LI>Z-indexing
         <LI>Client size and scrollbar position properties
      </UL>
   </BODY>
</HTML>

Движением изображения по экрану управляет таймер. Изображение перемещается за текстом, так как установлено минимальное значение свойства z-index. Данный пример анимирует изображение, но также может быть анимирован любой код HTML на экране. Например, вы можете заменить данное изображение элементом DIV, указать ширину элемента DIV, добавить HTML-содержание и анимировать его.


Эффекты исчезновения и появления

Программирование свойства CSS clip позволяет создавать интересные эффекты появления и исчезновения. Эффект появления заключается в том, что элемент постепенно выводится на экран, начиная появляться с одного края. Эффект исчезновения заключается в постепенном удалении элемента с экрана аналогичным образом. Приведенный ниже документ содержит функцию создания различных вертикальных и горизонтальных эффектов исчезновения/появления для абсолютно позиционированного элемента, а также кнопки для тестирования этих эффектов:

<HTML>
   <HEAD>
      <TITLE> Эффекты возникновения/удаления </TITLE>
      <STYLE TYPE="text/css">
         BODY {text-align:center}

         #wipe {position:absolute; top:200pt; left:40%;
            clip:rect(0 100% 100% 0); border:2pt navy solid;
            width:100pt; background:white}
         P {margin-top:0pt; margin-bottom:0pt}
         INPUT {width:100%}
      </STYLE>
      <SCRIPT LANGUAGE="JavaScript" ID="WipeEffects">
         function wipe(direction) {
            var el = document.all.wipe;
            /* Второй аргумент необязателен и определяет 
               появление или исчезновение элемента. По 
               умолчанию воспроизводится эффект появления. */
            var into = true;
            if (arguments[1] != null)
               into = arguments[1];

            if (null == el.init) {
               // Инициализация эффекта.
               // Вся информация появления/исчезновения хранится 
               // в этом элементе.
               el.init = true;
               el.clipTop = 0;
               el.clipRight = 0; 
               el.clipBottom = 0; 
               el.clipLeft = 0
               el.inc = 4;

               if (into)  // Установка эффекта появления.
                  switch (direction) {
                  case "clipBottom":
                     el.clipRight = "100%";
                     el.size = el.offsetHeight
                     break;
                  case "clipRight":
                     el.clipBottom = "100%";
                     el.size = el.offsetWidth;
                     break;
                  case "clipTop":
                     el.clipBottom = "100%";
                     el.clipRight = "100%";
                     el.clipTop = el.offsetHeight;
                     el.inc *= -1;
                     el.size = 0;
                     break;
                  case "clipLeft":
                     el.clipBottom = "100%";
                     el.clipRight = "100%";
                     el.clipLeft = el.offsetWidth;
                     el.inc *= -1;
                     el.size = 0;
                     break;
                  }
               else       // Установка эффекта исчезновения.
                  switch (direction) {
                  case "clipBottom":
                     el.clipRight = "100%";
                     el.clipBottom = el.offsetHeight;
                     el.size = 0;
                     el.inc *= -1;
                     break;
                  case "clipRight":
                     el.clipBottom = "100%";
                     el.clipRight = el.offsetWidth;
                     el.size = 0;
                     el.inc *= -1;
                     break;
                  case "clipTop":
                     el.clipBottom = "100%";
                     el.clipRight = "100%";
                     el.clipHeight = el.offsetHeight;
                     el.size = el.offsetHeight;
                     break;
                  case "clipLeft":
                     el.clipBottom = "100%";
                     el.clipRight = "100%";
                     el.clipLeft = 0;
                     el.size = el.offsetWidth;
                     break;
                  }
            }
            // Увеличение выреза.
            el[direction] += el.inc;
            // Set clip.
            el.style.clip = "rect(" + el.clipTop + " " +
               el.clipRight + " " + el.clipBottom + " " +
               el.clipLeft + ")";
            // Проверка завершения.
            if (((el.size >= el[direction]) && (el.inc > 0)) ||
                  ((el[direction] >= 0) && (el.inc < 0))) 
               setTimeout("wipe('" + direction + "', " + into + ")", 
                  10);
            else 
               el.init = null;
         }
      </SCRIPT>
   </HEAD>

   <BODY>
      <H1>Wipe Effects</H1>
      <P STYLE="padding-bottom:5pt">
         <INPUT TYPE=BUTTON STYLE="width:260pt" VALUE="Display"
            ONCLICK=
               "document.all.wipe.style.clip='rect(0 100% 100% 0)'">
      <FIELDSET STYLE="width:130pt">
         <LEGEND>Wipe-In Effects</LEGEND>
         <P><INPUT TYPE=BUTTON VALUE="Wipe to Bottom"
            ONCLICK="wipe('clipBottom')">
         <P><INPUT TYPE=BUTTON VALUE="Wipe to Right"
            ONCLICK="wipe('clipRight')">
         <P><INPUT TYPE=BUTTON VALUE="Wipe to Top"
            ONCLICK="wipe('clipTop')">
         <P><INPUT TYPE=BUTTON VALUE="Wipe to Left"
            ONCLICK="wipe('clipLeft')">
      </FIELDSET>

      <FIELDSET STYLE="width:130pt">
         <LEGEND>Wipe-Out Effects</LEGEND>
         <P><INPUT TYPE=BUTTON VALUE="Wipe from Bottom"
            ONCLICK="wipe('clipBottom', false)">
         <P><INPUT TYPE=BUTTON VALUE="Wipe from Right"
            ONCLICK="wipe('clipRight', false)">
         <P><INPUT TYPE=BUTTON VALUE="Wipe from Top"
            ONCLICK="wipe('clipTop', false)">
         <P><INPUT TYPE=BUTTON VALUE="Wipe from Left"
            ONCLICK="wipe('clipLeft', false)">
      </FIELDSET>
      <DIV ID=wipe>
         <P>Home
         <P>News
         <P>Info
         <P>About
         <P>Demo
      </DIV>
   </BODY>
</HTML>


Создание всплывающих меню

Используя абсолютное позиционирование можно создать меню, которые выводятся на экран, когда пользователь щелкает мышью по ключевому слову или строке меню, определенной посредством HTML. Вы можете расширить приведенный ниже код, который создает разворачиваемые меню адресов URL для использования в своих документах. Эти всплывающие меню могут быть легко расширены путем добавления эффектов появления/исчезновения, которые содержатся в предыдущем коде.

<HTML>
   <HEAD>
      <TITLE> Всплывающие меню </TITLE>
      <STYLE TYPE="text/css">
         /* Устанавливает всплывание меню слева от текста. */
         #menu {float:left; width:50pt; background:lightgrey;
            border:2px white outset; cursor:default} 
         /* В исходном состоянии меню будут скрыты. */
         #menu .popup {position:absolute; display:none;
            background:lightgrey; border:2px white outset;
            width:135pt; margin:2pt}
         #menu P {margin-top:0pt; margin-bottom:0pt}
         .over {color:navy; font-weight:bold}
      </STYLE>
      <SCRIPT LANGUAGE="JavaScript">
         var curPop = null;

         function clearCurrent() {
            // Скрытие всплывающего меню, которое 
            // отображается в данный момент.
            if (null != curPop)
               curPop.style.display = "";
            curPop = null;
         }

         function popup() {
            var el = event.srcElement;
            clearCurrent();
            // Отображение новой команды меню.
            if (("P" == el.tagName) &&
                  ("menu" == el.parentElement.id)) {
               // Размещение и отображение всплывающего меню.
               var elpop = document.all[el.sourceIndex + 1];
               elpop.style.pixelLeft = document.all.menu.offsetLeft +
                  document.all.menu.offsetWidth - 7;
               elpop.style.pixelTop  = el.offsetTop +
                  document.all.menu.offsetTop;
               elpop.style.display = "block";
               curPop = elpop;
            }
            event.cancelBubble = true;
         }

         function highlight() {
            // Выделение команд меню.
            if (null != event.fromElement)
               if ((event.fromElement.tagName == "P") &&

                     (event.fromElement.parentElement.id == "menu"))
                  event.fromElement.className = "";
            if (null != event.toElement)
               if ((event.toElement.tagName == "P") &&
                     (event.toElement.parentElement.id == "menu"))
                  event.toElement.className = "over";
         }
      </SCRIPT>
   </HEAD>
   <BODY ONCLICK="clearCurrent()">
      <H1>Menu Example</H1>
      <DIV ID="menu" ONCLICK="popup()" ONMOUSEOVER="highlight()"
            ONMOUSEOUT="highlight()">
         <P>Navigate
            <DIV CLASS="popup">
               <P><A HREF="home.htm">Home</A>
               <P><A HREF="insideDHTML.htm">Inside DHTML Information
                  </A>
               <P><A HREF="tip.htm">Tip of the Week</A>
            </DIV>
         <P>News
            <DIV CLASS="popup">
               <P><A HREF="headlines.htm">Headlines</A>
               <P><A HREF="internet.htm">Internet News</A>
               <P><A HREF="rumors.htm">Rumor Mill</A>
            </DIV>
      </DIV>
      <P>Click on a menu option in the box on the left.</P>
   </BODY>
</HTML>


Добавление возможности перемещения

Комбинируя абсолютное позиционирование с событиями мыши, можно моделировать перемещение элементов с помощью мыши. Для добавления поддержки перемещения элементов с помощью мыши можно написать сценарий, который ищет атрибут dragEnabled во всех элементах. Сценарий в приведенном ниже коде автоматически обрабатывает перемещения всех элементов, которые имеют данный атрибут, включая вложенные позиционированные элементы, так что код не требуется изменять при каждом добавлении элемента, доступного для перемещения. Если пользователь удерживает кнопку мыши нажатой на элементе, для которого установлен атрибут dragEnabled, а затем перемещает мышь, то элемент будет перемещаться, следуя за перемещением мыши. Другим методом является использование специального имени класса вместо атрибута dragEnabled.

<HTML>
   <HEAD>
      <TITLE> Добавление поддержки перемещения </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         // Данный код позволяет перемещать мышью любой 
         // абсолютно позиционированный элемент с 
         // индивидуальным атрибутом dragEnabled.
         var elDragged = null  // Перемещаемый элемент

         function doMouseMove() {
            // Проверяет, нажата ли кнопка мыши и находится ли 
            // элемент в состоянии перемещения.
            if ((1 == event.button) && (elDragged != null)) {
               // Перемещение элемента.
               // Сохранение положения мыши в документе.
               var intTop = event.clientY + document.body.scrollTop;
               var intLeft = event.clientX + document.body.scrollLeft;
               // Определение элемента, над которым находится 
               // указатель мыши.
               var intLessTop  = 0;
               var intLessLeft = 0;
               var elCurrent = elDragged.offsetParent;
               while (elCurrent.offsetParent != null) {
                  intLessTop += elCurrent.offsetTop;
                  intLessLeft += elCurrent.offsetLeft;
                  elCurrent = elCurrent.offsetParent;
               }
               // Установка нового положения.
               elDragged.style.pixelTop =
                  intTop - intLessTop - elDragged.y;
               elDragged.style.pixelLeft =
                  intLeft - intLessLeft - elDragged.x;
               event.returnValue = false;
            }
         }

         function checkDrag(elCheck) {
            // Проверка того, находится ли указатель мыши над элементом, 
            // Который поддерживает перемещение. 
            while (elCheck != null) {
               if (null != elCheck.getAttribute("dragEnabled")) 
                  return elCheck;
               elCheck = elCheck.parentElement;
            }      
            return null;
         }

         
         function doMouseDown() {
            // Сохранение перемещаемого элемента.
            var elCurrent = checkDrag(event.srcElement);
            if (null != elCurrent) {
               elDragged = elCurrent;
               // Определение местоположения указателя мыши в элементе.
               elDragged.x = event.offsetX;
               elDragged.y = event.offsetY;
               var op = event.srcElement;
               // Поиск действительного местоположения по отношению к 
               // перемещаемому элементу. 
               if ((elDragged != op.offsetParent) &&
                     (elDragged != event.srcElement)) {
                  while (op != elDragged) {
                     elDragged.x += op.offsetLeft;
                     elDragged.y += op.offsetTop;
                     op = op.offsetParent;
                  }
               }
            }
         }

         function doSelectTest() {
            // He разрешать выделение текста в перемещаемых элементах.
            return (null == checkDrag(event.srcElement) &&
               (elDragged!=null));
         }

         // Связать обработчики событий мыши.
         document.onmousedown = doMouseDown;
         document.onmousemove = doMouseMove;
         // Сброс элемента при отпускании кнопки мыши.
         document.onmouseup = new Function("elDragged = null;");
         document.ondragstart = doSelectTest;
         document.onselectstart = doSelectTest;
      </SCRIPT>
   </HEAD>
   <BODY>
      <H1>Dragging Positioned Elements</H1>
      <P>These contents are static and can't be dragged. The
         following image can be dragged even though it is behind
         this text.
      <IMG SRC="ball.gif" dragEnabled
         STYLE="position:absolute; top:10px; left:20px; cursor:hand;
            z-index:-1;">
      <DIV STYLE="position:absolute; top:150px; left:20px;
               border:2px navy solid; width:100; cursor:hand"
            dragEnabled>
         This text can be dragged.
      </DIV>
   </BODY>
</HTML>

Для перемещения элемента рассчитывается новое положение элемента в документе на основе положения мыши в документе. Положение мыши рассчитывается путем добавления свойств clientX и clientY в свойства scrollTop и scroliLeft элемента Body. Положение элемента относительно документа является суммой его смещений и смещений всех его предков относительно их относительных контекстов воспроизведения. Свойства смещения обсуждаются ниже в разделе данной главы "Контекст воспроизведения".



Относительное позиционирование

Элементы, которые были позиционированы относительно, занимают место в нормальном потоке документа. Данные элементы позиционированы за пределами их положения в нормальном потоке. Основной функций данного элемента является анимация элементов в их корректном положении в документе.

Приведенные ниже два примера демонстрируют анимированный текст на экране. Первый пример представляет введение в анимированный текст. Второй пример является более объемным и содержит набор функций для создания серии презентационных эффектов. Пример из раздела данной главы "Выравнивание относительно позиционированных элементов" демонстрирует запуск анимации всех относительно позиционированных элементов из одной точки на экране.


Плавающий текст

Если вы хотите создать текст, выплывающий из-за границы экрана, то он должен быть невидим в исходном состоянии и затем появляться по истечении определенного периода времени. Лучшим методом создания текста, выплывающего из-за границы экрана, является установка начала текста за пределами экрана с определенной отрицательной координатой и последующая установка его исходного положения на основе состояния браузера перед началом анимации.

Поскольку динамический HTML не определяет конкретного размера содержания и пользователь может прокручивать документ в любом направлении, то исходное положение элемента имеет большое значение. В исходном положении элемента должен быть учтен физический размер экрана и положение полос прокрутки. Приведенный ниже код демонстрирует создание текста, выплывающего из правой границы экрана. В данном примере текст запускается в отрицательном координатном пространстве, так что пользователь не может обратиться к тексту с помощью полос прокрутки. Перед началом анимации элемент устанавливается у правой границы экрана. Таким образом, независимо от места нахождения пользователя в документе, анимация элемента всегда начинается на странице без большой задержки и пользователь никогда не увидит элемент до начала анимации.

<HTML>
   <HEAD>
      <TITLE> Плавающий текст </TITLE>
      <STYLE TYPE="text/css">
         H1 {text-align:center}
         #tip {position:relative; left:-1000px}
      </STYLE>
      <SCRIPT LANGUAGE="JavaScript">
         function slideIn() {
            var el = document.all.tip;
            // Проверка, находится ли элемент за пределами экрана.
            if (-1000 == el.style.pixelLeft) {
               el.style.fontStyle = "italic";
               // Размещение элемента за пределами правой границы экрана.
               el.style.pixelLeft = document.body.offsetWidth +
                  document.body.scrollLeft;
            }
            if (20 <= el.style.pixelLeft) {
               el.style.pixelLeft -= 20;
               setTimeout("slideIn();", 50);
            }
            else {
               el.style.pixelLeft = 0;
               el.style.fontStyle = "";
            }
         }
      </SCRIPT>
   </HEAD>
   <BODY ONLOAD="slideIn();">
      <H1 ID="tip">Tip of the Week</H1>
      <P>Animating text from off screen
   </BODY>
</HTML>


Презентационные эффекты

Расширив возможности предыдущего примера, легко можно создать презентации с движущимся текстом. Следующий пример демонстрирует добавление элементов презентаций повторяющихся автоматически, или когда пользователь щелкает кнопкой мыши. Последовательность эффектов определяется возможностями динамического HTML для представления нераспознаваемых элементов. Элемент Sequence определяет набор элементов, которые должны быть анимированы и устанавливает автоматическую анимацию или запуск в ответ на нажатия кнопки мыши.

Приведенный ниже документ демонстрирует две серии - первая выполняется с использованием таймера, а вторая запускается при нажатии пользователем кнопки мыши:

<HTML>
   <HEAD>
      <SEQUENCE order="Text1, Text2, Text3, Text4, Text5" speed="20"
         type="auto" increments=15>
      <SEQUENCE order="Text6, Text7" speed="20" type="click"
         increments=15>
      <TITLE> Презентационные эффекты </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         var slideShow = new Object();
 
         function initSequence(s) {
            var sTemp = s.sequences[s.currentSequence];
            if (null != sTemp) {
               // Получение списка идентификаторов элементов серии.
               s.sequencer = new Array();
               s.sequencer = sTemp.getAttribute("order").split(", ");
               // Запуск серии.
               for (var intLoop = 0; intLoop < s.sequencer.length;
                     intLoop++)
                  if (null != document.all[s.sequencer[intLoop]]) {
                     var el = document.all[s.sequencer[intLoop]];
                     el.initTop = el.style.posTop;
                     el.initLeft = el.style.posLeft;
                  }
               s.speed = (null == sTemp.getAttribute("speed")) ?
                  20 : sTemp.getAttribute("speed");
               s.type = ("auto" == sTemp.getAttribute("type"));
               s.increments =
                  (null == sTemp.getAttribute("increments")) ?
                     15 : sTemp.getAttribute("increments");
               s.inc = 0;
               s.position = -1;
            }

            else {
               s.position = null;
               if (document.onclick == doFly)
                  document.onclick = new Function();
            }
         }

         function nextSequence(s) {
            // Запуск серии, если она доступна.
            if (null != s.position) {
               // s.position представляет элемент в серии. 
               // Выполнение до тех пор, пока имеются элементы; 
               // Затем поиск следующей серии.
               s.position++
               if (s.position < s.sequencer.length) {
                  s.inc = 0;
                  if (s.type)  // Запуск таймера
                     window.setTimeout("doFly();", s.speed)
                  else         // Запуск при возникновении события нажатия
                     document.onclick = doFly;
               }
               else {
                  s.currentSequence++;
                  initSequence(s);
                  nextSequence(s);
               }
            }
            else  {
               s.position = null;
               if (document.onclick == doFly)
                  document.onclick = null;
            }
         }

         function slide() {
            // Запуск распорядителя серии - получение 
            // всех тегов <SEQUENCE>.
            slideShow.sequences = document.all.tags("SEQUENCE");
            slideShow.sequencer = new Array();
            if (0 < slideShow.sequences.length) {
               slideShow.currentSequence = 0;
               initSequence(slideShow); // Инициализация.
               nextSequence(slideShow); // Запуск первой серии.
            }
         }
  
         function doFly() {
            var dt, dl;
            var el =
               document.all[slideShow.sequencer[slideShow.position]];
            document.onclick = null;  // Остановка событий нажатия до
                                      // завершения. 
            // Изменение положения элемента. 
            slideShow.inc++;
            dt = el.initTop / slideShow.increments;
            dl = el.initLeft / slideShow.increments;
    
            el.style.posTop = el.style.posTop - dt;
            el.style.posLeft = el.style.posLeft - dl;
  
            if (slideShow.inc < slideShow.increments) 
               window.setTimeout("doFly();", slideShow.speed)
            else {
               el.style.top = 0;
               el.style.left = 0;
               nextSequence(slideShow);
            }
         }
      </SCRIPT>
      <STYLE TYPE="text/css">
         BODY {color:white}
         DIV {position:relative; width:100%; font-size:16pt;
            height:40px}
         H1 {text-align:center; font-size:18pt}
      </STYLE>
   </HEAD>
   <BODY BACKGROUND="img001.gif" ONLOAD="slide();">
      <H1>Inside Dynamic HTML</H1>
      <DIV ID="Text1" STYLE="top:0px; left:-350px">
         Overview of HTML and CSS</DIV>
      <DIV ID="Text2" STYLE="top:0px; left:-350px">
         Fundamentals of HTML Scripting</DIV>
      <DIV ID="Text3" STYLE="top:0px; left:-350px">
         Dynamic HTML Event Model</DIV>
      <DIV ID="Text4" STYLE="top:0px; left:-350px">
         Dynamic Styles</DIV>
      <DIV ID="Text5" STYLE="top:0px; left:-350px; color:yellow">
         Click to Continue</DIV>
      <DIV ID="Text6" STYLE="top:0px; left:-350px">
         Dynamic Contents</DIV>
      <DIV ID="Text7" STYLE="top:0px; left:-350px">
         Dynamic Presentations!</DIV>
   </BODY>
</HTML>

Атрибуты тега <SEQUENCE>, который должен быть определен в заголовке документа, перечислены в табл. 12.2. Единственным необходимым атрибутом является атрибут order. Остальные атрибуты принимают значения по умолчанию, если их не определить явно.

Таблица 12.2. Атрибуты тега <SEQUENCE>


Имя атрибута Описание

order Определяет идентификаторы (ID) элементов, которые должны быть помещены в серию эффектов. Каждый элемент должен быть явно отделен, используя запятую и пробел
speed Определяет скорость анимации элементов. Это значение используется для определения задержки между элементами, которые воспроизводятся автоматически
type Определяет запуск последовательности автоматически посредством таймера (по умолчанию, auto) или вручную в ответ на нажатие кнопки мыши (click)
increments Определяет число промежуточных положений изображения до перехода в финальное положение. Большее число положений при более высокой скорости позволяет создать более плавную анимацию



Контекст воспроизведения

За невероятную гибкость позиционирования CSS иногда приходится расплачиваться увеличением сложности страницы. Приведенные выше примеры демонстрируют использование позиционирования CSS для элементов, которые размещаются независимо. Одним из ключевых преимуществ HTML является возможность автоматического изменения схемы размещения содержания в зависимости от размера содержания и размера окна. Если разработчик Web-страницы предполагает размещать элементы в соответствии с размером окна и содержания, то он должен написать собственный сценарий размещения вместо использования HTML. В общем разработчику проще создавать и поддерживать документы, в которых применяются динамические стили, используя преимущества природы автоматического потока HTML, чем создавать собственный сценарий размещения.

Динамический HTML обеспечивает информацию, которая, несмотря на всю свою сложность, необходима для создания мощной индивидуальной схемы размещения. Для каждого элемента эта информация включает информацию смещения и подлинности элемента, на основе которой рассчитывается смещение. Для написания собственных сценариев размещения, необходимо понимать отношения между данными смещениями.

Информация о размере и положении каждого элемента в теле документа рассчитывается браузером при каждом обновлении документа, называется информацией воспроизведения и является поэтому менее долговечной, чем информация анализа, которая включает в себя атрибуты, стили и содержание, определяемое атрибутами в исходном документе. Важно понимать различие между значениями, определяемыми документом, и значениями воспроизведения, рассчитанными браузером.

Например, значение свойства width может быть для элемента равно 20%, а значение его свойства height может быть не определено. Значение 20%, а также его эквивалент в пикселах, представлены свойством style. Однако значение height не представлено свойством style, поскольку оно не определено. Когда браузер воспроизводит элемент, то его высота рассчитывается и представляется в виде отдельного свойства. Кроме того, браузер рассчитывает и представляет верхнее и левое положения элемента. Данные значения не всегда совпадают со значениями top и left, определенными с помощью позиционирования CSS.

Каждый элемент позиционируется относительно другого элемента, называемого его относительным предком (offset parent). Относительный предок элемента устанавливает контекст воспроизведения (rendering context), в котором отображается элемент. Элемент Body является самым высшим относительным предком. Для многих элементов относительным предком является элемент Body, и браузер рассчитывает положение каждого элемента относительно верхнего левого угла документа. Но если элемент находится внутри абсолютно позиционированного элемента, например, DIV, то его положение рассчитывается относительно элемента DIV, который является относительным предком. Относительный предок обеспечивает контекст, в котором воспроизводится элемент. В частности, он определяет точку отсчета для смещений элемента.

Каждый элемент описывается уникальной информацией воспроизведения. Свойство offsetParent элемента содержит ссылку на элемент, определяя его контекст воспроизведения, а его свойства offsetTop и offsetLeft содержат его координаты по отношению к началу координат, определенному его свойством offsetParent. Кроме того, прямоугольные элементы обычно описываются свойствами offsetWidth и offsetHeight, которые определяют размер элемента.

Только некоторые элементы, принадлежащие определенным стилям, могут определять новые контексты воспроизведения и становиться относительными предками для других элементов. Перечисленные ниже элементы определяют контексты воспроизведения:

Каждый элемент имеет одного относительного предка и может определять контекст воспроизведения для любого числа дочерних элементов. В этом отношении относительный предок элемента сходен с его родительским элементом в дереве анализа. Но относительный предок не обязательно должен совпадать с предком элемента в дереве анализа. Свойства offsetParent и parentElement часто указывают на различные элементы. Диаграмма, на которой показаны относительные предки всех элементов в документе, называется деревом воспроизведения (rendering tree) документа.

На рис. 12.7 показано дерево анализа и дерево воспроизведения для приведенного ниже документа.

Рис. 12.7. Дерево анализа и дерево воспроизведения документа

<HTML>
   <HEAD>
      <TITLE> Анализ дерева относительно дерева воспроизведения </TITLE>
   </HEAD>
   <BODY>
      <P>The parsing tree represents the
         <EM>containership hierarchy</EM>
         defined by the contents of the HTML document.</P>
      <DIV ID=D1 STYLE="position:absolute; top:60; left:20">
         <P>The rendering tree represents the relationship between
            elements as they are rendered by the browser.</P>
         <DIV ID=D2 STYLE="height:80; width:100%; overflow:scroll">
            <P>This code creates a scrolling element. However, it does
               not define a new <EM>coordinate system</EM>. The
               following element is positioned based on the coordinate
               system of the absolutely positioned DIV.</P>
            <IMG STYLE="position:absolute; top:60; left:40"
               SRC="img1.gif">
         </DIV>
      </DIV>
   </BODY>
</HTML>

В данном примере элементы Paragraph, ЕМ и первый элемент DIV являются дочерними элементами элемента Body. Элемент ЕМ становится дочерним элементом воспроизведения тела документа, поскольку его родительский элемент Paragraph не является ограниченным элементом в соответствии с приведенным выше списком. Первый элемент DIV, с другой стороны, определяет новый контекст воспроизведения, поскольку он позиционирован абсолютно. Поэтому все элементы внутри элемента DIV являются дочерними элементами данного контейнера воспроизведения, если только внутри элемента DIV другой элемент не создает новый контекст воспроизведения.

Второй элемент DIV, D2, также создает новый контекст воспроизведения, поскольку он является ограниченным контейнером. Здесь нужно учесть некоторую хитрость. Если элемент позиционирован абсолютно, то он выделяется из потока документа и позиционируется относительно ближайшей координатной системы. Ограничивающий элемент не обязательно определяет новую систему координат. Прокручивание элемента DIV, D2, не создает новую систему координат, поскольку не установлено абсолютное или относительное позиционирование. Только элементы со значениями position, равными absolute или relative, создают новые системы координат. Поэтому изображение внутри элемента D2, которое позиционировано абсолютно, в действительности позиционировано относительно первого элемента DIV, D1. Данное отношение также поддерживается в отношениях воспроизведения. Элемент D1 является относительным предком для элемента D2.



Демонстрация контекста воспроизведения

Отношения между элементом и его контекстом воспроизведения становятся более понятными при рассмотрении примера HTML-документа. Приведенный ниже документ, который находится на прилагаемом компакт-диске, выводит информацию о смещениях любого элемента на странице. Документ также содержит примеры создания контекста воспроизведения. Щелчок по любому элементу в документе отображает список смещений для каждого контекста воспроизведения, внутри которого находится элемент.

<HTML>
   <HEAD>
      <TITLE> Демонстрация смещения </TITLE>
      <STYLE TYPE="text/css">
         BODY, TD, DIV, CAPTION, FIELDSET, LEGEND {cursor:default}
      </STYLE>
      <SCRIPT LANGUAGE="JavaScript">
         function doClick() {
            // Построение строки, содержащей все значения смещений,
            // начиная с нажатого элемента.
            var el = event.srcElement;
            var offset = "Offsets\n";
            while (el != null) {
               offset += "\n" + el.tagName + ":  (" + el.offsetTop +
                  ", " + el.offsetLeft + ")";
               el = el.offsetParent;
            }
            alert(offset);
         }
         document.onclick = doClick;
      </SCRIPT>
   </HEAD>
   <BODY>
      <H1>Offset Demonstration</H1>
      <P>Click on an element to see its rendering context and offset
         relationship. This page helps demonstrate how an element
         becomes constrained and creates a new rendering context for
         the elements it contains.
      <P>This is a standard paragraph containing
         <EM>emphasized text</EM>.
      <TABLE BORDER>
         <CAPTION>Table <EM>Demo</EM></CAPTION>
         <TR><TD>Table Cell 1</TD>
            <TD>Table Cell <STRONG>2</STRONG></TD></TR>
         <TR><TD>Table Cell 3</TD><TD>Table Cell 4</TD></TR>
      </TABLE>
      <FIELDSET STYLE="width:200pt">
         <LEGEND>Fieldset <EM>Demo</EM></LEGEND>
         <P>This is a fieldset.
         <BUTTON><P>HTML <STRONG>Button</STRONG></BUTTON>
      </FIELDSET>
      <P STYLE="position:relative; top:50; left:160pt">This is a
         <EM>relatively</EM> positioned paragraph.</P>
      <DIV STYLE="overflow:auto; height:50pt; width:150pt
            border:1pt gray solid">
         <P>This DIV element has a constrained width and height and
            may display scrollbars if the contents <EM>do not</EM>
            fit.
      </DIV>
      <DIV STYLE="position:absolute; top:300pt; left:150pt;
            width:100pt; border:1pt gray solid">
         <DIV STYLE="position:absolute; top:0pt; left:120pt;
               width:100pt; border:1pt gray solid">
            <P>This is an absolutely positioned DIV element within
               another absolutely positioned DIV element.
         </DIV>
         <P>This is an absolutely positioned DIV element.</P>
      </DIV>
   </BODY>
</HTML>



Свойства смещения относительно позиционированных элементов

Свойства стиля top и left относительно позиционированных элементов представляют его смещения относительно нормального положения в потоке, а его свойства offsetTop и offsetLeft представляют его положение по отношению к его относительному предку. На рис. 12.8 показаны отношения между этими свойствами стиля и воспроизводимыми свойствами положения.

Рис. 12.8. Свойства стиля top и left и свойства offsetTop и offsetLeft относительно позиционированного элемента

Свойства смещения являются только свойствами воспроизведения, которые представляют рассчитанные положения элемента в документе.



Определение отображения элемента

Приведенная ниже функция определяет, отображается ли верхний левый угол элемента на экране. Данная функция возвращает false, если верхний левый угол элемента невидим на экране, даже если элемент частично отображается на экране. Функция может быть применена к любому элементу на странице.


function onScreen(e) {
   // Проверка, является ли указанный элемент видимым.
   var rp = e.offsetParent;
   if (rp == null)
      return false;
   var pleft = e.offsetLeft;
   var ptop = e.offsetTop;
   while (true) {
      if (!((pleft >= rp.scrollLeft) &&
            (pleft <= rp.scrollLeft + rp.clientWidth) &&
            (ptop >= rp.scrollTop) &&
            (ptop <= rp.scrollTop + rp.clientHeight)))
         return false;
      pleft += rp.offsetLeft - rp.scrollLeft ;
      ptop += rp.offsetTop - rp.scrollTop;
      rp = rp.offsetParent;
      if (rp == null)
         return true;
   }
}

Данный код может быть легко расширен для проверки отображения на экране внутреннего элемента управления или ограничивающего элемента путем определения ширины и высоты элемента. Но метод не будет работать для непрямоугольных элементов, поскольку они не содержат свойства offsetWidth и offsetHeight.



Прокручивание элемента

Элемент в теле документа может быть открыт для просмотра с помощью метода scrollIntoView. Метод scrollIntoView поддерживает одиночный необязательный параметр, который определяет появление элемента в первой или последней строке в окне. Пропуск данного параметра или присвоение ему значения true прокручивает элемент до первой строки. Значение false прокручивает элемент до последней строки. Например, приведенный ниже код прокручивает первый элемент H1:


// Прокручивание элемента к первой строке. 
document.all.tags("H1").item(0).scrollIntoView()
// Прокручивание элемента к последней строке.
document.all.tags("H1").item(0).scrollIntoView(false)



Идентификация элемента в выбранном положении

Метод elementFromPoint объекта document используется для идентификации элемента в определенном положении в координатах ху на экране. Данный метод принимает положение в ху-пикселах относительно области клиентского окна и возвращает объект элемента в данном положении. Метод elementFrompoint используется для определения элемента, на котором находится мышь во время работы обработчика событий. Например, приведенный ниже код помещает имя тега элемента, над которым находится указатель мыши, в текстовое окно:

<HTML>
   <HEAD>
      <TITLE> Где находится указатель мыши? </TITLE>
      <SCRIPT FOR="document" EVENT="onmousemove()"
            LANGUAGE="JavaScript">
         document.all.txtCurrent.value =
            document.elementFromPoint(event.x, event.y).tagName; 
      </SCRIPT>
   </HEAD>
   <BODY>
      <H1>This Is a <EM>Header.</EM></H1>
      <P>Current Element: <INPUT TYPE=TEXT ID="txtCurrent" SIZE=20>
      </P>
   </BODY>
</HTML>



Элемент Map

Элемент Map определяет специальный контекст воспроизведения. Поскольку элемент Map может быть использован несколькими изображениями, то он считается находящимся за пределами контекстов воспроизведения. Поэтому элемент Map возвращает null для свойства offsetParent и о для свойств offsetTop и offsetLeft. Элементы Area внутри элемента мар возвращают значения для их свойств offsetTop и offsetLeft относительно верхнего левого угла элемента, содержащего мар, и возвращают элемент мар в качестве относительного предка. Поэтому, чтобы определить положение элемента Area на экране, необходимо учесть смещения определенного изображения.



Выравнивание относительно позиционированных элементов

Выравнивание элементов по горизонтали или по вертикали может представлять собой достаточно сложную операцию, требующую достаточное количество кода. При наличии двух абсолютно позиционированных элементов внутри одной системы координат выравнивание элементов также просто, как указание одинаковых значений свойств top и left. Поскольку относительно позиционированные элементы сдвинуты по отношению к их положению в потоке, то выравнивание относительно позиционированных элементов требует нескольких строк кода.

Приведенный ниже документ демонстрирует, как собрать все относительно позиционированные элементы друг над другом и затем переместить их обратно в нормальные положения в документе. Выравнивание элементов выполняется функцией alignElements, принимающей любые относительно позиционированные элементы и помещающей их над элементом с идентификатором ID, равным src. В противном случае вместо такого элемента может быть использована фиксированная точка на экране.

<HTML>
   <HEAD>
      <TITLE> Анимация из одной точки </TITLE>
      <STYLE TYPE="text/css">
         .fly {position:relative; color:navy; visibility:hidden}
      </STYLE>
      <SCRIPT LANGUAGE="JavaScript">
         function alignElements(el) {
            /* Помещение передаваемого в функцию относительно
               позиционированного элемента, который находится 
               в той же системе координат над элементом, 
               идентификатор которого равен src. */
            el.style.pixelTop
               = document.all.src.offsetTop - el.offsetTop;
            el.style.pixelLeft
               = document.all.src.offsetLeft - el.offsetLeft;
            el.style.visibility = "visible";
         }

         function moveIn(el) {
            // Если элемент не находится в своем положении в потоке, 
            // то переместить его ближе к этому месту.
            var moved = false;
            if (el.style.pixelTop < 0) {
               el.style.pixelTop += 8;
               if (el.style.pixelTop > 0)
                  el.style.pixelTop = 0;
               moved = true;
            }
            else {
               if (el.style.pixelTop > 0)  {
                  el.style.pixelTop -= 8;
                  if (el.style.pixelTop < 0)
                     el.style.pixelTop = 0;
                  moved = true;
               }
            }
            if (el.style.pixelLeft < 0) {
               el.style.pixelLeft += 8;
               if (el.style.pixelLeft > 0)
                  el.style.pixelLeft = 0;
               moved = true;
            }

            else {
               if (el.style.pixelTop > 0) {
                  el.style.pixelLeft -= 8;
                  if (el.style.pixelLeft < 0)
                     el.style.pixelLeft = 0;
                  moved = true;
               }
            }
            /* Переменная перемещения отражает, был ли перемещен 
               элемент. Если элемент уже перемещен в 
               соответствующее положение в потоке, то данная
               функция возвращает false.  */
            return moved;
         }

         function flyInTogether() {
            var more = false;
            // Перемещение всех элементов класса fly.
            for (var intLoop = 0; intLoop < document.all.length;
               intLoop++) {
               if ("fly" == document.all[intLoop].className)
                  more = moveIn(document.all[intLoop]) || more;
            }
            // Продолжает выполнение до тех пор, пока все элементы не
            // будут соответствующим образом размещены в потоке.
            if (more) 
               setTimeout("flyInTogether()", 10); 
         }
  
         function setup() {
            // Выравнивание всех элементов, которые должны быть анимированы.
            for (var intLoop = 0; intLoop < document.all.length;

                  intLoop++) {
               if ("fly" == document.all[intLoop].className)
                  alignElements(document.all[intLoop]);
            }
            flyInTogether();
         }

         window.onload = setup;
      </SCRIPT>
   </HEAD>
   <BODY>
      <H1 ID=src>Animate from a Single Point</H1>
      <UL>
         <LI CLASS="fly"><P>Create animated documents.</P>
         <LI CLASS="fly"><P>All elements start together
            at a single point.</P>
         <LI CLASS="fly"><P>This example works using relative
            positioning.</P>
         <LI CLASS="fly"><P>First align the elements, and then fly
            them into place.</P>
         <LI CLASS="fly"><P>Once the elements are in place, this is
            a standard HTML document!</P>
         <LI CLASS="fly"><P>Simply supplying a special class name
            animates an element.</P>
      </UL>
      <P STYLE="text-align:center">Not all text must be animated!
   </BODY>
</HTML>



Hosted by uCoz