"Позиція: липкий;" не працює 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>


10
позиція: липким потрібен координатор, щоб тел, куди приклеїти
G-Cyrillus

36
Ви також повинні бути обережні з батьківськими елементами. position: stickyможе перестати працювати, якщо він знаходиться у флексі, якщо ви не будете обережні, а також не вдасться, якщо там знаходиться overflow: hiddenабо overflow: autoміж ним, і все, що воно прокручується всередині (корінь тіла або найближчий пращур із переливом: прокрутка)
user56reinstatemonica8

2
@ user56reinstatemonica8 OMG thankkkkyou так багато за те, що ти сказав мені про overflow: hiddenі overflow: auto! Я
цілими днями чухав

Відповіді:


206

Клейке позиціонування - це гібрид відносного і нерухомого позиціонування. Елемент розглядають як відносно розташований до тих пір, поки він не переступить заданий поріг, і в цей момент він розглядається як фіксований.
...
Ви повинні вказати порогове значення з , щонайменше , один з 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>


124
Загалом, цієї відповіді недостатньо, щоб дотримуватися роботи, батьки також не повинні мати властивості переповнення.
ViliusL

Дякую за Ваш коментар Я згоден з вами, що для інших прикладів, ніж відповідь ОП, моя відповідь може бути недостатньою. Інші відповіді наголошують на цьому :)
Марвін

Я думаю, що хитрість полягає в тому, що позитивну позицію можна застосувати лише до дітей, які належать до прокручуваного батька з відомою висотою, (прямі діти у флексбоксі мають висоту знань, яка обчислюється з іншого
флекс

@ViliusL дякую за Ваш коментар! Це була проблема, яку я мав з позицією: липкий, я б не знав, що якби не для вас, як я ніде не знайшов цю інформацію.
Пьотр Шлагура

липке положення не повинно мати батьків з властивістю переповнення, також липке не підтримується в деяких веб-браузерах
Rohan Shenoy

331

Перевірте, чи є елемент предка встановлений перелив (наприклад overflow:hidden); спробуйте переключити його. Можливо, вам доведеться піднятися на дерево DOM вище, ніж ви очікували =).

Це може вплинути на ваш position:stickyелемент нащадка.


36
Бажаю, щоб я міг вас порушити! Це мене кусало частіше, ніж я б хотів визнати.
Олександр Варвейк

2
Це правильна відповідь. Однак важко знайти, який батьківський елемент викликає проблему. Я написав сценарій jquery, щоб допомогти визначити властивість переповнення батьків, які визначили проблему (просто запустіть її у своїй консолі). Оскільки сценарій - це кілька рядків, я додав відповідь, що містить сценарій нижче.
понеділок74

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елемента.


Це також правильна відповідь, але також дивіться мою відповідь, яка допомагає легко визначити батьків, що викликають проблему.
понеділок74

10
Ви повинні перевірити не тільки найближчий батьківський контейнер, але і всі батьківські елементи s .
Mariusz Pawelski

так, дивіться мою відповідь зробити саме це і перевірити ВСІХ батьків дуже швидко
daday74

1
Посилання мені теж допомогло. Мою проблему вирішили "... Якщо ви не використовуєте переповнення і все ще виникають проблеми, то варто перевірити, чи встановлена ​​висота на батьківській ..."
xenetics

Життєзбереження, дуже простий опис проблеми, але чи є робота над цим просто цікавим
Рахул Сінгх,

32

Ще кілька речей, які я натрапив:

Коли ваш липкий елемент - це компонент (кутовий тощо)

  • Якщо сам елемент 'sticky' - це компонент із спеціальним селектором елементів, наприклад, кутовий компонент з назвою, <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, який може вести себе по-різному.

@Sergey Мені не зовсім зрозуміло, що 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;
}

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є останнім елементом , вибраним в інструментах розробника.
Mariusz Pawelski

Можна також обробляти position: fixedі відповідні властивості за допомогою JavaScript. Питання не вказує на необхідність JavaScript.
vintproykt

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


1
дисплей: flex робить річ
MaciejLisCK

6

Якщо ви натрапили на це, і ваш клей не працює - спробуйте встановити батьків:

display: unset

Працювали для мене


Це одне.
мм-93

Ой! Це, здається, є обробкою для випадку, коли батьківський елемент має обмежену висоту (наприклад, контейнер для навбара або щось подібне, на відміну від цілого контейнера тіла або сторінки) - здається, що стикери не люблять прокручуватися поза їх батьки (що зовсім смішно!) Тепер усім просто пощастить, щоб мати можливість встановити батьків display: unset, що не завжди може бути негайно життєздатним
Бен Філіп

Також, здається, працює з contents, initial(?) Таinline
Бен Філіп

