CSS и iOS Safari

    image Доброго времени суток, дорогие хабрахабровцы!

    Всегда хочется, что бы твой сайт выглядел одинаково хорошо на разных устройствах, включая и мобильные. Но, если поведение в браузерах Android во многом предсказуемо, то с iOS возникает ряд «сюрпризов». О них сегодня и поговорим!

    Часть примеров уже публиковалась на Хабре, но я все-равно решил включить их в статью. Разделю статью на две части. В первой – приведу список полезных css-свойств для webkit, а во второй поговорим о фиксах проблем, возникающих при версте для iOS Safari.

    Свойства


    1. -webkit-overflow-scrolling: touch

    Это css-свойство добавит плавный скролл в блоках с overflow: scroll. Рекомендую добавлять это свойство везде, где внутри блока может возникать прокрутка, к примеру, в мобильном меню.

    .ov-scroll{
    	overflow-y: auto;
    	-webkit-overflow-scrolling:touch;
    }

    2. -webkit-text-size-adjust: none

    Отключает масштабирование текста в горизонтальной ориентации.

    body{
    	-webkit-text-size-adjust: none;
    }

    Пример:

    image

    3. -webkit-tap-highlight-color: #ccc

    Устанавливает цвет выделения активного элемента при тапе на нем (a, label). По умолчанию это серый цвет, и часто может быть ни к чему, или выбиваться из общего дизайна.

    a, label{
    	-webkit-tap-highlight-color: transparent;
    }
    

    Пример такого выделения:

    image

    4. -webkit-appearance: none

    Отключает наложение на элементы стилей системы: тени, border-radius и т.д. Применяется для input (но не всех), textarea, и т.д. Удобно, когда надо задать единый вид элементов на всех устройствах.

    input[type=text], input[type=submit], textarea{
    	-webkit-appearance: none;
    } 

    Применяется не только в верстке для Safari.

    5. media (pointer:coarse)

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

    @media (pointer:coarse){
    ...
    }

    Можно использовать не только в верстке для Safari.

    Фиксы


    1. background-attachment: fixed

    Проблема: background-attachment: fixed не работает в iOS Safari.

    Решение: Фиксировать не фон, а блок или псевдоэлемент.

    body:before {
        content: '';
        background-image: url(...);
        position: fixed;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        z-index: -1;
    }

    2. Нежелательный скролл модального окна

    Проблема: Это довольно редкий случай, но для общей информации, думаю, так же полезно будет знать о нем. Если модальное окно имеет собственную прокрутку и в закрытом состоянии просто установлен отрицательный z-index (и, к примеру, opacity: 0) — то при попытке скролла страницы, модальное окно может перехватить скролл. В результате чего не будет осуществляться прокрутка страницы.

    Решение: Добавляем pointer-events: none к модальному окну в закрытом состоянии.

    .modal{
    	position: fixed;
    	z-index: -9;
    	top: 0;
    	bottom: 0;
    	left: 0;
    	right: 0;
    	opacity: 0;
    	pointer-events: none;
    }

    3. Пропадание меню при скролле
    Для того, что бы меню «прилипало» к верхней границе экрана при скролле страницы, часто используют следующий прием. Изначально у меню установлено свойство position: absolute, и при достижении верхней границы окна, через js оно меняется на fixed. А при скролле страницы к началу, значение опять меняется на absolute.

    Проблема: В Safari на iOS, при смене position с fixed на absolute, меню пропадает с экрана пока скролл не завершится.

    Решение: Использовать для меню position: -webkit-sticky. Поведение меню будет сравнимо с вышеописанным, но пропадать ничего не будет! Плюс, не надо использовать js

    .nav{
    	.........
    	position: absolute;
    }
    
    .nav_fix{
    	position: fixed;
    }
    
    @supports ((position:sticky) or (position:-webkit-sticky)){
    	.nav, .nav_fix{
    		position: -webkit-sticky;
    		position: sticky;
    	}
    }

    К слову, значение sticky для свойства position сейчас поддерживается большим количеством браузеров, поэтому его можно использовать и в десктопных браузерах.

    4. Блок с position: fixed при скролле

    Если реализации решений предыдущих проблем я видел на некоторых сайтах, то данная проблема на сайтах встречается постоянно.

    Проблема: При скролле в браузере изменяется высота экрана. Отсюда, если при раскрытом меню или модальном окне не блокировать скролл, возникает подобный эффект:

    image

    Решение: Нужно сделать следующий «трюк», используя transform.

    .nav{
    	position: fixed;
    	left: 0;
    	right: 0;
    	bottom: 0;
    	top: -70px;
    	padding-bottom: 70px;
    	transform: translateY(70px);
    }

    Величина в 70px покрывает разницу в изменении высоты окна. И только transform позволяет прорисовывать фон элемента за пределами экрана в данной ситуации.

    Выводы


    А выводов особо нет, просто пользуйтесь ) Если знаете еще полезные css-свойства или «фиксы», применимые на практике, пишите в комментариях!

    Спасибо за внимание!

    Update
    В свойствах изменен пункт 5. Т.к. media (hover) имеет узкую поддержку. Спасибо dom1n1k за ценное замечание.
    Метки:
    Поделиться публикацией
    Комментарии 27
    • +2
      		position: sticky;
      		position: -webkit-sticky;
      

      На всякий случай замечу, что без префиксное свойство должно быть последним, поэтому правильнее будет переставить эти строки местами.
    • 0
      Увидев media (hover), хлопнул себя по лбу — блин, так всё просто, а я какие-то классы скриптом на боди вешаю.
      Но посмотрев браузерную поддержку, обратно разочаровался (IE, FF и несколько более экзотических — мимо).
      • +2

        Можно в обратную сторону:


        @media not (hover)
        • 0
          Да, с этими браузерами подстава) Изменил этот пункт. Спасибо!
          • 0
            Это всё равно не решает проблему до конца. Как ни крути, получится, что где-то либо нужный ховер отвалится, либо ненужный пролезет. Хотя, возможно, процент ошибок и снижается.
        • +1
          2. -webkit-text-size-adjust: none

          Отключает масштабирование текста в горизонтальной ориентации.
          Вот за это я бы руки отрывал. Часто текст слишком мелкий в портретной ориентации, поворачиваешь телефон горизонтально пытаясь сделать текст покрупнее, а он такой же мелкий. Иногда как бы издеваясь на долю секунды после поворота текст становится крупнее, а потом уменьшается. А в Reader Mode обычно половина контента отсутствует, или он вовсе не доступен.

          Хотя бывает и хуже, например так :)
          некоторые отключают ландшафтный режим вообще :)
          • 0
            Если в портретной ориентации слишком мелкий шрифт — то это недочет дизайна/верстки. И надо увеличивать шрифт, а не «заставлять» пользователей крутить телефон) Сайт должен быть удобен в любой ориентации.
            • 0
              Кому-то шрифт кажется слишком мелким, кому-то — слишком крупным, именно поэтому все браузеры испокон веков дают пользователю возможность самому выбрать оптимальный размер шрифта, а вебдизайнеру остаётся лишь использовать font-size:100%.
          • 0
            Да что-то iOS в последнее время сдает… все хуже и худе
            • 0
              Вместо media (hover) который судя по MDN не поддерживается в стандартном браузере Android можно использовать min-device-width: 1280px, который применяет ховер к большей части десктопных браузеров (хотя теперь он помечен как deprecated). Либо сочетать эти два способа вместе.

              Ну и забыли классику упомянуть: touch-action: manipulation (убирает задержку в 300ms на мобильных браузерах при таче)
              • +1
                -webkit-appearance убирает не только стили, но и стрелочку у выпадающего списка, стрелочки у полей типа «числа», иконку календарика у даты и тому подобное. В общем многие элементы которые относятся как Shadow DOM.
                Так что осторожней с ним!

                И поддерживается многими браузерами, со своими префиксами конечно.
                • +1
                  За «4. Блок с position: fixed при скролле» большое спасибо, только по проекту эту пакость обсуждали, как увидел статью ))
                • 0
                  4. Блок с position: fixed при скролле

                  height: calc(100% + 70px);
                  padding-bottom: 70px;


                  по моему так блок тоже будет за пределами экрана.
                  • 0
                    Будет за пределами… Но не будет прорисовываться во время скролла. Так что это не вариант =(
                  • 0

                    То, что «background-attachment: fixed» не работает — это ещё не так плохо. Гораздо хуже, что это свойство в сочетании с «background-size: cover» делает так, что фоновое изображение растягивается по размеру всей страницы, а не по размеру экрана.


                    В результате получается так:


                    Демо на CodePen


                    Оригинальное фоновое изображение

                    Оригинальное фоновое изображение


                    Настольный Safari

                    Настольный Safari


                    Мобильный Safari

                    Мобильный Safari


                    Приходится в CSS делать хаки для определения мобильного Safari и отключать для него «background-attachment: fixed».

                    • 0

                      Ещё бы актуальный способ «отключать» эластичный скролл.


                      Предыдущий уже не работает:


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

                        Попробуйте position:fixed; width: 100%; height: 100%, а скроллинг уже дла вложенного блока.

                        • 0

                          Этот хороший способ, ровно как и описанный мною, уже не работает.


                          Что же касается веб-приложений, то единственное, что можно сделать для предотвращения ужасающего скролла, при котором обнажается серый задний фон — это отслеживать любой touchmove и предотвращать его через event.preventDefault():


                          $(document).on('touchmove', function(event) {
                              event.preventDefault();
                          });

                          Но такой способ подходит только для веб-приложений не требующих скролла.


                          Надеюсь, что неправ и упустил какой-то рабочий способ.

                            • 0
                              «Доктор, да я не о том, я о ступеньках...»

                              Прошу прощения, в первом комментарии не уточнил, что речь идёт о веб-приложениях. Проблемы с эластичным скроллом именно там.


                              И у вас в том числе

                              image

                              • 0

                                Так и у нас веб приложение. Или вы про Кордову? Там отдельный параметр надо в config.xml добавить.

                                • 0

                                  Нет, я именно про веб-приложение, которое устанавливается из Сафари через «Add to Home Screen». Так вот там теперь неубиваемый скролл.


                                  В сообщении выше скрин установленного вашего $mol Demo с оттянутым экраном, где этот эластичный скролл во всей красе. К сожалению.

                      • 0

                        Промахнулся с ответом.

                        • 0
                          Предложил бы кто-нибудь вменяемый фикс для vh в ios safari
                          • 0

                            а что на счёт прокрутки контента под модальным окном? есть красивые решения?

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