我目前正在使用Twitter Bootstrap开发响应式网站。
该网站在移动设备/平板电脑/台式机上拥有全屏背景图片。这些图像使用两个div旋转并逐渐消失。
除了一个问题,它几近完美。在Android上使用iOS Safari,Android浏览器或Chrome时,当用户向下滚动页面并导致地址栏隐藏时,背景会略微跳跃。
该网站位于:http://lt2.daveclarke.me/
在移动设备上访问它并向下滚动,您会看到图像调整大小/移动。
我用于后台DIV的代码如下:
#bg1 {
background-color: #3d3d3f;
background-repeat:no-repeat;
background-attachment:fixed;
background-position:center center;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover; position:fixed;
width:100%;
height:100%;
left:0px;
top:0px;
z-index:-1;
display:none;
}
欢迎提出所有建议 - 这已经有一段时间了!
答案 0 :(得分:99)
这个问题是由URL栏缩小/滑动并改变#bg1和#bg2 div的大小引起的,因为它们是100%高度和“固定”。由于背景图像设置为“覆盖”,因此当包含区域较大时,它将调整图像大小/位置。
根据网站的响应性,背景必须扩展。我接受两种可能的解决方案:
1)将#bg1,#bg2高度设置为100vh。理论上,这是一个优雅的解决方案。但是,iOS有一个vh错误(http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/)。我尝试使用max-height来防止这个问题,但它仍然存在。
2)视口大小(由Javascript确定)不受URL栏的影响。因此,Javascript可用于根据视口大小在#bg1和#bg2上设置静态高度。这不是最好的解决方案,因为它不是纯CSS,并且页面加载时会有轻微的图像跳转。但是,考虑到iOS的“vh”错误(在iOS 7中似乎没有修复),这是唯一可行的解决方案。
var bg = $("#bg1, #bg2");
function resizeBackground() {
bg.height($(window).height());
}
$(window).resize(resizeBackground);
resizeBackground();
另外,我在iOS和Android中看到了这些调整大小的URL栏的问题。我理解其目的,但他们确实需要思考他们带给网站的奇怪功能和破坏。最新的更改是,您无法再使用滚动技巧“隐藏”iOS或Chrome上的页面加载网址栏。
编辑:虽然上面的脚本可以很好地保持背景不会调整大小,但是当用户向下滚动时会产生明显的差距。这是因为它将背景大小保持为屏幕高度的100%减去URL栏。如果我们向高度添加60px,正如瑞士所说,这个问题就消失了。这确实意味着当URL栏存在时我们无法看到背景图像的底部60px,但它可以防止用户看到间隙。
function resizeBackground() {
bg.height( $(window).height() + 60);
}
答案 1 :(得分:59)
我发现Jason的回答并不适合我,而且我还在跳跃。 Javascript确保页面顶部没有间隙,但只要地址栏消失/重新出现,背景仍然会跳跃。因此,除了Javascript修复,我还将transition: height 999999s
应用于div。这会创建一个持续时间太长的过渡,它实际上会冻结元素。
答案 2 :(得分:22)
我的网站标题上也有类似的问题。
html, body {
height:100%;
}
.header {
height:100%;
}
这将最终导致Android chrome上的滚动滚动体验,因为.header-container将在url-bar隐藏并且手指从屏幕移除后重新缩放。
<强> CSS-解决方案:强>
添加以下两行将阻止url-bar隐藏并且仍然可以进行垂直滚动:
html {
overflow: hidden;
}
body {
overflow-y: scroll;
-webkit-overflow-scrolling:touch;
}
答案 3 :(得分:14)
问题可以通过媒体查询和一些数学来解决。这是一个面向移民的解决方案:
@media (max-device-aspect-ratio: 3/4) {
height: calc(100vw * 1.333 - 9%);
}
@media (max-device-aspect-ratio: 2/3) {
height: calc(100vw * 1.5 - 9%);
}
@media (max-device-aspect-ratio: 10/16) {
height: calc(100vw * 1.6 - 9%);
}
@media (max-device-aspect-ratio: 9/16) {
height: calc(100vw * 1.778 - 9%);
}
由于当网址栏消失时,vh会发生变化,因此您需要以另一种方式确定高度。值得庆幸的是,视口的宽度是恒定的,移动设备只有几个不同的宽高比;如果你可以确定宽度和宽高比,一点数学将给你视口高度与vh 的工作方式完全相同。这是过程
1)为您要定位的宽高比创建一系列媒体查询。
使用设备宽高比而不是宽高比,因为后者会在网址消失时调整大小
我在设备宽高比中添加了'max'来定位最流行之间恰好跟随的任何宽高比。它不会那么精确,但它们只适用于少数用户,并且仍然非常接近正确的vh。
请记住使用水平/垂直的媒体查询,因此对于肖像,您需要翻转数字
2)对于每个媒体查询,将要素的垂直高度百分比乘以宽高比的倒数。
3)您必须确定网址栏高度,然后从高度减去该值。我还没有找到精确的测量结果,但我在景观中使用了9%的移动设备,而且看起来工作得相当好。
这不是一个非常优雅的解决方案,但其他选项也不是很好,考虑到它们是:
让您的网站对用户造成错误,
元素尺寸不合适,或
使用javascript进行某些基本样式,
缺点是某些设备可能具有与最流行的不同的网址高度或纵横比。但是,使用这种方法,如果只有少数设备遭受几个像素的加/减,这对我来说似乎比刷网时调整网站的每个人都好。
为了更容易,我还创建了一个SASS mixin:
@mixin vh-fix {
@media (max-device-aspect-ratio: 3/4) {
height: calc(100vw * 1.333 - 9%);
}
@media (max-device-aspect-ratio: 2/3) {
height: calc(100vw * 1.5 - 9%);
}
@media (max-device-aspect-ratio: 10/16) {
height: calc(100vw * 1.6 - 9%);
}
@media (max-device-aspect-ratio: 9/16) {
height: calc(100vw * 1.778 - 9%);
}
}
答案 4 :(得分:12)
此处的所有答案均使用window
高度,受网址栏的影响。大家都忘记了screen
身高吗?
这是我的jQuery解决方案:
$(function(){
var $w = $(window),
$background = $('#background');
// Fix background image jump on mobile
if ((/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera)) {
$background.css({'top': 'auto', 'bottom': 0});
$w.resize(sizeBackground);
sizeBackground();
}
function sizeBackground() {
$background.height(screen.height);
}
});
添加.css()
部分正在将不可避免的顶部对齐绝对定位元素更改为底部对齐,因此根本没有跳跃。虽然,我想没有理由不直接将它添加到普通的CSS中。
我们需要用户代理嗅探器,因为桌面上的屏幕高度没有帮助。
此外,这是假设#background
是填充窗口的固定位置元素。
对于JavaScript纯粹主义者(警告 - 未经测试):
var background = document.getElementById('background');
// Fix background image jump on mobile
if ((/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera)) {
background.style.top = 'auto';
background.style.bottom = 0;
window.onresize = sizeBackground;
sizeBackground();
}
function sizeBackground() {
background.style.height = screen.height;
}
编辑:很抱歉,这并不能直接解决您在多个背景下遇到的具体问题。但这是搜索固定背景在移动设备上跳跃的问题时的第一个结果之一。
答案 5 :(得分:9)
当我试图创建一个覆盖整个视口的入口屏幕时,我也遇到了这个问题。不幸的是,接受的答案不再适用。
1)每次视口大小更改时,高度设置为100vh
的元素都会调整大小,包括由(dis)显示的URL栏引起的情况。
2)$(window).height()
返回的值也会受到网址栏大小的影响。
一个解决方案是&#34;冻结&#34; the answer by AlexKempton中建议使用transition: height 999999s
的元素。缺点是这有效地禁用了对所有视口大小变化的适应性,包括由屏幕旋转引起的变化。
所以我的解决方案是使用JavaScript手动管理视口更改。这使我可以忽略可能由URL栏引起的小变化,并且只对大的变化做出反应。
function greedyJumbotron() {
var HEIGHT_CHANGE_TOLERANCE = 100; // Approximately URL bar height in Chrome on tablet
var jumbotron = $(this);
var viewportHeight = $(window).height();
$(window).resize(function () {
if (Math.abs(viewportHeight - $(window).height()) > HEIGHT_CHANGE_TOLERANCE) {
viewportHeight = $(window).height();
update();
}
});
function update() {
jumbotron.css('height', viewportHeight + 'px');
}
update();
}
$('.greedy-jumbotron').each(greedyJumbotron);
编辑:我实际上将这项技术与height: 100vh
一起使用。页面从一开始就正确呈现,然后javascript启动并开始手动管理高度。这样,在页面加载时(甚至之后),根本没有闪烁。
答案 6 :(得分:8)
我目前使用的解决方案是检查userAgent
上的$(document).ready
,看看它是否是违规浏览器之一。如果是,请按照以下步骤操作:
$(window).resize
上,只有在新的水平视口尺寸与其初始值不同时才更新相关的高度值或者,您也可以仅在超出地址栏高度时测试允许垂直调整大小。
哦,地址栏确实会影响$(window).height
。请参阅:Mobile Webkit browser (chrome) address bar changes $(window).height(); making background-size:cover rescale every time
JS "Window" width-height vs "screen" width-height?
答案 7 :(得分:4)
我发现了一个非常简单的解决方案,没有使用Javascript:
&#xA;&#xA; 转换:高度1000000s轻松;&#xA; -webkit-transition:height 1000000s轻松;&#xA; -moz-transition:高度1000000s轻松;&#xA; -o-transition:高度1000000s轻松;&#xA;
&#xA;&#xA; 所有这一切都是为了延迟运动,使其速度非常慢而且不会引人注意。
&#xA;答案 8 :(得分:3)
这是我解决此问题的解决方案,我已直接在代码上添加了注释。 我已经测试了这个解决方案并且工作正常。希望我们对每个人都有用同样的问题。
//remove height property from file css because we will set it to first run of page
//insert this snippet in a script after declarations of your scripts in your index
var setHeight = function() {
var h = $(window).height();
$('#bg1, #bg2').css('height', h);
};
setHeight(); // at first run of webpage we set css height with a fixed value
if(typeof window.orientation !== 'undefined') { // this is more smart to detect mobile devices because desktop doesn't support this property
var query = window.matchMedia("(orientation:landscape)"); //this is is important to verify if we put
var changeHeight = function(query) { //mobile device in landscape mode
if (query.matches) { // if yes we set again height to occupy 100%
setHeight(); // landscape mode
} else { //if we go back to portrait we set again
setHeight(); // portrait mode
}
}
query.addListener(changeHeight); //add a listner too this event
}
else { //desktop mode //this last part is only for non mobile
$( window ).resize(function() { // so in this case we use resize to have
setHeight(); // responsivity resisizing browser window
});
};
答案 9 :(得分:3)
我创建了一个使用VH单元的vanilla javascript解决方案。几乎任何地方使用VH都受地址栏的影响,最小化滚动。为了修复页面重绘时显示的jank,我在这里得到了这个js,它将使用VH单位抓取所有元素(如果你给它们类.vh-fix
),并给它们内联的像素高度。基本上在我们想要的高度冻结它们。您可以在旋转或视口大小更改时执行此操作以保持响应。
var els = document.querySelectorAll('.vh-fix')
if (!els.length) return
for (var i = 0; i < els.length; i++) {
var el = els[i]
if (el.nodeName === 'IMG') {
el.onload = function() {
this.style.height = this.clientHeight + 'px'
}
} else {
el.style.height = el.clientHeight + 'px'
}
}
这解决了我的所有用例,希望它有所帮助。
答案 10 :(得分:3)
我的解决方案涉及一些javascript。在div上保持100%或100vh(这将避免div在初始页面加载时不出现)。然后在页面加载时,抓住窗口高度并将其应用于相关元素。避免跳跃,因为现在你的div上有一个静态高度。
var $hero = $('#hero-wrapper'),
h = window.innerHeight;
$hero.css('height', h);
答案 11 :(得分:2)
这是我尝试过的最佳解决方案(最简单)。
...这并不能保留地址栏的原生体验!
例如,您可以将CSS的高度设置为100%,然后在加载文档时使用javascript将高度设置为px中窗口高度的0.9 *。
例如使用jQuery:
$("#element").css("height", 0.9*$(window).height());
)
不幸的是,没有任何东西可以用于纯CSS:P但也是minfull vh
和vw
在iPhone上有问题 - 使用百分比。
答案 12 :(得分:1)
我用javascript设置我的宽度元素。在我设置de vh。
之后<强> HTML 强>
<div id="gifimage"><img src="back_phone_back.png" style="width: 100%"></div>
<强> CSS 强>
#gifimage {
position: absolute;
height: 70vh;
}
javascript
imageHeight = document.getElementById('gifimage').clientHeight;
// if (isMobile)
document.getElementById('gifimage').setAttribute("style","height:" + imageHeight + "px");
这对我有用。我不使用jquery等。因为我希望它尽快加载。
答案 13 :(得分:1)
花了几个小时才了解这个问题的所有细节,并找出最佳实施方案。事实证明,截至2016年4月,只有iOS Chrome出现此问题。我试过Android Chrome和iOS Safari--没有这个修复就没问题。因此,我使用的iOS Chrome修复程序是:
$(document).ready(function() {
var screenHeight = $(window).height();
$('div-with-background-image').css('height', screenHeight + 'px');
});
答案 14 :(得分:1)
如果背景允许,一个简单的答案,为什么不将background-size:设置为只用媒体查询覆盖设备宽度的内容,并在:after位置旁边使用:fixed;入侵here。
IE:背景尺寸:901px;任何小于900像素的屏幕?效果不理想或反应迟钝,但是当我使用抽象BG时,在移动<480px上对我来说很有吸引力。
答案 15 :(得分:0)
我正在使用此解决方法: 修正bg1在页面加载时的高度:
var BG = document.getElementById('bg1');
BG.style.height = BG.parentElement.clientHeight;
然后将一个resize事件监听器附加到Window,它执行以下操作: 如果调整大小后的高度差异小于60px(任何超过url bar高度),则不执行任何操作,如果大于60px,则将bg1的高度再次设置为其父级的高度!完整代码:
window.addEventListener("resize", onResize, false);
var BG = document.getElementById('bg1');
BG.style.height = BG.parentElement.clientHeight;
var oldH = BG.parentElement.clientHeight;
function onResize() {
if(Math.abs(oldH - BG.parentElement.clientHeight) > 60){
BG.style.height = BG.parentElement.clientHeight + 'px';
oldH = BG.parentElement.clientHeight;
}
}
PS:这个bug很刺激!
答案 16 :(得分:0)
类似于@AlexKempton的回答。 (不能评论抱歉)
我一直在使用长转换延迟来阻止元素调整大小。
例如:
transition: height 250ms 600s; /*10min delay*/
与此相关的是它会阻止元素的大小调整,包括在设备上旋转,但是,如果这是一个问题,你可以使用一些JS来检测orientationchange
并重置高度。
答案 17 :(得分:0)
对于那些想要倾听窗口的实际内部高度和垂直滚动的人,当Chrome移动浏览器将URL栏从显示转换为隐藏,反之亦然时,我找到的唯一解决方案是设置间隔函数,并测量window.innerHeight
与其先前值的差异。
这介绍了这段代码:
var innerHeight = window.innerHeight;
window.setInterval(function ()
{
var newInnerHeight = window.innerHeight;
if (newInnerHeight !== innerHeight)
{
var newScrollY = window.scrollY + newInnerHeight - innerHeight;
// ... do whatever you want with this new scrollY
innerHeight = newInnerHeight;
}
}, 1000 / 60);
&#13;
我希望这会很方便。有谁知道更好的解决方案?
答案 18 :(得分:0)
我遇到类似问题时提出的解决方案是每次window.innerHeight
事件被触发时将元素的高度设置为touchmove
。
var lastHeight = '';
$(window).on('resize', function () {
// remove height when normal resize event is fired and content redrawn
if (lastHeight) {
$('#bg1').height(lastHeight = '');
}
}).on('touchmove', function () {
// when window height changes adjust height of the div
if (lastHeight != window.innerHeight) {
$('#bg1').height(lastHeight = window.innerHeight);
}
});
这使得元素始终完全覆盖可用屏幕的100%,不多也不少。即使在地址栏隐藏或显示期间也是如此。
然而,遗憾的是我们必须提出那种简单position: fixed
应该有用的补丁。
答案 19 :(得分:0)
借助iOS中CSS自定义属性(变量)的支持,您可以使用JS设置这些属性,并且只能在iOS上使用它们。
[ArgumentException: An item with the same key has already been added.]
System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) +52
System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) +13007142
System.Collections.Generic.CollectionExtensions.ToDictionaryFast(TValue[] array, Func`2 keySelector, IEqualityComparer`1 comparer) +116
System.Web.Mvc.ModelBindingContext.get_PropertyMetadata() +149
System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) +176
System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) +101
System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) +55
System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +1209
System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +333
System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +343
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +105
System.Web.Mvc.Async.<>c__DisplayClass3_1.<BeginInvokeAction>b__0(AsyncCallback asyncCallback, Object asyncState) +640
System.Web.Mvc.Async.WrappedAsyncResult`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +14
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +346
System.Web.Mvc.<>c.<BeginExecuteCore>b__152_0(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +27
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +494
System.Web.Mvc.<>c.<BeginExecute>b__151_1(AsyncCallback asyncCallback, Object callbackState, Controller controller) +16
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +20
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +403
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +16
System.Web.Mvc.<>c.<BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +54
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +427
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103
System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +48
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +159
const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if (iOS) {
document.body.classList.add('ios');
const vh = window.innerHeight / 100;
document.documentElement.style
.setProperty('--ios-10-vh', `${10 * vh}px`);
document.documentElement.style
.setProperty('--ios-50-vh', `${50 * vh}px`);
document.documentElement.style
.setProperty('--ios-100-vh', `${100 * vh}px`);
}
答案 20 :(得分:0)
我的答案是给所有来这里的人(像我一样)找到由隐藏地址裸露/浏览器界面引起的错误的答案。
隐藏的地址栏导致调整大小事件触发。但是与其他调整大小事件不同,例如切换到横向模式,这不会更改窗口的宽度。因此,我的解决方案是挂接到resize事件中,并检查宽度是否相同。
// Keep track of window width
let myWindowWidth = window.innerWidth;
window.addEventListener( 'resize', function(event) {
// If width is the same, assume hiding address bar
if( myWindowWidth == window.innerWidth ) {
return;
}
// Update the window width
myWindowWidth = window.innerWidth;
// Do your thing
// ...
});