Позиционирование блока относительно родителя с помощью position:fixed

25 мая 2008 г.

За столь продолжительный период верстки сегодня мне впервые пришлось столкнуться с необходимостью разместить на странице фиксированный блок (используя CSS-свойство position:fixed), который бы при скролле страницы всегда сидел в одном месте окна браузера.

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

У меня же стояла несколько иная задача. Имеется основной родительский блок с фиксированной шириной, выровненный по центру окна (margin: 0 auto). И необходимо справа от этого блока поместить фиксированный блок, т.е. позиционироваться он должен не от края окна браузера, а от основного блока. Вот готовый пример, о котором я веду речь.

Ниже расскажу, как я это реализовал, с учетом следующих моментов:

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

Итак, поехали.

HTML-код

Имеем следующую базовую разметку:

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="wrapper">
 
  <div id="container">
основное содержание страницы
  </div>
 
  <div id="fixed">
    <div class="fixed">
блок, который надо зафиксировать
    </div>
  </div>
 
</div>

CSS-код

Имеем следующие стили для основного и контентного блоков:

1
2
3
4
5
6
7
8
9
#wrapper {
  width: 642px;
  margin: 0 auto;
  padding-right: 243px;
}
#container {
  position: relative;
  z-index: 10;
}

Т.е. у нас имеется основной контейнер шириной 885px, размещенный по центру окна, из них 642px отдано под контент, который будет находиться в левой части, а 243px в правой части выделяем под наш фиксированный блок шириной в 240px. Собственное это и делает идентификатор #wrapper.

Хочу заострить внимание на параметрах идентификатора #container, используемого для блока с основным контентом. Необходимо обязательно обозначить уровень этого слоя выше (здесь - z-index: 10), чем слой с фиксированным блоком (это согласно условиям моего примера, в других случаях сие может быть не обязательным), иначе в FireFox’e нельзя будет выделить текст в этом блоке в части высоты, равной высоте фиксированного блока.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
#fixed {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
}
.fixed {
  position: relative;
  width: 240px;
  margin: 0 auto;
  top: 10px;
  left: 323px;
}

Подобрав отступ с помощью свойства left: 323px; к блоку .fixed, отцентрированному относительно окна браузера (margin: 0 auto;), я сдвинул фиксируемый блок в предназначенное для него место.

В результате у меня получилось то, что я и хотел. Смотрим пример всего описанного выше.

Данный пример прекрасно работает в следующих браузерах: Opera, FireFox, Safari, IE7, но не работает в…

Internet Explorer 6

Ну а как же без него? :) Само-знамо, курилка даже не представляет, ЧТО есть значение position: fixed, поэтому опять приходится латать его дыры его же ява-скриптами.

Чтобы укротить IE6 для нашей задачи, необходимо, во-первых, вместо position: fixed использовать абсолютное позиционирование position: absolute, во-вторых, применить expression, который и фиксирует блок. И поместим код в условные комментарии.

Вот что у нас получилось:

1
2
3
4
5
6
7
8
9
10
<!--[if lt IE 7]>
<style type="text/css">
#fixed {
  position: absolute;
  top: expression(parseInt(document.documentElement.scrollTop, 0) + "px");
  left: 50%;
  margin-left: -321px;
}
</style>
<![endif]-->

Объясняю, для чего здесь понадобились свойства left: 50%; и margin-left: -321px;. Дело в том, что, если использовать тот же самый отступ слева, что и для других браузеров, (left: 323px;), то фиксированный блок в IE6 ведет себя неправильно - при сужении окна браузера он смещается вправо от основного блока. Поэтому при помощи left: 50%; (данное свойство имеет здесь решающее значение, выявил “методом тыка”) и следующего дополнительного отрицательного отступа блок возвращается на предназначенное ему место.

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

Однако, если посмотрите на пример в этом браузере, то заметите следующий артефакт - при прокручивании страницы блок некрасиво подергивается. Чтобы устранить данный недостаток, необходимо тегу body назначить прозрачный фоновый рисунок с фиксированным позиционированием, т.е. вот так:

1
2
3
body {
  background: url(i/pixel.gif) fixed;
}

Что интересно, даже не обязательно наличие картинки pixel.gif на сервере, достаточно просто этой записи, чтобы дергание исчезло.

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

