Главная страница «Первого сентября»Главная страница журнала «Информатика»Содержание №11/2009


Спецвыпуски

CSS-верстка для продолжающих

Введение

Для кого этот материал

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

Вы уже собираетесь задвинуть его на полку? Не торопитесь, вдруг это именно то, что вам нужно!

Предполагается, что читатель умеет размечать страницу тегами HTML, знаком с CSS, но испытывает растерянность на практике.

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

Здесь излагаются алгоритмы работы базовых конструкций HTML/CSS и прокладывает тропинку от теории к практике (верстке страниц средствами CSS).

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

Хорошо писать коды, если не нужно гадать, как написанное отобразится на экране, и удивляться, когда ожидания не оправдываются. Хорошо, когда все предсказуемо. Хорошо, когда на любой возникший вопрос (свой, ученика или товарища) можно дать внятный ответ.

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

Это и есть основная цель — дать читателю определенность и избавить его (по возможности) от лишней головной боли.

Структура книги и перекрестные ссылки

Содержание книги охватывает три темы (разделы “Введение” и “Ссылки” не в счет):

Введение

Тема 1. Верстка потоком

Тема 2. Позиционирование

Тема 3. Плавающие блоки

Ссылки

В разделе “Тема 1. Верстка потоком” приводятся алгоритмы работы браузера по умолчанию.

В разделе “Тема 2. Позиционирование” рассмотрена верстка при помощи блоков, размещаемых в заданных координатах.

Раздел “Тема 3. Плавающие блоки” демонстрирует построение страниц при помощи блоков со свойством float

Читать книгу рекомендуется по порядку, темы тесно взаимосвязаны, и эта связь подчеркивается перекрестными ссылками, записываемыми в виде: “см. 1.2.4.” — ссылка на раздел первой темы “1.2.4. Устройство строчного элемента”.

В последнем разделе “Ссылки” собраны пронумерованные адреса сайтов Интернета, которые упоминаются в основном тексте. Ссылки на эту страницу выглядят так: “ссылка[2]” — определяет вторую запись в разделе “Ссылки”, в ней указан сайт с описанием стандарта HTML 4.1 от W3C (www.w3.org/TR/html401). Гораздо удобнее пользоваться электронной версией этой страницы (см. следующий раздел).

Загрузка электронных страниц

Для удобства читателей все примеры, обсуждаемые здесь, собраны в электронное приложение, которое настоятельно рекомендуется скопировать с адреса: http://inf.1september.ru, раздел “Download”.

Разверните скопированную запаковку в пустом каталоге, стартовый файл: index.htm.

В бумажной версии ссылки на электронные страницы записаны в виде: “поток/меню на вкладках/шаг 5” — на странице “поток” переходим к разделу “меню на вкладках”, а в нем — к пункту “шаг 5”. Видим запись:

Шаг 5: example/01/menu/v05/, index.htm, main.css

Щелчок на “Шаг 5” покажет вид обсуждаемого примера на пятом шаге его построения, щелчки на “index.htm” и “main.css” откроют страницы с кодами, а запись “example/01/menu/v05/ сообщает о каталоге, в котором расположены эти коды.

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

CSS-верстка — почему это важно?

2-0.gif (12640 bytes)

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

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

Иными словами:

· скорость Интернета возросла;

· браузеры стали поддерживать стандарты.

В соответствии с этим дизайнеры по всему миру стали по-другому строить свои сайты. В настоящее время стало наконец возможным изолировать визуальный образ сайта (в файле CSS) от его содержания (в файлах HTML).

Такой подход позволяет:

· Сократить объем HTML-кода за счет удаления из тегов значительной части атрибутов (сокращение может достигнуть 50%).

· Уменьшить время загрузки страниц за счет того, что единственный файл CSS кэшируется браузером.

· Упростить работу по изменению внешнего вида сайта. Редактировать придется единственный файл со стилевыми определениями, а не многочисленные файлы с кодами гипертекстовых страниц.

· Легко настраивать сайт на разные средства просмотра.

· Использовать гораздо больше свойств и значений CSS, чем это было возможно при помощи атрибутов HTML.

В заметках, представленных на страницах этой книги, рассматриваются вопросы, связанные с версткой гипертекстовых страниц при помощи CSS.

Начинающий сайтостроитель, берясь за свое дело, сразу начинает проклинать браузеры, ругаясь нехорошими словами на их разработчиков. На картинках-ссылках появляются “хвосты”, строчный элемент вылезает за пределы своего родителя, блочный со 100%-ной шириной включает линейку прокрутки…

Да, конечно, браузеры содержат ошибки. Но часто то, что принимается за ошибку, является задуманным, задокументированным и логичным поведением.

На сайтах web-разработчиков можно, например, встретить описание “трюка” margin: 0 auto, при помощи которого блок центрируется по горизонтали. На самом деле это никакой не трюк, а задокументированная стандартом и логичная функциональность (см. 1.3.3.1).

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

Шаблон HTML для проверки примеров

Примеры на HTML, которые содержатся на бумажных страницах, записаны в сокращенной форме: <BODY>содержимое примера</BODY>.

Полный шаблон страницы, в котором работают примеры, должен иметь вид:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ru">

 

<HEAD>

<META http-equiv="Content-Type" content="text/html; charset=windows-1251">

<META http-equiv="Content-Style-Type" content="text/css">

<STYLE type="text/css">@import url(main.css);</STYLE>

<TITLE>Заголовок окна</TITLE>

</HEAD>

 

<BODY>

Содержимое примера

</BODY>

 

</HTML>

Указана кодировка windows-1251 и проставлена ссылка на файл со стилями main.css.

Для DOCTYPE выбран вариант Transitional . Подробнее о декларации DOCTYPE рассказано ниже.

Декларация DOCTYPE

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

DOCTYPE является ключевым компонентом в совместимости страниц, кроме того, выбор DOCTYPE влияет на поведение вашей web-страницы в различных браузерах.

Джеффри Зельдман. “Web-дизайн по стандартам”

Очень сильно влияет! Ваша визуальная разметка, выполненная средствами CSS по стандартам W3C, может потерпеть крах на экране, если DOCTYPE не будет записан.

Элемент DOCTYPE предназначен для указания соответствия кода документа одному из стандартов W3C. Браузер, в зависимости от стандарта, по-разному интерпретирует элементы на странице.

Элемент DOCTYPE — это скорее даже не элемент, а описание (декларация), имеющее свой собственный синтаксис.

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

Варианты DOCTYPE для HTML 4.01 приводятся ниже.

Предусмотрено 3 стандарта языка HTML 4.01:

· Strict (строгий)

· Transitional (переходный)

· Frameset (аналогичен Transitional, но с фреймами)

Вариант Strict

Код не содержит элементов и атрибутов, помеченных W3C как “устаревшие” или “не одобряемые” (например: CENTER , FONT, S, U, align, background, bgcolor , color, size).

Декларация записывается в виде:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"

"http://www.w3.org/TR/html4/strict.dtd">

Вариант Transitional

Код может содержать устаревшие теги, вариант введен в целях совместимости со старыми версиями HTML.

Декларация записывается в виде:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

Вариант Frameset

Аналогичен Transitional, но содержит также элементы для создания наборов фреймов.

Декларация записывается в виде:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"

"http://www.w3.org/TR/html4/frameset.dtd">

Какой вариант DOCTYPE выбрать?

Вариант Frameset отбрасываем сразу, так как фреймы — это рудимент прошлого века, и использовать их мы не собираемся.

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

Таким образом, код любой нашей странички будет иметь вид:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ru">

...

</HTML>

Атрибут lang со значением ru определяет русский язык в качестве базового языка на страничке.

Информация о языке, определенная атрибутом lang, может быть использована Пользовательским Агентом (ПА) для управления представлением различными путями.

Вот некоторые ситуации, где предоставленная автором информация о языке может быть полезной:

· содействие поисковым машинам;

· содействие речевым синтезаторам;

· помощь ПА в выборе вариантов глифов для высококачественной печати;

· помощь ПА в выборе вариантов кавычек;

· помощь ПА в принятии решений о дефисах, лигатурах и пробелах;

· помощь программам проверки правописания.

Цель атрибута lang — создать ПА условия для более понятного представления содержимого на базе принятой для данного языка культурной практики.

Спецификация HTML 4.01 (ссылка [2])

Автор

Орудуя CSS, HTML и JavaScript, мы многого достигли на страницах этой книги, но все же поймали пока скромную рыбку.

Будет приятно, если изложенный материал поспособствует более крупному улову!

Дорогой товарищ!

Желаю тебе азарта, творческих успехов, хорошего настроения, а также оптимизма в борьбе с браузером IE!

Александр Александрович Дуванов, руководитель Роботландского университета из Переславля-Залесского

При подготовке иллюстративного материала использованы художественные заготовки, выполненные роботландским художником Александром Артуровичем Руссом.

Тема 1. Верстка потоком

 

— Настало время, когда нужно забыть старые приемы, полные разочарований, и приступить к производству сайтов по стандартам с радостным выражением лица! Это означает: начинаем осваивать верстку гипертекстовых страниц при помощи CSS.

— Было бы что верстать… Все время мы забываем о содержании. Все говорим о технике. А ведь дурной текст даже в красивых одеждах остается плохим.

— Ну, что вы! Интересные тексты? Они есть у нас!

Содержание темы

1.1. Элементы: блочные и строчные

1.2. Архитектура и поведение элемента

1.3. Размеры и выравнивание

1.4. Проблемы размеров и их решение

1.5. Как работает браузер. Верстка потоком

1.6. Пример построения меню на вкладках

1.1. Элементы: блочные и строчные

Интересные тексты? Они есть у нас!

Заголовок интересного текста

Первый абзац. В этом абзаце есть очень важное слово, которое выделено.

Второй абзац. В нем приводится небольшая цитата, которая поддерживает изложение.

(а здесь хотелось бы расположить иллюстрацию)

Заключительный текст.

Чтобы показать эту вкуснятину в окне браузера, разметим ее соответствующими тегами:

<H1>Заголовок интересного текста</H1>

<P>

Первый абзац. В этом абзаце есть очень важное <EM>слово</EM>, которое выделено.

</P>

<P>

Второй абзац. В нем приводится небольшая <CITE>цитата</CITE>, которая поддерживает изложение.

</P>

<P>

<IMG src="pic/pic.jpg" alt="Интересная иллюстрация">

</P>

Заключительный текст.

Код состоит из 5 элементов: одного заголовка, трех абзацев и одного безымянного элемента (условно названного БЛОК), в который автоматически собирается неразмеченный текст. Это — блочные элементы (block-level elements). Они выводятся на экран в прямоугольные области, следующие друг за другом сверху вниз. (Полный список блочных элементов: ссылкa[3].)

Внутри блоков расположены строчные элементы (inline elements). Строчные элементы занимают место внутри строки, переходя на следующие строки, если в текущей не хватило места. (Полный список строчных элементов: ссылка[4].) Текст, не размеченный тегами, браузер автоматически считает безымянными строчными элементами.

Картинка (строчный элемент) ведет себя почти так же, как и символ текста (и может идти вперемежку с текстом). Несколько IMG, записанных подряд, образуют “слово”. Если очередное “слово” не помещается в текущей строке, оно переносится на следующую строку.

Внутри блочных элементов могут располагаться не только строчные, но и блочные элементы вперемежку со строчными:

<DIV class=content>

<STRONG>Выделенный текст</STRONG>

<P>Первый абзац</P>

<P>Второй абзац</P>

Текст без разметки

</DIV>

Все строчные и неразмеченные элементы собираются в безымянные блоки:

<DIV class=content>

<БЛОК><STRONG>Выделенный текст</STRONG></БЛОК>

<P>Первый абзац</P>

<P>Второй абзац</P>

<БЛОК>Текст без разметки</БЛОК>

</DIV>

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

Блочный элемент P является исключением: внутрь него разрешается помещать только строчные элементы.

Можно ли размещать внутри строчного элемента блочные? Стандарт языка (ссылка[2]) запрещает это (“строчные элементы могут содержать только данные и другие строчные элементы”), однако браузеры относятся к такой разметке довольно лояльно. Например, отображая следующий фрагмент кода, все браузеры выведут на экран жирный текст:

<STRONG>

<P>Текст внутри абзаца</P>

</STRONG>

Однако браузер Firefox код

<CITE>

Текст снаружи

<P>Текст внутри абзаца</P>

</CITE>

преобразует в

<CITE>Текст снаружи</CITE>

<P>Текст внутри абзаца</P>

(это можно увидеть в отладчике Firebug (ссылка[16])), и текст внутри абзаца не будет курсивным.

В CSS есть свойство display, которое позволяет менять поведение элементов: значение block превращает элемент в блок, а значение inline — в строку. Так и происходит по поведению элемента на экране, но ни указание P {display:inline}, ни указание CITE {display:block} не помогают Firefox вывести курсивом текст внутри абзаца. И это соответствует стандарту.

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

<STRONG>

<P style="display: inline">Текст внутри абзаца</P>

</STRONG>

 

<CITE>

Текст снаружи

<P style="display: inline">Текст внутри абзаца</P>

</CITE>

 

<CITE style="display: block">

Текст снаружи

<P style="display: inline">Текст внутри абзаца</P>

</CITE>

Вывод: нужно следовать указаниям стандарта.

Итак, элементы бывают блочные и строчные. Можно предложить еще одно деление на два класса. Оно пригодится при анализе алгоритмов работы браузера.

Незамещаемый элемент — это элемент, содержание которого включено в HTML-код документа.

Например, абзац текста (P) является незамещаемым элементом, потому что его содержимое содержится в самом HTML-коде.

Замещаемый элемент — это элемент, HTML-код которого служит для подстановки другого объекта, отсутствующего в самом коде.

Например, элемент IMG является замещаемым элементом, потому что его код указывает на файл изображения, а само изображение в коде не присутствует. К замещаемым элементам относятся также элементы форм: обычные кнопки, радиокнопки, флажки, строки и поля для ввода текста.

1.2. Архитектура и поведение элемента

1.2.1. Устройство блочного элемента

Содержимое каждого блока окружается: границей (задается свойством border), внутренним отступом (задается свойством padding) и внешним отступом (задается свойством margin).

Внешний отступ — прозрачный, а внутренний содержит фон элемента, если тот задан (например, свойством background). Таким образом, если нужен отступ по фону, используем padding.

 

Содержимое + внутренний отступ + граница + внешний отступ = элемент.

Содержимое + внутренний отступ + граница = видимая часть элемента.

В описании стандарта (ссылка[1]) используются термины: content area, padding area, border area, margin area. На русский это обычно переводят так: содержание, отступы, границы и поля.

В этих заметках padding area называется внутренним отступом, а margin area — внешним отступом. Автору кажется, что так эти термины лучше запоминаются, ибо сам в свое время путал “отступ” с “полем”.

1.2.2. Схлопывание внешних отступов

Второй блок “проваливается” во внешний отступ первого блока на 10 пикселей.

При выводе на экран цепочки блоков происходит схлопывание внешних отступов. Расстояние от границ равно не сумме margin'ов каждого блока, а наибольшему из них.

Первый блок на иллюстрации имеет внешний отступ 20 пикселей, второй — 10. Расстояние между границами этих блоков получается не 30 (как можно было ожидать), а только 20 пикселей.

Схлопывание внешних отступов помогает правильной верстке элементов в потоке.

Такое поведение блоков имеет больше смысла, чем кажется на первый взгляд. Пусть, например, для абзацев задан внешний отступ P {margin: 1em} (примерно высота строки текущего шрифта). Благодаря схлопыванию внешних отступов расстояние между абзацами будет таким же, как и расстояние от крайних абзацев до границы содержащего блока, то есть — 1em.

1.2.3. Проваливание за границу родителя

Расположим на странице три последовательных блока:

<BODY>

<DIV class="header">

<H1>Заголовок</H1>

</DIV>

<DIV class="text">

<P>Текст 1</P>

</DIV>

<DIV class="text">

<P>Текст 2</P>

</DIV>

</BODY>

У всех трех блоков — нулевой внешний отступ, как и у заголовка внутри первого блока. Абзацы в двух последних блоках имеют внешние отступы по 30 пикселей от границ своего родителя.

Внешний вид опишем так:

BODY {margin: 0}

.header, .text

{

margin: 0;

background: blue;

}

.header H1

{

margin: 0px;

background: cyan;

}

.text P

{

margin: 30px;

background: orange;

}

Внешние отступы “проваливаются” за границу родителя и схлопываются с его отступами.

Отступ родителя теперь будет равняться наибольшему из двух: отступу родителя или “провалившемуся” отступу потомка.

Пробный запуск в браузере отображает на экран совсем другую картину: 30-пиксельный внешний отступ, который мы записали для абзаца, “проваливается” сверху и снизу за границы родительского блока text, отодвигая блоки text друг от друга. Заметим, что по горизонтали отступы получились правильными.

Поведение браузера можно изменить, если для блоков text задать границу при помощи свойства border, например, так: border: 1px solid black — теперь отступы “проваливаться” не будут.

Отменить “проваливание” можно и заданием внутреннего отступа для блоков text, например, так: padding: 1px 0 (1 пиксель — сверху и снизу, 0 — по горизонтали).

Описанные варианты (с border или с padding) приводят к появлению лишних пикселей, что иногда может оказаться очень некстати. Решить проблему можно, заменив margin для внутреннего блока padding'ом для родителя text:

BODY, .header, .header H1, .text P

{margin:0}

.text

{

padding:30px;

background:blue;

}

.header H1 {background:cyan}

.text P {background:orange}

1.2.4. Устройство строчного элемента

Строчный элемент, как и блочный, имеет: содержимое, внутренний отступ (padding), границу (border) и внешний отступ (margin). Отступы слева и справа ведут себя как обычно, а вертикальные отступы имеют особенности.

Пусть страница задана кодом:

<BODY>

<P>

Выделенное <STRONG>слово</STRONG> внутри предложения.

<P>

Здесь <CITE>длинная цитата, которая переходит с одной строки на другую</CITE>.

</BODY>

10-0.gif (7455 bytes)

На рисунке показан вид этой страницы в нешироком окне браузера.

Давайте посмотрим, как повлияет задание внешних и внутренних отступов на отображение строчных элементов STRONG и CITE.

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

Зададим внешние отступы:

P {background:#ffbf00}

P STRONG, P CITE

{

margin:1em;

background:cyan;

border:1px solid black;

}

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

Зададим внутренние отступы:

P {background:#ffbf00}

P STRONG, P CITE

{

padding:0.5em;

background:cyan;

border:1px solid black;

}

Таким образом, мы проверили на практике алгоритм форматирования строчных незамещаемых элементов:

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

Такое поведение мы обнаружим в процессе построения меню на вкладках (см. 1.6.3) и учтем его.

Что касается замещаемых элементов, то они ведут себя иначе.

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

Пусть страница задана кодом:

<BODY>

<P>

Выделенное <STRONG>слово</STRONG> внутри предложения.

<P>

Здесь <CITE>длинная цитата, которая переходит с одной строки на другую</CITE>.

А здесь расположена <IMG src='pic/logo.png' border=0 hspace=0 vspace=0 alt=''>

картинка.

</BODY>

11-0.gif (15429 bytes)

Отступы и рамка выделенного слова не изменили высоту первого абзаца. Картинка всеми своими отступами и рамкой расширила высоту родителя. Пунктиром условно обозначена внешняя граница внешнего отступа, заданного для картинки.

Зададим отступы и границы:

P {background:#ffbf00}

P STRONG, P CITE

{

padding:0.5em;

background:cyan;

border:1px solid black;

}

IMG

{

margin: 40px;

padding: 20px;

border:10px solid blue;

}

1.3. Размеры и выравнивание

1.3.1. Строчные элементы

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

Свойства width и height никакого влияния на текстовый элемент не оказывают.

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

· font-family — задает гарнитуру;

· font-size — кегль;

· font-style — начертание;

· font-weight — плотность;

· letter-spacing — расстояние между буквами;

· line-height — расстояние между строчками.

Размеры картинки определяются ее реальными размерами, но их можно задавать и атрибутами width, height элемента IMG или одноименными свойствами CSS.

Для выравнивания строчных элементов по горизонтали применяется свойство text-align со значениями: left, right, center, justify. Это свойство должно быть задано в родительском блоке.

 

Выключка справа для строчных элементов, расположенных внутри блока P:

P { text-align:right; }

1.3.2. Блочные элементы

Размеры блочного элемента определяют CSS-свойства width и height. Если размеры не заданы, то ширина блока совпадает с шириной родителя (вместе с границей и всеми отступами), а высота определяется по содержимому.

Если горизонтальный размер блока меньше родительского, его можно выравнивать с помощью значения auto для внешнего отступа (margin) выравниваемого блока.

Подробнее об интересном значении auto можно прочитать в следующем разделе.

1.3.3. Значение auto для размеров блока

Рассмотрим алгоритмы работы свойства auto отдельно при горизонтальном и при вертикальном форматировании блока.

1.3.3.1. Горизонтальное форматирование

 

Горизонтальным форматированием блока можно управлять при помощи семи свойств, задающих размеры:

· margin-left — внешний отступ слева;

· border-left — рамка слева;

· padding-left — внешний отступ слева;

· width — ширина содержимого;

· padding-right — внутренний отступ справа;

· border-right — рамка справа;

· margin-right — внешний отступ справа.

Только 3 свойства из 7 могут принимать значение auto :

· margin-left

· width >

· margin-right

Алгоритмы работы этих свойств при значении auto основаны на общем правиле горизонтального форматирования потока.

Сумма размеров горизонтальных компонентов блока в потоке всегда равна значению width родителя.

Если одному из свойств margin-left, width или margin-right задано значение auto, а для остальных — определенные значения, то свойство, заданное как auto, определяет размер, необходимый для размещения блока по ширине родителя.

Вот чем объясняется способ выравнивания блока слева и справа по отношению к родителю, когда он его меньше:

Если оба отступа установлены в auto , для них устанавливается одинаковый размер, и блок центрируется:

Браузеры IE пятых версий не центрируют блок таким образом. Эту ошибку IE5.* можно компенсировать другой ошибкой этих браузеров: по указанию text-align:center браузеры IE5.* центрируют не только текст (как требует стандарт), но и блоки.

Ниже приводится набор CSS-правил, которые обеспечивают центрирование BODY относительно HTML во всех браузерах:

HTML

{

text-align: center; /* Центрирование BODY для IE5 */

}

/* Определения для блока BODY, вложенного в блок HTML */

BODY

{

margin: 10px auto; /* Центрирование BODY (по стандарту) */

text-align: left; /* Выключка текста слева */

}

Посмотрим теперь, как будут вычисляться размеры, если присвоить значение auto одному из отступов и ширине.

14-0.gif (5143 bytes)

В данном случае в ноль обращается отступ margin-right.

Запишем определение:

.block

{

width:auto;

margin-left:50px;

margin-right:auto;

}

Отступ со значением auto обращается в ноль, а width принимает значение, необходимое, чтобы блок заполнил ширину родителя.

Если значение auto принимают все три свойства, то оба отступа обращаются в ноль, а ширина становится максимальной.

Наконец, если всем трем свойствам заданы определенные значения, то свойству margin-right принудительно присваивается auto для языков с написанием слева направо. Для языков с написанием справа налево в auto устанавливается свойство margin-left.

1.3.3.2. Вертикальное форматирование

Вертикальным форматированием блока можно управлять при помощи семи свойств, задающих размеры:

· margin-top — внешний отступ сверху; · padding-bottom — внутренний отступ снизу;

· border-top — рамка слева; · border-bottom — рамка снизу;

· padding-top — внешний отступ слева; · margin-bottom — внешний отступ снизу.

· height — высота содержимого;

Только 3 свойства из 7 могут принимать значение auto :

· margin-top

· height

Алгоритмы работы этих свойств при значении auto основаны на общем правиле вертикального форматирования потока.

По вертикали блок в потоке стремится занять размер по содержимому этого блока.

Если для свойств margin-top или margin-bottom задано значение auto, им автоматически присваивается нулевое значение.

Размер блока со значением height:auto определяется таким образом, чтобы его высоты как раз хватило для размещения содержимого.

1.4. Проблемы размеров и их решение

1.4.1. Проблемы

В этом определении заданы:

· внутренний отступ в 10 пикселей (padding: 10px);

· внешний отступ в 20 пикселей (margin: 20px);

· черная (black) непрерывная (solid) рамка толщиной в 5 пикселей (border: 5px solid black).

Пусть блок задан при помощи кода:

<DIV class=area>

Содержимое блока

</DIV>

 

Напишем для area такое определение:

.area

{

padding: 10px;

margin: 20px;

border: 5px solid black;

width: 400px;

height: 200px;

}

Кроме того, заданы:

· ширина 400 пикселей (width: 400px);

· высота 200 пикселей (height: 200px).

Возникает вопрос: к какому объекту относятся 400 и 200 пикселей?

 

По стандарту W3C эти размеры относятся к содержимому блока.

Браузеры, построенные на движке Gecko (например, Mozilla Firefox), и браузер Opera точно следуют в этом вопросе стандарту W3C.

А вот браузеры Internet Explorer версий 5 и 6 трактуют ширину и высоту блока по-другому. Они считают, что заданные в определении ширина и высота относятся ко всему блоку в целом, исключая внешние отступы.

Таким образом, в IE 5 и IE 6 ширина и высота содержимого блока в соответствии с заданным определением area будут равны:

· ширина содержимого: 400 – 10 – 10 – 5 – 5 = 370 пикселей;

· высота содержимого: 200 – 10 – 10 – 5 – 5 = 170 пикселей.

Эта разница приводит к краху блочной разметки в устаревших (но еще популярных) версиях IE, если разработчик следовал стандартам.

Указанная особенность полностью относится к IE пятых версий и к версии IE6, если в декларации DOCTYPE (см. введение) указан стандарт Transitional (или Frameset). Модель Strict браузер IE6 обрабатывает уже по стандарту W3C.

Самый простой способ избежать обозначенной проблемы — не задавать внутренние отступы и границы для блока, если для него указаны ширина или высота. Отступы и границу можно задавать для родителя или потомков. Если такое решение невозможно, можно воспользоваться трюками, описанными ниже.

1.4.2. Решение Тантека Целика

Решение проблемы описано Тантеком Целиком (Tantek Celik) — сотрудником компании Microsoft — в статье “Box Model Hack”. С русским переводом этой статьи можно ознакомиться на сайте Webmascon (ссылка[7] ) (статья “Трюк с блочной моделью CSS”, ссылка[11]).

Тантек Целик предлагает следующий трюк:

1 .area

2 {

3 padding: 10px;

4 border: 5px solid black;

5 width: 430px; /* подделка для IE5 и IE6 Transitional */

6 height: 230px; /* подделка для IE5 и IE6 Transitional */

7 voice-family: "\"}\"";

8 voice-family:inherit;

9 width: 400px; /* размер содержимого по стандарту */

10 height: 200px; /* размер содержимого по стандарту */

11 }

В строках 5 и 6 задаются ширина и высота блока для IE5 и IE6. Затем в строках 7 и 8 старые браузеры сбиваются с толку правилами CSS2, которые они не понимают. “Умные” браузеры продолжают чтение правил и доходят до строк 9 и 10, в которых указаны размеры по стандарту.

Объясним подробнее, что происходит.

IE5 и IE6 не понимают свойства voice-family, поэтому игнорируют его. Но когда они натыкаются на закрывающую фигурную скобку в строке 7, то воспринимают ее как конец всего определения area (это известный баг этих браузеров). То есть IE5 и IE6 не смогут прочитать строк 9 и 10, в которых указаны значения по стандарту.

Браузеры, которые понимают свойство voice-family, видят, что ему назначено неизвестное значение, и полностью (вместе с “}”) игнорируют его. Чтобы люди, которые сайты не читают, а слушают, могли услышать и этот блок, в строке 8 задается свойство voice-family:inherit: оно указывает, что параметр голоса наследуется от родительского элемента.

Возможно, трюк показался вам сложным, тогда просто запомните инструкцию, не вникая в ее подробности:

· сначала указываем размер блока для IE5 и IE6 (оно равно размеру содержимого плюс суммарный размер внутренних отступов плюс суммарный размер границ);

· потом записываем “магические” строки 7 и 8, чтобы остановить IE5 и IE6;

· наконец, указываем размер блока по стандарту (совпадает с размером содержимого).

С браузером Opera 7 возникает дополнительная проблема. Этот браузер обрабатывает размер блока по стандарту, понимает CSS2, но имеет тот же баг, связанный с разбором выражения "\"}\"", что и IE5, это не позволяет ему прочитать правильный размер в строках 9 и 10.

Для преодоления этой сложности Тантек Целик предложил использовать дополнительное определение (специально для Opera 7):

html>body .area /* Реверанс для Opera 7 */

{

width: 400px; /* размер содержимого по стандарту */

height: 200px; /* размер содержимого по стандарту */

}

Селектор “>” является селектором CSS2 (задает дочернюю зависимость). Этот селектор браузеры IE5 и IE6 не понимают, а Opera поддерживает с версии 5.

1.4.2.1. Пример построения блока

Пусть требуется построить блок area, изображенный на рисунке.

1.4.2.1. Пример построения блока

Пусть требуется построить блок area , изображенный на рисунке.

Решением будет следующий набор CSS-определений:

.area

{

margin: 15px;

border: 5px solid #4d4d4d;

padding: 20px;

width: 450px; /* подделка для IE5 и IE6 Transitional */

height: 350px; /* подделка для IE5 и IE6 Transitional */

voice-family: "\"}\""; /* остановим IE5/6 (трюк Целика) */

voice-family:inherit; /* наследуем голос от родителя */

width: 400px; /* размер содержимого по стандарту */

height: 300px; /* размер содержимого по стандарту */

}

html>body .area /* реверанс для Opera 7 */

{

width: 400px; /* размер содержимого по стандарту */

height: 300px; /* размер содержимого по стандарту */

}

1.4.3. Упрощенные уловки

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

Однако существуют и более простые решения. Опишем два из них.

1.4.3.1. Первая упрощенная уловка

Вот она:

.area

{

width: 400px; /* Для хороших старых браузеров */

\width: 450px; /* Обман для IE5 */

w\idth: 400px; /* Для всех новых хороших браузеров */

}

Трюк основан на использовании символа “\” — обратной косой черты. Это допустимый символ, описанный в стандарте CSS. Он используется в качестве модификатора, меняющего специальный смысл следующего за ним знака на обычный.

Рассмотрим пример. Приведенное ниже определение задает рамку для всех картинок, у которых атрибут alt имеет значение "Фото класса":

IMG[alt="Фото класса"] { border: 1px solid black }

Кавычки, окружающие строку, являются специальными символами языка. А что если кавычки нужны внутри строки? Вот здесь нам и поможет символ “\”:

IMG[alt="Фото 5\"А\" класса"] { border: 1px solid black }

Обратная косая черта отменяет специальный смысл кавычки, которая следует непосредственно за ней.

А если у символа нет специального смысла? Значит, и отменять нечего, символ остается прежним. Использовать обратную косую черту можно не только в записи строки, но и в записи идентификатора. Таким образом, \width и w\idth полностью эквивалентны width. Какой же смысл в приведенном трюке?

.area

{

width: 400px; /* Для хороших старых браузеров */

\width: 450px; /* Обман для IE5 */

w\idth: 400px; /* Для всех новых хороших браузеров */

}

Первая строка уловки — для тех браузеров, которые работают по стандарту, но не понимают модификатора (к ним относится, например, браузер Opera 5). Эти браузеры будут рассматривать символ “\” как обычный знак, входящий в состав имени свойства, не “узнают” width и пропустят строки 2 и 3.

Вторая строка — для браузера IE5, который работает не по стандарту, не считает обратную косую черту модификатором в середине слова, но, по счастью, считает этот знак модификатором, если с него слово начинается. Таким образом, IE5 (и IE6, если он работает в режиме IE5) сначала прочитает 400px в первой строке, потом изменит это значение на 450px из второй строки, а третью строку проигнорирует.

Третья строка — для совсем хороших браузеров: тех, которые работают во всем по стандарту, в том числе правильно понимают символ обратной косой черты.

Пример построения блока

 

Пусть требуется построить блок area, изображенный на рисунке.

Решением будет следующий набор CSS-определений:

.area

{

margin: 15px;

border: 5px solid #4d4d4d;

padding: 20px;

width: 400px; /* Для хороших старых браузеров по стандарту */

\width: 450px; /* Обман для IE5 */

w\idth: 400px; /* Для всех новых хороших браузеров по стандарту */

height: 400px; /* Для хороших старых браузеров по стандарту */

\height: 450px; /* Обман для IE5 */

he\ight: 400px; /* Для всех новых хороших браузеров по стандарту */

}

Нельзя было записать h\eight по следующей причине. Знак “\” используется и для кодирования символов 16-ричными цифрами. Если за обратной косой чертой следует один из знаков 0-9, a, b, c, d, e, f, то это воспринимается как начало 16-ричного кода.

Отметим заодно еще одну функцию обратной косой черты — обозначать продолжение записи на следующей строке:

IMG[alt="Фото класса, которое было выполнено \

Петром Ивановичем Сидоровым, классным \

руководителем (во всех смыслах)"]

{ border: 1px solid black }

1.4.3.2. Вторая упрощенная уловка

Вторая уловка представлена следующими правилами:

.area

{

width: 400px; /* Для всех хороших браузеров */

}

 

* HTML .area /* Это правило понимают только IE */

{

width: 450px; /* Обман для IE5 */

w\idth: 400px; /* Для хороших IE */

}

По стандарту в корне иерархии элементов страницы расположен элемент HTML. Именно так строят объектную модель страницы все браузеры, кроме IE. Браузеры IE располагают в корне некий безымянный элемент, а HTML содержится в нем уже как потомок.

Селектор * HTML .area определяет элементы с классом area, которые являются потомками элемента HTML, который, в свою очередь, является потомком какого-либо другого элемента (селектор *).

Для любого браузера, кроме IE, селектор * HTML .area не указывает ни на один объект, так как нет элементов, у которых потомком был бы HTML. Таким образом, этот селектор сработает только для IE.

Пример построения блока

 

Пусть требуется построить блок area, изображенный на рисунке.

Решением будет следующий набор CSS-определений:

.area

{

margin: 15px;

border: 5px solid #4d4d4d;

padding: 20px;

width: 400px; /* По стандарту */

height: 400px; /* По стандарту */

}

* HTML .area /* Это правило понимают только IE */

{

width: 450px; /* Обман для IE5 */

w\idth: 400px; /* Для хороших IE */

height: 450px; /* Обман для IE5 */

he\ight: 400px; /* Для хороших IE */

}

Представительный набор CSS-уловок (с подробным описанием) собран в удобную таблицу на странице CSS-only Filters Summary (ссылка[12]).

1.5. Как работает браузер. Верстка потоком

1.5.1. Дизайн кода и слепой браузер

Благовоспитанный разработчик трепетно заботится о дизайне своего кода: короткие строки, пустые промежутки, отступы вправо, выравнивание — все идет в ход для создания соответствия между логической структурой кода и его внешним видом.

В правильно сверстанном коде иерархическая лесенка подпирает теговый каркас на блочных элементах и почти не мешает читать содержание (строчные элементы), набранное по обычным правилам — ровный край слева и максимально ровный край справа:

<BODY>

<H1>Дизайн кода<H1> <!-- Первый раздел -->

<P>

В <EM>правильно сверстанном коде</EM> иерархическая лесенка подпирает теговый каркас на <EM>блочных элементах</EM> и почти не мешает читать содержание (<EM>строчные элементы
</EM>), набранное по обычным правилам&nbsp;&#8212; ровный край слева и максимально ровный край справа.

</P>

</BODY>

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

<BODY> <H1>Дизайн кода<H1> <P> В <EM>правильно сверстанном коде</EM> иерархическая лесенка подпирает теговый каркас на <EM>блочных элементах</EM> и почти не мешает читать содержание (<EM>строчные элементы</EM>), набранное по обычным правилам&nbsp;&#8212; ровный край слева и максимально ровный край справа. </P> </BODY>

Перед браузером стоит задача отобразить одномерную строку кода на двумерную поверхность своего окна.

Посмотрим, как браузер выполняет эту работу по умолчанию, то есть когда в его деятельность не вмешиваются позиционированные (см. 2) и плавающие (перемещаемые) (см. 3) элементы. Такая верстка называется потоком.

В описаниях стандарта (смотрите, например, описание CSS2.1, ссылка[1]) используется термин “normal flow” — нормальный поток. Так как “ненормальных” потоков нет, для краткости будем говорить просто поток.

“Ненормальным” потоком можно было бы назвать поток, в котором есть перемещаемые (плавающие) элементы, так как они заставляют “нормальные” элементы себя обтекать.

1.5.2. Верстка потоком

 

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

По умолчанию браузер выводит блочные элементы друг за другом сверху вниз. При этом ширина блочного элемента совпадает с доступной шириной родителя (его свойством width), а высота определяется по содержимому.

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

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

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

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

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

1.6. Пример построения меню на вкладках

Постановка задачи: построить меню, изображенное на рисунке:

Много говорилось о преимуществах CSS, о том, как этот механизм позволяет сократить код HTML, сделать его простым, логичным, полностью удалить из него визуальное наполнение, упростить будущие правки и тем не менее сохранить контент доступным для тех средств просмотра, которые не поддерживают CSS (старые браузеры, карманные компьютеры и мобильные телефоны).

Построим меню на вкладках, используя верстку потоком.

1.6.1. HTML-код

Вот так это выглядит в браузере (поток/меню на вкладках/шаг 1).

Именно так меню отобразится в средствах просмотра, которые не поддерживают CSS: старые браузеры, мобильные телефоны, карманные компьютеры. Конечно, красот нет, но функциональность — полная.

Меню — это список. Поэтому логично оформить его в виде списка HTML:

<UL class="menu">

<LI class=first><SPAN>начало</SPAN>

<LI><A href="01.htm">страница 1</A>

<LI><A href="02.htm">страница 2</A>

<LI><A href="03.htm">страница 3</A>

<LI><A href="04.htm">страница 4</A>

</UL>

Вы не поверите, но это все! Больше к этому HTML мы не прикоснемся. Мы описали структуру, а все визуальные изыски переложим на CSS. Здорово, правда?

Чтобы связать нашу HTML-конструкцию с определениями CSS, блоку-контейнеру UL присвоен класс menu.

Мы будем по-другому отображать пункт, относящийся к текущей странице, вот почему он “обернут” в строчный элемент SPAN. Остальные пункты доступны по селектору .menu A, а этот — по селектору .menu SPAN.

Наконец, первый элемент списка выделен классом first. Только для того, чтобы можно было задать для него внешний отступ слева. Конечно, можно было бы не заводить этот класс и получить доступ к первому потомку блока UL при помощи селектора .menu LI:first-child, но IE-6 не понимает этого указания.

1.6.2. Применим CSS

Вначале сформулируем правила CSS, которые сделают список горизонтальным. Заодно добавим фоновую полоску и зададим свойства шрифта.

.menu

{

margin:0; /* удалим списочный отступ */

list-style:none; /* запретим показывать маркер */

white-space:nowrap; /* запретим переносить строку */

background: #ffcd2d; /* фоновая полоска */

}

 

.menu LI

{

display:inline; /* превратим LI в строчный элемент */

font-family: Arial, sans-serif;

font-size:70%;

}

 

.menu LI.first /* отступ первого LI */

{

margin-left:40px;

}

Вот что теперь мы увидим на экране (поток/меню на вкладках/шаг 2).

1.6.3. Придадим вкладкам форму

.menu A, .menu SPAN /* правила для всех вкладок */

{

border: 1px solid #9b8748; /* рамка */

padding:2px 6px; /* отступы */

color:#333; /* серый цвет шрифта */

background: #f9e9a9; /* фон вкладки */

text-decoration: none; /* уберем подчеркивание со ссылок */

}

 

.menu SPAN /* переопределения для вкладки текущей страницы */

{

border-color: black; /* черный цвет для рамки */

background: white; /* белый цвет фона */

color:black; /* черный цвет для шрифта */

}

 

Получили такое изображение (поток/меню на вкладках/шаг 3).

Может показаться странным, что вкладки вышли по вертикали за пределы содержащего их блока menu. Однако это не баг, а следование алгоритму построения строк в потоке, который мы обсуждали в разделе “Архитектура и поведение элемента” (см. 1.2.4).

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

.menu

{

margin:0; /* удалим списочный отступ */

list-style:none; /* запретим показывать маркер */

white-space:nowrap; /* запретим переносить строку */

background: #ffcd2d; /* фоновая полоска */

padding: 14px 0 2px 0px; /* расширение фоновой полоски */

}

Получается гораздо лучше (поток/меню на вкладках/шаг 4).

Теперь нужно провести черную линию снизу у общего фона, а также изменить цвет нижней рамки у всех вкладок: у всех A — на черный, а у вкладки SPAN — на белый.

.menu

{

margin:0; /* удалим списочный отступ */

list-style:none; /* запретим показывать маркер*/

white-space:nowrap; /* запретим переносить строку*/

background: #ffcd2d; /* фоновая полоска */

padding: 14px 0 2px 0px; /* расширение фоновой полоски */

border-bottom: 1px solid black; /* черная рамка снизу */

}

.menu A, .menu SPAN /* правила для всех вкладок */

{

border: 1px solid #9b8748; /* рамка */

padding:2px 6px; /* отступы */

color:#333; /* серый цвет шрифта */

background: #f9e9a9; /* фон вкладки */

text-decoration: none; /* уберем подчеркивание ссылок */

border-bottom-color: black; /* черный цвет у рамки снизу */

}

.menu SPAN /* переопределения для вкладки текущей страницы */

{

border-color: black; /* черный цвет для рамки */

background: white; /* белый цвет фона */

color:black; /* черный цвет для шрифта */

border-bottom-color: white; /* белый цвет у рамки снизу */

}

Получается практически готовый результат (поток/меню на вкладках/шаг 5).

Картинки увеличены в 10 раз и показаны на темном фоне, чтобы увидеть белую полоску сверху толщиной в 1 пиксель.

Для придания объема вкладкам придется взять в руки графический редактор и создать две небольшие картинки с вертикальной градиентной заливкой и белой полоской сверху.

Цветовая растяжка для вкладки SPAN заканчивается белым цветом, чтобы слиться с фоном страницы, а для вкладок A — цветом #f9e9a9, который определен для них в качестве фонового.

Мы собираемся замостить картинками фон вкладок по горизонтали, поэтому для ширины достаточно взять размер в 1 пиксель. Реальная ширина — 10 пикселей, так как Самизнаетекакой браузер замедляется при замощении фона малопиксельной картинкой.

Подключим созданные картинки при помощи следующих CSS-правил:

.menu A, .menu SPAN /* правила для всех вкладок */

{

border: 1px solid #9b8748; /* рамка */

padding:2px 6px; /* отступы */

color:#333; /* серый цвет шрифта */

text-decoration: none; /* уберем подчеркивание со ссылок */

border-bottom-color: black; /* черный цвет у рамки снизу */

background: #f9e9a9 url(pic/offkey.png) repeat-x top left; /* фон вкладки */

}

.menu SPAN /* переопределения для вкладки текущей страницы */

{

border-color: black; /* черный цвет для рамки */

color:black; /* черный цвет для шрифта */

border-bottom-color: white; /* белый цвет у рамки снизу */

background: white url(pic/onkey.png) repeat-x top left; /* фон вкладки */

}

Вот как это выглядит в окне браузера (поток/меню на вкладках/шаг 6).

23-0.gif (5717 bytes)

1.6.4. Динамические свойства ссылок

Воспользуемся псевдоклассами, которые задают свойства ссылок:

/* Динамические свойства ссылок */

.menu A:link {color:#333} /* цвет непосещенной ссылки */

.menu A:visited {color:purple} /* цвет посещенной ссылки */

.menu A:hover /* когда курсор над ссылкой */

{

background: #ff7f00 url(pic/hoverkey.png) repeat-x top left;

color:white;

border-color: white;

border-bottom-color: black;

}

.menu A:active {color:red} /* цвет активной ссылки */

Для события A:hover пришлось нарисовать еще одну фоновую картинку (hoverkey.png). Теперь, когда курсор над ссылкой, ссылка сигналит о своей готовности выполнить переход (поток/меню на вкладках/шаг 7 — работают переходы на страницу 1 и начало).

23-1.gif (5876 bytes)

Порядок, в котором идут определения стилей ссылок, важен. Он должен подчиняться правилу LVHA: A:link, A:visited, A:hover, A:active.

Почему так? Потому что эти правила работают вместе и могут конфликтовать. При щелчке на непосещенной ссылке, например, последняя сопоставляется с тремя правилами — A:link, A:hover и A:active. Побеждает то правило, которое идет последним.

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

A:active { ... }

A:hover { ... }

A:link { ... }

A:visited { ... }

При таком расположении определений ни одна из ссылок никогда не продемонстрирует стили A:hover и A:active, потому что всегда будут побеждать правила A:link и A:visited, которые идут последними.

1.6.5. Подключаем JavaScript

В самом начале раздела мы записали меню в виде:

<UL class="menu">

<LI class=first><SPAN>начало</SPAN>

<LI><A href="01.htm">страница 1</A>

<LI><A href="02.htm">страница 2</A>

<LI><A href="03.htm">страница 3</A>

<LI><A href="04.htm">страница 4</A>

</UL>

Это меню — для главной страницы сайта. На странице 1 оно будет иметь вид:

<UL class="menu">

<LI class=first><A href="index.htm">начало</A>

<LI><SPAN>страница 1</SPAN>

<LI><A href="02.htm">страница 2</A>

<LI><A href="03.htm">страница 3</A>

<LI><A href="04.htm">страница 4</A>

</UL>

Аналогично меню записываются и для других страниц сайта: для текущей страницы элемент A заменяется элементом SPAN.

Несложно, но… все же придется повозиться с каждой страницей, утешаясь тем, что эта работа выполняется один раз.

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

Ужасно! Мы поместили визуальное представление объекта в отдельный файл и гордо заявляем, что для правки внешнего вида придется править только один этот файл CSS, а не сотни файлов HTML.

Какой казус! Но решение есть. Пустим в ход моторчик JavaScript: напишем функцию putmenu. У этой функции будет один параметр — номер текущей страницы.

Тогда меню на начальной странице будет задаваться так:

<!-- Меню -->

<SCRIPT language="JavaScript" type="text/javascript">

<!--

putMenu(0);

//-->

</SCRIPT>

На странице 1 так:

<!-- Меню -->

<SCRIPT language="JavaScript" type="text/javascript">

<!--

putMenu(1);

//-->

</SCRIPT>

И так далее. Определение функции поместим в отдельный файл JS, а в головной части каждого HTML поставим ссылку на этот файл (main.js). Заметим, что ссылка на файл со стилями (main.css) давно уже присутствовала:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ru">

<HEAD>

<META http-equiv="Content-Type" content="text/html; charset=windows-1251">

<META http-equiv="author" content="А. А. Дуванов">

<META http-equiv="Content-Style-Type" content="text/css">

<!--LINK rel="stylesheet" type="text/css" href="main.css" -->

<STYLE type="text/css">@import url(main.css);</STYLE>

<SCRIPT language="JavaScript" type="text/javascript" src="main.js"></SCRIPT>

<TITLE>Заголовок окна</TITLE>

</HEAD>

<BODY>

<H1>Заголовок сайта</H1>

<!-- Меню -->

<SCRIPT language="JavaScript" type="text/javascript">

<!--

putMenu(0);

//-->

</SCRIPT>

<H2>Заголовок страницы</H2>

<P>Содержание</P>

</BODY>

</HTML>

Заметим, что для подключения файла со стилями использована директива @import вместо обычного указания LINK, которое закомментировано. Директиву @import понимают только современные браузеры, поэтому старые загрузить стили не смогут. И это хорошо! Например, Netscape Navigator 4 “думает”, что он понимает CSS, и превращает страницу в кашу. Пусть лучше он показывает сайт без всяких стилей. Красот не будет, но функциональность останется.

1.6.5.1. Разработка функции putmenu

Создаем пустой файл main.js и начинаем работу. Прежде всего опишем данные.

// Пункты меню

// -----------

var ItemsMenu = new Array (

new Array ("начало", "index.htm"),

new Array ("страница 1", "01.htm"),

new Array ("страница 2", "02.htm"),

new Array ("страница 3", "03.htm"),

new Array ("страница 4", "04.htm"),

new Array ("ссылки", "links.htm")

);

// Константы

// ---------

var classMenu = "menu"; // Имя CSS-класса меню

var classFirstLi = "first"; // Имя CSS-класса первого элемента списка

Пункты меню размещаются в двумерном массиве ItemsMenu:

· ItemsMenu[i][0] — название i-го пункта;

· ItemsMenu[i][1] — имя файла для i-го пункта.

А теперь код самой функции:

// Построение меню

// ---------------

// Функция строит меню вида (в <SPAN> обертывается текущая страница):

// <UL class="menu">

// <LI class=first><SPAN>начало</SPAN>

// <LI><A href="01.htm">страница 1</A>

// <LI><A href="02.htm">страница 2</A>

// ...

// </UL>

function putMenu(page) // page -- номер текущей страницы в ItemsMenu

{

var str = '<UL class="'+ classMenu + '">';

for (var i = 0; i<ItemsMenu.length; i++)

{

str += '<LI' + (i ? '' : (' class="' + classFirstLi + '"')) + '>';

if (i == page)

str += '<SPAN>' + ItemsMenu[i][0] + '</SPAN></LI>';

else

str += '<A href="' + ItemsMenu[i][1] +

'">' + ItemsMenu[i][0] + '</A></LI>';

}

str += '</UL>';

document.write(str);

}

Функция формирует HTML-код в строке str и выводит его в окно браузера с помощью метода document.write.

Посмотрим результат (поток/меню на вкладках/шаг 8 — работают переходы на все страницы).

26-0.gif (6229 bytes)

Замечаем, что исчезли промежутки между вкладками.

Эти промежутки были благодаря концам строк в записи списка UL. Как известно, браузер воспринимает конец строки как пробел, поэтому расстояние между вкладками было равно ширине пробела текущего шрифта. HTML-код на JavaScript мы формировали плотно, без всяких пробелов, вот промежутки и пропали.

Ура, если с самого начала вам казалось, что промежутков и не должно быть. Если же, напротив, они кажутся необходимыми, то их легко восстановить, добавив нужное указание в стилевые свойства:

.menu LI

{

display:inline; /* превратим LI в строчный элемент */

font-family: Arial, sans-serif;

font-size:70%;

margin-left:0.5em;

}

1.6.6. Что мы получили

Мы создали один файл CSS, в который вынесли весь визуальный образ объекта. Мы создали один файл JavaScript, в котором расположили формирование HTML-кода объекта в зависимости от номера страницы. Мы создали много файлов HTML, в которых объект строится при помощи функции на JavaScript.

В итоге возникли следующие преимущества.

· Мы отделили структуру объекта от его визуального образа, полностью перенеся последний в CSS-файл.

· HTML-код объекта получился предельно простым и коротким. Он отражает только структуру и не содержит никакого визуального мусора (картинок, таблиц).

· Небольшой HTML-код объекта был еще сокращен до вызова единственной функции putmenu на JavaScript.

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

· Кроме того, мы облегчили себе работу по редактированию сайта. Если нужно поменять визуальный образ объекта, мы будем работать с единственным файлом CSS, а не с сотнями файлов HTML. Если нужно поменять содержание объекта, мы будем работать с единственным файлом JavaScript, а не с сотнями файлов HTML.

· В построенном меню хорошо видны посещенные ссылки — они отображаются пурпурным цветом. Значит, пользователь не будет дважды щелкать по одной ссылке, просматривая страницы сайта.

· Попробуйте увеличить или уменьшить размер шрифта в браузере. Наше меню автоматически масштабируется, радуя глаза пользователя. Попробуйте менять ширину окна — меню снова устояло, оно не разваливается на куски, не превращается в кашу.

· Попробуйте посмотреть на наше меню в браузере без CSS. Оно имеет понятный вид списка и работает, как ни в чем не бывало.

Ах, какие же мы молодцы!

Тема 2. Позиционирование

 

Позиционирование — это управление размещениемразмерами, как это не покажется странным) элемента в окне браузера.

CSS предлагает для позиционирования свойство position. Значения этого свойства:

· absolute (абсолютное позиционирование);

· fixed (фиксированное позиционирование);

· relative (относительное позиционирование);

· static (статическое позиционирование).

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

Содержание темы

2.1. Абсолютное позиционирование (absolute)

2.2. Фиксированное позиционирование (fixed)

2.3. Относительное позиционирование (relative)

2.4. Пример (построение сайта “Роботландия”)

2.5. Продолжение 1

2.6. Продолжение 2

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

Сначала рассмотрим абсолютное позиционирование блочных элементов, а затем уточним приведенные алгоритмы для строчных элементов.

2.1.1. Позиционирование блочных элементов

Абсолютно позиционированный блок изымается из потока и может располагаться в любом месте над потоком (перекрывая его).

По умолчанию браузер выполняет верстку потоком: блоки выводятся прямоугольниками сверху вниз, занимая всю доступную ширину (свойство width) родителя (вместе с границами и всеми своими отступами).

Если для какого-то блока указать абсолютное позиционирование (position:absolute), он изымается из потока, а на его место подтягиваются блоки, которые шли за ним в потоке.

Идентификаторы или классы?

CSS-определение можно связать с элементом при помощи класса (class=имя) или идентификатора (id=имя). Нужно помнить только одно важное правило:

Элементов с одним и тем же классом может быть на странице много, а каждый идентификатор — уникален.

Идентификаторы удобны, когда с элементом планируется связать не только CSS, но и JavaScript.

Поставим несколько опытов. Зададим на странице три блока:

<BODY>

<DIV id=block1>Блок 1</DIV>

<DIV id=block2>Блок 2</DIV>

<DIV id=block3>Блок 3</DIV>

</BODY>

Чтобы прямоугольники, ограничивающие блоки, были лучше видны, зададим границы, внутренние отступы и фон:

Как и ожидалось, блоки выводятся потоком, сверху вниз, занимая по ширине все пространство родителя BODY.

BODY { margin:0; padding:0; }

#block1, #block2, #block3

{

border: 1px solid black;

background:cyan;

padding: 10px;

text-align:right;

}

Что произошло:

· блок изъят из потока;

· занимает положение “выше” потока (по отношению к читателю);

· координаты верхнего левого угла не изменились;

· размеры установились по содержимому.

Зададим для второго блока абсолютное позиционирование и покрасим его в другой цвет:

#block2

{

position:absolute;

background:#fff2a6;

}

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

 

Абсолютно позиционированный блок можно поместить в любое место, задавая смещения при помощи свойств: left, top, right, bottom.

 

Иллюстрация демонстрирует положения блока при разных наборах свойств left, top,right и bottom.

Например, поместить блок в левый верхний угол можно при помощи определения:

#block2

{

position:absolute;

left:0;

top:0;

background:#fff2a6;

}

Если смещения, задающие координаты левого верхнего угла, не заданы, то они сохраняют значения, которые имели бы в потоке.

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

Если задать только одно смещение (например, left), второе (top) сохранит то значение, которое имелось бы у блока в потоке.

#block2

{

position:absolute;

left:100px;

background:#fff2a6;

}

Так как задано нулевое расстояние блока от левого и правого краев, он вынужден растягиваться, занимая всю ширину (вместе с границей и всеми своими отступами).

Можно задавать три и более смещений, и тогда это повлияет на размеры позиционированного блока:

#block2

{

position:absolute;

top:120px;

left:0;

right:0;

background:#fff2a6;

}

Возникает важный вопрос: относительно чего указываются смещения для абсолютно позиционированного блока?

Простой ответ “относительно родительского блока” оказывается верным, если для родителя также задано позиционирование (любое, кроме static). Если это не так, то смещения откладываются от “дедушки”, то есть от родителя родителя. Если “дедушка” не позиционирован, то от его родителя. И так далее до корня иерархии, то есть до HTML.

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

Так как BODY не позиционирован, смещения отсчитываются от HTML, то есть от границ документа. Именно документа, а не области просмотра.

Область просмотра (viewport) перемещается по документу при скролировании, и верхний левый угол документа уходит за ее пределы.

В рассмотренном примере смещения отсчитывались именно от HTML, так как элемент BODY не был позиционирован:

BODY { margin:0; padding:0; }

#block1, #block2, #block3

{

border: 1px solid black;

background:cyan;

padding: 10px;

text-align:right;

}

#block2

{

position:absolute;

left:100px;

right:100px;

background:#fff2a6;

}

Видим, что положение позиционированного блока на экране не изменилось.

Чтобы убедиться, что начало отсчета связано именно с HTML, зададим для BODY внешний отступ:

BODY

{

margin:50px;

padding:0;

}

Смещения блока стали отсчитываться от BODY. Само BODY осталось на месте, так как для него смещения не заданы.

А теперь назначим для BODY относительное позиционирование (не задавая никаких смещений):

BODY

{

position: relative;

margin:50px;

padding:0;

}

Зададим для BODY толстую синюю рамку (border: 10px solid blue), внутренний отступ (padding:10px;), а для блока укажем нулевые left и top.

Блок “прилип” к левому верхнему углу внутреннего отступа BODY.

Это означает, что начало координат для left и top совпадает именно с этой точкой.

Эта точка относится к первому предку, который позиционирован, или к HTML, если другие позиционированные предки отсутствуют.

Стало понятным, откуда отсчитываются смещения — от внешней границы внутреннего отступа первого позиционированного предка.

Разберемся теперь с тем, до каких именно границ смещаемого блока они распространяются.

Внутренний отступ у нас уже задан для всех блоков. Увеличим ширину границы и зададим внешний отступ для второго блока:

Внешний край внешнего отступа смещаемого блока условно обозначен пунктирной линией. Именно он “прилип” к началу координат.

#block2

{

position:absolute;

background:#fff2a6;

left:0; top:0;

margin:20px;

border: 10px solid red;

}

Видим, что смещение распространяется до внешнего края внешнего отступа смещаемого блока.

 

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

Смещения left, top, right и bottom для абсолютно позиционированного блока отсчитываются от сторон прямоугольника, проведенного по внешней границе внутреннего отступа первого позиционированного предка (или HTML, если другие позиционированные предки отсутствуют).

Смещения распространяются до внешних краев внешних отступов смещаемого блока. То есть у блока смещается все: внешние отступы, рамка, внутренние отступы и содержимое.

Ранее был рассмотрен пример, в котором для абсолютно позиционированного блока одновременно задавались противоположные смещения (left:0 и right:0).

К сожалению, одновременное указание противоположных смещений не работает в браузере IE (он выполняет left:0, но игнорирует right:0). Подробнее об этом в следующем разделе.

2.1.2. Проблема противоположных смещений

Рассмотрим пример, в котором для абсолютно позиционированного блока одновременно задаются противоположные смещения (left:0 и right:0).

31-0.gif (5499 bytes)

Так как задано нулевое расстояние блока от левого (left:0) и правого (right:0) краев, он вынужден растягиваться, занимая всю ширину позиционированного родителя (вместе с границами и всеми своими отступами).

BODY

{

position:relative;

margin:0; padding:0;

}

#block1, #block2, #block3

{

border: 1px solid black;

padding: 10px;

background:cyan;

text-align:right;

}

#block2

{

position:absolute;

top:120px;

left:0; right:0;

background:#fff2a6;

}

 

К сожалению, одновременное указание противоположных смещений не работает в браузере IE (он выполняет left:0, но игнорирует right:0).

Для IE можно написать отдельную строку, в которой нужная ширина блока будет вычисляться при помощи выражения на JavaScript:

/* Это работает во всех современных браузерах */

#block2

{

position:absolute;

top:120px;

left:0;

right:0; /* IE это указание игнорирует, поэтому специально для него

указываем ширину блока выражением на JavaScript: */

width: expression(this.parentNode.offsetWidth-22);

background:#fff2a6;

}

Для свойства width указано значение функции expression от выражения на JavaScript. Здесь:

· this — текущий блок;

· this.parentNode — родитель текущего блока;

· this.parentNode.offsetWidth — ширина родителя;

· 22 — сумма padding'ов и border'ов с двух сторон текущего блока.

Показанный прием обеспечивает правильную работу во всех браузерах. Все, кроме IE, правильно отработают right:0 и пропустят expression, так как не понимают этой функции. IE, наоборот, пропустит right:0 (или left:0 для языков с написанием справа налево), зато выполнит expression.

Блок вылезает за пределы окна на 22 пикселя, и появляется линейка прокрутки.

Прокрутка будет в окне любого размера, ибо 100% относятся к содержимому блока, а вместе с отступами и границами получается 100% + 22.

Казалось бы, проблему можно решить проще, указав width:100%:

/* Это не работает */

#block2

{

position:absolute;

top:120px;

left:0;

width:100%;

background:#fff2a6;

}

2.1.3. Позиционирование строчных элементов

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

Пусть HTML-код записан в следующем виде:

<BODY>

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

<P>

В этом абзаце есть <STRONG>выделенный фрагмент текста</STRONG>.

Для этого фрагмента задано абсолютное позиционирование.

</P>

</BODY>

Позиционирование не задано ни для одного элемента, поэтому свойства left и top, заданные для STRONG, игнорируются.

Игнорируется и свойство width, ведь элемент STRONG — строчный, а для строчных элементов свойства width и height не работают.

Зададим стилевые правила:

BODY { margin:10px; padding:0px; }

P { border: 1px solid black; }

STRONG

{

left:100px; top:150px;

width:10em;

padding:10px;

background:cyan;

border: 1px solid black;

}

Элемент STRONG превратился в блочный и сместился на заданные расстояния по отношению к HTML, так как ни родитель P, ни дедушка BODY не позиционированы.

Зададим для STRONG абсолютное позиционирование:

STRONG

{

position: absolute;

left:100px; top:150px;

width:10em;

padding:10px;

background:cyan;

border: 1px solid black;

}

Теперь смещения элемента STRONG отсчитываются от позиционированного родителя P.

Добавим к свойствам P относительное позиционирование (без каких-либо смещений):

P

{

position: relative;

border: 1px solid black;

}

2.1.4. Значение auto

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

Рассмотрим этот вопрос подробнее. Пусть HTML-код записан в следующем виде:

<BODY>

<H1>Значение auto</H1>

<P>

В этом абзаце есть выделенное <STRONG>слово</STRONG><SPAN>*</SPAN>.

За этим словом следит маркер в виде красной звездочки.

</P>

</BODY>

33-0.gif (5860 bytes)

Вот так выглядит изображение, когда не заданы стили.

33-1.gif (6448 bytes)

Абсолютно позиционированная звездочка прилипла к левой границе BODY — первого своего позиционированного предка. Так произошло потому, что задано left:0.

Смещение по вертикали осталось таким, каким было в потоке. Так произошло потому, что задано: top:auto.

Зададим следующий набор определений:

BODY

{

position: relative;

margin: 10px 10px 10px 2em;

border-left: 1px dotted black;

padding-left: 10px;

}

SPAN

{

position: absolute;

left:0;

top:auto;

color:red;

font-weight:bold;

}

33-2.gif (6494 bytes)

Для смещений разрешается задавать отрицательные значения.

Сместим звездочку в левый внешний отступ BODY, задав отрицательное смещение для left:

SPAN

{

position: absolute;

left:-1em;

top:auto;

color:red;

font-weight:bold;

}

33-3.gif (6923 bytes)

Маркер действительно следит за выделенным словом.

Уменьшим ширину окна так, чтобы выделенное слово переместилось в следующую строку. Звездочка так же сместилась на строку ниже. Смещение top получает то значение, которое элемент имел бы в потоке.

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

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

2.2. Фиксированное позиционирование

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

На базе значения fixed можно построить, например, навигационное меню, которое всегда остается под рукой пользователя.

Запишем соответствующий код HTML:

<BODY>

<!-- Меню, которое не должно скролироваться -->

<DIV class="menu">

<UL>

<LI>пункт 1

<LI>пункт 2

<LI>пункт 3

<LI>пункт 4

<LI>пункт 5

</UL>

</DIV>

<DIV class="content">

Длинное содержание страницы

</DIV>

</BODY>

34-0.gif (17554 bytes)

Для блока content задан левый внешний отступ размером в 170 пикселей. Меню позиционировано в освободившееся пространство.

Так как для меню задано position:fixed, при прокрутке оно сохранит свое положение в окне (не будет скролироваться вместе с содержимым).

Стилевые определения построим так:

BODY {margin:0; padding:0}

.menu

{

position:fixed;

width:150px;

top:10px; left:10px;

border: 1px solid black;

background:#fff2a6;

}

.content

{

margin: 10px 10px 10px 170px;

padding:10px;

border: 1px solid black;

background:#a7fbc0;

}

Сделаем два важных для практики замечания.

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

При горизонтальной прокрутке контент может “подлезть” под фиксированный блок и перекрыться им.

К сожалению, фиксированное позиционирование не поддерживают браузеры IE вплоть до версии IE7 (здесь поддержка включена).

Рассмотрим возможные способы моделирования фиксированного позиционирования при помощи абсолютного.

2.2.1. Вариант 1

Все изменения (по отношению к предыдущему набору определений) выделены:

HTML

{

width:100%; height:100%;

overflow:hidden;

}

BODY

{

width:100%; height:100%;

margin:0; padding:0;

overflow:auto;

}

Для меню назначено абсолютное позиционирование. Первым позиционированным предком для этого блока является HTML, поэтому смещения top:10px и left:10px будут отсчитываться именно от него.

Но для HTML запрещена прокрутка (overflow:hidden), поэтому меню останется неподвижным вместе с ним.

Напротив, для BODY прокрутка разрешена (overflow:auto), поэтому содержимое будет нормально прокручиваться при необходимости.

.menu

{

position:absolute;

width:150px;

top:10px; left:10px;

border: 1px solid black;

background:#fff2a6;

}

.content

{

margin: 10px 10px 10px 170px;

padding:10px;

border: 1px solid black;

background:#a7fbc0;

}

2.2.2. Вариант 2

Рассмотрим еще один способ, в котором фиксированное позиционирование задается для всех браузеров, а для IE моделируется абсолютным при помощи JavaScript.

Стилевые правила зададим следующим образом:

BODY

{

margin:0; padding:0;

/* Зафиксируем фон, чтобы не было дрожаний */

background: url(empty.gif) no-repeat;

background-attachment: fixed;

}

.menu

{

width:150px;

top:10px; left:10px;

border: 1px solid black;

background:#fff2a6;

/* Для хороших браузеров */

position:fixed;

/* Для IE */

//position: absolute;

top: expression(eval(document.body.scrollTop ?

(document.body.scrollTop+10) :

(document.documentElement.scrollTop+10))+"px");

}

.content

{

margin: 10px 10px 10px 170px;

padding:10px;

border: 1px solid black;

background:#a7fbc0;

}

Строка с expression выглядит немного жутковато, но в ней нет ничего сложного, как мы увидим. Давайте разбираться по порядку.

В определении для content ничего не изменилось.

Для BODY задан фиктивный фоновый рисунок empty.gif (такого файла нет в каталоге) и задано свойство background-attachment: fixed, обеспечивающее неподвижность фона при скролировании. Все это сделано, чтобы избежать дрожания меню при скролировании окна в IE. Эта уловка описана в Техногрете (ссылка[8]) студии Лебедева в статье Андрея Шитова “Полноценный fixed в MSIE”.

Наконец, подойдем к самому главному — к описанию свойств menu. Начало вполне добропорядочно, оно устанавливает position:fixed для “хороших” браузеров и задает смещения блока (top и left ):

.menu

{

width:150px;

top:10px; left:10px;

border: 1px solid black;

background:#fff2a6;

/* Для хороших браузеров */

position:fixed;

...

}

Следующая строка переустанавливает свойство position в absolute для браузеров IE:

.menu

{

width:150px;

top:10px; left:10px;

border: 1px solid black;

background:#fff2a6;

/* Для хороших браузеров */

position:fixed;

/* Для IE */

//position: absolute;

top: expression(eval(document.body.scrollTop ?

(document.body.scrollTop+10) :

(document.documentElement.scrollTop+10))+"px");

}

Еще одна особенность IE. Если поставить перед свойством две наклонные черты (//), оно будет восприниматься лишь IE (всех версий). Другие браузеры такое свойство проигнорируют.

Вот и добрались до последней строки. В ней значение для top вычисляется функцией expression, содержащей выражение на JavaScript. Как уже отмечалось в разделе “2.1.2. Проблема противоположных смещений”, функцию expression понимают только браузеры IE.

Что же делает функция expression? Она вычисляет вертикальную координату области просмотра относительно начала документа.

Эту координату содержит свойство scrollTop прокручиваемого объекта. В старых IE таким объектом является document.body , в новых — document.documentElement .

Таким образом, для старых IE нужно записать:

top: expression(document.body.scrollTop);

Для новых:

top: expression(document.documentElement.scrollTop);

Чтобы попасть в оба случая, применим условный оператор, который на JavaScript имеет такую форму:

условие ? выражение1 : выражение2

Работает это так. Проверяется условие. Если оно верное, вычисляется выражение1, иначе выражение2.

В нашем случае в качестве условия записано document.body.scrollTop:

document.body.scrollTop ? выражение1 : выражение2

Если скролл относится к объекту document.body, то при вертикальной прокрутке значение document.body.scrollTop будет отлично от нуля, и условие станет справедливым. Теперь понятно, что надо записать в качестве первого и второго выражений:

document.body.scrollTop ?

document.body.scrollTop :

document.documentElement.scrollTop

Чтобы опустить меню вниз от края окна, добавим 10 к вычисляемым значениям:

document.body.scrollTop ?

(document.body.scrollTop+10) :

(document.documentElement.scrollTop+10)

Наконец, добавим к результату строку "px", как это требует CSS:

eval(document.body.scrollTop ?

(document.body.scrollTop+10) :

(document.documentElement.scrollTop+10))+"px"

Вот так это выглядит в браузере (позиционирование/фиксированное меню/вариант 2).

Если в HTML убрать указание DOCTYPE, то новые IE переключатся в режим совместимости со старыми браузерами, и можно проверить работу кода и в них.

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

Относительное позиционирование задается указанием position: relative.

2.3.1. Как это работает

Если для такого элемента не заданы смещения (при помощи указаний left, right, top, bottom), он ведет себя как статический: остается в потоке и форматируется так, будто позиционирование для него не задано вовсе.

Именно в таком качестве относительное позиционирование применяется чаще всего (без указания смещений). Рассматривая абсолютное позиционирование (см. 2.1.1), мы уже видели, зачем это нужно: таким образом указывается блок-предок, относительно которого отсчитываются смещения для абсолютно позиционированного элемента.

Если для предков позиционирование не задано (static не в счет), смещения будут откладываться от HTML.

Пусть для элемента block2 задано абсолютное позиционирование:

#block2

{

position: absolute;

left: …; top: …;

}

BODY становится началом отсчета, оставаясь в потоке.

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

BODY { position: relative; }

#block2

{

position: absolute;

left: …; top: …;

}

Элемент block1 становится началом отсчета, оставаясь в потоке.

Если за начало отсчета смещений нужно взять block1, задаем позиционирование для него:

.block1 { position: relative; }

#block2

{

position: absolute;

left: …; top: …;

}

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

В качестве примера запишем такой HTML-код:

<BODY>

<H1>Занимательная история</H1>

<P>Первый абзац.

<P class=pos>Второй абзац.

<P>Третий абзац.

</BODY>

Ничего особенного. Все элементы выводятся на экран потоком.

Чтобы блоки абзацев были лучше видны, зададим для них фон (отдельный для второго абзаца) и рамку:

P

{

border: 1px solid black;

background: #a7fbc0;;

}

P.pos { background: #fff2a6; }

Второй абзац сместился по отношению к своему прежнему положению в потоке. Остальные элементы этого “не заметили” — третий абзац не подтянулся на место второго.

Видим, что второй абзац “приподнялся” над потоком и стал перекрывать его.

А теперь зададим для второго абзаца относительное позиционирование и смещения:

P

{

border: 1px solid black;

background: #a7fbc0;;

}

P.pos

{

position: relative;

left: 200px; top: 60px;

background: #fff2a6;

}

Получается, что относительно позиционированный элемент ведет себя как двуликий Янус! С одной стороны, он остается в потоке (даже если смещается), а с другой — располагается над ним.

При изменении размеров окна или шрифта элемент с position: relative ведет себя так, будто находится в потоке. Он переформатируется вместе с потоком, а затем смещается.

Продемонстрируем это поведение на следующем примере:

<BODY>

<H1>Строчный элемент</H1>

<P>

В этом абзаце задан <STRONG>относительно позиционированный строчный элемент</STRONG> STRONG.

</BODY>

Вот так этот код отображается на экране, когда не задано позиционирование:

P

{

border: 1px solid black;

background:#a7fbc0;;

}

Элемент STRONG “зарезервировал” свое место в потоке, а сам сместился вниз на 80 пикселей.

А теперь зададим относительное позиционирование для элемента STRONG:

P

{

border: 1px solid black;

background:#a7fbc0;;

}

P STRONG

{

position:relative;

top:80px;

background:#fff2a6;

}

Уменьшим ширину окна. Абзац и STRONG переформатировались под новую ширину так, будто STRONG по-прежнему находится в абзаце.

2.3.2. Противоположные смещения

Что произойдет, если относительно позиционированному элементу задать противоположные смещения? Например, такие:

P.pos

{

position: relative;

left: 100px; right: 60px;

}

Элемент должен сместиться одновременно на 100 пикселей вправо (left: 100px) и на 60 пикселей влево (right: 60px ).

Стандарт CSS2.1 (ссылка[1]) утверждает, что в этом случае одному из смещений присваивается значение, противоположное другому, основному. В качестве основных называются смещения left и top (right > и top для языков с написанием справа налево).

Таким образом, для русского языка приведенное выше определение эквивалентно следующему:

P.pos

{

position: relative;

left: 100px; right: -100px;

}

Или такому:

P.pos

{

position: relative;

left: 100px;

}

 

2.4. Пример (построение сайта “Роботландия”)

Посмотреть (позиционирование/сайт “Роботландия”/шаг 13).

Макет — стандартный, а сайт получился интересным! Работая по правилам, можно получать штучные вещи.

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

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

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

2.4.1. Обсуждение макета

Макет представлен на рисунке.

 

Заголовочная часть (блок header) содержит логотип и заголовок сайта.

Боковая панель (блок sidebar) — меню и новости.

Подвал (блок footer) — авторские права и контактную информацию.

Основное содержание располагается в блоке content.

Мы можем блокам header, sidebar и content назначить абсолютное позиционирование, если зафиксировать высоту блока header. Но как быть с подвалом?

Высоты блоков sidebar и content будут меняться в зависимости от наполнения колонок. Значит, мы не знаем top для блока footer. Смещение bottom:0 вообще для него не годится — поток пуст, значит, низ блока footer поднимется (под вырванными из потока блоками) и склеится с верхом документа: footer вылезет вверх за пределы окна. (Если это рассуждение показалось вам неочевидным, остановитесь и подумайте, прежде чем двигаться далее.)

На самом деле высоту header тоже не хочется фиксировать — пусть она гибко меняется под размер шрифта, если того пожелает пользователь.

Может быть, оставить header и footer в потоке, а для sidebar и content задать абсолютное позиционирование?

Нет, тоже не годится. Блок footer подтянется к header, так как sidebar и content будут вырваны из потока.

Примем такое решение: все блоки, кроме sidebar, оставим в потоке. Для блока content зададим широкий внешний отступ слева и в освободившееся пространство поместим блок sidebar.

2.4.2. HTML-код

 

Задаем все блоки, которые указаны в макете:

<BODY>

<!-- Заголовочная часть -->

<DIV id="header">

</DIV>

<!-- Боковая панель -->

<DIV id="sidebar">

</DIV>

<!-- Содержание -->

<DIV id="content">

</DIV>

<!-- Подвал -->

<DIV id="footer">

</DIV>

</BODY>

С небольшим наполнением:

<BODY>

<!-- Заголовочная часть -->

<DIV id="header">

<H1>Роботландия</H1>

</DIV> <!-- Конец header -->

<!-- Боковая панель -->

<DIV id="sidebar">

<H2>Содержание</H2>

<UL>

<LI>Начало

<LI><A href="01.htm">Продукты</A>

<LI><A href="02.htm">Университет</A>

<LI><A href="03.htm">Ссылки</A>

<LI><A href="04.htm">Автор</A>

</UL>

<H2>Новости</H2>

<H3>31.01.09</H3>

<P>Роботландии исполнилось 18 лет!</P>

</DIV> <!-- Конец sidebar -->

<!-- Содержание -->

<DIV id="content">

<H2>О Роботландии</H2>

<P>

Курс с таким названием вошел в историю школьной информатики как образец комплексного

педагогического продукта, удачно соединяющего в себе идейный фундамент, учебник для

школьника, программное обеспечение и рекомендации для учителя.

</P>

</DIV> <!-- Конец content -->

<!-- Подвал -->

<DIV id="footer">

</DIV> <!-- Конец footer -->

</BODY>

2.4.3. Без CSS

Посмотреть (позиционирование/сайт “Роботландия”/шаг 1).

Вот так страница выглядит в окне браузера.

Пока не начали записывать стилевые правила, давайте отладим внешний вид сайта для браузеров, которые CSS не поддерживают. Пусть они тоже будут довольны!

Сделаем две вещи. Во-первых, отделим разделы друг от друга при помощи HR. Во-вторых, после меню запишем ссылку на раздел content.

Посмотреть (позиционирование/сайт “Роботландия”/шаг 2).

Горизонтальные прямые разделят страницу на логические части, а ссылка позволит прыгать через новости (когда они уже изучены).

Все введенные элементы снабдим классом none:

<A class="none" href="#content">Пропустить новости</A>

<HR class="none">

В стилях же пропишем:

.none { display: none}

Если браузер поддерживает CSS, он проигнорирует элементы с этим классом, иначе покажет их на экране.

Ссылки

Официальные документы

· CSS2.1

www.w3.org/TR/2007/CR-CSS21-20070719

Описание стандарта от W3C.

· HTML 4.01

www.w3.org/TR/html401

Описание стандарта от W3C.

· Блочные элементы

www.htmlhelp.com/reference/html40/block.html

Полный список блочных элементов.

· Строчные элементы

www.htmlhelp.com/reference/html40/inline.html

Полный список строчных элементов.

Учебники

· Учебник Ивана Сагалаева

http://softwaremaniacs.org/blog/category/web/primer/

Лучшее из того, что можно назвать “учебником” по CSS-верстке. По крайней мере из того, что мне попадалось в Сети. Заметки по CSS, представленные на текущих страницах, написаны под впечатлением учебника Сагалаева.

Справочники

· Свойства CSS

http://htmlbook.ru/css/

Справочник Влада Мержевича.

Сборники статей

· Webmascon

www.webmascon.com

“Здравствуйте, меня зовут Александр Качанов. Я — владелец и руководитель проекта Webmascon (ISSN: 1810-9527). Цель проекта — донести русскоязычному населению Интернета информацию по веб-дизайну, которая доступна только на английском языке. Более глобальная цель — пропаганда качественного, чистого, культурного и стандартного веб-дизайна”.

· Техногрет

www.artlebedev.ru/tools/technogrette

На этих страницах технологи студии Артемия Лебедева делятся своими знаниями.

· Статьи

http://htmlbook.ru/content

Статьи на сайте Влада Мержевича.

Форумы

· Форум Web

http://softwaremaniacs.org/forum/web/866

Форум Ивана Сагалаева.

Частные решения

· Трюк с блочной моделью CSS

www.webmascon.com/topics/coding/38a.asp

Трюк Тантека Целика.

· CSS-only Filters Summary.

http://dithered.chadlindstrom.ca/css_filters/css_only/index.php

Представительный набор CSS-уловок (с подробным описанием) в виде удобной таблицы.

· Ложные колонки

http://alistapart.com/articles/fauxcolumns

Решение Дэна Седерхольма для колонок фиксированной ширины.

· Ложные колонки (Дуглас Бауман)

http://stopdesign.com/archive/2004/09/03/liquid-bleach.html

Ложные колонки (Эрик Мейер)

http://meyerweb.com/eric/thoughts/2004/09/03/sliding-faux-columns/

Решение для колонок процентной ширины.

Разное

· Lorem Ipsum

www.lorem-ipsum.info/generator3

Lorem Ipsum генератор на разных языках (в том числе и на русском).

· Firebug

http://firebug.ru

Отладчик Firebug.

· Роботландия

www.botik.ru/~robot

Сайт Роботландии.

А.. А.. Дуванов,
г. Переславль-Залесский

TopList