«Позиция: липкая;» не работает CSS и HTML

177

Я хочу, чтобы панель навигации прилипала к вершине, как только я ее прокручиваю, но она не работает, и я понятия не имею, почему. Если вы можете помочь, вот мой HTML и CSS код:

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato",sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover{
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav style="position: sticky; position: -webkit-sticky;">
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

Harleyoc1
источник
10
позиция: липкий нужен координаты, чтобы сказать, где придерживаться
G-
36
Вы также должны быть осторожны с родительскими элементами. position: stickyможет перестать работать, если он находится внутри flexbox, если вы не будете осторожны, и также потерпит неудачу, если есть overflow: hiddenили overflow: autoмежду ним и всем, что он прокручивает внутри (корень тела или ближайший предок с переполнением: scroll)
user56reinstatemonica8
2
@ user56reinstatemonica8 OMG спасибо большое за то, что рассказали мне о overflow: hiddenи overflow: auto! Я несколько дней
чесал

Ответы:

207

Липкое позиционирование - это гибрид относительного и фиксированного позиционирования. Элемент обрабатывается как относительное положение до тех пор, пока он не пересекает заданный порог, после чего он рассматривается как фиксированное положение.
...
Вы должны указать пороговое значение с , по меньшей мере , один из top, right, bottomили leftдля липких позиционирования вести себя , как ожидалось. В противном случае он будет неотличим от относительного позиционирования. [ источник: MDN ]

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

html, body {
  height: 200%;
}

nav {
  position: sticky;
  position: -webkit-sticky;
  top: 0; /* required */
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

Marvin
источник
124
В общем, этого ответа недостаточно, чтобы работать, родитель также не должен иметь свойства переполнения.
ViliusL
Спасибо за ваш комментарий. Я согласен с вами, что для других примеров, кроме ОП, моего ответа может быть недостаточно. Другие ответы указывают на это :)
Марвин
Я думаю, хитрость в том, что позиция sticky может применяться только к дочерним элементам, принадлежащим прокручиваемому родителю с известной высотой (прямые дочерние элементы во flexbox имеют известную высоту, которая вычисляется из другого flex-элемента)
code4j
@ViliusL спасибо за ваш комментарий! Это была проблема, с которой я столкнулся: я не знал, что если бы не ты, я нигде не нашел эту информацию.
Петр Шлагура
позиция закрепления не должна иметь родителя со свойством переполнения, также закрепление закрепления не поддерживается в некоторых веб-браузерах
Rohan Shenoy
331

Проверьте, не установлен ли элемент-предок переполнения (например overflow:hidden); попробуйте переключить это. Возможно, вам придется подняться на дерево DOM выше, чем вы ожидаете =).

Это может повлиять на ваш position:stickyэлемент-потомок.

MarsAndBack
источник
36
Хотелось бы, чтобы я проголосовал за тебя несколько раз! Это укусило меня чаще, чем я хотел бы признать.
Александр Варвийк
2
Это правильный ответ. Однако может быть трудно определить, какой родительский элемент вызывает проблему. Я написал скрипт jquery, чтобы помочь идентифицировать свойство переполнения для родителей, которые идентифицировали проблему (просто запустите его в своей консоли). Поскольку сценарий состоит из нескольких строк, я добавил ответ, содержащий следующий сценарий.
danday74
5
Я пропустил "s" в ваших "родительских элементах"
che-azeh
5
Я также пропустил "s" :( и это было проблемой. Во многих местах люди пишут, что вы должны проверять только родителей, а не всех родителей. Я нашел свою проблему, проверив $(stickyElement).parents().css("overflow", "visible"), поможет ли вызов в веб-консоли, и это помогло. Затем я нашел дальний родитель со overflow:hiddenстилем, который вызвал проблему. Я хотел бы прочитать этот ответ более тщательно
Мариуш Павельски
2
Если вам нужна проверка overflow:hidden, вы можете запустить этот скрипт в консоли браузера, чтобы проверить всех родителей / предков данного элемента: gist.github.com/brandonjp/478cf6e32d90ab9cb2cd8cbb0799c7a7
brandonjp
100

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

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

В частности, ищите любое свойство переполнения, установленное на родительском объекте. Вы не можете использовать : overflow: hidden, overflow: scrollили overflow: autoна родителя position: stickyэлемента.

Мифтах Мизвар
источник
Это также правильный ответ, но также посмотрите мой ответ, который помогает легко определить родителя, вызвавшего проблему.
danday74
10
Вы должны проверить не только ближайший родительский контейнер, но и все родительские элементы s .
Мариуш Павельски
да, посмотрите мой ответ, чтобы сделать именно это и очень быстро проверить ВСЕХ родителей
danday74
1
Ссылка мне тоже помогла. Моя проблема была решена с помощью «... Если вы не используете переполнение и у вас все еще есть проблемы, стоит проверить, установлена ​​ли высота на родительском
элементе
Спасатель жизни, действительно простое описание проблемы, но есть ли
Рахул Сингх
32

Еще несколько вещей, с которыми я столкнулся:

Когда ваш липкий элемент является компонентом (угловым и т. Д.)

  • Если сам «липкий» элемент является компонентом с пользовательским селектором элементов, таким как названный угловой компонент, <app-menu-bar>вам необходимо добавить следующее в css компонента:

    :host { display: block; }   

    или

    app-menu-bar  { display: block; }   // (in the containing component's css)

    В частности, Safari для iOS требует display:blockдаже корневого элемента app-rootуглового приложения или не будет зависать.

  • Если вы создаете компонент и определяете CSS внутри компонента (теневой DOM / инкапсулированные стили), убедитесь, что position: stickyон применяется к «внешнему» селектору (например, app-menu-barв devtools должно отображаться закрепленное положение), а не верхний уровень div внутри компонент. С Angular это может быть достигнуто с помощью:host селектора в CSS для вашего компонента.

    :host
    {
        position: sticky;
        display: block;   // this is the same as shown above
        top: 0;
        background: red;    
    }

Другой

  • Если элемент, следующий за вашим липким элементом, имеет сплошной фон, вы должны добавить следующее, чтобы он не скользил снизу:

    .sticky-element { z-index: 100; }
    .parent-of-sticky-element { position: relative; }
  • Ваш липкий элемент должен быть первым (перед вашим контентом), если вы используете top и после него при использовании bottom.

  • Есть осложнения при использовании overflow: hidden вашего элемента-обертки - в общем, это убьет липкий элемент внутри. Лучше объяснил в этом вопросе

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

  • Убедитесь, что у вас есть:

    position: sticky;

    и нет

    display: sticky;

Проблемы с юзабилити

  • Будьте осторожны, если ваш дизайн требует приклеивать вещи к нижней части экрана на мобильных устройствах. На iPhone X, например, они отображают узкую линию, чтобы указать область прокрутки (чтобы вернуться на домашнюю страницу) - и элементы внутри этой области не кликабельны. Поэтому, если вы что-то вставите, обязательно протестируйте на iPhone X, чтобы пользователи могли его активировать. Большая кнопка «Купить сейчас» бесполезна, если люди не могут нажать на нее!
  • Если вы размещаете рекламу на Facebook, веб-страница отображается в элементе управления «просмотр веб-страниц» в мобильных приложениях Facebook. Особенно при отображении видео (где ваш контент начинается только в нижней половине экрана) - они часто полностью портят липкие элементы, помещая вашу страницу в прокручиваемое окно просмотра, которое фактически позволяет вашим липким элементам исчезать с верхней части страницы. Обязательно протестируйте в контексте реальной рекламы, а не только в браузере телефона или даже в браузере Facebook, которые могут вести себя по-разному.
Simon_Weaver
источник
@ Сергей Я не совсем уверен, что display: blockи position: relativeвызывает правильное поведение в Safari - казалось ли, что display: blockнужно было только ? Конечно, это, вероятно, не помешает, чтобы оба указали
Simon_Weaver
2
Просто display: blockбыло достаточно
Сергей
27

Это продолжение ответов от MarsAndBack и Miftah Mizwar.

Их ответы верны. Тем не менее, трудно определить проблему предка (ей).

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

$('.your-sticky-element').parents().filter(function() {
    console.log($(this));
    console.log($(this).css('overflow'));
    return $(this).css('overflow') === 'hidden';
});

Где предок не должен overflow: visibleменять свой CSS так, чтобы он это делал!

Также, как указано в другом месте, убедитесь, что ваш липкий элемент имеет это в CSS:

.your-sticky-element {
    position: sticky;
    top: 0;
}
danday74
источник
2
Это было очень полезно. Мне удалось быстро определить родительский элемент, который имел значение overflow: invisible.
Дэвид Брауэр
4
Если у вас нет jQuery на вашей странице, вы можете запустить этот небольшой фрагмент в консоли, чтобы добавить его: (async function() { let response = await fetch('https://code.jquery.com/jquery-3.3.1.min.js'); let script = await response.text(); eval(script); })();
magikMaker
8
Вы также можете запустить этот фрагмент код , который не требует JQuery найти ноны «видимый» перелив родитель: var p = $0.parentElement; while(p != null) { var ov = getComputedStyle(p).overflow; if(ov !== 'visible') console.warn(ov, p); else console.log(ov, p); p = p.parentElement; }Где $0является последним элементом , выбранным в инструментах разработчика.
Мариуш Павельски
Можно также обрабатывать position: fixedи присваивать свойства с помощью JavaScript. Вопрос не говорит о необходимости JavaScript.
винтпроект
12

Мне пришлось использовать следующий CSS, чтобы заставить его работать:

.parent {
    display: flex;
    justify-content: space-around;
    align-items: flex-start;
    overflow: visible;
}

.sticky {
    position: sticky;
    position: -webkit-sticky;
    top: 0;
}

Если выше не работает, то ...

Пройдите через всех предков и убедитесь, что ни один из этих элементов не имеет overflow: hidden. Вы должны изменить это наoverflow: visible

Unicco
источник
1
дисплей: Flex делает вещь
MaciejLisCK
6

Если вы столкнулись с этим, и ваш стикер не работает - попробуйте установить для родителя:

display: unset

Работал для меня

brianokinyi
источник
Это тот самый.
мм-93
Ой! Похоже, что это обходной путь для случая, когда родительский элемент имеет ограниченную высоту (например, контейнер navbar или что-то, в отличие от контейнера всего тела или страницы) - кажется, что стикеры не любят прокручивать вне их родители (что очень смешно!) Теперь всем просто нужно повезти, чтобы иметь возможность установить родителя display: unset, что не всегда может быть жизнеспособным
Бен Филипп
Также, кажется, работает с contents, initial(?) Иinline
Бен Филипп
5

Забавный момент, который не был очевиден для меня: по крайней мере, в Chrome 70 position: stickyне применяется, если вы установили его с помощью DevTools.

ик
источник
У вас есть источник для этого или какая-либо другая информация о том, как обойти это?
AJMansfield
5

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

solaris333
источник
Спасибо, это было то, что я искал! Для меня не было ни родителей с переполнением, ни проблем с ростом. Было бы неплохо увидеть эту информацию и в принятом ответе.
saglamcem
Я только что выяснил, экспериментируя, что sticky не будет прокручиваться за пределы родительского элемента. Неважно, сколько у него других братьев и сестер, но его родитель, очевидно, не может быть контейнером navbar, но должен быть чем-то на уровне страницы / контейнера содержимого :( Это смешно
Бен Филипп
Но вот! Если вы можете, если вы установите ограничивающий родительский элемент display: unset, это ограничение будет снято! см. stackoverflow.com/a/60560997/2902367 Также, похоже, работает с contents, initial(?) иinline
Бен Филипп
4

из моего комментария:

position:sticky нужна координата, чтобы тел, где придерживаться

nav {
  position: sticky;
  top: 0;
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}

body {
  height: 200vh;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

Существует полифилл для использования в других браузерах, кроме FF и Chrome. Это экспериментальные правила, которые могут быть реализованы или нет в любое время через браузеры. Хром добавить его пару лет назад, а затем уронил, кажется, назад ... но как долго?

Ближайшей будет позиция: относительные + координаты обновляются при прокрутке, как только она достигнет «липкой точки», если вы хотите превратить это в скрипт javascript

G-Кирилл
источник
4

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

В overflow:hiddenответ покрывают 90% случаев. Это более или менее сценарий «липкой навигации».

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

Ваш контейнер должен иметь высоту, на которую вы хотите, чтобы ваш элемент прокручивался. Который в моем сценарии «правой колонки» является высотой левой колонки. Лучший способ добиться этого - использовать display:table-cellстолбцы. Если вы не можете, и застряли с float:rightтаким, как я, вам придется угадать высоту левого столбца, чтобы вычислить его с помощью Javascript.

Тристан М
источник
2
«Если ваш липкий элемент является единственным дочерним элементом контейнера, контейнер имеет точно такой же размер, и нет места для прокрутки». ЗОЛОТО!!! Спасибо!
Марк Джексон
Да! Мне понадобилось время, чтобы понять это. Сначала я посчитал это смешным ограничением, но я полагаю, что должен быть хотя бы вариант для этого. Я бы предпочел что-то вроде sticky-limit: parent, sticky-limit: bodyили sticky-limit: nth-parent(3)... Во всяком случае: если вы можете, вы можете снять это ограничение, установив родительский ограничитель на display: unset, как отмечено в stackoverflow.com/a/60560997/2902367 . Также, кажется, работает с contents, initial(?) Иinline
Бен Филипп
3

Я знаю, что это старый пост. Но если есть кто-то вроде меня, который только недавно начал возиться с позицией: прилипать, это может быть полезно.

В моем случае я использовал position: sticky как элемент сетки. Это не работало, и проблема была в переполнении х: скрыто на htmlэлементе. Как только я удалил это свойство, оно работало нормально. Было bodyпохоже, что наличие overflow-x: hidden на элементе работает, пока не знаю, почему.

Марко Перальта
источник
1

два ответа здесь:

  1. удалить overflowсвойство из bodyтега

  2. установить, height: 100%чтобы bodyрешить проблему сoverflow-y: auto

min-height: 100% не работает вместо height: 100%

Джавад Эбрахими
источник
1

Я считаю, что эта статья много говорит о том, как stickyработает

Как CSS Position Sticky действительно работает! CSS-позиция sticky состоит из двух основных частей: липкого элемента и липкого контейнера .

Sticky Item  - это элемент, который мы определили с позиции: липкие стили. Элемент будет плавать , когда положение окна просмотра совпадает с определением местоположения, например: top: 0px.

Sticky Container - это HTML-элемент, который оборачивает липкий элемент. Это максимальная площадь, в которой может плавать липкий предмет.

Когда вы определяете элемент с помощью position: sticky, вы автоматически определяете родительский элемент как прикрепленный контейнер!

yuval.bl
источник
1

Реальное поведение липкого элемента:

  • Сначала это относительно некоторое время
  • тогда это исправлено на некоторое время
  • наконец, это исчезает из поля зрения

Липко позиционируемый элемент обрабатывается как относительно позиционированный, пока его содержащий блок не пересечет указанный порог (например, установив top в значение, отличное от auto) в пределах своего корневого потока (или контейнера, в котором он прокручивается), в этот момент он рассматривается как «застрявший» "до встречи с противоположным краем содержащего его блока.

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

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

Этот пример поможет вам понять:

code https://codepen.io/darylljann/pen/PpjwPM

Хуанма Менендес
источник
0

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

В моем случае у меня было два ребенка, один плавающий влево и один плавающий вправо. Я хотел, чтобы правый плавающий стал липким, но мне пришлось добавить <div style="clear: both;"></div>в конце родительского элемента, чтобы придать ему высоту.

Фло
источник
Не уверен, почему кто-то за это проголосовал, но это был именно мой случай: я добавил float:leftк родительскому элементу (без float его высота была 0) и position:stickyработал.
aexl
0

Я использовал решение JS. Работает в Firefox и Chrome. Любые проблемы, дайте мне знать.

HTML

<body>
  <header id="header">
    <h1>Extra-Long Page Heading That Wraps</h1>
    <nav id="nav">
      <ul>
        <li><a href="" title="">Home</a></li>
        <li><a href="" title="">Page 2</a></li>
        <li><a href="" title="">Page 3</a></li>
      </ul>
    </nav>
  </header>
  <main>
    <p><!-- ridiculously long content --></p>
  </main>
  <footer>
    <p>FOOTER CONTENT</p>
  </footer>
  <script src="navbar.js" type="text/javascript"></script>
</body>

CSS

nav a {
    background: #aaa;
    font-size: 1.2rem;
    text-decoration: none;
    padding: 10px;
}

nav a:hover {
    background: #bbb;
}

nav li {
    background: #aaa;
    padding: 10px 0;

}

nav ul  {
    background: #aaa;
    list-style-type: none;
    margin: 0;
    padding: 0;

}

@media (min-width: 768px) {

    nav ul {
        display: flex;
    }
}

JS

function applyNavbarSticky() {
    let header = document.querySelector('body > header:first-child')
    let navbar = document.querySelector('nav')
    header.style.position = 'sticky'

    function setTop() {
        let headerHeight = header.clientHeight
        let navbarHeight = navbar.clientHeight
        let styleTop = navbarHeight - headerHeight

        header.style.top = `${styleTop}px`
    }

    setTop()

    window.onresize = function () {
        setTop()
    }
}
Карл Брубейкер
источник
0

z-indexтоже очень важно. Иногда это будет работать, но вы просто не увидите этого. Попробуйте установить его на очень большое число, просто чтобы быть уверенным. Также не всегда ставьте, top: 0но попробуйте что-нибудь повыше, если оно где-то спрятано (под панелью инструментов).

Рексин Ходжа
источник
0

Вот что меня сбивало с толку ... мой липкий div был внутри другого div, так что родительскому div нужно некоторое дополнительное содержимое ПОСЛЕ липкого div, чтобы сделать родительский div "достаточно высоким", чтобы sticky div "скользил" по другому контенту как Вы прокручиваете вниз.

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

    %div{style:"height:600px;"} 
      &nbsp;

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

JPW
источник
-1

Это правда, что overflowнеобходимо удалить или установить, initialчтобы сделать position: stickyработу над дочерним элементом. Я использовал Material Design в своем приложении Angular и обнаружил, что некоторые компоненты Material изменили overflowзначение. Исправление для моего сценария

mat-sidenav-container, mat-sidenav-content {
  overflow: initial;
}
Ан Нгуен
источник