Вот, собственно, и все, о чем хотелось сказать в настоящей статье.

* * *

Отличный подарок на день рождения мальчику - игрушки лего, которые в большом ассортименте представлены в интернет-магазине “Lego для всех”. Осуществляется доставка как в пределах России, так и по СНГ.

Теги: , , автор: Dimox | рубрика CSS-верстка

Комментарии (28): »

  1. правый блок уплывает под основной контент, при уменьшении ширины

    @
  2. Есть такой плагинчик для ВП — там фиксированный блок мягко подплывает сверху к верхнему краю окна при скроллинге и всегда остается наверху: LC-StatusLine http://ardy.or.id/2007/11/19/wordpress-plugins-limosin-creative-status-line.xhtml
    В общем, тоже может пригодится — зависит от целей :)

    @
  3. Для каждого агента можно делать свой стиль или нужно, пока сам в размышлениях

  4. Выглядит отлично и вообще может быть полезно для размещения навигации или невысокого сайдбара.
    Заметил только один небольшой глючок - при уменьшении окна до возникновения горизонтальной прокрутки блок ведёт себя эээ… ненормально :)

    Проверял только на Opera 9.50, на последнем билде.

  5. Позитивно.
    Еще посмотри на Полноценный fixed в MSIE, а то твой пример в шестом ИЕ прыгает капец некрасиво.

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

  6. правый блок уплывает под основной контент, при уменьшении ширины

    Да, я знаю. Но этого не избежать, по крайней мере, я не знаю способа для устранения данного недостаток. Но, я считаю, он не существенен, поскольку пользователей с разрешением 800х600 - менее 5% (это в РУнете). Однако, на случай просмотра такой страницы с мобильных устройств данный метод, получается, не подходит.

    sonika, я встречал такие штуки. Без ява-скрипта они работать не будут. Мой же пример сделан на голом CSS, за исключением IE6.

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

    Не понял, о чем ты говоришь.

    Заметил только один небольшой глючок - при уменьшении окна до возникновения горизонтальной прокрутки блок ведёт себя эээ… ненормально :)

    Чуть выше я ответил по этому поводу.

    но всё же, в IE6 блок прыгает, как ни крути.

    Прыгает, потому что я специально не добавил фоновый прозрачный рисунок, чтобы можно было наглядно увидеть, КАК он нехорошо прыгает :)

  7. Интересно для чего это применялось?

    @
  8. Для баннера и картинки RSS-подписки.

  9. Пойдёт статейка для начинающих)

  10. Dimox - спасибо за позновательные статьи, каждый раз читаю и нахожу что то новое и интересное:)

  11. Нет, Дмитрий не очень хороший вариант :)
    Для Вадима Lasto, а здесь улучшенный вариант: http://time-info.info/show/
    по моему сделал проще, и без expression.
    Минус твоего решения и в том, что при разных разрешениях все будет разваливаться.
    Так же при уменьшении размеров окна браузера, фиксированный блок не прячется под областью контента, а отрывается от нее, но все равно часть его остается не доступной.
    Тут не должно быть компромиссов :)

    @
  12. Хм..
    gordi, благодарю. По ссылке нашел отличное решение.

  13. Рыскал по Интернету, но не нашёл нужный пример. Мне необходимо зафиксить полноценно в родительском блоке элемент, т.е. если родительский элемент не на всю высоту документа и он вне зоны видимости, то и “блок, который фиксируем” вне зоны видимости. Надеюсь, изложил понятно свою мысль. Никто с таким примером не сталкивался? Заранее благодарен.

    @
  14. а здесь улучшенный вариант: http://time-info.info/show/

    В Опере 9.27 наблюдается глюк - страница не прокручивается, пока не отключишь ява-скрипты.

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

    Что будет разваливаться? Если разрешение экрана 1024х768 и выше, ничего не разваливается! Зачем вообще брать во внимание разрешения ниже 1024х768? Мы живем в 21 веке.

    Сергей, твой вариант тоже не очень хорош - фиксированный блок начинает прятаться под основной, когда ширина окна браузера примерно 1250 пикселей и ниже, т.е. фиксированный блок виден на разрешениях, начиная от 1280px и выше, при том, что ширина всего контентного блока - 1000px.

    К тому же в FireFox’e (2-я версия) наблюдается некрасивый эффект - та часть основного блока, которая при сужении окна закрывает фиксированный блок, ужасно дергается.

    ИМХО, в твоем варианте минусов больше, чем в моем.

  15. Im Eugene, в вашем случае нужно использовать position: absolute.

  16. № 14
    >В Опере 9.27 наблюдается глюк
    Тут попытался решить проблему для разных разрешений через скрипт,
    чтобы между колонками по сравнению дефолтом 1024*768, при более высоком разрешении не было пустоты, может получилось не совсем удачно :), но похоже это правильный путь.

    Сам макет заточен именно под 1024*768 и во всех браузерах - IE6(7), FF, OPERA 9.23
    не вижу проблем описанных тобой.

    А OPERA вообще и с position:absolute; и с position:fixed; как кошка, что гуляет сама по себе :)
    Писал об этом у себя на блоге.

    Да в FF есть такая неприятность :), но на сколько это критично?

    Дима, в твоем варианте, у меня в IE6 фиксированный блок сваливается под область контента. Могу прислать скрин.

    @
  17. А OPERA вообще и с position:absolute; и с position:fixed; как кошка, что гуляет сама по себе :)

    Насчет fixed не уверен, но с absolute я в Опере никогда не наблюдал проблем.

    Дима, в твоем варианте, у меня в IE6 фиксированный блок сваливается под область контента. Могу прислать скрин.

    Весьма странно. У меня в нем же все на месте.

  18. Да. Все здорово. Вот только у меня body уже дает свой фон на сайте. Но, думаю, можно закрыть глаза на этот баг.

  19. Извините за идиотский вопрос: <!–[if lt IE 7]>………<![endif]–> - это что и зачем?

  20. LisenOK, это называется условными комментариями, которые используются для Internet Explorer. “if lt IE 7″ - обозначает условие “если версия IE меньше 7-й.

  21. Понятно, тока у меня все равно не получается. В mozilla все супер, а в IE….перечитаю еще раз статью :(. Спасибо

  22. Фиксированные блоки на web-странице
    Наконец-то удалось сделать то, что так давно хотелось :)

    @
  23. Круто, что тут еще скажешь. Молодец ;)

  24. Круто…

    Вот, когда сделаю, если получится, конечно, прокрутку страницы при нахождении крсора мыши над фиксированным блоком, тогда да :)
    Будет полный фен-шуй :)

    @
  25. Наконец-то созрел и открыл ресурс посвященный фиксированным блокам (колонкам) на web-страницах.
    Приглашаю - fixed.name
    Без графических выкрутасов, сугубо технические моменты и детали, примеры.

    @
  26. #wrapper {
    width: 642px;

    Я полагаю здесь должно быть так:
    #wrapper {
    width: 885px;

    ?

    @
  27. правый блок уплывает под основной контент, при уменьшении ширины

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

    Лечится заданием минимальной ширины для блока c position:fixed

    @
  28. Народ, может кто подсказать как правильно сделать:
    ventern.ru/321.htm
    Собственно все хорошо, пока не появлется горизонтальный скрол, начинаешь его двигать туда сюда меню на месте текст ездит, смотрится кошмарно, как вылечить?

    @

Присоединяйтесь к обсуждению!

Отправляя кoммeнтapий, Вы автоматически принимаете правила кoммeнтиpoвaния на этом блоге.

Правила кoммeнтиpoвaния на блоге dimox.name:

  1. Первый кoммeнтapий всегда проходит премодерацию.
  2. В поле "URL блога" можно указывать только ссылку на главную страницу вашего блога. Ссылки на прочие веб-ресурсы (в том числе блоги/сплоги, созданные не для людей) будут удалены.
  3. Запрещается использовать в качестве имени комментатора слоганы/названия сайтов, рекламные фразы, ключевые и т.п. слова. В случае несоблюдения этого условия имя изменяется по усмотрению владельца блога. Просьба указывать нормальное имя или ник.
  4. Весьма вероятно, что короткий и неинформативный кoммeнтapий вида "Спасибо!", "Интересная статья", будет удален. Исключение составляют знакомые автору блога комментаторы.

Подписаться, не комментируя

Предыдущие из рубрики