लक्ष्यीकरण स्थिति: चिपचिपे तत्व जो वर्तमान में 'अटक' स्थिति में हैं


110

स्थिति: चिपचिपा अब कुछ मोबाइल ब्राउज़रों पर काम करता है, इसलिए आप पृष्ठ के साथ मेनू बार स्क्रॉल कर सकते हैं, लेकिन तब व्यूपोर्ट के शीर्ष पर रहें जब भी उपयोगकर्ता इसे स्क्रॉल करता है।

लेकिन क्या होगा अगर आप अपने स्टिकी मेनू बार को थोड़ा संयम में रखना चाहते हैं जब भी वह वर्तमान में 'चिपका हुआ' हो? उदाहरण के लिए, यदि आप पृष्ठ के साथ स्क्रॉल करना चाहते हैं, तो आप बार को गोल कर सकते हैं, लेकिन फिर जैसे ही यह व्यूपोर्ट के शीर्ष पर चिपक जाता है, आप शीर्ष गोल कोनों से छुटकारा पाना चाहते हैं, और नीचे की ओर थोड़ा ड्रॉप शैड जोड़ना चाहते हैं यह।

क्या ::stuckउन तत्वों को लक्षित करने के लिए किसी भी प्रकार का छद्मकोश (जैसे ) है position: sticky और वर्तमान में चिपका हुआ है? या क्या ब्राउज़र विक्रेताओं के पास पाइपलाइन में ऐसा कुछ है? यदि नहीं, तो मैं इसका अनुरोध कहां करूंगा?

एनबी। जावास्क्रिप्ट सॉल्यूशंस इसके लिए अच्छे नहीं हैं क्योंकि मोबाइल पर आमतौर पर आपको केवल एक ही scrollघटना मिलती है जब उपयोगकर्ता अपनी उंगली जारी करता है, इसलिए JS सटीक क्षण नहीं जान सकता है कि स्क्रॉल थ्रेशोल्ड पास किया गया था।

जवाबों:


104

वर्तमान में कोई भी चयनकर्ता नहीं है जो उन तत्वों के लिए प्रस्तावित किया जा रहा है जो वर्तमान में 'अटक' हैं। Postioned लेआउट मॉड्यूल जहां position: stickyपरिभाषित किया गया है या तो किसी भी तरह के चयनकर्ता उल्लेख नहीं है।

CSS के लिए फ़ीचर अनुरोधों को www-स्टाइल मेलिंग सूची में पोस्ट किया जा सकता है । मेरा मानना ​​है कि एक :stuckछद्म वर्ग ::stuckछद्म तत्व की तुलना में अधिक समझ में आता है , क्योंकि आप तत्वों को खुद को लक्षित करना चाहते हैं जब वे उस स्थिति में होते हैं। वास्तव में, कुछ समय पहले एक :stuckछद्म वर्ग की चर्चा की गई थी ; मुख्य जटिलता, यह पाया गया था, कि किसी भी प्रस्तावित चयनकर्ता के बारे में सिर्फ एक विपत्तियां हैं जो एक गाया या गणना की शैली के आधार पर मिलान करने का प्रयास करती हैं: परिपत्र निर्भरताएं।

एक के मामले में :stuckछद्म वर्ग, घेरा का सरलतम मामले निम्नलिखित सीएसएस के साथ होता है:

:stuck { position: static; /* Or anything other than sticky/fixed */ }
:not(:stuck) { position: sticky; /* Or fixed */ }

और ऐसे कई और मामले हो सकते हैं जिन्हें संबोधित करना मुश्किल होगा।

हालांकि यह आम तौर पर इस बात पर सहमत होता है कि कुछ लेआउट राज्यों के आधार पर चयन करने वाले चयनकर्ता अच्छे होंगे , दुर्भाग्य से प्रमुख सीमाएं मौजूद हैं जो लागू करने के लिए इन गैर-तुच्छ बनाती हैं। मैं जल्द ही इस समस्या के लिए शुद्ध सीएसएस समाधान के लिए अपनी सांस नहीं रोकूंगा।


