Ios8 में सफारी स्क्रॉलिंग स्क्रीन है जब निश्चित तत्वों को फोकस मिलता है


96

IOS8 सफारी में एक नया बग है जिसमें पोजिशन तय है।

यदि आप एक निश्चित पैनल में है एक textarea ध्यान केंद्रित करते हैं, तो सफारी आपको पृष्ठ के निचले भाग में स्क्रॉल करेगा।

इससे सभी प्रकार के UI के साथ काम करना असंभव हो जाता है, क्योंकि आपके पास अपने पृष्ठ को सभी तरह से स्क्रॉल करने और अपना स्थान खोने के बिना textareas में पाठ दर्ज करने का कोई तरीका नहीं है।

क्या इस बग को साफ-सुथरा बनाने का कोई तरीका है?

#a {
  height: 10000px;
  background: linear-gradient(red, blue);
}
#b {
  position: fixed;
  bottom: 20px;
  left: 10%;
  width: 100%;
  height: 300px;
}

textarea {
   width: 80%;
   height: 300px;
}
<html>
   <body>
   <div id="a"></div>
   <div id="b"><textarea></textarea></div>
   </body>
</html>

1
#B मदद पर z- इंडेक्स सेट करना चाहेंगे?
बेन

1
z इंडेक्स कोई मदद नहीं है, हो सकता है कि कुछ फैंसी नो ऑप सीएसएस ट्रांसफॉर्म स्टैक संदर्भों के साथ बहुत अधिक हों, निश्चित नहीं।
सैम केसरॉन

1
यहाँ संदर्भ के लिए चर्चा है: प्रवचन: meta.discourse.org/t/dealing-with-ios-8-ipad-mobile-safari-bugs/…
सैम केसर

79
iOS सफारी नई IE
geedubb

4
@geedubb सहमत हो गया। कोई भी नैतिक ओएस, जो अपने डिफ़ॉल्ट ब्राउज़र संस्करण को ओएस के नीचे रखता है, उन मुद्दों से बेईमानी करने वाला है जो पिछले 7 वर्षों से IE से ग्रस्त हैं।
dewd

जवाबों:


58

इस मुद्दे के इस अच्छे विश्लेषण के आधार पर , मैंने इसका उपयोग htmlऔर bodyतत्वों को सीएसएस में किया है:

html,body{
    -webkit-overflow-scrolling : touch !important;
    overflow: auto !important;
    height: 100% !important;
}

मुझे लगता है कि यह मेरे लिए बहुत अच्छा काम कर रहा है।


2
मेरे लिए भी काम किया। जब से मैं लोड पर अपने DOM में हेरफेर कर रहा हूँ, तब से इसने बहुत सी अन्य चीजों को खराब कर दिया है, इसलिए मैं इसे एक वर्ग में बनाता हूं, और इसे html में जोड़ दिया, शरीर के बाद DOM स्थिर हो गया। स्क्रॉलटॉप जैसी चीजें बहुत अच्छी तरह से काम नहीं करती हैं (मैं ऑटो स्क्रॉलिंग कर रहा हूं), लेकिन फिर से, आप स्क्रॉलिंग ऑपरेशन करते समय क्लास को जोड़ / हटा सकते हैं। हालांकि सफारी टीम के हिस्से में काम करना मुश्किल है।
आमर्ष

1
इस विकल्प को देखने वाले लोग stackoverflow.com/questions/7808110/…transform: translateZ(0); से भी परीक्षण करना चाहते हैं
lkraav

1
यह समस्या को हल करता है, लेकिन अगर आपके पास एनिमेशन हैं तो वे बहुत ही चॉपी दिखेंगे। मीडिया क्वेरी में इसे लपेटना बेहतर हो सकता है।
मिमीला

मेरे लिए iOS 10.3 पर काम किया।
15

यह समस्या को हल नहीं करता है। वर्चुअल कीबोर्ड दिखाई देने पर आपको स्क्रॉलिंग को इंटरसेप्ट करना होगा और ऊंचाई को विशिष्ट मान में बदलना होगा: stackoverflow.com/a/46044341/84661
ब्रायन कैनार्ड

36

सबसे अच्छा समाधान जो मैं आ सकता position: absolute;था, वह है फोकस पर प्रयोग करना और उस स्थिति की गणना करना, जब वह उपयोग कर रहा था position: fixed;। चाल यह है कि focusघटना बहुत देर से फायर करती है, इसलिए touchstartइसका उपयोग किया जाना चाहिए।

