Мобильные устройства, position: fixed; и во что это выливается



    По ходу редизайна блога появилось желание создать 'Scroll to Top' функцию не только для десктопа, но и для мобильных устройств. В связи с небольшим свободным пространством на экране смартфона было решено сделать кнопку возвращения на верх в виде полоски высотой в 20px прикрепленную к нижней границе экрана. Код довольно простой:

    $('body').append("<div class='scroll-to-top-mobile'>Scroll To Top</div>"); // Создаем элемент на странице
    
    $(window).scroll( function() {
       if ( $(this).scrollTop() > $(window).height() ) { // Если длина прокрутки страницы больше высоты экрана, то...
          $('.scroll-to-top-mobile').fadeIn(); // Показать кнопку
       }   else   { // Если нет, то...
          $('.scroll-to-top-mobile').fadeOut(); // Скрыть кнопку
       }
    });
    
    $('.scroll-to-top-mobile').on('click', function() {
       $('html, body').animate({scrollTop : 0}, 800); // По клику на кнопку прокручиваем страницу вверх
       return false;
    });
    


    .scroll-to-top-mobile {
       width: 100%;
       height: 20px;
       background: #e6e6e6;
       border-top: 1px solid #ddd;
       position: fixed; /* Фиксированное размещение кнопки в окне, позиция не меняется относительно окна во время прокрутки страницы */
       bottom: 0; /* Прижимаем к нижнему краю окна */
       z-index: 9999; /* Поднимаем кнопку над всеми элементами страницы */
       text-align: center;
       display: none; /* Изначально кнопку не видно */
       cursor: pointer;
       font-size: 12px;
    }
    


    На десктопе работает отлично, но во время тестирования на Android 2.3 оказалось, что position: fixed; не работает, элемент позиционируется абсолютно. Немного поискав выяснилось, что фиксированное позиционирование не поддерживается в iOS до 5й версии и в Android до 3й версии. О поддержке остальными браузерами пишут здесь.

    Там же говорят о том, что Android 2.3 можно научить понимать данное свойство с помощью медиа запроса:

    @viewport {
       user-zoom: fixed;
    }
    


    Или используя meta-тег:

    <meta name=”viewport” content=”user-scalable=no” />
    


    Эта функция отключает возможность масштабирования страницы.

    Теперь, без возможности зума документа актуальным становится вопрос о читаемости текста на экрана смартфона. Визуальный размер текста на экране десктопа отличается от размера на экране смартфона, подробнее об это здесь. Т.к. блог полностью построен по технике RWD, то делать отдельную версию для телефонов не имеет смысла. Здесь может помочь идентифицирование мобильных устройств с помощь медиа запроса device-aspect-ratio. Эта функция позволяет применять содержащийся в ней CSS только на устройствах с заданным соотношением сторон. На iPhone этот показатель равен 1.5, на Android 1.3 — 1.5. Таким образом можно определить нужные нам устройства и задать для них оптимальный размер шрифта на странице:

    @media all and (max-device-aspect-ratio: 1.5) {
    	body {
    		font-size: 16px;
    		line-height: 1.4em;
    	}
    }
    


    Или с помощью meta-тега:

    <link rel=”stylesheet” href=”css/mobile.css” type=”text/css” media=”all and (max-device-pixel-ratio: 1.5)” />
    


    Протестировав новые настройки на своем Android 2.3 я обнаружил, что параметры заданные с помощью медиа запроса вступают в силу только после перезагрузки страницы, а иногда и не одной. Здесь на помощь пришло замечательное решение стоимостью в несколько строк JS кода. Мы можем определить мобильное устройство с помощью простого скрипта:

    // Определяем устройство
    var mobile = (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));
    if(mobile){
       // Создаем ссылку на CSS
       var cssLink = document.createElement("link");
       cssLink.setAttribute("type", "text/css");
       cssLink.setAttribute("rel", "stylesheet");
       cssLink.setAttribute("href", "css/mobile.css");
       document.head.appendChild(cssLink);
    }
    


    navigator.userAgent возвращает строку User-Agent'а, дальше мы ищем в ней название одного из указанных устройств. Если такое имеется, то создаем для него ссылку на CSS файл содержащий нужные нам параметры для адаптирования текста под мобильный экран. Правда из-за того, что скрипт срабатывает только после загрузки документа, параметры из подключенного CSS вступают в силу через 1 — 1.5 секунды.

    Так вот простая функция 'Scroll to Top' тянет за собой череду проблем, благо решение для каждой из них есть.

    Ссылки


    Поделиться публикацией
    Комментарии 28
      0
      Почему бы просто тот самый absolute; на мобильных устройствах не привязывать к нижней границе по координатам, минус размер самого элемента? На браузерах поддерживающих fixed; делать его а на остальных делать так выше сказано в чем же разница в мобильных (на моей практике ее не замечено). Как по мне так отсутствие zoom + доп. ratio скорее минус.
        +6
        Ах, да забыл спросить: — зачем(!?) scroll to top на телефоне с сенсорным экраном?
          0
          Если страница очень большая, то это лучше, чем листать её вручную вверх.
            +4
            Быстрое движение по экрану от верха к низу экрана (android 2.3, htc legend) позволяло перемотать к началу ленту из 500+ комментариев Хабра к началу статьи. В отличии от этого кнопка занела бы «полезную площадь» хотя конечно — это не так критично, чем в одно, два движения переместиться к верху прочитанного контента.
              0
              Вы знаете, у меня htc wildfire и 2000 смс с девушкой.
              И когда он по какой-то причине при открытии проглючивает и бросает в верх этого списка, то я проклинаю его за то, что нету кнопки «Scroll to Bottom». Никаких «2-3 движания» — сиди и листай.
                0
                Внизу последнее сообщение (у меня так же но с женой :) ) открыл, перекинуло от глюка вверх, закрыл оно снова внизу на последнем сообщении и прекрасно :)
                  0
                  Пробовал, естественно. У меня не срабатывает( Если открылось вверху, то до выключения телефона будет открываться вверху. Может, конечно, можно как-то выгрузить приложение из памяти, но я — не заморачивался
                    0
                    Вот, от случая к случаю, но — это никогда не было проблемой. В контексте темы обсуждения я ее, проблемы тоже не вижу, только плохая организация контента (в смс на андроиде (их необходимо как-то группировать) — плохо, например), плохая организация интерфейса — вот здесь проблема а не в наличии кнопки перейти ниже/выше < — это следствие.
            +4
            На iOS если тапнуть по верхней полоске (там где часы) происходит то же самое.
              +1
              К тому же в iOS всегда есть возможность «проскролить» к началу страницы с помощью нажатия на верхнюю полоску статус бара. Более бесполезного занятия трудно найти ) Извини, топик-стартер.
            +2
            Столько «костылей» ради полоски «scroll to the top»,
            А польза от этого довольна сомнительна — я на своём HTC MyTouch 4G только с третьего раза попал пальцем в эту полоску, то есть проще было отмотать вверх.

            В своём проекте я использовал JavaScript, который стырил отсюда, но это работает только для мобильников.

            Костыли, костыли, вокруг одни костыли…
              0
              На счет попасть по кнопке: думаю это зависит от калибровки сенсора. Т.к. в моем Galaxy Gio с диагональю экрана в 3.2" мне совершенно не составляет труда тапнуть по этой полоске.
              +5
              В Сафари на iOS тап по верхней, статусной панели выполняет функцию «Scroll to top».
                0
                и position:fixed есть с пятой версии если не ошибаюсь
                  0
                  в, ну в статье про это как раз есть
                  в следующий раз я буду внимательней
                  +4
                  В Opera Mobile если быстро прокручивать вверх или вниз, то браузер показывает кнопку по нажатию на которую можно бытро спуститься или подняться до упора.
                    –1
                    Я вам открою тайну, это работает во всех приложениях, где используется стандартный Scroll View контрол.
                    +3
                    Осталось добавить полоски «Scroll to bottom», «Scroll to the topmost comment», «Scroll to my first comment», «Scroll to my last comment» и, главное, «Take me out of here now!».
                      +1
                      А что с формой поиска? Размер уехал куда-то влево и далеко.
                        0
                        Вправо, простите ))
                          0
                          Да, действительно. В фф съехала. Спасибо!
                          0
                          Только позавчера боролся с этой же проблемой.
                          У вас, видимо, ее нет (т.к. кнопка не показывается, если страница в самом верху). А у меня дело вот в чем: меню вверху, задано position: fixed. При клике на пункты меню страница прокручивается влево-вправо. Проблема в том, что при прокрутке страницы JS-ом все fixed-ы фактически едут вместе со страницей (хотя рисуются правильно), и чтобы их вернуть на место надо чуть-чуть подвигать страницу пальцем. Так вот и получается, что я 1 раз жму — страница крутится, и больше меню не нажимается, т.к. фактически оно тоже уехало. Надо подвигать страницу пальцем, тчобы меню снвоа заработало.
                          Может вы знаете как решить эту проблемку?
                          Для меня решение очевидно — вынести меню из скроллящейся области, но верстка не моя и она крайне убога и вся завязана на таблицах, что влечет за собой переверстку пол-сайта(
                            0
                            Не могли бы вы дать ссылку? Думаю так будет проще.
                            0
                            Проверка регулярным выражением на наличие подстроки «android» может выйти боком, когда Android станут ставить не только на мобильники да планшетки, но и на более компьютероподобные устройства — ASUSовские ноутбуки, например.
                              +1
                              $(window).scroll( function() {
                                 if ( $(this).scrollTop() > $(window).height() ) { // Если длинна прокрутки страницы больше высоты экрана, то...
                                    $('.scroll-to-top-mobile').fadeIn(); // Показать кнопку
                                 }   else   { // Если нет, то...
                                    $('.scroll-to-top-mobile').fadeOut(); // Скрыть кнопку
                                 }
                              });
                              

                              Это сколько же фейдИнов накидается в queue, пока будут происходить onscroll.
                              может хотя бы .stop().fadeIn() и .stop().fadeOut()
                                0
                                Спасибо за решение!
                                  +1
                                  var mobile = (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));
                                  

                                  Тут не нужен toLowerCase(), т.к. в регулярке уже стоит параметр «i», который указывает на нечувствительность к регистру.
                                    0
                                    Помню, была такая же беда с fixed элементом. Но использовать
                                    <meta name=”viewport” content=”user-scalable=no” />
                                    

                                    было нельзя.
                                    В итоге пришлось пересчитывать его позицию с помощью

                                    window.addEventListener(«orientationchange»
                                    window.addEventListener(«scroll»

                                    Единственное, мобильная опера вообще не поддавалась лечению, так что пришлось ампутировать:
                                    if( clientBrowser.isOpera ) {
                                    	$('.box').hide()
                                    }
                                    

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое