CSS Media Query - Bàn phím mềm phá vỡ các quy tắc định hướng css - giải pháp thay thế?


83

Tôi đang làm việc với nhiều thiết bị máy tính bảng - cả Android và iOS. Hiện tại, tôi có các biến thể độ phân giải sau cho tất cả các máy tính bảng.

  • 1280 x 800
  • 1280 x 768
  • 1024 x 768 (iPad rõ ràng) - iPad không có vấn đề này

Cách đơn giản nhất để áp dụng kiểu dựa trên hướng thiết bị là sử dụng định hướng của truy vấn phương tiện bằng cú pháp sau.

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

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

Điều này hoạt động hoàn toàn tốt trên tất cả các thiết bị máy tính bảng. NHƯNG , vấn đề là, khi thiết bị ở chế độ dọc và người dùng nhấn vào bất kỳ trường nhập liệu nào (ví dụ: tìm kiếm), bàn phím mềm sẽ bật lên - điều này làm giảm diện tích hiển thị của trang web và buộc nó hiển thị trong css dựa trên chiều ngang. Trên thiết bị máy tính bảng Android, nó phụ thuộc vào chiều cao của bàn phím. Vì vậy, cuối cùng trang web trông bị hỏng. Do đó, tôi không thể sử dụng truy vấn phương tiện định hướng của CSS3 để áp dụng các kiểu dựa trên hướng (trừ khi có truy vấn phương tiện tốt hơn cho hướng đích). Đây là một http://jsfiddle.net/hossain/S5nYP/5/ mô phỏng điều này - để kiểm tra thiết bị, hãy sử dụng trang kiểm tra đầy đủ - http://jsfiddle.net/S5nYP/embedded/result/

Đây là ảnh chụp màn hình của hành vi được lấy từ trang demo. nhập mô tả hình ảnh ở đây

Vì vậy, có bất kỳ giải pháp thay thế nào để giải quyết vấn đề này không, tôi sẵn sàng sử dụng giải pháp dựa trên JavaScript nếu giải pháp dựa trên CSS gốc không hoạt động.

Tôi đã tìm thấy một đoạn mã trên http://davidbcalhoun.com/2010/dealing-with-device-orientation đề xuất thêm lớp và nhắm mục tiêu dựa trên đó. Ví dụ:

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

Các bạn nghĩ gì về điều này? Bạn có giải pháp tốt hơn?


Chỉ cần phát hiện ra, iPad không KHÔNG có vấn đề này. CHỈ có hệ điều hành android (máy tính bảng tổ ong) và điện thoại di động có vấn đề này.
Hossain Khan

Tôi đã gặp sự cố tương tự với trang web trên điện thoại di động của mình. Sau khi thử nghiệm trên một vài thiết bị Android, nó dường như không bị giới hạn ở bất kỳ hệ điều hành hoặc thiết bị di động / máy tính bảng cụ thể nào. Có vẻ như nó chủ yếu là vấn đề với các thiết bị Motorola và Samsung. Tôi không thể tái tạo sự cố trên điện thoại HTC của chúng tôi.
TJ Kirchner

1
Vấn đề này chủ yếu xảy ra với các thiết bị Android, điện thoại di động / máy tính bảng - cách duy nhất bạn có thể tái tạo điều này là cài đặt bàn phím tùy chỉnh có chiều cao lớn, để khi bàn phím hiển thị, chiều cao khả dụng cho webview nhỏ hơn chiều rộng khả dụng. Chỉ khi đó, chế độ xem web mới kích hoạt thay đổi hướng. Ví dụ: trong ảnh chụp màn hình, nếu tôi có thể tắt lớp đề xuất trên bàn phím, thì vấn đề này sẽ không có ở đó, bởi vì, chiều cao của webview sẽ lớn hơn chiều rộng. Nhưng, dù sao, tôi vẫn chưa có bất kỳ giải pháp thanh lịch và hiệu quả nào.
Hossain Khan

