CSS硬件加速宽度?

我正在尝试构建一个Phonegap应用程序,允许用户通过移动中间分隔符来更改两列布局的大小。

我能够使这个工作,但有一个巨大的UX问题:它是滞后的。 这并不可怕,但在最新的iPad上它甚至引人注目,让我担心。

这是我的JSresize:

$("div").on("touchmove", "#columnResizeIcon", function(e) { e.preventDefault(); var left = e.originalEvent.touches[0].pageX; var right = $("#columnContainer").width() - left; $("#leftColumn").css({ "width":left - 1 + "px", "right":"auto", }); $("#rightColumn").css({ "width":right - 1 + "px", "left":"auto", }); $("#columnResize").css({ "-webkit-transform":"translate3d(" + left + "px" + ", 0, 0)", "left":"auto", }); $("#columnResizeIcon").css({ "-webkit-transform":"translate3d(" + left + "px" + ", 0, 0)", "left":"auto", }); }); 

你会注意到我利用translate3d()来改变元素的“左”值,因为它是硬件加速的。 我相信滞后是通过改变左右列的宽度产生的,这是我需要硬件加速的。

我认为可能有效的解决方案是使用-webkit-transform:translate3d(50%, 0, 0)将右列推到页面的一半,然后只更改该值,希望它只会延长到它到达了父母。 然而,它仍在继续,并且占据了50%的页面,而不是父母的50%。

我的HTML标记如下所示:

 
Left Header
Right Header

