【问题标题】:What is the best method of re-rendering a web page on orientation change?在方向更改时重新呈现网页的最佳方法是什么?
【发布时间】:2011-10-27 16:26:47
【问题描述】:

我有一个流畅的 CSS 布局,当我改变方向时,它在 iphone 上的渲染很糟糕。 (刷新后看起来还不错)。

我正在使用下面的代码在方向更改时刷新页面,效果很好 - 这样做感觉有点不对劲。有什么方法可以实现这一点而不必重新加载整个页面?这是一个移动网站,我真的不想强迫用户加载页面两次。

var supportsOrientationChange = "onorientationchange" in window,
    orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

window.addEventListener(orientationEvent, function() {
    window.location.reload()
}, false);   

编辑:

在 iphone 上测试时的两个主要问题是:

我有一个 100% 宽度,右对齐的背景图像。 当我将方向从纵向更改为横向时,身体宽度保持在纵向模式下的呈现方式,反之亦然。从横向到纵向更成问题,因为页面太宽,而且似乎会渲染两次图像。

【问题讨论】:

  • 你已经在使用 CSS 媒体查询了吗?
  • @Pointy 不,没有媒体查询。页面布局是相同的水平或垂直(相同的 CSS)。我已经更新了我的答案,以便更好地解释。
  • 您是否只为 iPhone 制作页面? ipad、android、WM7等呢?如果使用不同宽度/大小的浏览器导致您的页面显示不佳,您需要查看布局。
  • @Ryan Ternier 是的,所有手机。如果在方向更改后刷新页面,则布局显示正常,因此这不是布局问题,问题在于手机在方向转换后呈现页面时。
  • @theorise 有一个示例页面,所以我可以测试你描述的内容?

标签: javascript iphone mobile orientation


【解决方案1】:

假设您的 CSS 已经在各种尺寸的移动设备屏幕上愉快地呈现,您需要在模板的

中定义视口。

例如,这会将页面宽度设置为设备的屏幕宽度和 100% 的初始缩放。初始缩放在页面加载时应用,但在方向改变时不应用。

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

通过向视口添加 maximum-scale=1.0 参数,您将强制 iPad/iPhone 保持缩放级别并在方向更改时重新布局页面。这样做的缺点是它会禁用缩放。但是,优点是您可以使用媒体查询进行布局调整,以适合当前方向的方式呈现内容。您可以在此处阅读有关视口的更多信息:Choosing a ViewPort

现在到媒体查询。您应该将媒体查询放在 CSS 文件的底部,并按照屏幕宽度从最小宽度到最大宽度的顺序放置。例如,取自Html5BoilerPlate CSS 示例:

@media only screen and (min-width: 480px) {
  /* Style adjustments for viewports 480px and over go here */

}

@media only screen and (min-width: 768px) {
  /* Style adjustments for viewports 768px and over go here */

}

所以你所有的普通样式都在此之上并首先应用,然后如果屏幕为 480 像素或更宽,则应用下一个样式块,然后如果屏幕为 768 像素或更宽,则应用最后一个样式块。

通过将固定缩放级别与 1.0 和媒体查询相结合,您可以使您的网站响应式调整大小以适应屏幕大小和方向,而无需 javascript。显然,您需要确保网站设计得很好,这样用户就不需要缩放。如果您的网站针对移动设备进行了优化,这应该不是问题。

请注意:其他非 safari 移动浏览器可能会重新布局页面,而无需在视口上设置最大比例。但是这种行为是不一致的,即使实现比其他设备差,大多数开发人员似乎也迎合了苹果设备。当方向改变时,其他一些设备将保持缩放级别并重新定位视口。但是所有设备都可以将缩放级别固定为 1.0。