1
Chỉ cần nhận ra rằng WebApp toàn màn hình IOS 7.0.0 cũng có hành vi này
Alexandre

Thật đáng buồn. Tôi không thể giải quyết vấn đề một cách hiệu quả, do đó đã đánh dấu nó là known limitation.
Hossain Khan

Câu trả lời:


104

Tôi biết điều này đã muộn vài năm nhưng tôi đã tìm ra một giải pháp tuyệt vời

Đối với phương tiện ngang:

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

Và đối với phương tiện dọc:

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

Có thể tìm thấy giải pháp đầy đủ và tại sao nó hoạt động tại đây Michael Barret - Những thách thức đối với trình duyệt Android

Chỉnh sửa: liên kết này hiện đã hết hạn, nhưng bạn có thể tìm thấy ảnh chụp nhanh trên kho lưu trữ trên internet: Michael Barret - Thử thách trình duyệt Android


2
Nó giải quyết vấn đề, nhưng vấn đề tạo thêm về các thiết bị khác đối với tôi (chủ yếu là máy tính xách tay và máy tính)
Stephan Bijzitter

Rất tiếc, giải pháp này không hoạt động trên tất cả các thiết bị di động.
Diogo Cardoso

@StephanBijzitter có lẽ bạn có thể sử dụng thuộc tính 'max-width'?
Sean Routledge,

3
Giải pháp này rất khó và sẽ không hoạt động trên một số thiết bị. Ví dụ: điện thoại của tôi cho khoảng 17,7 / 9 khi mở bàn phím mềm, trong khi tỷ lệ khung hình ngang thấp hơn nhiều trên nhiều thiết bị khác.
raacer

2
Liên kết giải pháp đầy đủ bị hỏng.
Sparkm Taxi

27

Vấn đề nằm ở cách tính toán định hướng:

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

Tính năng phương tiện 'hướng' là 'dọc' khi giá trị của tính năng phương tiện 'chiều cao' lớn hơn hoặc bằng giá trị của tính năng phương tiện 'chiều rộng'. Nếu không, 'hướng' là 'ngang'.

Vì chiều cao / chiều rộng được tính toán trên khung nhìn hiển thị, bàn phím mềm dường như làm cho hướng lật bây giờ khi chiều rộng của khung nhìn nhỏ hơn chiều cao. Một giải pháp sẽ chỉ là sử dụng các truy vấn phương tiện của bạn chỉ dựa trênwidth để thay thế. Điều này làm cho nó linh hoạt hơn trên các thiết bị bất kể hướng nào, chưa kể chiều rộng / chiều cao được hỗ trợ rộng rãi hơn so với định hướng.

Nếu bạn muốn tính chiều rộng thay vì hướng, tôi sẽ sử dụng iPhone làm ví dụ:

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

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

Cách tiếp cận này linh hoạt hơn định hướng vì các truy vấn không giới hạn ở các thiết bị / tác nhân người dùng hỗ trợ định hướng, chưa kể đến định hướng cho bạn biết rất ít so với chiều rộng.

Tất nhiên nếu bạn thực sự cần biết định hướng, có vẻ như thiết lập lớp học ban đầu và chỉ sử dụng đó có thể là lựa chọn tốt nhất của bạn.


1
Tôi hiểu cách trình duyệt tính toán chiều ngang và chiều dọc. Tuy nhiên, cần có cách thay thế và tốt hơn để xử lý việc này. Một điều thú vị khác là iPad không kích hoạt thay đổi hướng khi bàn phím lên. Tôi không biết tại sao **** android phải thực hiện theo cách đó.
Hossain Khan

Tôi chỉ tò mò là tại sao bạn đặc biệt cần hướng của thiết bị thay vì chỉ chiều rộng. Vấn đề bạn đang cố gắng giải quyết là gì mà chỉ chiều rộng sẽ không giải quyết được?
scurker

