Zapytanie o media CSS - Klawiatura miękka łamie reguły orientacji css - alternatywne rozwiązanie?

84

Pracuję z wieloma tabletami - zarówno z systemem Android i iOS. Obecnie mam następujące warianty rozdzielczości dla wszystkich tabletów.

  • 1280 x 800
  • 1280 x 768
  • 1024 x 768 (oczywiście iPad) - iPad nie ma tego problemu

Najprostszym sposobem zastosowania stylu opartego na orientacji urządzenia jest użycie orientacji zapytania o media przy użyciu następującej składni.

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

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

Działa to doskonale na wszystkich tabletach. ALE problem polega na tym, że gdy urządzenie jest w trybie portretowym i użytkownik stuka w dowolne pole wejściowe (np. Wyszukiwanie), pojawia się klawiatura ekranowa - co zmniejsza widoczny obszar strony internetowej i zmusza ją do renderowania w css opartym na poziomie. Na tabletach z Androidem zależy to od wysokości klawiatury. Ostatecznie strona wygląda na zepsutą. Dlatego nie mogę użyć zapytania o media w CSS3 do stosowania stylów opartych na orientacji (chyba że istnieje lepsze zapytanie o media do orientacji docelowej). Oto http://jsfiddle.net/hossain/S5nYP/5/ skrzypce, które to emuluje - do testowania urządzeń użyj pełnej strony testowej - http://jsfiddle.net/S5nYP/embedded/result/

Oto zrzut ekranu przedstawiający zachowanie pobrane ze strony demonstracyjnej. wprowadź opis obrazu tutaj

Czy jest więc jakaś alternatywa, aby rozwiązać ten problem, jestem otwarty na rozwiązanie oparte na JavaScript, jeśli natywne rozwiązanie oparte na CSS nie działa.

Znalazłem fragment na http://davidbcalhoun.com/2010/dealing-with-device-orientation, który sugeruje dodanie klasy i celu na tej podstawie. Na przykład:

<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; }

Co o tym myślicie? Czy masz lepsze rozwiązanie?

Hossain Khan
źródło
Właśnie dowiedziałem się, iPad ma nie mieć tego problemu. TYLKO system operacyjny Android (tablety o strukturze plastra miodu) i telefony komórkowe mają ten problem.
Hossain Khan
Wystąpił podobny problem z moją witryną mobilną. Po przetestowaniu na kilku urządzeniach z Androidem wydaje się, że nie ogranicza się do żadnego konkretnego systemu operacyjnego ani urządzenia mobilnego / tabletu. Wygląda na to, że jest to przede wszystkim problem z urządzeniami Motorola i Samsung. Nie udało mi się odtworzyć problemu na naszym telefonie HTC.
TJ Kirchner
1
Ten problem dotyczy głównie urządzeń z systemem Android, telefonów komórkowych / tabletów - jedynym sposobem na odtworzenie tego jest zainstalowanie niestandardowej klawiatury o dużej wysokości, aby podczas wyświetlania klawiatury dostępna wysokość widoku internetowego była mniejsza niż dostępna szerokość. Dopiero wtedy webview powoduje zmianę orientacji. Na przykład na zrzucie ekranu, jeśli mogę wyłączyć warstwę sugestii na górze klawiatury, to tego problemu nie będzie, ponieważ wysokość widoku internetowego będzie większa niż szerokość. W każdym razie nie mam jeszcze żadnego eleganckiego i wydajnego rozwiązania.
Hossain Khan
1
Po prostu uświadom sobie, że pełnoekranowa aplikacja internetowa IOS 7.0.0 również ma takie zachowanie
Alexandre,
To smutne. Nie udało mi się skutecznie rozwiązać problemu, dlatego oznaczyłem go jako known limitation.
Hossain Khan

Odpowiedzi:

105

Wiem, że to opóźnienie o kilka lat, ale znalazłem świetne rozwiązanie

W przypadku mediów w orientacji poziomej:

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

A dla mediów portretowych:

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

Pełne rozwiązanie i dlaczego działa, można znaleźć tutaj Michael Barret - Wyzwania przeglądarki Android

Edycja: ten link wygasł, ale migawkę można znaleźć w archiwum internetowym: Michael Barret - wyzwania przeglądarki Android

Sean Routledge
źródło
2
Rozwiązuje problem, ale tworzy dla mnie więcej problemów na innych urządzeniach (głównie laptopach i komputerach)
Stephan Bijzitter
Niestety to rozwiązanie nie działa na wszystkich urządzeniach mobilnych.
Diogo Cardoso
@StephanBijzitter może przydałabyś się właściwość „max-width”?
Sean Routledge
3
To rozwiązanie jest bardzo szorstkie i nie będzie działać na niektórych urządzeniach. Na przykład mój telefon daje około 17,7 / 9 po otwarciu miękkiej klawiatury, podczas gdy proporcje krajobrazu są znacznie mniejsze na wielu innych urządzeniach.
raacer
2
Link do pełnego rozwiązania jest uszkodzony.
Sparkmorry
27

Problem leży w sposobie obliczania orientacji:

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

Funkcja multimediów „orientacja” to „portret”, gdy wartość funkcji multimediów „wysokość” jest większa lub równa wartości funkcji multimediów „szerokość”. W przeciwnym razie „orientacja” to „pozioma”.

Ponieważ wysokość / szerokość jest obliczana dla widocznej rzutni, klawiatura programowa najwyraźniej powoduje zmianę orientacji teraz, gdy szerokość rzutni jest mniejsza niż wysokość. Jednym z rozwiązań byłoby po prostu użycie zapytań o media w oparciu o to samo width. To sprawia, że ​​jest bardziej elastyczny w różnych urządzeniach, niezależnie od orientacji, nie wspominając o szerokości / wysokości jest bardziej obsługiwana niż orientacja.

Jeśli chcesz wziąć pod uwagę szerokość zamiast orientacji, użyję iPhone'a jako przykładu:

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

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

Takie podejście jest bardziej elastyczne niż orientacja, ponieważ zapytania nie ograniczają się do urządzeń / klientów użytkownika obsługujących orientację, nie wspominając o tym, że orientacja mówi niewiele w porównaniu z szerokością.

Oczywiście, jeśli naprawdę potrzebujesz znać orientację, wydaje się, że początkowo ustawiasz klasę i po prostu użyj tego, co może być najlepszą opcją.

scurker
źródło
1
Rozumiem, jak przeglądarki obliczają orientację poziomą i pionową. Ale potrzebujesz alternatywnego i lepszego sposobu radzenia sobie z tym. Inną interesującą rzeczą jest to, że iPad nie powoduje zmiany orientacji, gdy klawiatura jest podniesiona. Nie wiem, dlaczego ten **** android musiał to zaimplementować.
Hossain Khan
Jestem po prostu ciekawy, dlaczego potrzebujesz konkretnej orientacji urządzenia, a nie tylko szerokości. Jaki jest problem, który próbujesz rozwiązać, a którego sama szerokość nie rozwiąże?
scurker
Pracuję z wieloma urządzeniami o różnej rozdzielczości. Czy mógłbyś podać przykład, w jaki sposób szerokość może być używana jako alternatywa dla orientacji? O, użyciu zmiany orientacji, istnieje wiele aplikacji na zmianę orientacji - zwykle dostępna przestrzeń różni się w różnych orientacjach. Dlatego niektóre elementy można ukryć lub zmienić rozmiar w zależności od orientacji. Dzięki za wszelką pomoc.
Hossain Khan
@HossainKhan @media all and (max-device-wdith:NNNpx){}lub @media all and (min-device-wdith:NNNpx){}lub@media all and (device-wdith:NNNpx){}
RaphaelDDL
1
ostatecznie, usuwając and (orientation:portrait)i po prostu stosując maksymalną i minimalną szerokość, rozwiązało mój problem. !!!
Libin
16

Alternatywą może być użycie device-aspect-ratio, które pozostaje niezmienione. Jednak w Webkicie obracanie urządzenia nie powoduje aktualizacji reguł CSS przy użyciu tego zapytania, mimo że testy JavaScript zwracają wartość true dla nowego współczynnika proporcji. Najwyraźniej jest to spowodowane błędem , ale nie mogę znaleźć raportu o błędzie. Używanie kombinacji orientationi {min,max}-device-aspect-ratiowydaje się działać dobrze:

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

Użycie orientationwyzwalaczy aktualizuje się zgodnie z oczekiwaniami, a użycie device-aspect-ratioograniczeń zaktualizowano zgodnie z rzeczywistymi zmianami orientacji.

muru
źródło
Niestety ta funkcja jest teraz przestarzała developer.mozilla.org/en-US/docs/Web/CSS/@media/…
Eugene Gluhotorenko
w połowie 2020 roku i to nadal działa pomimo tego, że zostało wycofane ... świetne rozwiązanie, jedyne, które faktycznie działało dla mnie we wszystkich przypadkach, które mam!
qraqatit
6

Przerobiłem opcje wymienione powyżej i żadna z nich nie rozwiązała problemów. Przerzuciłem się na używanie screen.availHeight, ponieważ daje spójne wyniki wysokości, unikając problemu z wyświetlaniem klawiatury.

// 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);
Robby Jennings
źródło
Więc testowałem to trochę więcej i nie jest to takie proste. Urządzenia z Androidem muszą używać screen.availHeight i screen.availWidth. IOS jest z nimi wadliwy, więc użyj window.orientation dla IOS. Pulpit powinien używać window.innerHeight, window.innerWidth tak, jak chcesz, aby były to wymiary okna, a nie wymiary ekranu.
Robby Jennings
Za pomocą powyższego kodu waliłem głową o ścianę. Zbyt wybredny. Nie obsługuję pulpitu dla tej aplikacji, więc używam window.orientation to magiczne rozwiązanie dla Androida i IOS. Teraz działa dobrze. var orientacja = Math.abs (window.orientation) === 90? 'krajobraz': 'portret';
Robby Jennings
3

Dla mnie to załatwiło sprawę:

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

Chociaż max-aspect-ratiodba o uruchomienie trybu portretowego po prostu przez zmianę rozmiaru okna (przydatne w przypadku komputerów PC i innych urządzeń tylko w max-device-aspect-ratioorientacji poziomej ), pomaga w przypadku smartfonów lub innych urządzeń o zmiennej orientacji. A ponieważ nie deklaruję konkretnych ustawień trybu poziomego, nawet jeśli max-aspect-ratiozgłaszam systemowi> 1, tryb portretowy nadal będzie uruchamiany przezmax-device-aspect-ratio jeśli urządzenie z Androidem jest zorientowane w ten sposób.

1/1Część w zasadzie oznacza, że jeśli stosunek wynosi <= 1, to idzie do wykonywania portretów, w przeciwnym razie przechodzi do trybu poziomego.

helveciofneto
źródło
2
A co, gdy pojawi się klawiatura?
adi518
Gdy klawiatura wirtualna pojawia się na urządzeniu mobilnym, nic się nie zmienia, ponieważ współczynnik proporcji urządzenia (maksymalny współczynnik proporcji urządzenia) zmienia się tylko wtedy, gdy faktycznie obrócisz urządzenie lub gdy celowo zmienisz orientację ekranu z pionowej na poziomą i vice -versa.
helveciofneto
Tak, ostatecznie wdrożyłem i przetestowałem to samodzielnie. Rozwijam
adi518
Wrócił z zapytaniem na jeszcze jedno (max-aspect-ratio: 1/1). Wygląda na to, że potrzebujemy tylko tego kawałka, aby wykryć portret na pulpicie?
adi518
Dobrze. 1/1 ma zapewnić, że idealny kwadrat nadal uruchamia tryb portretowy (co jest możliwe w systemach, które umożliwiają zmianę rozmiaru okna, takich jak okno przeglądarki na pulpicie). Bez tego dziwne rzeczy dzieją się w dokładnie takim stosunku.
helveciofneto
1

Przejrzałem kilka powyższych odpowiedzi i żadna z nich nie zrobiła dokładnie tego, czego chciałem, czyli jak najdokładniej naśladować funkcjonalność iPhone'a. Oto, co teraz pracuje dla mnie w produkcji.

Działa poprzez przypisanie szerokości i wysokości okna urządzenia do atrybutu danych w celu późniejszego sprawdzenia. Ponieważ telefony nie zmieniają rozmiaru podczas podnoszenia klawiatury, tylko wysokość, sprawdzenie proporcji ORAZ szerokość w stosunku do oryginalnej szerokości może powiedzieć, czy klawiatura jest podniesiona. Nie znalazłem jeszcze przypadku użycia, który się nie powiódł, ale jestem pewien, że tak. Jeśli wszyscy znajdziecie, dajcie mi znać.

Używam niektórych globali, takich jak InitialRun i MobileOrientation, które są używane do przełączania js, używam również atrybutów danych html5 do przechowywania informacji w DOM do manipulacji 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'});
            }
        }

    }
therebelrobot
źródło
1