而我的CSS:

 body{ background-color:#000; } #columnContainer{ position: absolute; bottom:0; top:0; right:0; left:0; background-color:#000; } #leftColumn{ position: absolute; top:0; left:0; right:50%; bottom:0; -webkit-overflow-scrolling: touch; z-index: 1; margin-right: 1px; } #rightColumn{ position: absolute; top:0; left:50%; right:0; bottom:0; -webkit-overflow-scrolling: touch; z-index: 1; margin-left: 1px; } .header{ position: absolute; left:0; right:0; height:33px; z-index: 5; background: -webkit-linear-gradient(top, #f4f5f7 0%,#a7abb7 100%); box-shadow: inset 0 1px 0 #fff, inset 0 -1px 0 #7A8090, 3px 0 2px rgba(0,0,0,.3); border-top-left-radius: 5px; border-top-right-radius: 5px; font-size: 17px; font-family: Helvetica; font-weight: bold; letter-spacing: .2px; text-align: center; padding-top:9px; color:#71787F; text-shadow: 0 1px 0 #E3E5E9; } .content{ position: absolute; left:0; right: 0; top:42px; bottom: 0; } #leftColumn .content{ background-color:#F5F5F5; } #rightColumn .content{ background-color:#fff; } #columnResize{ position: absolute; width:2px; top:0; bottom: 0; left:50%; margin-left:-1px; background-color:#000; z-index: 2; } #columnResizeIcon{ position: absolute; z-index: 3; width:10px; height:30px; top:50%; bottom:50%; margin-top:-15px; left:50%; margin-left:-7px; border-left:2px solid #000; border-right:2px solid #000; } 

我终于想出了一个比我的解决方案更好的解决方案。 基本上,我为容器设置了动画,我在resize时隐藏了内容。 然后,当resize完成后,我再次显示内容。 在隐藏/显示时,我使用动画使其看起来很漂亮。 代码将比我更好地解释它:

万能的小提琴

1 http://jsfiddle.net/charlescarver/hnQHH/134/

我的解释

滑动滑块时,它会使用translate3d()变换将所有文本元素推离页面,然后隐藏div。 这是因为如果我在显示元素时尝试更新宽度,则会返回滞后。 因此,一旦隐藏了div,我就可以再次使用translate3d()变换向左或向右移动列。 我可以做到这一点,而不会让每个元素的宽度停止,因为我将leftright值设置为一个永远无法达到的值,因此它的扩展远远超出了页面。 这样,我可以简单地改变它而不用担心它会过早地切断。

怪事

有些部分可能是多余的,但我会尽快清理它们。 你也可能会注意到一些奇怪的事情,比如(1) cornerLeft ,(2) dummy ,(3) shadow ,以及JS,(4) minimum

  1. 当我调整页面大小时, dummy导航栏会扩展左右列的整个宽度,这意味着它会占据宽度的1000%。 这意味着我无法在导航栏上为每列的左侧和右侧设置border-radius ,因为它离屏幕太远,以至于它不可见。 所以,我做了一个简单的角落来掩盖窗户的每一面,使它看起来很漂亮。

  2. 我resize时会隐藏.contentLeft.contentRight ,因为它会在显示时导致滞后。 我不想摆脱导航栏,所以我制作一个总是在页面上的dummy ,并且只是在resize即将发生时显示。 我认为这减少了滞后,因为我不必添加元素,因为它始终存在。

  3. 然而,一个问题是,当普通导航覆盖虚拟导航时, box-shadow重叠,导致它变暗200ms。 我不喜欢这个。 因此,无论导航显示什么,我都会在导航器上放置一个阴影。

  4. 我现在可以轻松设置可拖动列在停止之前可以达到的界限。 方便,对吧?

HTML:

 
Praesent id metus massa, ut blandit odio. Proin quis tortor orci. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus.
Praesent id metus massa, ut blandit odio. Proin quis tortor orci. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus.

CSS:

 * { -webkit-text-size-adjust:none; } #container { position:fixed; left:0; right:0; bottom:0; top:0; background-color:#000; -webkit-transform: translateZ(0); -webkit-perspective: 1000; } .left { -webkit-transform:translate3d(0, 0, 0); position:absolute; left:-3000px; right:50%; top:0; bottom:0; border-right:1px solid #000; -webkit-perspective: 1000; -webkit-backface-visibility: hidden; } .right { -webkit-transform:translate3d(0, 0, 0); position:absolute; left:50%; right:-3000px; top:0; bottom:0; border-left:1px solid #000; -webkit-perspective: 1000; -webkit-backface-visibility: hidden; } .divider { width:24px; height:40px; border-left:2px solid #000; border-right:2px solid #000; position:absolute; left:50%; z-index:3; margin-left:-14px; margin-top:-20px; top:50%; -webkit-transform:translate3d(0, 0, 0); -webkit-perspective: 1000; -webkit-backface-visibility: hidden; -webkit-touch-callout: none; -webkit-user-select: none; } .contentLeft { position:absolute; right:0; bottom:0; top:0; -webkit-transform: translateZ(0); -webkit-perspective: 1000; -webkit-backface-visibility: hidden; } .contentRight { position:absolute; left:0; bottom:0; top:0; -webkit-transform: translateZ(0); -webkit-perspective: 1000; -webkit-backface-visibility: hidden; } .cornerLeft:after { content:""; height:5px; position:absolute; left:0; width:5px; background: -webkit-linear-gradient(top, #F0F2F4 0%, #EAEBEE 100%); z-index:700; border-top-left-radius:5px; box-shadow:inset 0 1px 0 #fff; } .cornerLeft { position:absolute; z-index:700; left:0; width:5px; height:5px; background-color:#000; } .cornerRight:after { content:""; height:5px; position:absolute; right:0; width:5px; background: -webkit-linear-gradient(top, #F0F2F4 0%, #EAEBEE 100%); z-index:700; border-top-right-radius:5px; box-shadow:inset 0 1px 0 #fff; } .cornerRight { position:absolute; z-index:700; right:0; width:5px; height:5px; background-color:#000; } .header, .dummy { position: absolute; left:0; right:0; height:35px; background: -webkit-linear-gradient(top, #f4f5f7 0%, #a7abb7 100%); border-top-left-radius: 5px; border-top-right-radius: 5px; font-size: 17px; font-family: Helvetica; font-weight: bold; letter-spacing: .2px; text-align: center; padding-top:9px; color:#71787F; text-shadow: 0 1px 0 #E3E5E9; word-break: break-all; box-shadow:inset 0 1px 0 #fff, inset 0 -1px 0 #7A8090; } .shadow { height:44px; position:absolute; left:0; right:0; box-shadow:0 1px 2px rgba(0, 0, 0, .2); z-index:600; } .header { z-index:500; } .dummy { z-index:100; } .headerbehind { position:absolute; background-color:#000; left:0; right:0; height:44px; z-index:499; } .text, .dummybg { margin-top:44px; background-color:#fff; position:absolute; top:0; right:0; left:0; bottom:0; } .text { z-index:2; padding:20px 40px; -webkit-animation-duration:200ms; -webkit-animation-timing-function:ease; } .contentLeft, .contentRight { z-index:300; } .leftOut { -webkit-transform:translate3d(-100%, 0, 0); -webkit-animation-name:leftOut; -webkit-perspective: 1000; -webkit-backface-visibility: hidden; } .leftIn { -webkit-transform:translate3d(0, 0, 0); -webkit-animation-name:leftIn; -webkit-perspective: 1000; -webkit-backface-visibility: hidden; } @-webkit-keyframes leftOut { 0% { -webkit-transform:translate3d(0, 0, 0); } 100% { -webkit-transform:translate3d(-100%, 0, 0); } } @-webkit-keyframes leftIn { 0% { -webkit-transform:translate3d(-100%, 0, 0); } 100% { -webkit-transform:translate3d(0, 0, 0); } } .rightOut { -webkit-transform:translate3d(100%, 0, 0); -webkit-animation-name:rightOut; } .rightIn { -webkit-transform:translate3d(0, 0, 0); -webkit-animation-name:rightIn; } @-webkit-keyframes rightOut { 0% { -webkit-transform:translate3d(0, 0, 0); } 100% { -webkit-transform:translate3d(100%, 0, 0); } } @-webkit-keyframes rightIn { 0% { -webkit-transform:translate3d(100%, 0, 0); } 100% { -webkit-transform:translate3d(0, 0, 0); } } 

JS:

 minimum = 100; $(".contentLeft").css("width", ($("#container").width() / 2) - 1); $(".contentRight").css("width", ($("#container").width() / 2) - 1); $("div").on("touchstart", ".divider", function (e) { $(".textLeft").removeClass("leftIn"); $(".textLeft").addClass("leftOut"); $(".textRight").removeClass("rightIn"); $(".textRight").addClass("rightOut"); setTimeout(function () { $(".contentLeft, .contentRight").hide(); }, 200); }); $("div").on("touchmove", ".divider", function (e) { e.preventDefault(); if ($(".contentLeft").css("display", "none")) { var page = $("#container").width(); var left = e.originalEvent.touches[0].pageX; var right = page - left; updateWidth(page, left, right); } }); //$(".contentLeft, .contentRight").hide(); $("div").on("touchend", ".divider", function (e) { setTimeout(function () { $(".textLeft").removeClass("leftOut"); $(".textLeft").addClass("leftIn"); $(".textRight").removeClass("rightOut"); $(".textRight").addClass("rightIn"); $(".contentLeft, .contentRight").show(); }, 200); }); $(window).on('orientationchange', function (e) { var page = $("#container").width(); var leftWidth = $(".contentLeft").width(); var rightWidth = $(".contentRight").width(); var previousWidth = (leftWidth + rightWidth); if (leftWidth + rightWidth + 2 < page) { var left = (page / 2) - (previousWidth / 2) + leftWidth; } else if (leftWidth + rightWidth + 2 > page) { var left = leftWidth - ((previousWidth / 2) - (page / 2)); } var right = page - left; updateWidth(page, left, right); }); function updateWidth(page, left, right) { if (left < minimum) { var finalLeft = minimum; var finalRight = (-1 * (page - minimum)); var finalRightWidth = (page - minimum); } else if (right < minimum) { var finalLeft = (page - minimum); var finalRight = (-1 * minimum); var finalRightWidth = minimum; } else { var finalLeft = (left); var finalRight = (0 - right); var finalRightWidth = (right); } $(".divider").css({ "-webkit-transform": "translate3d(" + finalLeft + "px, 0, 0)", "left": "auto", }); $(".left").css({ "-webkit-transform": "translate3d(" + finalLeft + "px, 0, 0)", "right": "100%", }); $(".right").css({ "-webkit-transform": "translate3d(" + finalRight + "px, 0, 0)", "left": "100%", }); $(".contentLeft").css("width", finalLeft); $(".contentRight").css("width", finalRightWidth); } 

1 是的,我花了134次尝试。

通过在硬件加速堆栈中推动这两个元素,我取得了一些成功:

 #leftColumn, #rightColumn { -webkit-transform: translate3d(0,0,0); } 

似乎要更顺利地resize。 并不是改变width本身是优化的,而是更快地重新渲染元素本身。

我在这里设置了一个插件: http : //plnkr.co/edit/5RMtCl1Sql8f3CmQLHFz