इस उत्तर में समाधान आईओएस 7 में हमारे पास बहुत ही सही व्यवहार की नकल करता है।

आवश्यकताएँ:

bodyजब तत्व निरपेक्ष स्थिति पर स्विच करता तत्व उचित स्थिति सुनिश्चित करने के लिए स्थिति होना आवश्यक है।

body {
    position: relative;
}

कोड ( लाइव उदाहरण ):

निम्नलिखित कोड प्रदान किए गए परीक्षण-केस के लिए एक मूल उदाहरण है, और इसे आपके विशिष्ट उपयोग-केस के लिए अनुकूलित किया जा सकता है।

//Get the fixed element, and the input element it contains.
var fixed_el = document.getElementById('b');
var input_el = document.querySelector('textarea');
//Listen for touchstart, focus will fire too late.
input_el.addEventListener('touchstart', function() {
    //If using a non-px value, you will have to get clever, or just use 0 and live with the temporary jump.
    var bottom = parseFloat(window.getComputedStyle(fixed_el).bottom);
    //Switch to position absolute.
    fixed_el.style.position = 'absolute';
    fixed_el.style.bottom = (document.height - (window.scrollY + window.innerHeight) + bottom) + 'px';
    //Switch back when focus is lost.
    function blured() {
        fixed_el.style.position = '';
        fixed_el.style.bottom = '';
        input_el.removeEventListener('blur', blured);
    }
    input_el.addEventListener('blur', blured);
});

तुलना के लिए हैक के बिना यहां एक ही कोड है

चेतावनी:

अगर द position: fixed; तत्व में पोजिशनिंग के साथ कोई अन्य मूल तत्व हैं body, तो स्विचिंग position: absolute;में अप्रत्याशित व्यवहार हो सकता है। की प्रकृति के कारण position: fixed;शायद यह एक बड़ा मुद्दा नहीं है, क्योंकि ऐसे तत्वों का घोंसला करना आम नहीं है।

अनुशंसाएँ:

हालांकि touchstartईवेंट का उपयोग अधिकांश डेस्कटॉप वातावरणों को फ़िल्टर करेगा, आप संभवतः उपयोगकर्ता-एजेंट को सूँघने का उपयोग करना चाहेंगे ताकि यह कोड केवल टूटे हुए iOS 8 के लिए चले, न कि अन्य उपकरणों जैसे कि Android और पुराने iOS संस्करणों के लिए। दुर्भाग्य से, हम अभी तक यह नहीं जानते हैं कि Apple कब iOS में इस मुद्दे को ठीक करेगा, लेकिन मुझे आश्चर्य होगा कि अगर यह अगले प्रमुख संस्करण में तय नहीं हुआ।


मुझे आश्चर्य है कि अगर एक डिव के साथ डबल रैपिंग और पारदर्शी रैपिंग डिव पर 100% की ऊँचाई सेट करें तो इससे बचना मुश्किल हो सकता है ...
सैम केसर

@SamSaffron क्या आप स्पष्ट कर सकते हैं कि इस तरह की तकनीक कैसे काम कर सकती है? मैंने सफलता के बिना इस तरह की कुछ चीजों की कोशिश की। चूंकि दस्तावेज़ की ऊंचाई अस्पष्ट है, मुझे यकीन नहीं है कि यह कैसे काम कर सकता है।
अलेक्जेंडर ओ'मैरा

मैं सोच रहा था कि बस एक "तय" 100% ऊंचाई आवरण इस के आसपास काम कर सकते हैं, संभवतः नहीं
सैम केसर

@downvoter: क्या मुझे कुछ गलत लगा? मैं मानता हूं कि यह एक भयानक समाधान है, लेकिन मुझे नहीं लगता कि कोई बेहतर उपाय हैं।
अलेक्जेंडर ओ'मैरा

4
यह मेरे लिए काम नहीं किया, इनपुट क्षेत्र अभी भी चलता है।
रॉड्रिगो रूइज़

8

मुझे एक ऐसा तरीका मिला जो बिना किसी स्थिति को बदलने की आवश्यकता के पूर्ण रूप से काम करता है !

पूर्ण अपूर्ण कोड

var scrollPos = $(document).scrollTop();
$(window).scroll(function(){
    scrollPos = $(document).scrollTop();
});
var savedScrollPos = scrollPos;

function is_iOS() {
  var iDevices = [
    'iPad Simulator',
    'iPhone Simulator',
    'iPod Simulator',
    'iPad',
    'iPhone',
    'iPod'
  ];
  while (iDevices.length) {
    if (navigator.platform === iDevices.pop()){ return true; }
  }
  return false;
}