Tôi đang làm việc với nhiều thiết bị có độ phân giải khác nhau. Bạn có thể vui lòng cho ví dụ về cách chiều rộng có thể được sử dụng thay thế cho định hướng? Về, sử dụng thay đổi hướng, có nhiều ứng dụng về thay đổi hướng - thường có sẵn không gian khác nhau theo hướng khác nhau. Vì vậy, một số phần tử có thể được ẩn hoặc thay đổi kích thước dựa trên định hướng. Cảm ơn vì sự giúp đỡ.
Hossain Khan

@HossainKhan @media all and (max-device-wdith:NNNpx){}hoặc @media all and (min-device-wdith:NNNpx){}hoặc@media all and (device-wdith:NNNpx){}
RaphaelDDL

1
cuối cùng bằng cách loại bỏ and (orientation:portrait)và chỉ áp dụng chiều rộng tối đa và tối thiểu đã giải quyết được vấn đề của tôi. !!!
Libin

16

Một giải pháp thay thế có thể được sử dụng device-aspect-ratio, mà vẫn không thay đổi. Tuy nhiên, trong Webkit, việc xoay thiết bị không kích hoạt cập nhật các quy tắc CSS bằng cách sử dụng truy vấn này, mặc dù các thử nghiệm JavaScript trả về true cho tỷ lệ khung hình mới. Đây dường như là do lỗi , nhưng tôi không thể tìm thấy báo cáo lỗi. Sử dụng kết hợp orientation{min,max}-device-aspect-ratiodường như hoạt động tốt:

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

Việc sử dụng các orientationbản cập nhật kích hoạt như mong đợi và việc sử dụng các device-aspect-ratiohạn chế được cập nhật theo các thay đổi thực tế của hướng.


Rất tiếc, tính năng này hiện không được dùng nữa developer.mozilla.org/en-US/docs/Web/CSS/@media/…
Eugene Gluhotorenko

giữa năm 2020 và điều này vẫn hoạt động mặc dù không được chấp nhận ... giải pháp tuyệt vời, giải pháp duy nhất thực sự hiệu quả với tôi trong tất cả các trường hợp tôi có!
qraqatit

6

Tôi đã làm việc thông qua các tùy chọn được liệt kê ở trên và không có cách nào khắc phục được sự cố cho tôi. Tôi đã chuyển sang sử dụng screen.availHeight vì nó cho kết quả độ cao nhất quán tránh được sự cố hiển thị bàn phím.

// 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);

Vì vậy, tôi đã thử nghiệm điều này thêm một chút và nó không quá dễ dàng. Các thiết bị Android cần sử dụng screen.availHeight và screen.availWidth. Tuy nhiên, iOS đang gặp lỗi với những điều này, vì vậy hãy sử dụng window.orientation cho IOS. Máy tính để bàn nên sử dụng window.innerHeight, window.innerWidth khi bạn muốn kích thước cửa sổ không phải kích thước màn hình.
Robby Jennings

Tôi đã đập đầu vào tường với đoạn mã trên. Quá tinh vi. Tôi không hỗ trợ máy tính để bàn cho ứng dụng này, vì vậy tôi đang sử dụng window.orientation là giải pháp kỳ diệu cho Android và IOS. Đang hoạt động tốt. var hướng = Math.abs (window.orientation) === 90? 'chân dung phong cảnh';
Robby Jennings

3

Đối với tôi, điều này đã thực hiện thủ thuật:

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

Mặc dù max-aspect-ratiođảm nhiệm việc kích hoạt chế độ Chân dung đơn giản bằng cách thay đổi kích thước cửa sổ (hữu ích cho PC và các thiết bị chỉ nằm ngang khác), max-device-aspect-ratiogiúp cho điện thoại thông minh hoặc các thiết bị khác có hướng thay đổi. Và bởi vì tôi không khai báo các cài đặt cụ thể cho Chế độ ngang, ngay cả khi max-aspect-ratiođang báo cáo> 1 cho hệ thống, chế độ Chân dung sẽ vẫn được kích hoạt bởimax-device-aspect-ratio nếu thiết bị Android được định hướng theo cách đó.