14
कि एक शर्म की बात है। मैं इस समस्या का भी हल ढूंढ रहा था। क्या केवल एक नियम को लागू करना काफी आसान नहीं होगा जो कहता है कि चयनकर्ता positionपर संपत्तियों की :stuckअनदेखी की जानी चाहिए? (ब्राउज़र विक्रेताओं के लिए एक नियम, मेरा मतलब है, नियमों के बारे में समान है कि कैसे पहले leftसे अधिक समय लगता है right))
पॉवरबॉय

5
यह सिर्फ स्थिति नहीं है ... कल्पना करें :stuckकि topमान से परिवर्तन होता 0है 300px, फिर नीचे स्क्रॉल करें 150px... क्या यह छड़ी होनी चाहिए या नहीं? या एक तत्व के बारे में सोचें जहां position: stickyऔर bottom: 0जहां :stuckशायद परिवर्तन होता है font-sizeऔर इसलिए तत्वों का आकार (इसलिए उस क्षण को बदलना चाहिए जिसमें इसे
रोमन

3
Github.com/w3c/csswg-drafts/issues/1660 देखें जहां प्रस्ताव यह जानना चाहता है कि जब कुछ अटक / अनस्टक हो जाता है, तो यह जानने के लिए जेएस इवेंट हों। कि एक छद्म चयनकर्ता मुद्दों का परिचय नहीं होना चाहिए।
रुब

27
मेरा मानना ​​है कि एक ही गोलाकार समस्याओं को पहले से मौजूद मौजूदा छद्म वर्गों (जैसे: होवर बदलते चौड़ाई और: नहीं (होवर) को फिर से वापस बदलने) के साथ बनाया जा सकता है। मैं प्यार करता हूँ: छद्म वर्ग अटक गया और लगता है कि डेवलपर अपने कोड में परिपत्र मुद्दों नहीं होने के लिए जिम्मेदार होना चाहिए।
मारेक लिस्फी

12
ठीक है ... मैं वास्तव में इसे गलती के रूप में नहीं समझता - यह कहने के लिए है कि whileचक्र बुरी तरह से डिज़ाइन किया गया है क्योंकि यह अंतहीन लूप की अनुमति देता है :) हालांकि इस को साफ़ करने के लिए धन्यवाद;)
मारेक लिस्फी

26

कुछ मामलों में एक साधारण IntersectionObserverचाल कर सकता है, अगर स्थिति ठीक से निपटने के बजाय अपने रूट कंटेनर के बाहर एक पिक्सेल या दो से चिपके रहने की अनुमति देती है। इस तरह जब यह किनारे से परे बैठता है, पर्यवेक्षक आग लगाता है और हम रवाना हो जाते हैं।

const observer = new IntersectionObserver( 
  ([e]) => e.target.toggleAttribute('stuck', e.intersectionRatio < 1),
  {threshold: [1]}
);

observer.observe(document.querySelector('nav'));

तत्व को उसके कंटेनर से बाहर रखें top: -2px, और फिर stuckविशेषता के माध्यम से लक्षित करें ...

nav {
  background: magenta;
  height: 80px;
  position: sticky;
  top: -2px;
}
nav[stuck] {
  box-shadow: 0 0 16px black;
}

यहाँ उदाहरण: https://codepen.io/anon/pen/vqyQEK


1
मुझे लगता है कि एक stuckवर्ग एक कस्टम विशेषता से बेहतर होगा ... क्या आपकी पसंद का कोई विशेष कारण है?
कोलिमार्को

एक वर्ग ठीक भी काम करता है, लेकिन यह सिर्फ एक उच्च स्तर की तुलना में थोड़ा अधिक लगता है, क्योंकि यह एक व्युत्पन्न संपत्ति है। एक विशेषता मुझे अधिक उपयुक्त लगती है, लेकिन या तो यह स्वाद का मामला है।
rackable

पहले से तय हेडर के कारण मुझे 60px का टॉप चाहिए, इसलिए मुझे काम करने के लिए आपका उदाहरण नहीं मिल रहा है
FooBar

1
जो कुछ भी अटक रहा है उसमें कुछ शीर्ष पैडिंग जोड़ने की कोशिश करें, शायद padding-top: 60pxआपके मामले में :)
टिम विलिस

5

Google डेवलपर्स ब्लॉग पर किसी व्यक्ति ने IntersectionObserver के साथ एक प्रदर्शनकारी जावास्क्रिप्ट-आधारित समाधान पाया है ।

प्रासंगिक कोड बिट यहां:

/**
 * Sets up an intersection observer to notify when elements with the class
 * `.sticky_sentinel--top` become visible/invisible at the top of the container.
 * @param {!Element} container
 */
function observeHeaders(container) {
  const observer = new IntersectionObserver((records, observer) => {
    for (const record of records) {
      const targetInfo = record.boundingClientRect;
      const stickyTarget = record.target.parentElement.querySelector('.sticky');
      const rootBoundsInfo = record.rootBounds;

      // Started sticking.
      if (targetInfo.bottom < rootBoundsInfo.top) {
        fireEvent(true, stickyTarget);
      }

      // Stopped sticking.
      if (targetInfo.bottom >= rootBoundsInfo.top &&
          targetInfo.bottom < rootBoundsInfo.bottom) {
       fireEvent(false, stickyTarget);
      }
    }
  }, {threshold: [0], root: container});

  // Add the top sentinels to each section and attach an observer.
  const sentinels = addSentinels(container, 'sticky_sentinel--top');
  sentinels.forEach(el => observer.observe(el));
}

मैंने खुद इसे दोहराया नहीं है, लेकिन शायद यह किसी को इस सवाल पर ठोकर खाने में मदद करता है।


3

वास्तव में स्टाइलिंग सामान (यानी getBoudingClientRect, स्क्रॉल सुनना, आकार बदलना) के लिए js हैक का उपयोग करने का प्रशंसक नहीं है, लेकिन यह है कि मैं वर्तमान में समस्या को हल कर रहा हूं। इस समाधान में उन पृष्ठों के साथ समस्याएँ होंगी जिनमें न्यूनतम / अधिकतम सामग्री (<विवरण>), या नेस्टेड स्क्रॉलिंग या वास्तव में कोई वक्र बॉल्स हैं। यह कहा जा रहा है, यह एक सरल उपाय है जब समस्या सरल है।

let lowestKnownOffset: number = -1;
window.addEventListener("resize", () => lowestKnownOffset = -1);

const $Title = document.getElementById("Title");
let requestedFrame: number;
window.addEventListener("scroll", (event) => {
    if (requestedFrame) { return; }
    requestedFrame = requestAnimationFrame(() => {
        // if it's sticky to top, the offset will bottom out at its natural page offset
        if (lowestKnownOffset === -1) { lowestKnownOffset = $Title.offsetTop; }
        lowestKnownOffset = Math.min(lowestKnownOffset, $Title.offsetTop);
        // this condition assumes that $Title is the only sticky element and it sticks at top: 0px
        // if there are multiple elements, this can be updated to choose whichever one it furthest down on the page as the sticky one
        if (window.scrollY >= lowestKnownOffset) {
            $Title.classList.add("--stuck");
        } else {
            $Title.classList.remove("--stuck");
        }
        requestedFrame = undefined;
    });
})

ध्यान दें कि स्क्रॉल ईवेंट श्रोता को मुख्य थ्रेड पर निष्पादित किया जाता है जो इसे एक प्रदर्शन हत्यारा बनाता है। इसके बजाय इंटरसेक्शन ऑब्जर्वर एपीआई का उपयोग करें।
संशय जूल

if (requestedFrame) { return; }यह एनीमेशन फ्रेम बैचिंग के कारण "प्रदर्शन हत्यारा" नहीं है। हालांकि इंसर्सेशन ऑब्जर्वर अभी भी एक सुधार है।
सिपाही रीड

0

जब आप तत्व के ऊपर एक तत्व रखते हैं, तो उसके लिए एक कॉम्पैक्ट तरीका position:sticky। यह उस विशेषता को सेट करता है stuckजिसे आप CSS में मेल कर सकते हैं header[stuck]:

HTML:

<img id="logo" ...>
<div>
  <header style="position: sticky">
    ...
  </header>
  ...
</div>

जे एस:

if (typeof IntersectionObserver !== 'function') {
  // sorry, IE https://caniuse.com/#feat=intersectionobserver
  return
}

new IntersectionObserver(
  function (entries, observer) {
    for (var _i = 0; _i < entries.length; _i++) {
      var stickyHeader = entries[_i].target.nextSibling
      stickyHeader.toggleAttribute('stuck', !entries[_i].isIntersecting)
    }
  },
  {}
).observe(document.getElementById('logo'))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.