$('input[type=text]').on('touchstart', function(){
    if (is_iOS()){
        savedScrollPos = scrollPos;
        $('body').css({
            position: 'relative',
            top: -scrollPos
        });
        $('html').css('overflow','hidden');
    }
})
.blur(function(){
    if (is_iOS()){
        $('body, html').removeAttr('style');
        $(document).scrollTop(savedScrollPos);
    }
});

इसे तोड़कर

पहले आपको HTML में पृष्ठ के शीर्ष की ओर निश्चित इनपुट फ़ील्ड की आवश्यकता होती है (यह एक निश्चित तत्व है, इसलिए इसे शब्दार्थ रूप से किसी भी तरह शीर्ष के पास होना चाहिए):

<!DOCTYPE HTML>

<html>

    <head>
      <title>Untitled</title>
    </head>

    <body>
        <form class="fixed-element">
            <input class="thing-causing-the-issue" type="text" />
        </form>

        <div class="everything-else">(content)</div>

    </body>

</html>

फिर आपको वैश्विक स्क्रॉल में वर्तमान स्क्रॉल स्थिति को सहेजने की आवश्यकता है:

//Always know the current scroll position
var scrollPos = $(document).scrollTop();
$(window).scroll(function(){
    scrollPos = $(document).scrollTop();
});

//need to be able to save current scroll pos while keeping actual scroll pos up to date
var savedScrollPos = scrollPos;

फिर आपको iOS उपकरणों का पता लगाने का एक तरीका चाहिए ताकि यह उन चीजों को प्रभावित न करे जिन्हें ठीक करने की आवश्यकता नहीं है ( https://stackoverflow.com/a/9039885/1611058 से लिया गया फ़ंक्शन )

//function for testing if it is an iOS device
function is_iOS() {
  var iDevices = [
    'iPad Simulator',
    'iPhone Simulator',
    'iPod Simulator',
    'iPad',
    'iPhone',
    'iPod'
  ];

  while (iDevices.length) {
    if (navigator.platform === iDevices.pop()){ return true; }
  }

  return false;
}

अब हमारे पास वह सब कुछ है जिसकी हमें आवश्यकता है, यहाँ ठीक है :)

//when user touches the input
$('input[type=text]').on('touchstart', function(){

    //only fire code if it's an iOS device
    if (is_iOS()){

        //set savedScrollPos to the current scroll position
        savedScrollPos = scrollPos;

        //shift the body up a number of pixels equal to the current scroll position
        $('body').css({
            position: 'relative',
            top: -scrollPos
        });

        //Hide all content outside of the top of the visible area
        //this essentially chops off the body at the position you are scrolled to so the browser can't scroll up any higher
        $('html').css('overflow','hidden');
    }
})

//when the user is done and removes focus from the input field
.blur(function(){

    //checks if it is an iOS device
    if (is_iOS()){

        //Removes the custom styling from the body and html attribute
        $('body, html').removeAttr('style');

        //instantly scrolls the page back down to where you were when you clicked on input field
        $(document).scrollTop(savedScrollPos);
    }
});

+1। यदि आपके पास गैर-तुच्छ डोम पदानुक्रम है, तो स्वीकृत उत्तर की तुलना में यह काफी कम जटिल है। यह अधिक upvotes होना चाहिए
Anson Kao

क्या आप इसे मूल जेएस में भी प्रदान कर सकते हैं? बहुत बहुत धन्यवाद!
मेसकाइब

@SamSaffron, क्या यह उत्तर वास्तव में यू के लिए काम किया है? क्या मैं यहाँ कुछ उदाहरण रख सकता हूँ यह मेरे लिए काम किया?
गणेश पूत ta

@ SamSaffron, क्या यह जवाब वास्तव में आपकी समस्या का हल है, क्या आप कुछ उदाहरण भेज सकते हैं जो यू के लिए काम करते हैं, मैं उसी पर काम कर रहा हूं, लेकिन यह मेरे लिए काम नहीं करता है।
गणेश पूत ta

@GaneshPutta यह संभव है कि हाल ही में iOS अपडेट ने इसे और अधिक कारगर नहीं बनाया है। मैंने इसे 2.5 साल पहले पोस्ट किया था। यह अभी भी काम करना चाहिए, अगर आपने सभी निर्देशों का ठीक से पालन किया है: /
डैनियल टोनन

4