Các 1/1phần cơ bản có nghĩa là nếu tỷ lệ này là <= 1, nó đi vào chế độ Portrait, nếu không nó đi vào chế độ phong cảnh.


2
Còn khi bàn phím xuất hiện thì sao?
adi518,

Khi bàn phím ảo xuất hiện trên thiết bị di động, không có gì thay đổi, bởi vì tỷ lệ khung hình của thiết bị (tỷ lệ khung hình tối đa thiết bị) chỉ thay đổi khi bạn thực sự xoay thiết bị hoặc khi bạn cố tình thay đổi hướng màn hình từ Dọc sang Ngang và ngược lại -qua.
helveciofneto

Vâng, tôi đã kết thúc việc triển khai và thử nghiệm nó cho chính mình. Tôi đang phát triển một gói xung quanh này: npmjs.com/package/mobile-orientation
adi518

Quay lại để hỏi thêm một điều: (max-aspect-ratio: 1/1) . Có vẻ như chúng ta chỉ cần chút này để phát hiện chân dung trên máy tính để bàn?
adi518

Đúng. 1/1 là để đảm bảo rằng một hình vuông hoàn hảo vẫn kích hoạt chế độ dọc (có thể thực hiện được trong các hệ thống cho phép thay đổi kích thước cửa sổ, như cửa sổ trình duyệt trên máy tính để bàn). Nếu không có nó, những điều kỳ lạ xảy ra theo tỷ lệ chính xác này.
helveciofneto

1

Tôi đã xem qua một số câu trả lời ở trên và không câu trả lời nào trong số họ làm được chính xác những gì tôi muốn, đó là, bắt chước chức năng của iPhone càng gần càng tốt. Sau đây là những gì đang làm việc cho tôi trong sản xuất bây giờ.

Nó hoạt động bằng cách gán chiều rộng và chiều cao cửa sổ của khung nhìn thiết bị cho một thuộc tính dữ liệu để kiểm tra trong tương lai. Vì điện thoại không thay đổi kích thước chiều rộng khi kéo bàn phím lên nên chỉ có chiều cao, việc kiểm tra tỷ lệ VÀ chiều rộng so với chiều rộng ban đầu mới có thể cho bạn biết bàn phím có nâng lên hay không. Tôi chưa tìm thấy trường hợp sử dụng nào mà nó không thành công, nhưng tôi chắc chắn rằng tôi sẽ làm được. Nếu tất cả các bạn tìm thấy một, xin vui lòng cho tôi biết.

Tôi đang sử dụng một số toàn cầu, như InitialRun và MobileOrientation, được sử dụng để chuyển đổi js, tôi cũng đang sử dụng thuộc tính dữ liệu html5 để lưu trữ thông tin trong DOM cho thao tác 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

Tôi đã sử dụng một thủ thuật đơn giản để giải quyết vấn đề này

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

Tôi thấy rằng max-width: 896px có thể được sử dụng cho tất cả các thiết bị di động. hãy thử giải pháp này nó hoạt động!


bạn save my day :), nhưng khi nó quay lại từ ngang sang dọc, zoom của trang bị hỏng làm thế nào để xử lý đây?
Amir Farahani

Điều này phụ thuộc vào chiều rộng tối đa hiện tại của thiết bị di động và khi cải tiến công nghệ, những thay đổi này sẽ thay đổi. Vì vậy, chúng ta có nên thay đổi kịch bản tất cả các truy vấn phương tiện không? Tôi nghĩ đây là một ý tưởng tồi.
QMaster


0

