11 июля в 16:20

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 за ценное замечание.
Дмитрий @lipton_ice_tea
карма
21,0
рейтинг 17,6
Web-разработчик
Самое читаемое Разработка

Комментарии (26)

  • +2
    		position: sticky;
    		position: -webkit-sticky;
    

    На всякий случай замечу, что без префиксное свойство должно быть последним, поэтому правильнее будет переставить эти строки местами.
    • 0
      спасибо! поправил!
  • 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
      Пользуйтесь на здоровье! ;)
  • 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

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