मैं आवश्यक चयन तत्वों में एक ईवेंट श्रोता को जोड़कर चुनिंदा सूचनाओं के लिए इसे ठीक करने में सक्षम था, फिर एक पिक्सेल की ऑफसेट द्वारा स्क्रॉल करना जब प्रश्न चयन में चयन होता है।

यह आवश्यक रूप से एक अच्छा समाधान नहीं है, लेकिन यह मेरे द्वारा देखे गए अन्य उत्तरों की तुलना में बहुत सरल और अधिक विश्वसनीय है। ब्राउज़र स्थिति को फिर से प्रस्तुत करने / फिर से गणना करने के लिए लगता है: निश्चित; Window.scrollBy () फ़ंक्शन में दिए गए ऑफसेट के आधार पर विशेषता।

document.querySelector(".someSelect select").on("focus", function() {window.scrollBy(0, 1)});

2

मार्क रयान सलीली ने सुझाव दिया, जैसे कि मैंने पाया कि गतिशील रूप से मेरी पृष्ठभूमि तत्व की ऊंचाई और अतिप्रवाह बदल रहा है - यह सफारी को स्क्रॉल करने के लिए कुछ भी नहीं देता है।

इसलिए मोडल के शुरूआती एनीमेशन के खत्म होने के बाद, पृष्ठभूमि की स्टाइल को बदलें:

$('body > #your-background-element').css({
  'overflow': 'hidden',
  'height': 0
});

जब आप मोडल बंद करते हैं तो उसे वापस बदल दें:

$('body > #your-background-element').css({
  'overflow': 'auto',
  'height': 'auto'
});

जबकि अन्य उत्तर सरल संदर्भों में उपयोगी होते हैं, पूर्ण / निश्चित स्थिति स्वैप का उपयोग करने के लिए मेरा DOM बहुत जटिल (धन्यवाद SharePoint) था।


1

सफाई से? नहीं।

मुझे हाल ही में एक चिपचिपे हेडर में एक निश्चित खोज क्षेत्र के साथ खुद यह समस्या थी, इस समय आप जो सबसे अच्छा कर सकते हैं वह है कि हर समय एक चर में स्क्रॉल की स्थिति बनाए रखें और चयन पर एक शीर्ष के साथ तय की बजाय निश्चित तत्व की स्थिति को पूर्ण बनाएं दस्तावेज़ की स्क्रॉल स्थिति के आधार पर स्थिति।

यह हालांकि बहुत बदसूरत है और फिर भी सही जगह पर उतरने से पहले कुछ अजीब तरह से आगे और पीछे स्क्रॉल करता है, लेकिन यह सबसे निकटतम है जो मुझे मिल सकता है।

किसी भी अन्य समाधान में ब्राउज़र के डिफ़ॉल्ट स्क्रॉल यांत्रिकी को ओवरराइड करना शामिल होगा।


1

यह अब iOS 10.3 में तय हो गया है!

भाड़े की अब जरूरत नहीं होनी चाहिए।


1
क्या आप किसी भी जारी किए गए नोटों की ओर इशारा कर सकते हैं जो इसे निश्चित होने के रूप में इंगित करते हैं?
ब्लूपैन जूल

Apple बहुत गुप्त हैं, उन्होंने मेरी बग रिपोर्ट को बंद कर दिया मैंने पुष्टि की कि यह अब उचित काम करता है, यही सब मुझे मिला :)
सैम भगवा

अभी भी IOS 11 पर यह मुद्दा है
13

0

इस विशेष बग से निपटा नहीं गया, लेकिन शायद एक अतिप्रवाह डाल दिया: छिपा हुआ; शरीर पर जब पाठ क्षेत्र दिखाई देता है (या सिर्फ सक्रिय, आपके डिजाइन पर निर्भर करता है)। यह ब्राउज़र को कहीं भी "डाउन" करने के लिए स्क्रॉल नहीं करने का प्रभाव हो सकता है।