【讨论】:

  • 看起来您可以放弃上面建议的最大比例,如果您愿意,可以使用一些 javascript 来增加布局(无需重新加载页面)。查看其他有关通过 JavaScript 操作视口的 stackoverflow 页面:Manipulate ViewPort with JavaScript
  • 您还可以使用orientation:landscapeorientation:portrait 媒体查询。
  • @BobAman 你是对的,我认为 Html5Boilerblate CSS 使用屏幕宽度的原因是为了跨平台支持,包括台式机/笔记本电脑。例如,如果您只是将桌面计算机上的浏览器窗口大小调整为纵向形状怎么办。 (例如:在 Windows 7 机器上按 Win+Left 可在左侧占据一半屏幕 - 通常用于并排查看 2 个应用程序)。但我想如果您需要不同的场景,您可以扩展上述媒体查询以包括尺寸调整和方向调整。
  • 这也是设备维度支持更广泛的问题。
  • BenSwayne 的回答:“通过向视口添加 maximum-scale=1.0 参数,您将强制 iPad/iPhone 保持缩放级别并在方向更改时重新布局页面。”似乎不再起作用了。页面不会重新布局。自从回答了这个帖子后,iOS 更新是否改变了什么?
【解决方案2】:

2015 年更新

所有其他答案都不正确或已过时。以下是有效的:

  window.addEventListener('orientationchange', function () {
    var originalBodyStyle = getComputedStyle(document.body).getPropertyValue('display');
    document.body.style.display='none';
    setTimeout(function () {
      document.body.style.display = originalBodyStyle;
    }, 10);
  });

代码监听orientationchange event 并通过隐藏body 元素并在10 毫秒后显示它来强制重新流动。它不依赖于任何&lt;meta&gt; 标签或媒体查询。

其他答案建议使用媒体查询,但您已经使用它们,因为您说“刷新时看起来很好”。

一些other 的答案建议使用location.reload()。这是非常低效的,因为它会重新加载整个页面,包括图像等。尤其是在移动设备上,你不想这样做。

还有其他答案建议添加&lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt; 或其变体。从 Safari 7 开始,这不再有效。这是demo。为确保您了解它是如何工作的,请从 iPad 以横向模式开始,加载页面,然后旋转。请注意,尽管一直使用 flexbox,但页面并没有展开到全高。

将其与 this page 进行比较,我们在生产中使用隐藏/显示身体技术。

【讨论】:

  • 这对我来说开箱即用。很好的解决方案。
  • 好的,所以我过早地说谢谢。它对我不起作用,而且我确实正确设置了元标记。有问题的 div 是一个动态呈现的幻灯片,它创建一个具有内联样式定位绝对的子 div。这是第三方的事情,所以我当然不能直接接触代码本身(而且我没有选择告诉我的雇主把它扔掉)所以......给我一个骨头,任何人!
  • 如果orientationchange 事件在10 毫秒内被触发两次怎么办......你可能会完全失去body display 属性并最终没有显示...... @Dan Dascalescu
【解决方案3】:

使用了一种在单个 javascript 堆栈帧中导致重绘和重排的方法。不热衷于视口特定的答案,因为它通常是保持捏缩放等可访问性的要求。

$(window).on('orientationchange', function() {
    document.body.style.display='none';
    document.body.offsetHeight; //cause a reflow
    document.body.style.display='block'; //cause a repaint
}); 

或非 jquery 等价物

window.addEventListener('orientationchange', function () {
    document.body.style.display='none';
    document.body.offsetHeight; //cause a reflow
    document.body.style.display='block'; //cause a repaint
});

