CSS hardware accelerated width?

后端 未结 2 1716
栀梦
栀梦 2021-02-09 09:55

I am attempting to build a Phonegap app that will allow the user to change the size of a two column layout by moving the middle divider.

I was able to get this working,

相关标签:
2条回答
  • 2021-02-09 10:05

    I finally figured out a solution that works a lot better than what I had. Basically, I animate the container, and I hide the content when I'm resizing. Then, when the resizing is done, I show the content again. I used an animations to make it look pretty when hiding/showing. The code will explain it better than I will:

    The almighty fiddle

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

    My explanation

    When the slider is tapped, it pushes all the text elements off the page with a translate3d() transform, then hides the div. This is because the lag returns if I try to update the width while the elements are shown. So, once the divs are hidden, I then just move the columns left or right with the translate3d() transform once again. I can do this without having the width of each element stop short because I set the left or right values to a value that can never be reached so it's extended far enough beyond the page. That way, I can simply shift it without worrying that it will cut off prematurely.

    Weirdness

    There are parts of this that are probably redundant, but I'll clean those up soon. You'll also probably notice some weird things going on, such as (1) cornerLeft, (2) dummy, (3) shadow, and in the JS, (4) minimum:

    1. When I resize the page, the dummy nav bar extends the entire width of the left and right columns, which means it goes 1000% of the width. That means that I can't set a border-radius on the nav for the left and right sides of each column, as it would be so far off the screen that it wouldn't be visible. So, I made a simple corner to mask each side of the window, making it look pretty.

    2. I hide .contentLeft and .contentRight when I resize as it causes lag when it's shown. I don't want to get rid of the nav bar though, so I make a dummy one that is always there on the page, and is simply revealed when the resize is about to happen. I think this reduces the lag as I don't have to add the element in, since it's always there.

    3. One problem with that, however, is that when the normal nav overlays the dummy nav, the box-shadow's overlap, causing it to become darker for 200ms. I don't like this. So, I put in a shadow that is always on top of the nav, regardless of what nav is showing.

    4. I can now easily set a bound that the draggable columns can reach before stopping. Convenient, right?

    Code

    HTML:

    <div id="container">
        <div class="cornerLeft"></div>
        <div class="cornerRight"></div>
        <div class="shadow"></div>
        <div class="left">
            <div class="contentLeft">
                <div class="header"></div>
                <div class="headerbehind"></div>
                <div class="text textLeft">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.</div>
            </div>
            <div class="dummy"></div>
            <div class="dummybg"></div>
        </div>
        <div class="divider"></div>
        <div class="right">
            <div class="contentRight">
                <div class="header"></div>
                <div class="headerbehind"></div>
                <div class="text textRight">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.</div>
            </div>
            <div class="dummy"></div>
            <div class="dummybg"></div>
        </div>
    </div>
    

    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 Yes, it took me 134 tries.

    0 讨论(0)
  • 2021-02-09 10:30

    I had some success by pushing the two elements into question in the hardware-accelerated stack:

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

    Seems to be resizing much more smoothly. It's not that changing width itself is optimized, rather the elements themselves are re-rendered much more quickly.

    I set up a plunk here: http://plnkr.co/edit/5RMtCl1Sql8f3CmQLHFz

    0 讨论(0)
提交回复
热议问题