1
मैं भी काफी पहले भी कि हैक :( विचार करने के लिए ट्रिगर करने के लिए touchstart पाने के लिए लग रहे हैं नहीं कर सकते
सैम केसर

0

इनपुट क्षेत्र को बदलने के लिए एक संभावित समाधान होगा।

  • मॉनिटर एक div पर घटनाओं पर क्लिक करें
  • कीबोर्ड को रेंडर करने के लिए एक छिपे हुए इनपुट फ़ील्ड पर ध्यान केंद्रित करें
  • नकली इनपुट फ़ील्ड में छिपे इनपुट फ़ील्ड की सामग्री को दोहराएं

function focus() {
  $('#hiddeninput').focus();
}

$(document.body).load(focus);

$('.fakeinput').bind("click",function() {
    focus();
});

$("#hiddeninput").bind("keyup blur", function (){
  $('.fakeinput .placeholder').html(this.value);
});
#hiddeninput {
  position:fixed;
  top:0;left:-100vw;
  opacity:0;
  height:0px;
  width:0;
}
#hiddeninput:focus{
  outline:none;
}
.fakeinput {
  width:80vw;
  margin:15px auto;
  height:38px;
  border:1px solid #000;
  color:#000;
  font-size:18px;
  padding:12px 15px 10px;
  display:block;
  overflow:hidden;
}
.placeholder {
  opacity:0.6;
  vertical-align:middle;
}
<input type="text" id="hiddeninput"></input>

<div class="fakeinput">
    <span class="placeholder">First Name</span>
</div> 


codepen


0

इनमें से किसी भी समाधान ने मेरे लिए काम नहीं किया क्योंकि मेरा DOM जटिल है और मेरे पास डायनामिक अनंत स्क्रॉल पृष्ठ हैं, इसलिए मुझे अपना स्वयं का बनाना था।

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

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

अपेक्षित समाधान: जब उपयोगकर्ता चिपचिपा तत्व में इनपुट पर क्लिक करता है, तो iOS में कोई भी स्क्रॉल नहीं होता है।

उपाय:

     /*Returns a function, that, as long as it continues to be invoked, will not
    be triggered. The function will be called after it stops being called for
    N milliseconds. If `immediate` is passed, trigger the function on the
    leading edge, instead of the trailing.*/
    function debounce(func, wait, immediate) {
        var timeout;
        return function () {
            var context = this, args = arguments;
            var later = function () {
                timeout = null;
                if (!immediate) func.apply(context, args);
            };
            var callNow = immediate && !timeout;
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
            if (callNow) func.apply(context, args);
        };
    };

     function is_iOS() {
        var iDevices = [
          'iPad Simulator',
          'iPhone Simulator',
          'iPod Simulator',
          'iPad',
          'iPhone',
          'iPod'
        ];
        while (iDevices.length) {
            if (navigator.platform === iDevices.pop()) { return true; }
        }
        return false;
    }

    $(document).on("scrollstop", debounce(function () {
        //console.log("Stopped scrolling!");
        if (is_iOS()) {
            var yScrollPos = $(document).scrollTop();
            if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
                $('#searchBarDiv').css('position', 'absolute');
                $('#searchBarDiv').css('top', yScrollPos + 50 + 'px'); //50 for fixed header
            }
            else {
                $('#searchBarDiv').css('position', 'inherit');
            }
        }
    },250,true));

    $(document).on("scrollstart", debounce(function () {
        //console.log("Started scrolling!");
        if (is_iOS()) {
            var yScrollPos = $(document).scrollTop();
            if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
                $('#searchBarDiv').css('position', 'fixed');
                $('#searchBarDiv').css('width', '100%');
                $('#searchBarDiv').css('top', '50px'); //50 for fixed header
            }
        }
    },250,true));

आवश्यकताएँ: काम करने के लिए JQuery मोबाइल आवश्यक है।

चिपचिपा तत्व द्वारा बनाई गई किसी भी अंतराल को सुचारू करने के लिए वाद-विवाद शामिल है।

IOS10 में परीक्षण किया गया।


0

मैं कल कुछ इस तरह से कूद गया कि # ए की अधिकतम दृश्यमान ऊंचाई (शरीर की ऊंचाई मेरे मामले में थी) की ऊंचाई निर्धारित करके जब # बी दिखाई दे रहा है

उदाहरण के लिए:

    <script>
    document.querySelector('#b').addEventListener('focus', function () {
      document.querySelector('#a').style.height = document.body.clientHeight;
    })
    </script>

ps: देर से उदाहरण के लिए खेद है, बस देखा कि यह आवश्यक था।


14
कृपया यह स्पष्ट करने के लिए एक कोड उदाहरण शामिल करें कि आपका फिक्स कैसे मदद कर सकता है
roo2

@EruPenkman खेद है कि आपकी टिप्पणी पर ध्यान दिया गया, आशा है कि मदद करता है।
ओनूर उयार

0

मेरे पास समस्या थी, कोड की लाइनों ने मेरे लिए इसे हल किया -

html{

 overflow: scroll; 
-webkit-overflow-scrolling: touch;

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.