I have a project with angularjs and bootstrap where I'm trying to replicate iOS's navigationController.
The problem is speed. It seems like one of the biggest issues is scrolling up/down when doing the transition between views. It just doesn't feel right.
My question is: how can I improve the speed of scrolling up/down and left/right in mobile safari iOS? I know it's doable (ionic is one good example, but we can't use them since they are mobile only).
This is my current code:
/* View animations */
.view-animate-container {
position: relative;
width: 100%;
}
.view-animate {
-webkit-backface-visibility: hidden;
}
.view-animate.ng-leave {
z-index: 1054;
}
.view-animate.ng-enter {
z-index: 1053;
}
.view-animate.ng-enter, .view-animate.ng-leave {
-webkit-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s;
transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s;
position: absolute;
width: 100%;
display: block;
}
.rtl .view-animate.ng-enter {
-webkit-transform: translate3d(100%, 0, 0);
-webkit-transition-delay: 0.1s;
opacity: 0;
}
.rtl .view-animate.ng-enter.ng-enter-active {
-webkit-transform: translate3d(0, 0, 0);
opacity: 1;
}
.rtl .view-animate.ng-leave.ng-leave-active {
-webkit-transform: translate3d(-100%, 0, 0);
opacity: 0;
}
.ltr .view-animate.ng-enter {
-webkit-transform: translate3d(-100%, 0, 0);
-webkit-transition-delay: 0.1s;
opacity: 0;
}
.ltr .view-animate.ng-enter.ng-enter-active {
-webkit-transform: translate3d(0, 0, 0);
opacity: 1;
}
.ltr .view-animate.ng-leave.ng-leave-active {
-webkit-transform: translate3d(100%, 0, 0);
opacity: 0;
}
/* End of View animations */
<div class='view-animate-container' ng-class='direction'>
<div id='mApp' ng-view class='view-animate' autoscroll='false'></div>
</div>
// Random scrollHeight fix. Moves the scroll position up during the transition.
function scrollToTop() {
var ua = $('html')[0].className;
var diff = document.body.scrollHeight;
var delay = ((ua.indexOf('ua-mobile') > -1 && ua.indexOf('ua-webkit') > -1) ? (320 + diff/17) : 50);
window.setTimeout(function() {
window.scrollTo(0, 0);
}, delay)
}
I would try two things:
On the overflowed div (that is the div that you have set the overflow property), setting the overflow property to 'scroll', rather then using 'auto'.
Then, use $scope.$evalAsync which will be executed right after the digest has been finished (but before the actual rendering).
If it still doesn't work, you can combine the $evalAsync and setTimeout (or $timeout) - setting the timeout inside the $evalAsync.
Related
I have a balloon that when hovered, will expand n disappear (a popping-like animation). I made this in CSS but when the cursor moves, the balloon returned. I want the balloon to disappear forever until I refresh the page, so I guess it needs to be onclick, but that selector is not available in CSS.
Here's what I have in CSS
#keyframes pop
{
from{
opacity:1;
transform: translateZ(0) scale(1,1);
}
to{
opacity:0;
transform: translateZ(0) scale(1.5,1.5);
}
}
.balloon:hover
{
animation: pop 0.5s cubic-bezier(0.16, 0.87, 0.48, 0.99) forwards;
}
I saw another question that said the closest thing is :active but it requires the mouse to be held down. If I want it to be onclick, I need to use Javascript. But I don't know what I need to write to trigger the animation.
And is it also possible to make it so that when I pop 1 balloon, all the others will pop too automatically with a 1s delay inbetween? (There are 5 balloons).
You can add and remove the class of the animation with JS using classList.
Add:
object.classList.add('balloon');
Remove:
object.classList.remove('balloon');
Working example:
const add = () => {
document.getElementById('balloon').classList.add('animation')
}
const remove = () => {
document.getElementById('balloon').classList.remove('animation')
}
#keyframes pop {
from {
opacity: 1;
transform: translateZ(0) scale(1, 1);
}
to {
opacity: 0;
transform: translateZ(0) scale(1.5, 1.5);
}
}
.animation {
animation: pop 0.5s cubic-bezier(0.16, 0.87, 0.48, 0.99) forwards;
}
.balloon {
height: 125px;
width: 110px;
background-color: #FF6B6B;
border-radius: 50%;
}
.controls{
position: absolute;
bottom: 10px;
right: 10px;
}
<div id="balloon" class="balloon" onmouseover="add()"></div>
<div class="controls">
<button onClick="add()">Hide</button>
<button onClick="remove()">Show</button>
</div>
Here is a solution which makes balloons hiding one by one with interval .5s between them
var balloons = document.getElementsByClassName('balloon');
[...balloons].forEach( (e, i)=>{
e.onmouseover = function() {
this.classList.add('hidden');
setTimeout(hideAll, 500, balloons);
}
});
function hideAll(arg){
[...arg].forEach( (e, i)=>{
if ( ! e.classList.contains('hidden') ) {
e.style.animationDelay = i+'s';
e.classList.add('hidden');
}
});
}
#keyframes pop
{
from{
opacity:1;
transform: translateZ(0) scale(1,1);
}
to{
opacity:0;
transform: translateZ(0) scale(1.5,1.5);
}
}
.balloon.hidden
{
animation: pop .5s cubic-bezier(0.16, 0.87, 0.48, 0.99) forwards;
}
<div class="balloon">Balloon</div>
<div class="balloon">Balloon</div>
<div class="balloon">Balloon</div>
<div class="balloon">Balloon</div>
<div class="balloon">Balloon</div>
I am starting to use the IntersectionObserver API and could create some basic animations, which includes hiding and appearing of elements. However, once a person wants to scroll back to the top, the elements which disappeared by one of the triggers are not getting visible again.
My Solution so far
So I thought I might create another test variable within the intersection observer callback function (the stepI and stepII variable in my code), which checks if the callback function was previously triggered. If so, instead of disappearing the elements, let them appear again.
My current problem
So let's say a background image (id="hiddenImg") should appear when the first text block (id="I") passes the 50% border of the viewport and it disappears when the second text block (id="II") enters this area. Even though the image is getting visible again when scrolling back up, if the user does not scroll back completely (so that the second text block goes out of the viewport) and then scrolls back to the bottom, the disappearing trigger of that second text block is not called. This would mean that the background image would stay visible, which it shouldn't.
Here is the js part:
var stepI = false;
var stepII = false;
// list of options
let options = {
rootMargin: '0px 0px -50%' //WHEN reaching half of the viewport
};
// instantiate a new Intersection Observer
"use strict";
var intersectionObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (change) {
if (change.isIntersecting) {
if (change.target.id == "I") {
$("#hiddenImg").removeClass("hidden_img");
$("#hiddenImg").addClass("visible_img");
stepI = true;
observer.unobserve(change.target);
}
if (change.target.id == "II") {
if (stepII == false) {
$("#hiddenImg").removeClass("visible_map");
$("#hiddenImg").addClass("hidden_map");
stepII = true
} else {
$("#hiddenImg").removeClass("hidden_map");
$("#hiddenImg").addClass("visible_map");
stepII = false;
}
}
}
});
},options);
// list of paragraphs
let elements = document.querySelectorAll(".stepper");
for (let elm of elements) {
intersectionObserver.observe(elm);
}
Here is my complete code:
<html>
<head>
<!-- Load the polyfill. -->
<script src="/js/intersection-observer.js"></script>
<script src='https://unpkg.com/intersection-observer#0.5.0/intersection-observer.js'></script>
</head>
<body>
<style>
.intro-imgs {
display: block;
margin: 0 auto; /* Will not center vertically and won't work in IE6/7. */
left: 0;
right: 0;
position: fixed;
position: expression(fixed);
}
.hidden_img {
visibility: hidden;
opacity: 0;
-ms-transform: scaleX(0); /* IE 9 */
-webkit-transform: scaleX(0); /* Safari 3-8 */
-o-transform: scaleX(0);
-moz-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: visibility 0s 0.5s, opacity 0.5s linear, -webkit-transform 0.5s;
-moz-transition: visibility 0s 0.5s, opacity 0.5s linear, -moz-transform 0.5s;
-o-transition: visibility 0s 0.5s, opacity 0.5s linear, -o-transform 0.5s;
transition: visibility 0s 0.5s, opacity 0.5s linear, transform 0.5s;
}
.visible_img {
visibility: visible;
opacity: 1;
-ms-transform: scaleX(1); /* IE 9 */
-webkit-transform: scaleX(1); /* Safari 3-8 */
-o-transform: scaleX(1);
-moz-transform: scaleX(1);
transform: scaleX(1);
-webkit-transition: opacity 0.5s linear, -webkit-transform 0.5s;
-moz-transition: opacity 0.5s linear, -moz-transform 0.5s;
-o-transition: opacity 0.5s linear, -o-transform 0.5s;
transition: opacity 0.5s linear, transform 0.5s;
}
.stepper{
max-width: 70rem;
margin: 550px auto 600px auto;
width: 90%;
background-color: rgba(248, 248, 248, 0.95);
font-family: "Helvetica";
font-size: 17px;
line-height: 26px;
padding: 15px;
}
</style>
<!--HTML-->
<div class="headline">
<img id="hiddenImg" class="hidden_img intro-imgs" src="https://image.shutterstock.com/image-photo/funny-portrait-hero-260nw-410898763.jpg" >
</div>
<div id="I" class="stepper">
<p>Lorem Ipsum</p>
</div>
<div id="II" class="stepper">
<h1>THE HEADLINE</h1>
</div>
<!-- SCRIPT-->
<script>
var stepI = false;
var stepII = false;
// list of options
let options = {
rootMargin: '0px 0px -50%' //WHEN reaching half of the viewport
};
// instantiate a new Intersection Observer
"use strict";
var intersectionObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (change) {
if (change.isIntersecting) {
if (change.target.id == "I") {
$("#hiddenImg").removeClass("hidden_img");
$("#hiddenImg").addClass("visible_img");
stepI = true;
observer.unobserve(change.target);
}
if (change.target.id == "II") {
if (stepII == false) {
$("#hiddenImg").removeClass("visible_map");
$("#hiddenImg").addClass("hidden_map");
stepII = true
} else {
$("#hiddenImg").removeClass("hidden_map");
$("#hiddenImg").addClass("visible_map");
stepII = false;
}
}
}
});
},options);
// list of paragraphs
let elements = document.querySelectorAll(".stepper");
for (let elm of elements) {
intersectionObserver.observe(elm);
}
</script>
</body>
I added the messenger plugin script and DIV right above the HEAD section on my HTML.
The plugin does not work as described in https://developers.facebook.com/docs/messenger-platform/discovery/customer-chat-plugin#steps
Cannot close the text bubble.
Plugin do not default on hidden for mobile.
The attributes do not seem to work either.
Any thoughts?
I just found a solution:
<style>
.fb_customer_chat_bounce_out_v2 { animation-fill-mode: forwards; display: unset !important; }
.fb_customer_chat_bounce_in_v2 { display: unset !important; }
.fb_iframe_widget iframe { display: none; }
</style>
This worked for me.
Until Facebook will fix this bug, you can temporarily fix this by adding display: none to their .fb_customer_chat_bounce_out_v2 class:
.fb_customer_chat_bounce_out_v2 {
display: none;
}
if you select left direction
so you can add this css
<style>
#keyframes fb_bounce_in_from_right {
0% {
opacity: 0;
transform: scale(0, 0);
transform-origin: bottom left
}
50% {
transform: scale(1.03, 1.03);
transform-origin: bottom left
}
100% {
opacity: 1;
transform: scale(1, 1);
transform-origin: bottom left
}
}
#keyframes fb_bounce_out_from_right {
0% {
opacity: 1;
transform: scale(1, 1);
transform-origin: bottom left
}
100% {
opacity: 0;
transform: scale(0, 0);
transform-origin: bottom left
}
}
</style>
I am using the AtomicCSS framework from acss.io, so far so good.
However, I am stuck with creating animations. The reference page is silent about it and the examples page does not deliver any examples.
https://acss.io/reference.html
https://acss.io/guides/syntax.html#examples-
Let this be a starting point of my animation and show what I am looking for(fade in):
#keyframes fadeIn {
from {
opacity: 0;
transform: translate3d(0, -20%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
try this
#keyframes fadeIn {
from {
opacity: 0;
transform: translate3d(0, -20%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
<div class="Animn(fadeIn)"></div>
I am trying to work around this bug: http://code.google.com/p/chromium/issues/detail?id=20574 thinking of performing the transform, and then afterwards removing it while positioning the element in its end position via JavaScript.
I tried
document.getElementById('popover').style.setProperty("-webkit-transform", "translate3d(0,0,0)")
and
document.getElementById('popover').style.setProperty("-webkit-transform", "none")
None seem to have any effect.
If I remove the transforms and position the elements manually the fixed element does behave as it should.
Here are the transforms themselves:
#popover.open {
display: block;
position: relative;
-webkit-animation: openpopup 0.2s 1;
-webkit-animation-fill-mode: forwards;
}
#popover.closed {
-webkit-animation: closepopup 0.2s 1;
-webkit-animation-fill-mode: forwards;
}
#-webkit-keyframes openpopup {
from {
-webkit-transform: translate3d(0, 100%, 0);
}
to {
-webkit-transform: translate3d(0, 0%, 0);
}
}
#-webkit-keyframes closepopup {
from {
-webkit-transform: translate3d(0, 0%, 0);
}
to {
-webkit-transform: translate3d(0, 100%, 0);
}
}
Javascript had a different name for the css property you are trying to change. It's called WebkitTransform.
document.getElementById('popover').style.setProperty("WebkitTransform", "none"); Should work.