Użyłem prostej sztuczki, aby rozwiązać ten problem

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

Odkryłem, że max-width: 896px może być używane na wszystkich urządzeniach mobilnych. wypróbuj to rozwiązanie działa!

Mohit Soni
źródło
ratujesz mi dzień :), ale gdy wraca z krajobrazu do portretu, powiększenie strony jest zepsute, jak sobie z tym poradzić?
Amir Farahani
Zależy to od obecnej maksymalnej szerokości urządzeń mobilnych i przy ulepszaniu technologii ulegną one zmianie. Czy zatem powinniśmy zmienić scenariusz dotyczący wszystkich zapytań o media? Myślę, że to kiepski pomysł.
QMaster
0

Pomysł: usuń parametr portretu z zapytania o media i pozostaw go tylko z minimalną szerokością. Wykonaj swój normalny styl dla trybu pionowego w zapytaniu o media. Następnie utwórz kolejne zapytanie o media dla trybu poziomego z minimalną wysokością na tyle wysoką, aby przeglądarka nie używała tego zapytania, gdy pojawi się klawiatura. Musiałbyś poeksperymentować z tym, czym jest ta `` wystarczająco wysoka minimalna wysokość '', ale nie powinno to być zbyt trudne, ponieważ większość (jeśli nie wszystkie) trybów poziomych ma wysokość większą niż w przypadku wyskakiwania klawiatury. Dodatkowo możesz dodać „minimalną szerokość” do zapytania poziomego, która jest większa niż większość smartfonów w widoku pionowym (tj. Około ~ 400 pikseli), aby ograniczyć zakres zapytania.

Oto alternatywne (i wątłe) rozwiązanie: - Dodaj pusty dowolny element do swojego html, który będzie miał „display: none” w trybie innym niż portret. - Utwórz odbiornik jquery lub javascript do wprowadzania danych: fokus. Po kliknięciu wejścia, twój javascript sprawdza właściwość display dowolnego elementu. Jeśli zwróci „blok” lub cokolwiek ustawisz w trybie portretu, możesz nadpisać swój styl za pomocą JS do zapytań w trybie portretowym. I odwrotnie, miałbyś detektor input: blur, aby wyczyścić właściwości style.cssText elementów zakodowanych na stałe.

Sam eksperymentuję z tym teraz - wyślę kod tego, co działa, gdy dostanę coś solidnego i łatwego do zarządzania. (Moje pierwsze rozwiązanie wydaje się najbardziej rozsądne).

user3718546
źródło
0

U mnie to działa niezawodnie. Używam http://detectmobilebrowsers.com/ dla rozszerzenia jQuery do wykrywania pliku $ .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;

Oto mój kod służący do modyfikowania rzutni na podstawie orientacji. Ta funkcja jest wywoływana tylko w przypadku urządzeń mobilnych, nawet tabletów. To pozwala mi łatwo pisać CSS dla 400px i 800px (portret vs krajobraz).

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

Ze względu na charakter moich wymagań nie byłem w stanie tego zrobić w samych zapytaniach CSS Media, ponieważ sam DOM musiał się zmieniać w zależności od orientacji. Niestety w mojej pracy ludzie biznesu piszą wymagania dotyczące oprogramowania bez wcześniejszej konsultacji z programistami.

Chris Fremgen
źródło
0

Z tym samym problemem spotkałem się na iPadzie.
to znaczy; gdy klawiatura ekranowa pojawia się w trybie pionowym, urządzenie jest wykrywane w orientacji poziomej, a na ekranie stosowane są style krajobrazu, co powoduje pomieszanie widoku.

Specyfikacja urządzenia

  • Urządzenie : iPad Mini 4
  • OS : iOS 11.2.6
  • Rozdzielczość ekranu : 1024 x 768

niestety u mnie to rozwiązanie nie zadziałało.

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

Tak więc napisałem zapytanie o media, takie jak ten, dla mojego trybu portretowego.

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

to znaczy; kiedy pojawia się miękka klawiatura, wysokość ekranu zmniejsza się, ale szerokość ekranu pozostaje do 768 pikseli, co spowodowało wykrycie ekranu w orientacji poziomej przez zapytanie o media. Stąd obejście podane powyżej.

Jacob Nelson
źródło
0

Ponieważ iPhone 11 Pro Max Viewport ma 414 x 896 PX - powinno wystarczyć do uzyskania orientacji: pozioma z min-width: 500px

Ivan Maslov
źródło