CSS Media Query - мягкая клавиатура нарушает правила ориентации css - альтернативное решение?

84

Я работаю с несколькими планшетными устройствами - оба Android и iOS. В настоящее время у меня есть следующие варианты разрешения для всех планшетов.

  • 1280 х 800
  • 1280 x 768
  • 1024 x 768 (очевидно, для iPad) - iPad не имеет этой проблемы

Самый простой способ применить стиль, основанный на ориентации устройства, - использовать ориентацию медиа-запроса с использованием следующего синтаксиса.

@media all and (orientation:portrait)
{
  /* My portrait based CSS here */
}

@media all and (orientation:landscape)
{
  /* My landscape based CSS here */
}

Это отлично работает на всех планшетных устройствах. НО , проблема в том, что когда устройство находится в портретном режиме, а пользователь нажимает на любое поле ввода (например, поиск), появляется программная клавиатура, которая уменьшает видимую область веб-страницы и заставляет ее отображать в ландшафтном CSS. На планшетах Android это зависит от высоты клавиатуры. Итак, в конечном итоге веб-страница выглядит сломанной. Поэтому я не могу использовать медиа-запрос ориентации CSS3 для применения стилей на основе ориентации (если нет лучшего медиа-запроса для целевой ориентации). Вот скрипка http://jsfiddle.net/hossain/S5nYP/5/, которая эмулирует это - для тестирования устройства используйте полную тестовую страницу - http://jsfiddle.net/S5nYP/embedded/result/

Вот скриншот поведения, взятого с демонстрационной страницы. введите описание изображения здесь

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

Я нашел фрагмент на http://davidbcalhoun.com/2010/dealing-with-device-orientation, который предлагает добавить класс и настроить таргетинг на основе этого. Например:

<html class="landscape">
  <body>
    <h1 class="landscape-only">Element Heading - Landscape</h1>
    <h1 class="portrait-only">Element Heading - Portrait</h1>
    <!-- .... more... ->

# CSS
.landscape .landscape-only { display:block; }
.landspace .portrait-only  { display:none; }
.portrait .portrait-only   { display:block; }
.portrait .landscape-only  { display:none; }

Что вы думаете об этом, ребята? У вас есть лучшее решение?

Хоссейн Хан
источник
Только что узнал, IPad это НЕ имеет этой проблемы. ТОЛЬКО ОС Android (сотовые планшеты) и мобильные телефоны имеют эту проблему.
Hossain Khan
Я столкнулся с аналогичной проблемой на своем мобильном сайте. После тестирования на нескольких устройствах Android, похоже, он не ограничен какой-либо конкретной ОС или мобильным / планшетным устройством. Похоже, это в первую очередь проблема с аппаратами Motorola и Samsung. Мне не удалось воспроизвести проблему на нашем телефоне HTC.
Т.Дж. Киршнер
1
Эта проблема в основном связана с устройствами Android, мобильными устройствами / планшетами - единственный способ воспроизвести это - установить настраиваемую клавиатуру с большой высотой, чтобы при отображении клавиатуры доступная высота для веб-просмотра была меньше доступной ширины. Только тогда веб-просмотр запускает изменение ориентации. Например, на скриншоте, если я могу отключить слой предложений над клавиатурой, тогда этой проблемы не будет, потому что высота веб-просмотра будет больше ширины. Но, в любом случае, элегантного и эффективного решения у меня пока нет.
Хоссейн Хан
1
Просто поймите, что полноэкранное веб-приложение IOS 7.0.0 также имеет такое поведение,
Александр
Это печально. Мне не удалось эффективно решить проблему, поэтому я пометил ее как known limitation.
Hossain Khan

Ответы:

105

Я знаю, что это опоздание на пару лет, но я нашел отличное решение

Для ландшафтных СМИ:

@media screen and (min-aspect-ratio: 13/9) { /* landscape styles here */}

А для портретных носителей:

@media screen and (max-aspect-ratio: 13/9) { /* portrait styles here */}

Полное решение и причины его работы можно найти здесь Майкл Баррет - Проблемы с браузером Android

Изменить: срок действия этой ссылки истек, но ее снимок можно найти в интернет-архиве: Майкл Баррет - Проблемы с браузером Android

Шон Рутледж
источник
2
Это решает проблему, но создает больше проблем на других устройствах для меня (в основном, ноутбуках и компьютерах)
Стефан Биджзиттер
К сожалению, это решение работает не на всех мобильных устройствах.
Диого Кардосо,
@StephanBijzitter, может быть, вы могли бы использовать свойство max-width?
Шон Рутледж
3
Это очень грубое решение и не будет работать на некоторых устройствах. Например, мой телефон дает около 17,7 / 9 при открытии программной клавиатуры, в то время как соотношение сторон альбомной ориентации намного меньше на многих других устройствах.
raacer
2
Ссылка на полное решение не работает.
Sparkmorry
27

Проблема заключается в способе расчета ориентации:

http://www.w3.org/TR/css3-mediaqueries/#orientation

«Ориентация» медиа-функции является «портретной», когда значение медиа-функции «высота» больше или равно значению медиа-функции «ширина». В противном случае «ориентация» будет «альбомной».

Поскольку высота / ширина вычисляется для видимого окна просмотра, мягкая клавиатура, по-видимому, заставляет ориентацию переворачиваться теперь, когда ширина окна просмотра меньше высоты. Одним из решений было бы просто использовать ваши медиа-запросы на основеwidth вместо. Это делает его более гибким для разных устройств независимо от ориентации, не говоря уже о том, что ширина / высота поддерживается более широко, чем ориентация.

Если вы хотите учитывать ширину, а не ориентацию, я буду использовать в качестве примера iPhone:

@media screen and (max-width: 320px) {
  /* rules applying to portrait */
}

@media screen and (max-width: 480px) {
  /* rules applying to landscape */
}

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

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

мерзавец
источник
1
Я понимаю, как браузеры рассчитывают пейзаж и портрет. Но нужен альтернативный и лучший способ справиться с этим. Еще один интересный момент: iPad не меняет ориентацию при поднятой клавиатуре. Я не знаю, почему этот **** андроид реализовал именно так.
Hossain Khan
Мне просто любопытно, почему вам нужна именно ориентация устройства, а не только ширина. Какую проблему вы пытаетесь решить, которую нельзя решить одной лишь шириной?
scurker
Я работаю с несколькими устройствами с разным разрешением. Не могли бы вы привести пример использования ширины в качестве альтернативы ориентации? Насчет использования изменения ориентации, есть несколько приложений по изменению ориентации - обычно доступное пространство отличается в разной ориентации. Таким образом, некоторые элементы можно скрыть или изменить размер в зависимости от ориентации. Спасибо за помощь.
Hossain Khan
@HossainKhan @media all and (max-device-wdith:NNNpx){}or @media all and (min-device-wdith:NNNpx){}or@media all and (device-wdith:NNNpx){}
RaphaelDDL
1
В конечном итоге, удалив and (orientation:portrait)и просто применив максимальную и минимальную ширину, я решил мою проблему. !!!
Либин
16

Альтернативой может быть использование device-aspect-ratio, которое остается неизменным. Однако в Webkit поворот устройства не запускает обновление правил CSS с использованием этого запроса, даже если тесты JavaScript возвращают значение true для нового соотношения сторон. Очевидно, это из-за ошибки , но я не могу найти отчет об ошибке. Использование комбинации orientationи, {min,max}-device-aspect-ratioкажется, работает нормально:

@media screen and (max-device-aspect-ratio: 1/1) and (orientation: portrait)
@media screen and (min-device-aspect-ratio: 1/1) and (orientation: landscape)

Использование orientationтриггеров обновляется, как ожидалось, а использование device-aspect-ratioограничений обновляется с учетом фактических изменений ориентации.

Муру
источник
К сожалению, эта функция сейчас устарела developer.mozilla.org/en-US/docs/Web/CSS/@media/…
Евгений Глухоторенко
середина 2020 года, и это все еще работает, несмотря на то, что оно устарело ... отличное решение, единственное, которое действительно сработало для меня во всех случаях, которые у меня есть!
qraqatit
6

Я проработал перечисленные выше варианты, и ни один из них не устранил проблемы. Я перешел на screen.availHeight, так как он дает стабильные результаты по высоте, избегая проблем с отображением клавиатуры.

// Avoiding the keyboard in Android causing the portrait orientation to change to landscape. 
// Not an issue in IOS. Can use window.orientation.
var currentOrientation = function() {
  // Use screen.availHeight as screen height doesn't change when keyboard displays.  
  if(screen.availHeight > screen.availWidth){
    $("html").addClass('portrait').removeClass('landscape'); 
  } else {
    $("html").addClass('landscape').removeClass('portrait'); 
  }
}

// Set orientation on initiliasation
currentOrientation();
// Reset orientation each time window is resized. Keyboard opening, or change in orientation triggers this.
$(window).on("resize", currentOrientation);
Робби Дженнингс
источник
Итак, я тестировал это немного больше, и это не так просто. Устройства Android должны использовать screen.availHeight и screen.availWidth. В IOS с ними есть ошибки, поэтому используйте window.orientation для IOS. Рабочий стол должен использовать window.innerHeight, window.innerWidth, поскольку вы хотите, чтобы размеры окна, а не размеры экрана.
Робби Дженнингс,
Я бился головой об стену с помощью приведенного выше кода. Слишком привередливы. Я не поддерживаю этот рабочий стол для этого приложения, поэтому использую window. Ориентация - волшебное решение для Android и IOS. Сейчас работает нормально. var direction = Math.abs (window.orientation) === 90? 'картина ландшафта';
Робби Дженнингс,
3

Для меня это сработало:

  @media screen and (max-device-aspect-ratio: 1/1), (max-aspect-ratio: 1/1){
        /*Portrait Mode*/
};

В то время как max-aspect-ratioзаботится о запуске портретного режима, просто изменяя размер окна (полезно для ПК и других устройств с альбомной max-device-aspect-ratioориентацией ), помогает со смартфонами или другими устройствами с переменной ориентацией. И поскольку я не объявляю конкретные настройки для ландшафтного режима, даже если система max-aspect-ratioсообщает> 1, портретный режим все равно будет активирован, max-device-aspect-ratioесли устройство Android ориентировано таким образом.

1/1Часть в основном означает , что если отношение <= 1, он переходит в режим портретной, в противном случае она переходит в ландшафтный режим.

Helveciofneto
источник
2
Что насчет того, когда подойдет клавиатура?
adi518
Когда виртуальная клавиатура появляется на мобильном устройстве, ничего не меняется, потому что соотношение сторон устройства (max-device-aspect-ratio) изменяется только тогда, когда вы фактически поворачиваете устройство или когда вы намеренно меняете ориентацию экрана с книжной на альбомную и наоборот. -верс.
helveciofneto
Да, в итоге я реализовал и протестировал его на себе. Я разрабатываю пакет вокруг этого: npmjs.com/package/mobile-orientation
adi518
Вернулся, чтобы узнать еще об одном: (max-aspect-ratio: 1/1) . Кажется, нам нужен этот бит только для определения портрета на рабочем столе?
adi518 03
Правильно. 1/1 гарантирует, что идеальный квадрат по-прежнему запускает портретный режим (что возможно в системах, которые позволяют изменять размер окна, например, окно браузера на рабочем столе). Без него в этом точном соотношении происходят странные вещи.
helveciofneto 05
1

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

Он работает, назначая ширину окна и высоту области просмотра устройства атрибуту данных для будущей проверки. Поскольку телефоны не меняют ширину при поднятии клавиатуры, только высота, проверка соотношения И ширины относительно исходной ширины может сказать вам, поднята ли клавиатура. Я еще не нашел варианта использования, но я уверен, что найду. Если вы все найдете, дайте мне знать.

Я использую некоторые глобальные объекты, такие как InitialRun и MobileOrientation, которые используются для переключения js, я также использую атрибуты данных html5 для хранения информации в DOM для манипуляций css.

    var InitialRun = true; // After the initial bootstrapping, this is set to false;
    var MobileOrientation = 'desktop';
    function checkOrientation(winW, winH){ // winW and winH are the window's width and hieght, respectively
        if (InitialRun){
            if (winW > winH){
                $('body').attr('data-height',winW);
                $('body').attr('data-width',winH);
                MobileOrientation = 'landscape';    
                $('body').attr('data-orientation','landscape'); 
            }
            else{
                $('body').attr('data-height',winH);
                $('body').attr('data-width',winW);
                MobileOrientation = 'portrait';
                $('body').attr('data-orientation','portrait');
            }
        }
        else{
            if (winW > winH && winW != $('body').data('width')){
                MobileOrientation = 'landscape';    
                $('body').hdata('orientation','landscape'); //TODO:uncomment
                $('body, #wrapper').css({'height':"100%",'overflow-y':'hidden'});
                //$('body').attr('data-orientation','portrait');
            }
            else{
                MobileOrientation = 'portrait';
                $('body').attr('data-orientation','portrait');
                $('body, #wrapper').css({'height':$('body').data('height'),'overflow-y':'auto'});
            }
        }

    }
тамбельробот
источник
1

Я использовал простой прием, чтобы решить эту проблему

@media (max-width: 896px) and (min-aspect-ratio: 13/9){/* Landscape content*/}

Я обнаружил, что max-width: 896px можно использовать для всех мобильных устройств. попробуйте это решение, оно работает!

Мохит Сони
источник
вы спасаете мне день :), но когда он возвращается с ландшафта на портрет, масштабирование страницы нарушается, как с этим справиться?
Амир Фарахани
Это зависит от текущей максимальной ширины мобильных устройств, и при улучшении технологии она изменится. Так стоит ли менять сценарий всех медиа-запросов? Я думаю, это плохая идея.
QMaster
0

Взгляните на эту ссылку: http://www.alistapart.com/articles/a-pixel-identity-crisis/
Опора не только на ориентацию, но и на max-device-heightто, что device-pixel-ratioможет помочь. Во всяком случае, я не тестировал, поэтому не уверен, что это поможет.

Сергей Т.
источник
0

Идея: уберите параметр портрета из своего медиа-запроса и оставьте его только с минимальной шириной. Сделайте свой обычный стиль для портретного режима в этом медиа-запросе. Затем создайте еще один медиа-запрос для ландшафтного режима с минимальной высотой, достаточной для того, чтобы браузер не использовал этот запрос при появлении клавиатуры. Вам придется поэкспериментировать с тем, что такое эта «достаточно высокая минимальная высота», но это не должно быть слишком сложно, поскольку большинство (если не все) ландшафтные режимы имеют высоту больше, чем у вас, когда появляется клавиатура. Кроме того, вы можете добавить «минимальную ширину» к запросу с альбомной ориентацией, которая больше, чем у большинства смартфонов в портретной ориентации (т.е. около 400 пикселей), чтобы ограничить область действия запроса.

Вот альтернативное (и непрочное) решение: - Добавьте в свой html пустой произвольный элемент, который будет иметь «display: none» ни в чем другом, кроме портретного режима. - Создайте прослушиватель jquery или javascript для input: focus. При щелчке по входу ваш javascript проверяет свойство отображения произвольного элемента. Если он возвращает «block» или что-то еще, что вы установили в портретном режиме, вы можете переопределить свой стиль с помощью JS для запросов в портретном режиме. И наоборот, у вас будет прослушиватель input: blur, чтобы очистить свойства style.cssText элементов, которые вы жестко закодировали.

Я сам сейчас экспериментирую с этим - я выложу код того, что работает, когда получу что-то надежное и управляемое. (Мое первое решение кажется наиболее разумным).

user3718546
источник
0

У меня это работает надежно. Я использую http://detectmobilebrowsers.com/ для расширения jQuery для обнаружения $ .browser.mobile.

if ($.browser.mobile) {
  var newOrientationPortrait = true;

//Set orientation based on height/width by default
  if ($(window).width() < $(window).height())
      newOrientationPortrait = true;
  else
      newOrientationPortrait = false;

//Overwrite orientation if mobile browser supports window.orientation
if (window.orientation != null)
    if (window.orientation === 0)
        newOrientationPortrait = true;
    else
        newOrientationPortrait = false;

Вот мой код для изменения области просмотра в зависимости от ориентации. Эта функция вызывается только для мобильных устройств, даже не для планшетов. Это позволяет мне легко писать CSS для 400 пикселей и 800 пикселей (портрет против ландшафта).

_onOrientationChange = function() {
    if (_orientationPortrait) 
        $("meta[name=viewport]").attr("content", "width=400,user-scalable=no");
    else 
        $("meta[name=viewport]").attr("content", "width=800");
}

Из-за характера моих требований я не мог сделать это только в запросах CSS Media, так как сама DOM должна была изменяться в зависимости от ориентации. К сожалению, на моей работе деловые люди пишут требования к программному обеспечению без предварительной консультации с разработчиками.

Крис Фремген
источник
0

Я столкнулся с той же проблемой в iPad.
т.е. когда программная клавиатура отображается в портретном режиме, устройство обнаруживается в альбомной ориентации, и к экрану применяются стили для альбомной ориентации, что приводит к искаженному представлению.

Спецификация устройства

  • Устройство : iPad Mini 4
  • ОС : iOS 11.2.6
  • Разрешение экрана : 1024 x 768

к сожалению, для меня это решение не сработало.

@media screen and (min-aspect-ratio: 13/9) { /* landscape styles here */}
@media screen and (max-aspect-ratio: 13/9) { /* portrait styles here */}

Итак, что я сделал, я написал такой медиа-запрос для моего портретного режима.

@media only screen and (min-width : 300px) and (max-width : 768px) and (orientation : landscape) {
/* portrait styles, when softkeyboard appears, goes here */
}

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

Джейкоб Нельсон
источник
0

Так как iPhone 11 Pro Max Viewport имеет размер 414 x 896 PX, этого должно быть достаточно, чтобы иметь ориентацию: альбомная с min-width: 500 пикселей.

Иван Маслов
источник