5

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


У вас є джерело для цього чи будь-яка інша інформація про те, як вирішити цю проблему?
AJMansfield

5

Схоже, що вказівник, який слід наклеювати, не повинен міститися в жодному розділі або розділі з іншим вмістом. Жодне рішення не працювало для мене, поки я не вийняв navbar з div, яким navbar ділився з іншою верхньою панелю.


Дякую, саме це я шукав! Для мене не було батьків із переповненням, а також не було проблем з ростом. Було б добре побачити цю інформацію і в прийнятій відповіді.
saglamcem

Я просто виявив, експериментуючи, що липкий не прокручується поза його батьківського елемента. Це не так вже й важливо, скільки інших братів і сестер у нього є, але, мабуть, його батько не може бути контейнером для навігації, але повинен бути чимось на рівні контейнера сторінки / вмісту :( Це смішно
Бен Філіп

Але Ло! Якщо ви можете, якщо встановити обмежувальний батьків 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. Це експериментальні правила, які можна будь-коли реалізувати або не використовувати через браузери. Chrome додав його пару років тому, а потім скинув, здається, назад ... але на скільки часу?

Найближчим було б положення: відносні + координати оновлюються під час прокрутки, колись досягнуто клейкої точки, якщо ви хочете перетворити це на сценарій javascript


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

Я знаю, що це стара публікація. Але якщо є хтось на зразок мене, який нещодавно почав возитися з положенням: липким це може бути корисно.

У моєму випадку я використовував позицію: липкий як елемент сітки. Це не працювало, і проблема полягала в надлишку x: приховано на htmlелементі. Як тільки я вилучив цю власність, вона працювала чудово. Маючи overflow-x: прихований на bodyелементі здавався спрацьованим, не знаю, чому ще.


1

тут є дві відповіді:

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

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

min-height: 100% не працює замість height: 100%


1

Я вважаю, що ця стаття багато говорить про те, як stickyпрацює

Як реально працює позиція CSS! CSS позиція sticky має дві основні частини, липкий предмет & липкий контейнер .

Sticky Item  - це елемент, який ми визначили з позицією: липкі стилі. Елемент буде плавати , коли становище вікна перегляду збігається з визначенням місця розташування, наприклад: top: 0px.

Клейкий контейнер - це HTML-елемент, який загортає липкий предмет. Це максимальна площа, на якій може плавати клейкий предмет.

Коли ви визначаєте елемент з позицією: sticky, ви автоматично визначаєте батьківський елемент як липкий контейнер!


1

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

  • По-перше, це деякий час відносно
  • потім воно фіксується на деякий час
  • нарешті, вона зникає з виду

Клейко розташований елемент трактується як відносно розміщений, поки його блок, що містить, не перетне визначений поріг (наприклад, встановлення верхнього значення, ніж авто) у межах кореня потоку (або контейнера, в якому він прокручується), і в цей момент він вважається "застряглий" ", поки не зустріне протилежний край її містить блок.

Елемент розміщується відповідно до нормального потоку документа, а потім зміщується відносно найближчого предка прокрутки і містить блок (найближчий предка рівня блоку), включаючи елементи, пов’язані з таблицею, на основі значень верхнього, правого, нижнього, і пішов. Зсув не впливає на положення будь-яких інших елементів.

Це значення завжди створює новий контекст укладання. Зауважте, що липкий елемент "прилипає" до найближчого предка, який має "механізм прокрутки" (створюється, коли переповнення приховано, прокручуйте, автоматично або накладіть), навіть якщо цей пращур не є найближчим фактично прокручуваним предком.

Цей приклад допоможе вам зрозуміти:

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


0

якщо виправлення daday74 не працює, перевірте, чи має батьківський елемент висоту.

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


Не впевнений, чому це хтось спричинив, але це був саме мій випадок: я додав float:leftдо батьківського елемента (без поплавця його висота була 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{style:"height:600px;"} 
      &nbsp;

(У моїй програмі є дві бічні біки, із "високим" зображенням ліворуч та короткою формою для введення даних праворуч. Я хотів, щоб форма введення даних плавала поруч із зображенням, коли ви прокручуєте вниз, тому форма завжди є на екрані. Вона не працюватиме, доки я не додав вище "додатковий вміст", щоб клейкий дів мав щось "ковзати"


-1

ІСТИНА, що її overflowпотрібно видалити або встановити, initialщоб зробити position: stickyроботи над дочірнім елементом. Я використовував Material Design у своїй програмі Angular і дізнався, що деякі компоненти матеріалу змінили overflowзначення. Виправлення мого сценарію є

mat-sidenav-container, mat-sidenav-content {
  overflow: initial;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.