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,
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:
1 http://jsfiddle.net/charlescarver/hnQHH/134/
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.
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
:
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.
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.
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.
I can now easily set a bound that the draggable columns can reach before stopping. Convenient, right?
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 Yes, it took me 134 tries.