安卓键盘缩小了使用vh单位的CSS视口和元素

46

我正在经历一种非常奇怪和独特的问题。

由于项目的性质,所有我的页面都使用vh和vw CSS单位而不是px。

问题:在Android平板电脑上,当您触摸输入字段时,默认键盘会推动视口,导致页面及页面中的所有元素缩小。

在iPad上不存在此问题,因为键盘重叠在屏幕上并且不会推动屏幕。

寻找任何解决方案以避免Android键盘推动浏览器视口并保持原始大小。

注意:我唯一的选择是避免键盘推动视口,我将无法更改CSS单位或使用xml、manifest。这些是出现此问题的Web页面。


如果你想防止视口缩放,请尝试以下代码:<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"> - thdoan
11个回答

55

我知道这是一个老问题,但是我的应用程序中也遇到了完全相同的问题。我发现的解决方案非常简单。(我的应用程序是在Angular中,所以我将它放在了app.componentngOnInit函数中,但是document.ready()或任何其他“初始化完成”的回调都可以通过适当的实验正常工作)

setTimeout(function () {
        let viewheight = $(window).height();
        let viewwidth = $(window).width();
        let viewport = document.querySelector("meta[name=viewport]");
        viewport.setAttribute("content", "height=" + viewheight + "px, width=" + viewwidth + "px, initial-scale=1.0");
    }, 300);

这将强制 viewport meta 明确设置视口高度,而硬编码则不会

<meta name="viewport" 
content="width=device-width, height=device-height, initial-scale=1">

当Android软键盘打开时,设备的宽度和高度会发生变化,因此不起作用。


完美的解决方案!非常有效。我在 http://szanata.com 上尝试了一下,这是一个分成多个部分的着陆页面,每个部分都有100vh的高度。谢谢! - szanata
2
这个解决方案很好,但我发现了一个小问题。当在移动设备仿真模式下使用Chrome开发者工具时,window.innerHeightwindow.innerWidth(或$(window).height()$(window).width())的值不会被正确设置。因此,如果您正在使用此工具进行开发,请在代码运行于开发浏览器中时查询window.visualViewport.heightwindow.visualViewport.width - Merlin Denker
如果页面小于或等于视口,则窗口在输入时停止滚动。 - Kudayar Pirimbaev
3
对我来说这个不起作用。我可以确认高度和宽度已经在 meta 标签中设置(使用 devtools 远程设备),但仍然缩小了,以至于用户无法看到所选的输入。 - fideldonson
3
不需要指定“px”。 - anvd
显示剩余4条评论

19

根据Tyler的问题,这是一个纯净版的脚本:

addEventListener("load", function() {
    var viewport = document.querySelector("meta[name=viewport]");
    viewport.setAttribute("content", viewport.content + ", height=" + window.innerHeight);
})

如果您在元标记声明后使用它,甚至可以摆脱那个addEventListener

var viewport = document.querySelector("meta[name=viewport]");
viewport.setAttribute("content", viewport.content + ", height=" + window.innerHeight);

3
你是一位神,我将这段内容放在script标签中的元标记声明下面,它完美地工作了,非常感谢你。 - Baptiste
2
在 React 页面中运行得非常好。 - Rael Gugelmin Cunha
1
谢谢您没有使用jQuery哈哈。 - Zack Plauché
三年后,这证明是一个超级有用的答案!完美地起作用 :) - ardentia

7

这里有一个考虑到屏幕方向变化的更完整的解决方案:

// Original viewport definition, note the "id" that I use to modify the viewport later on:
<meta name="viewport" id="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>

<script>
// Global boolean variable that holds the current orientation
var pageInPortraitMode;

// Listen for window resizes to detect orientation changes
window.addEventListener("resize", windowSizeChanged);

// Set the global orientation variable as soon as the page loads
addEventListener("load", function() {
  pageInPortraitMode = window.innerHeight > window.innerWidth;
  document.getElementById("viewport").setAttribute("content", "width=" + window.innerWidth + ", height=" + window.innerHeight + ", initial-scale=1.0, maximum-scale=1.0, user-scalable=0");
})

// Adjust viewport values only if orientation has changed (not on every window resize)
function windowSizeChanged() {
  if (((pageInPortraitMode === true) && (window.innerHeight < window.innerWidth)) || ((pageInPortraitMode === false) && (window.innerHeight > window.innerWidth))) {
    pageInPortraitMode = window.innerHeight > window.innerWidth;
    document.getElementById("viewport").setAttribute("content", "width=" + window.innerWidth + ", height=" + window.innerHeight + ", initial-scale=1.0, maximum-scale=1.0, user-scalable=0");
  }
}
</script>

3

最近我也遇到了同样的问题,花费了一些时间才找到一个不错的解决方案。我正在使用html5、css3和angularjs设计cordova应用程序。但是更重要的是,我希望我的应用程序适合每个屏幕,而不需要编写大量媒体查询和最终难以阅读的css。我从viewport和vh开始,但是键盘破坏了一切。

因此,您只需要使用一点javascript(这里是jquery),如下所示:

$("html").css({"font-size": ($(window).height()/100)+"px"});

现在你可以像使用“vh”一样使用“rem”,但视口不会影响字体大小。“rem”仅设置在html根字体大小上,我们只需使用jquery将其设置为屏幕高度的1%。