【讨论】:

    【解决方案4】:

    根据我的经验,最好的方法就是这样

    <meta name = "viewport" content = "user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width /">
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    

    根据我的经验,像@BenSwayne 那样做不会在您更改方向时重新缩放回初始比例。不知道为什么

    【讨论】:

    • 那也行不通。这是demo。为确保您了解它是如何工作的,请从 iPad 以横向模式开始,加载页面,然后旋转。请注意,尽管一直使用 flexbox,但页面并没有展开到全高。
    【解决方案5】:

    我遇到了类似的问题,这就是我用 jQuery 修复它的方法。

    在我的情况下,我的 &lt;nav&gt; 元素的样式没有正确更改。我使用了kidkaos77代码的修改版本结合$.get()只加载页面的特定部分:

    $(window).bind("resize",function() {
        //on resize reload only nav & replace
        $.get("index.php" +  ' nav', function(data) {
            $("nav").replaceWith($(data).find("nav"));
        });
    });
    

    使用此方法,您不必重新加载整个页面,但您必须准确指定受方向更改影响的元素,在您的情况下,您似乎只需要一个 div。

    【讨论】:

    • 这个方案可以不用页名吗?只是 $.get(this + 'div.className', function(data) ... ?如果没有,为什么不呢?
    【解决方案6】:

    另一种选择是在您的 html 元素(div、var、span 等)中添加和删除 CSS 类。 这样,您可以只修改给您带来麻烦的元素,并且如果用户调整浏览器窗口的大小,您还可以调整非移动浏览器上的内容。

    这是您需要的 Javascript/JQuery 代码:

    // Code to run when page has finished loading
    $(function() {
        // Add CSS-class to body depending on device platform using user agent string
        // You can add more validations here and/or separate Android from iPhone or add more customized classes like "landscape_iPad", "landscape_iPhone", etc.
       // You can also validate browser types and add classes like "background_IE" or "background_Chrome", etc
        if ((navigator.userAgent.indexOf("iPad") != -1)) {
            $("#background").addClass("landscape");
        } else if ((navigator.userAgent.indexOf("Android") != -1) || (navigator.userAgent.indexOf("iPhone") != -1) || 
        (navigator.userAgent.indexOf("iPhone") != -1)) {
            $("body").addClass("iPhone");
        }
    
        // Get the initial orientation on iOS devices
        if (!isNaN(window.orientation)) {
            var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
            // Index php
            $("#background").addClass(orientation);
        } else {
            // Choose layout depending on viewport/window width
            var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
            // Index php
            $("#background").addClass(orientation);
        }
    
        // Bind orientationChange (or viewport/window size changes)
        if (window.onorientationchange != undefined) {
            window.onorientationchange = function() {
                var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
                // Index php
                $("#background").removeClass("portrait landscape").addClass(orientation);
            }
        } else {
            // Use landscape styling if it's wider than 980 pixels. 
            // This is for non mobile browsers, this way if the user resize the browser window, content will adjust too.
            $(window).bind('resize', function(){
                var orientation = ($(window).width() < 980) ? "portrait" : "landscape";
                // Index php
                $("#background").removeClass("portrait landscape").addClass(orientation);
            });
        }
    });
    

    这里是示例元素“背景”的 CSS 类:

    #background.portrait {
        position:absolute;
        top:0px;
        left:0px;
        width:768px;
        height:946px;
        z-index:0;
        background:url(background.png) top center no-repeat;
    }
    #background.landscape {
        position:absolute;
        top:10px;
        left:20px;
        width:1024px;
        height:724px;
        z-index:0;
        background:url(background_landscape.png) top center no-repeat;
    }
    

    通过这种方式,您可以自定义横向和纵向行为,并且可以添加更多类,例如:“landscape_iPhone”、“portrait_Android”或任何您需要控制每个特定设备的页面呈现的类。

    另外,您不需要重新加载页面,它会即时调整它。

    希望它对您或其他人有所帮助 =),这使我能够使用相同的 HTML 但不同的 CSS 类创建针对每种屏幕尺寸、移动品牌甚至浏览器类型定制的网站。

    【讨论】:

    • 我为你的热情喝彩,但 UserAgent 嗅探正变得“过时”,有利于特征检测。您永远不知道下一款平板电脑或浏览器何时上市,可能会破坏您的 UserAgent 嗅探。此外,我看不到媒体查询没有做到什么。我们不会尝试支持 IE6 来更改方向,因此我们可以自信地使用适当的当前技术。 IMO,JavaScript 应该只用于填补浏览器之间的不足,即 iOS 的 Safari 的视口处理与其他平板浏览器的差异。
    【解决方案7】:

    试试这样的:

    $(function(){
    
        changeOrientation(window.orientation == 0 ? "portrait" : "landscape");
    
        $('body').bind('orientationchange',function(event){
            changeOrientation(event.orientation)
        });
    
        function changeOrientation(ori){
            $("#orientation").removeClass('portrait landscape');
            $("#orientation").addClass(ori);
        }     
    });
    

    【讨论】:

    • 没有解释或 #orientation 元素的 HTML 和 CSS,我怀疑其意图与 my answer 中正文的隐藏/显示相同。
    【解决方案8】:
    $(window).bind('resize', function() { location.reload(); });
    

    这段代码对我有用。

    【讨论】:

      猜你喜欢
      • 2016-09-17
      • 1970-01-01
      • 1970-01-01
      • 2020-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-16
      • 2011-10-31
      相关资源
      最近更新 更多