Ý tưởng: Loại bỏ thông số dọc khỏi truy vấn phương tiện của bạn và chỉ để lại thông số chiều rộng tối thiểu. Tạo kiểu bình thường của bạn cho chế độ dọc trong truy vấn phương tiện đó. Sau đó, tạo một truy vấn phương tiện khác cho chế độ ngang với chiều cao tối thiểu đủ cao để trình duyệt không sử dụng truy vấn đó khi bàn phím bật lên. Bạn sẽ phải thử nghiệm xem 'chiều cao tối thiểu đủ cao' này là gì, nhưng nó không quá khó vì hầu hết (nếu không phải tất cả) chế độ ngang có chiều cao lớn hơn bạn có khi bàn phím bật lên. Ngoài ra, bạn có thể thêm 'chiều rộng tối thiểu' vào truy vấn ngang lớn hơn mà hầu hết các điện thoại thông minh ở chế độ xem dọc (tức là khoảng ~ 400px) để giới hạn phạm vi truy vấn.

Đây là một giải pháp thay thế (và dễ hiểu): - Thêm một phần tử tùy ý trống vào html của bạn sẽ có 'display: none' trong bất kỳ thứ gì khác ngoài chế độ dọc. - Tạo trình nghe jquery hoặc javascript cho đầu vào: focus. Khi một đầu vào được nhấp, javascript của bạn sẽ kiểm tra thuộc tính hiển thị của phần tử tùy ý. Nếu nó trả về 'khối' hoặc bất kỳ thứ gì bạn đặt nó trong chế độ dọc, thì bạn có thể ghi đè kiểu bằng JS vào các truy vấn ở chế độ dọc của mình. Ngược lại, bạn sẽ có một đầu vào: làm mờ trình nghe để xóa các thuộc tính style.cssText của các phần tử bạn đã mã hóa cứng.

Tôi đang tự mình thử nghiệm điều này ngay bây giờ - Tôi sẽ đăng mã về những gì hoạt động khi tôi nhận được thứ gì đó chắc chắn và có thể quản lý được. (Giải pháp đầu tiên của tôi có vẻ hợp lý nhất).


0

Điều này làm việc đáng tin cậy đối với tôi. Tôi đang sử dụng http://detectmobilebectors.com/ cho tiện ích mở rộng jQuery để phát hiện $ .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;

Đây là mã của tôi để sửa đổi khung nhìn dựa trên định hướng. Chức năng này chỉ được gọi cho thiết bị di động, thậm chí không phải máy tính bảng. Điều này cho phép tôi dễ dàng viết CSS cho 400px và 800px (Portrait vs Landscape).

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

Do bản chất của các yêu cầu của tôi, tôi không thể thực hiện điều này chỉ trong các truy vấn CSS Media, vì bản thân DOM cần thay đổi dựa trên hướng. Thật không may trong công việc của tôi, những người kinh doanh viết các yêu cầu phần mềm mà không tư vấn phát triển trước.


0

Tôi gặp phải vấn đề tương tự trong iPad.
I E; khi bàn phím mềm xuất hiện ở chế độ dọc, thiết bị được phát hiện theo hướng ngang và các kiểu cho ngang được áp dụng cho màn hình, dẫn đến chế độ xem lộn xộn.

Thông số thiết bị

  • Thiết bị : iPad Mini 4
  • Hệ điều hành : iOS 11.2.6
  • Độ phân giải màn hình : 1024 x 768

Thật không may, đối với tôi, giải pháp này đã không hoạt động.

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

Vì vậy, những gì tôi đã làm là, tôi đã viết một truy vấn phương tiện như thế này cho chế độ dọc của tôi.

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

I E; khi bàn phím mềm xuất hiện, chiều cao màn hình giảm nhưng chiều rộng màn hình vẫn còn 768px, dẫn đến màn hình phát hiện truy vấn phương tiện theo hướng ngang. Do đó công việc xung quanh đưa ra như trên.


0

Vì iPhone 11 Pro Max Viewport là 414 x 896 PX - nên đủ để có hướng: ngang với chiều rộng tối thiểu: 500px

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.