希望这能有所帮助!

编辑1: 我刚遇到一个新问题,所以在这里提供我的解决方案。大多数时候,智能手机都有最小字体大小限制。 您必须更改所有的rem值,并将其除以3或4。 然后,您需要更改javascript代码:

$("html").css({"font-size": ($(window).height()/25)+"px"}); /*(this is if you divide with 4)*/

如果您使用SASS,那么更容易实现,您可以创建一个rem函数,它会为您执行除法运算。


1
差不多一年晚了,但我也想分享一下我的解决方案,这个问题变得越来越重要。
我创建了一个小的JS函数SET,它在DOM完成后加载。
每个分配给特殊类(在这种情况下是“.pheight”)的元素在视口高度减少时不会调整大小。只有当视口高度增加或视口宽度改变时才允许调整大小。
因此,在我的应用程序中,它完美地工作!
  var docwidth = window.innerWidth;
  var docheight = window.innerHeight;
  function pheigt_init() {    
    pheigt_set_prevent_height();
    window.onresize = function() {
        if (docwidth !== window.innerWidth || docheight < window.innerHeight) {
            pheigt_upd_prevent_height();
        }
    };
  }
  function pheigt_set_prevent_height() {
    document.querySelectorAll('.pheight').forEach(function(node) {
     node.style.height = node.offsetHeight + 'px';
    });
  }
  function pheigt_upd_prevent_height() {
    document.querySelectorAll('.pheight').forEach(function(node) {
        node.style.removeProperty('height');
    }); 
    setTimeout(function(){ pheigt_set_prevent_height(); }, 100);
    docheight = window.innerHeight;
    docwidth = window.innerWidth;
  }
  document.addEventListener('DOMContentLoaded', pheigt_init());

0

在Angular 4+中

import {Meta} from "@angular/platform-browser";


constructor(private metaService: Meta){}

ngOnInit() {
  this.metaService.updateTag({
  name: 'viewport',
    content: `height=${this.height}px, width=${this.width}px, initial-scale=1.0`
  },
  `name='viewport'`
);
}


0

您可以使用 %,它似乎不受此问题的影响,或者使用 vw(由于明显的原因)即使是对于高度也不受影响。


0

我正在创建一个PWA,其中禁用了所有滚动和缩放功能,对我来说问题是,我使用视口单位来精确计算我的布局。通过事件设置视口有所帮助,但是当Android键盘出现时,window.onresize事件也会被调用。我的解决方案是通过检查document.activeElement是否为文本区域或输入字段来判断是否使用了键盘。

唯一的缺点是,当用户在使用键盘时更改屏幕方向(这并不常见)时,视口调整大小会失败。为了防止这种情况发生,元素会失焦,从而关闭键盘,以避免布局破坏。虽然不太用户友好,但这可以被认为是一个相当罕见的边缘情况。

最终代码:

window.onresize = () => {
    if(document.activeElement.tagName !== 'TEXTAREA' && document.activeElement.tagName !== 'INPUT'){
        setViewportSize();
    }
}

window.onorientationchange = () => {
    // check if keyboard is used
    if(document.activeElement.tagName === 'TEXTAREA' || document.activeElement.tagName === 'INPUT'){
        document.activeElement.blur();
    }
    setViewportSize();
}

function setViewportSize(){
    document.documentElement.style.setProperty('--screen-width', `${window.innerWidth}px`);
    document.documentElement.style.setProperty('--screen-height', `${window.innerHeight}px`);
}

请记住window.onorientationchange已被弃用,可能在某些时候无法使用


0

也许需要使用一个函数来刷新视口高度(或仅高度)?

const reference = useRef();

function avoidKeyboard(){
    setTimeout(
        ()=>{reference.current.querySelector("#win").style.height = "calc(100vh)"}
    ,2000)
}

return (
    <ref={reference} div>
       <input type="text" id="win" onFocus={avoidKeyboard} onBlur={avoidKeyboard}/>
    </div>
)

-1

同样的问题让我失去了信心。我没有找到任何CSS解决方案或变通方法来解决这个问题。

然而,如果你可以使用jQuery(或几乎任何JavaScript),我有一些代码可以帮助你解决它。

var viewportHeight = $(window).height();
var viewportWidth = $(window).width();
$('body,html').css("height",viewportHeight); //if vh used in body/html too
$('.someClass').css("height",viewportHeight*0.12);// or whatever percentage you used in vh
$('#someId').css("width",viewportWidth*0.12);

好的,这只是一个例子,你可以使用百分比、jQuery标识符等等。

提示:把代码放在HTML的最后或者$(document).ready(function() {};中,并且如果你需要响应式设计,在orientationchange事件中也要添加;就像这样。

$(window).on("orientationchange",function(event){ window.setTimeout(function(){
var viewportHeight = $(window).height();
var viewportWidth = $(window).width();
$('body,html').css("height",viewportHeight);
$('.someClass').css("height",viewportHeight*0.12);
$('.someClass').css("width",viewportWidth*0.09);
$('#someId').css("height",viewportHeight*0.1);
}}, 450);});

我放了一个450毫秒的定时器,因为设备进行方向更改时有延迟。

对不起我的英语, 干杯


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接