CSS Media Query-软键盘打破了CSS定位规则-替代解决方案?


83

我正在使用多个平板电脑设备-均为Android 和iOS。目前,对于所有平板电脑,我都有以下分辨率差异。

  • 1280 x 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/

这是从演示页面获取的行为的屏幕截图。 在此处输入图片说明

因此,除了解决此问题外,还有什么替代方法,如果基于本机CSS的解决方案不起作用,我愿意接受基于JavaScript的解决方案。

我在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 OS(蜂窝平板电脑)和手机存在此问题。
Hossain Khan

我的移动网站遇到了类似的问题。在多个Android设备上进行测试后,它似乎并不局限于任何特定的OS或移动/平板电脑设备。看来这主要是摩托罗拉和三星设备的问题。我无法在HTC手机上重现该问题。
TJ Kirchner

1
此问题主要是与Android设备,移动设备/平板电脑有关-您可以重现此问题的唯一方法是安装高度较大的自定义键盘,以便在显示键盘时,Webview的可用高度小于可用宽度。只有这样,Webview才会触发方向更改。例如,在屏幕截图中,如果我可以禁用键盘顶部的建议层,则不会出现此问题,因为Webview的高度将大于宽度。但是,无论如何,我还没有任何优雅而有效的解决方案。
侯赛因汗

1
只需意识到IOS 7.0.0全屏WebApp也具有此行为
Alexandre

真伤心 我无法有效解决问题,因此将其标记为known limitation
Hossain Khan 2013年

Answers:


104

我知道这已经晚了几年,但是我找到了一个很好的解决方案

对于横向媒体:

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

对于肖像媒体:

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

完整的解决方案及其工作原理可在此处找到Michael Barret-Android浏览器挑战

编辑:此链接现已过期,但可以在Internet存档中找到快照:Michael Barret-Android浏览器挑战


2
它可以解决问题,但会为我在其他设备(主要是笔记本电脑和计算机)上创建更多问题
Stephan Bijzitter 2015年

不幸的是,该解决方案并非在所有移动设备上都适用。
Diogo Cardoso 2015年

@StephanBijzitter也许您可以使用“最大宽度”属性?
肖恩·鲁特里奇

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不会触发方向更改。我不知道为什么**** Android必须采用这种方式。
Hossain Khan 2012年

我很好奇为什么您特别需要设备的方向而不是宽度。您要解决的问题是仅靠宽度无法解决?
scurker 2012年

我正在使用具有不同分辨率的多个设备。您能否举个例子,如何将宽度用作定向的替代方法?关于方向更改的使用,方向更改有多种应用程序-通常可用空间不同,方向不同。因此,某些元素可以隐藏或根据方向调整大小。感谢您的所有帮助。
侯赛因汗

@HossainKhan@media all and (max-device-wdith:NNNpx){}@media all and (min-device-wdith:NNNpx){}@media all and (device-wdith:NNNpx){}
RaphaelDDL 2012年

1
最终通过删除and (orientation:portrait)并仅应用最大和最小宽度解决了我的问题。
利宾2013年

16

可以使用替代方法device-aspect-ratio,该方法保持不变。但是,在Webkit中,即使JavaScript测试针对新的宽高比返回true,旋转设备也不会使用此查询触发CSS规则的更新。这显然是由于bug引起的,但是我找不到bug报告。结合使用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限制的使用则根据方向的实际变化进行了更新。



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遇到这些问题,但请为IOS使用window.orientation。桌面应使用window.innerHeight,window.innerWidth,因为您希望窗口尺寸而不是屏幕尺寸。
罗比·詹宁斯

我一直在用上面的代码在墙上砸头。太挑剔了。我不支持此应用程序的桌面,所以我使用window.orientation是Android和IOS的神奇解决方案。现在工作正常。var orientation = 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只需调整窗口大小即可触发人像模式(适用于PC和其他仅横向设备),但max-device-aspect-ratio有助于智能手机或其他方向可变的设备。而且因为我没有声明横向模式的特定设置,所以即使max-aspect-ratio向系统报告> 1,max-device-aspect-ratio如果Android设备以这种方式定向,纵向模式仍将触发。

1/1部分基本上意味着如果比率<= 1,则进入纵向模式,否则进入横向模式。


2
键盘抬起怎么办?
adi518 '18

当虚拟键盘出现在移动设备上时,不会发生任何变化,因为仅当您实际旋转设备或故意将屏幕方向从纵向更改为横向时,设备的纵横比(最大设备纵横比)才会更改-反之亦然。
helveciofneto

是的,我最终为自己实施和测试了它。我正在围绕以下方面开发一个软件包:npmjs.com/package/mobile-orientation
adi518 '18

回来查询另外一件事:(max-aspect-ratio: 1/1)。似乎我们只需要这一点就可以在桌面上检测人像?
adi518 '18

对。1/1是为了确保完美的正方形仍会触发人像模式(在允许调整窗口大小的系统中(例如桌面上的浏览器窗口),这是可能的。没有它,奇怪的事情就会以这种确切的比例发生。
helveciofneto

1

我已经经历了以上几个答案,但没有一个答案能完全满足我的要求,即尽可能接近地模仿iPhone功能。以下是目前在生产中对我有用的内容。

它通过将设备视口的窗口宽度和高度分配给data属性以供将来检查而起作用。由于手机在拉起键盘时不会调整宽度大小,因此仅将高度,检查比例和宽度与原始宽度进行比较,即可知道键盘是否向上。我还没有找到一个失败的用例,但是我敢肯定。如果大家都找到一个,请告诉我。

我正在使用一些全局变量,例如用于JS切换的InitialRun和MobileOrientation,也正在使用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*/}

我发现最大宽度:896px可以用于所有移动设备。试试这个解决方案,它的工作原理!


您保存了我的一天:),但是当它从横向回到纵向时,页面缩放被破坏了怎么处理?
Amir Farahani

这取决于当前移动设备的最大宽度,并且在改进技术时,这些都会改变。那么,我们应该更改所有媒体查询方案吗?我认为这是一个糟糕的主意。
QMaster


0

想法:从媒体查询中删除portrait参数,并将其保留为最小宽度。在该媒体查询中对肖像模式进行常规样式设置。然后,为最小高度创建足够高的横向模式的另一个媒体查询,以使弹出键盘时浏览器将不使用该查询。您必须尝试一下“足够高的最小高度”是什么,但是它应该不会太难,因为大多数(如果不是全部)横向模式的高度都比弹出键盘时的高度大。此外,您可以在横向查询中添加一个“最小宽度”,该宽度要小于大多数智能手机在纵向视图中的宽度(即约400像素),以限制查询范围。

这是一种替代的(脆弱的)解决方案:-在html中添加一个空的任意元素,除了纵向模式以外,其他任何元素都将具有“ display:none”。-为input:focus创建一个jquery或javascript侦听器。单击输入后,您的JavaScript会检查任意元素的display属性。如果返回“阻止”或您在纵向模式下设置的任何值,则可以将JS样式替换为纵向模式查询。相反,您将具有一个input:blur侦听器,以清除您硬编码的元素的style.cssText属性。

我现在正在自己进行尝试-我将发布在获得可靠且可管理的内容时会起作用的代码。(我的第一个解决方案似乎是最合理的)。


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;

这是我的代码,用于根据方向修改视口。仅在移动设备(甚至平板电脑)上需要调用此功能。这使我可以轻松地为400px和800px(纵向vs横向)编写CSS。

_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 */
}

即 当出现软键盘时,屏幕高度减小,但屏幕宽度保持为768px,这导致媒体查询将屏幕检测为横向。因此,解决方法如上所述。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.