I have some CSS code that creates a typing animation (see snippet).
The two lines load simultaneously. How do I make them load one after another?
body{
background: #000;
color: lime;
}
div.a{
font-size: 14px;
margin: 30px;
white-space:nowrap;
overflow: hidden;
width: 30em;
animation: type 5s steps(50, end) 1;
}
#keyframes type{
from{ width: 0;}
}
#keyframes blink{
to{ opacity: .0;}
}
<div class="a">Supercalifragilisticexpialidocious<br /> Another sentence...</div>
Basically you can do that by checking whether the CSS3 Animation has ended or not like explained in this link
http://blog.teamtreehouse.com/using-jquery-to-detect-when-css3-animations-and-transitions-end
then create a function to apply the animation class and call it on jQuery ready, inside the function when the animation ended, check whether there's still another line of sentences that want to be animated
Here's the updated code that should work like what you wanted it to be
nb: this will work only if the sentences is only one line, and if it's more, you must separate it in another element like in the example, also the alert in the end is only to show that the function to animate the typing will not start anymore
nb2: I forgot that the question doesn't include the JavaScript or jQuery tag, but I hope this could help if by chance someone else needed to use the jQuery
var $typeAnimation;
$(function(){
$typeAnimation = $(".view").first();
if($typeAnimation.size() > 0) {
startAnimation();
}
});
function startAnimation() {
$typeAnimation.addClass("animate");
$typeAnimation.one('webkitAnimationEnd oanimationend msAnimationEnd animationend',
function(e) {
$typeAnimation = $typeAnimation.next(".view");
if($typeAnimation.size() > 0) {
startAnimation();
} else {
alert("No More Sentence to be animated");
}
});
}
body{
background: #000;
color: lime;
}
.view {
display: none;
}
.view.animate{
display: block;
font-size: 14px;
margin: 30px;
white-space:nowrap;
overflow: hidden;
width: 30em;
animation: type 5s steps(50, end) 1;
}
#keyframes type{
from{ width: 0;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<div class="view">Supercalifragilisticexpialidocious</div>
<div class="view">Another sentence...</div>
<div class="view">Yet Another sentences...</div>
<div class="view">And Also Another Final sentence...</div>
Related
I am trying to add typewriter effect to some text on a webpage, however, it is not working as intended. Since this question is about animation I have given small video (only 5-6 sec) links bellow.
How do I make that cursor stop from going further than it needs to be ? See Here
This animation starts as soon as I open the website, but this section in in the middle of the webpage so the user is not able to see that animation.See here
This does not adjust itself, when viewed it mobile. So what should I do so that it automatically get smaller with small screen (keeping the whole text in the same line). See here
.pcb-text p {
font-size: 60px;
animation: type-writer-effect 3s steps(56), blink-caret 0.85s step-end infinite;
overflow: hidden;
white-space: nowrap;
margin: 0 auto;
border-right: .12em solid orange;
/ width: 28ch;
}
#keyframes type-writer-effect {
0% {
text-align: center;
width: 0ch;
}
100% {
width: 28ch;
}
}
/* The typewriter cursor effect */
#keyframes blink-caret {
from,
to {
border-color: transparent
}
50% {
border-color: orange;
}
}
<div class="pcb-text">
<div class="text-center">
<p>Physics, Chemistry, Biology.</p>
</div>
</div>
In order to avoid your problem, you need to set flex rules for the parent .pcb-text, and also, in keyframes, change it to the transition - from{} and to{}.
.pcb-text {
display: flex;
justify-content: center;
align-items: center;
}
.pcb-text p {
font-size: 60px;
animation: typing 3s steps(56), blink-caret 0.85s step-end infinite;
overflow: hidden;
white-space: nowrap;
margin: 0 auto;
border-right: .12em solid orange;
}
#keyframes typing {
from {
width: 0;
}
to {
width: 100%;
}
}
#keyframes blink-caret {
from, to { border-color: transparent }
50% { border-color: orange }
<div class="pcb-text">
<div class="text-center">
<p>Physics, Chemistry, Biology.</p>
</div>
</div>
This would be the effect with JS
<!DOCTYPE html>
<html>
<body>
<button onclick="typeWriter()">Click me</button>
<p id="demo"></p>
<script>
var i = 0;
var txt = 'Physics, Chemistry, Biology.';
var speed = 50;
function typeWriter() {
if (i < txt.length) {
document.getElementById("demo").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
}
</script>
</body>
</html>
To call the effect when your element is visible you can do something like that with jQuery:
var has_fired;
$("html").on("scroll", function () {
if (!has_fired && $(this).scrollTop() >= $("#yourElement").offset().top) {
typeWriter()
has_fired = true; // use this if only want fired once
}
});
If you want to use a CSS animation you can check out: https://css-tricks.com/snippets/css/typewriter-effect/
You can start the CSS animation just like the JS animation
var has_fired;
$("html").on("scroll", function () {
if (!has_fired && $(this).scrollTop() >= $("#yourElement").offset().top) {
$("#yourElement").addClass("animation-class");
has_fired = true; // use this if only want fired once
}
});
First of all, if you want the animation to start when the user scrolls to the section in which it exists you're going to need a java-script (you can use jQuery too) code like the one in this link.
Secondly in order to have different font sizes in different screens, I would prefer to use Bootstrap but if you're not familiar with Bootstrap, you may use CSS media queries like below:
#media only screen and (max-width: 600px) {
.pcb-text p {
text-align: center;
font-size: 20px;
animation: type-writer-effect 3s steps(56), blink-caret 0.85s step-end infinite;
overflow: hidden;
white-space: nowrap;
margin: 0 auto;
border-right: .12em solid orange;
}
}
#media only screen and (min-width: 601px) {
.pcb-text p {
text-align: center;
font-size: 60px;
animation: type-writer-effect 3s steps(56), blink-caret 0.85s step-end infinite;
overflow: hidden;
white-space: nowrap;
margin: 0 auto;
border-right: .12em solid orange;
width: 28ch;
}
}
These two media queries are written for two screen sizes (screens with width of 600 pixels or less and screens with with of 601 pixels or more). You can expand these for your own needs.
Finally for the cursor I have to say that as you do not know the width of you p tag in advance, it's a nice idea to put it inside a div and set the width of the p tag to 100%. In this case the cursor will not move to the end as p tags by default get 100% of the width of their container tags. But to find the exact width of the p tag (which is the length of it), you'd better use a java-script code like below:
<script>
var text = document.getElementById("myParagraph").innerText;
var textLength = text.trim().length;
//Then set the length of your div which holds the p tag equal to textLength considering the number of pixel each character takes in your chosen font-size
</script>
I have two divs that appear like this:
The idea is that when you close the bottom div (click on the 'X'), it should disappear.
And when you close the top div, it should disappear, and also the bottom div should slide up and take its place.
I'm very new to jQuery, but this is my first attempt:
function initAnnouncements() {
$(document)
// Closes announcement modules
.on('click', 'annoucements-close', function () {
$('announcement-div').hide();
})
}
#keyframes slideInFromRight {
0% {
transform: translateX(100%);
}
.1%{
opacity: 1;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
.announcements-container {
position: fixed;
top: 80px;
right: 20px;
z-index: 1001;
display: flex;
flex-direction: column;
width: 300px;
/* align-items: flex-end; */
}
.announcements-1 {
animation: slideInFromRight 0.4s ease;
opacity: 0;
animation-fill-mode: forwards;
}
.announcements-2 {
/* animation: 0.4s ease-out 0s 1 slideInFromRight; */
animation: slideInFromRight 0.4s ease;
opacity: 0;
animation-fill-mode: forwards;
animation-delay: .4s;
margin-top: 15px;
}
.annoucements-header {
background-color: #1481C3;
color: #ffffff;
font-family: "Proxima Nova Bold";
padding: 7px 10px;
}
.annoucements-close {
position: absolute;
right: 5px;
width: 24px;
height: 36px;
cursor: pointer;
opacity: .85;
}
.annoucements-close:hover {
opacity: 1;
}
.annoucements-close::before,
.annoucements-close::after {
content: '';
width: 24px;
height: 2px;
background: white;
position: absolute;
top: 7px;
left: 0;
}
.annoucements-close::before {
transform: rotate(-45deg);
}
.annoucements-close::after {
transform: rotate(45deg);
}
/*opened or closed*/
.announcement-div-opened {
display: none;
}
.announcement-div.opened .announcement-div-opened {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class="announcements-container">
<div class="announcement-div announcements-1">
<div class="annoucements-header">
<span class="annoucement-type-quantity">2 School Announcements</span>
<i class="annoucements-close"></i>
</div>
</div>
<div class="announcement-div announcements-2">
<div class="annoucements-header">
<span class="annoucement-type-quantity">1 Admin Announcement</span>
<i class="annoucements-close"></i>
</div>
</div>
</div>
</body>
As you can see this isn't doing anything. I'm trying to toggle the class from 'open' (display:block) to 'closed' (display:none) when the annoucements-close <i> element is clicked on.
And ideally I would like for the second div to slide up when the top one is closed, but first I'd just like to get either one to disappear.
What's wrong with my code where that's not working as expected?
Link to JSFiddle
There are 2 issues with your code: the click() event is inside the function initAnnouncements that doesn't get called. You could move it outside of this function or call the function. Then you have issues with your selectors: It's
.on('click', '.annoucements-close', function () {
$('.announcement-div').hide();
})
instead of
.on('click', 'annoucements-close', function () {
$('announcement-div').hide();
})
for class selectors. Working Fiddle.
If you just want to hide the annoucement which was clicked upon, just change it to
.on('click', '.annoucements-close', function () {
$(this).closest('.announcement-div').hide();
})
I looked at your code and adjusted it a little to demonstrate:
Added your common class on the two announcements "announcement-div"
Attached the document click handler with the jQuery ready event
Used the delegated event selector to listen to clicks within the document that match that common selector
On click of one of the announcement-div's animate the height to 0 and then remove the element
Comments are included in the fiddle. Hope this is helpful!
// Fire this function when the document is ready
$(function() {
// Listen on the whole document for click events on the .announcement-div element
$(document).on('click', '.annoucements-close', function () {
// From the close button find the closest parent "announcement-div"
var annoucement = $(this).closest('.announcement-div');
// Function to run after animating the element (use .hide() to keep element but display:none)
function destroy() {
annoucement.remove();
}
// Animate the annoucement's height to 0 over 400ms and then call the destroy function
annoucement.animate({ height: "0px" }, 400, destroy);
});
});
Updated JS Fiddle
I have been trying to get this to work for a while.
The point is that the inner div will have some shape and there will probably more than one (That's why I used the nth-child selector).
This inner div is supposed to be shown and then be hidden again both for some set amount of time.
the problem is, that I would like to animate all the (later) multiple inner divs in one animation. For this I thought I could use CSS variables, but this does not seem to work.
What I am trying to archieve in this example is the inner div basically just blinking by using the variable. But my result in Firefox is just a black box.
Am I missing anything? I already looked up if one could even use CSS variables in #keyframes and sure enough you can.
The only problem with them in animations seems to be that they are not interpolated in between but that they suddenly switch which is not a problem in this case.
#keyframes test{
from{
--one: 0;
}
to{
--one: 1;
}
}
#test{
width: 100px;
height: 200px;
background-color: black;
animation: test 1s infinite;
}
#test :nth-child(1){
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
}
<div id="test">
<div></div>
</div>
This can be achieved by defining variables using (as of writing this, not well-supported) #property, which allows declaring types and that allows the browser to "understand", for example, that a certain property (variable) is a Number and then it can gradually animate/transition that variable.
Example Code:
#property --opacity {
syntax: '<number>'; /* <- defined as type number for the transition to work */
initial-value: 0;
inherits: false;
}
#keyframes fadeIn {
50% {--opacity: 1}
}
html {
animation: 2s fadeIn infinite;
background: rgba(0 0 0 / var(--opacity));
}
The current types that are allowed include:
length, number, percentage, length-percentage, color, image, url, integer, angle, time, resolution, transform-list, transform-function, custom-ident (an identifier string)
Helpful articles:
https://web.dev/at-property/#writing-houdini-custom-properties
https://css-tricks.com/using-property-for-css-custom-properties
Cool Houdini demos
As stated in the specification:
Animatable: no
and also
Notably, they can even be transitioned or animated, but since the UA
has no way to interpret their contents, they always use the "flips at
50%" behavior that is used for any other pair of values that can’t be
intelligently interpolated. However, any custom property used in a
#keyframes rule becomes animation-tainted, which affects how it is
treated when referred to via the var() function in an animation
property.
So even if you use opacity with var() in the keyframes it won't animate:
#keyframes test {
from {
--one:0;
opacity: var(--one);
}
to {
opacity: var(--one);
--one: 1;
}
}
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
animation: test 1s infinite;
}
<div id="test">
<div></div>
</div>
By the way you can make it working if you use it as a transition because in this case you will apply a transtion to the opacity and not the custom property:
#test {
width: 100px;
height: 200px;
background-color: black;
}
#test:hover {
--one:1;
}
#test :nth-child(1) {
width: 20px;
height: 20px;
margin: auto;
background-color: white;
opacity: var(--one,0);
transition:1s all;
}
<div id="test">
<div></div>
</div>
.box {
width: 100px;
height: 100px;
background: red;
transition: all 1s ease-in-out;
}
.box:hover {
background: yellow;
}
<div class="box"></div>
If the cursor is over the .box for less than a second, the transition stops and falls back to it's original phase.
Is there a way to somehow force the whole animation, regardless of hover duration?
fiddle
Edit: Similar solution but relying on transition and animation: https://jsfiddle.net/ok7pnrsL/
This is my solution: https://jsfiddle.net/9yu0cozq/1/
Basically you need to add a container for the box and then play with CSS animations.
<div id="container">
<div class="box"></div>
</div>
When the mouse enters the .box then the hidden container appears (please note that for this to work that container should have enough width and height to fit the whole area where the mouse might go).
This container creates an animation for itself to "hide" back in 1s. and while it is shown the .box has an animation for the same time.
#container {
position:absolute;
z-index:1;
width: 0;
height: 0;
}
#container:hover{
animation-name:changeSize;
animation-duration: 1s;
}
#container:hover .box{
animation-name:changeColor;
animation-duration: 1s;
}
.box {
z-index:0;
position:absolute;
width: 100px;
height: 100px;
background: red;
transition:1s background;
}
.box:hover {
background: yellow;
}
#keyframes changeColor {
0% {
background: red;
}
100% {
background: yellow;
}
}
#keyframes changeSize {
0%,99% {
width: 100%;height: 100%;
}
100% {
width: 0;height: 0;
}
}
So, without knowing the real context, this solution gives a series of assumptions that might or might not fit your exact case but gives an idea of how to solve it using pure CSS.
I think you heave to use JS for this. First you need to create animation for background change, and and then you can set it as class and add that class on hover, and remove it when animation ends or on webkitAnimationEnd.
$('.box').hover(function() {
$(this).addClass('animate');
$(this).on('webkitAnimationEnd', function() {
$(this).removeClass('animate');
})
})
.box {
width: 100px;
height: 100px;
background: red;
display: inline-block;
margin: 10px;
}
.box.animate {
animation: changeColor 2s linear;
}
#keyframes changeColor {
0% {
background: red;
}
50% {
background: yellow;
}
100% {
background: red;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box"></div>
<div class="box"></div>
I don't think you can do this without javascript, but it would be interesting to find out.
A light weight javascript solution could be something like this:
// Get the elemnt
var myDiv = document.getElementById('box');
// Detect hover
myDiv.onmouseover = function() {
// Add a force class to the element
myDiv.className += " force";
// Reset the cass name after 1sec (100ms)
setTimeout(function(){ myDiv.className = "box"; }, 1000, myDiv);
}
Change your markup slightly to make things easier for now:
<div id="box" class="box"></div>
And add an extra class to your css styles along with the hover state:
.box {
width: 100px;
height: 100px;
background: red;
transition: all 1s ease-in-out;
}
.box.force,
.box:hover {
background: yellow;
}
Check the jsfiddle
I am currently having a problem with CSS animations. A random background is called from an array, shows up and changes and so on. I applied two animation for the image caption id, a slide in and a delayed slide out. The slide in and out runs well for the first time, but when the second background shows up, the caption just appears to the screen without any animation.
This is my test page and below is my code.
HTML code:
<script type="text/javascript">
function loadRandomImage(imgs) {
var index = Math.floor(Math.random() * imgs.length);
console.log("loadRandomImages(): index = "+ index);
$.backstretch(imgs[index].url, {duration: 30000, fade: 1200});
$("#caption").html(imgs[index].caption);
}
var images = new Array(); //array of imgs objects
images[0] = {url: "https://s-media-cache-ak0.pinimg.com/736x/a5/47/45/a5474577f4a4ae93c85db719d0cbafd4.jpg", caption: "Caption0"};
images[1] = {url: "https://s-media-cache-ak0.pinimg.com/736x/e6/41/74/e64174e355f78a0f07e951bcec62ca96.jpg", caption: "Caption1"};
images[2] = {url: "https://media.giphy.com/media/3o7abHrsGbV10rCeze/giphy.gif", caption:"Caption2"};
images[3] = {url: "https://media.giphy.com/media/Bbt5FxRiArl3a/giphy.gif", caption:"Caption3"};
// Preload
setTimeout(loadRandomImage, 1000, images);
// Change images every 3 seconds
setInterval(loadRandomImage, 30000, images);
</script>
<div id="pattern"></div>
<div id="pattern2"></div>
<div id="caption"></div>
CSS code:
#caption {
position: relative;
font: 1.5em Trebuchet, sans-serif;
text-align: center;
margin-left: 75%;
z-index: 56;
color: #ffffff;
background: rgba(0, 0, 0, 0.7);
padding: 8px;
animation: slidein 3s, slideout 3s 27s;
}
#caption:empty
{
display: none;
}
#keyframes slidein {
0% {
margin-left: 100%;
width:100%;
visibility:hidden;
opacity: 0;
}
100% {
margin-left: 75%;
width:100%;
opacity: 1;
visibility:visible;
}
}
#keyframes slideout {
0% {
margin-left: 75%;
width:100%;
opacity: 1;
visibility:visible;
}
100% {
margin-left: 100%;
width:100%;
opacity:0;
visibility:hidden;
}
}
CSS animations have iteration count (animation-iteration-count) as only 1 when no value is given for that property. Here since you've not specified any value, the animation executes only once (that is on page load). There is no pure CSS way to re-trigger an animation once it has completed its cycle. It has to be removed from the element and then re-attached for it to start all over again.
So, for your case here is what you have to do - (a) Set the animations on #caption using JS on page load as it makes it easier to remove and re-add them (b) Upon completion of the slideout animation, remove both the animations from the element (that is, set animation-name: none) and also set html of #caption to none because :empty selector would only then hide it. (c) As soon as the next image is set on the element (using loadRandomImage function), set the animations back on the element. This would re-trigger the animation and so during each image switch, the caption would slide-in and out.
Note: I've changed some parts in the HTML and JS that are not relevant to this answer (like removing the two div and replacing them with 1, avoiding the $.backstretch and loading image using css() etc. But these are only auxiliary items and will not affect the crux of this answer (which is, to remove and add the animations).
function loadRandomImage(imgs) {
var index = Math.floor(Math.random() * imgs.length);
$('#img').css('background-image', 'url(' + images[index].url + ')');
$('#caption').css({
'animation-name': 'slidein, slideout',
'animation-duration': '3s, 3s',
'animation-delay': '0s, 7s'
});
$("#caption").html(imgs[index].caption);
}
var images = new Array(); //array of imgs objects
images[0] = {
url: "http://lorempixel.com/100/100/nature/1",
caption: "Caption0"
};
images[1] = {
url: "http://lorempixel.com/100/100/nature/2",
caption: "Caption1"
};
images[2] = {
url: "http://lorempixel.com/100/100/nature/3",
caption: "Caption2"
};
images[3] = {
url: "http://lorempixel.com/100/100/nature/4",
caption: "Caption3"
};
// Preload
setTimeout(loadRandomImage, 1000, images);
$('#caption').on('animationend', function(e) {
if (e.originalEvent.animationName == 'slideout') {
$('#caption').css('animation-name', 'none');
$('#caption').html('');
setTimeout(function() { /* dummy timeout to make sure browser sees animation as none before adding it again */
loadRandomImage(images);
}, 0);
}
});
#caption {
position: relative;
font: 1.5em Trebuchet, sans-serif;
text-align: center;
margin-left: 75%;
z-index: 56;
color: #ffffff;
background: rgba(0, 0, 0, 0.7);
padding: 8px;
}
#caption:empty {
display: none;
}
#keyframes slidein {
0% {
margin-left: 100%;
width: 100%;
visibility: hidden;
opacity: 0;
}
100% {
margin-left: 75%;
width: 100%;
opacity: 1;
visibility: visible;
}
}
#keyframes slideout {
0% {
margin-left: 75%;
width: 100%;
opacity: 1;
visibility: visible;
}
100% {
margin-left: 100%;
width: 100%;
opacity: 0;
visibility: hidden;
}
}
/* Just for demo */
#img {
height: 100px;
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="img"></div>
<div id="caption"></div>
The animationend event still requires vendor prefixes in some browsers.
You need to use a callback, which is explained here:
How do create perpetual animation without freezing?
I think the animation direction needs to be altered.
These are the possibilities:
animation-direction: normal|reverse|alternate|alternate-reverse|initial|inherit;
I think you need to do one of these:
alternate
The animation will be played as normal every odd time (1,3,5,etc..) and in reverse direction every even time (2,4,6,etc...)
alternate-reverse
The animation will be played in reverse direction every odd time (1,3,5,etc..) and in a normal direction every even time (2,4,6,etc...)
At the moment it is set as
animation-direction: initial, initial;
Seen here: http://www.w3schools.com/cssref/css3_pr_animation-direction.asp
Rather than the Javascript suggestions already provided, you could do a straight CSS solution.
Just set animation-iteration-count to "infinite" (to continuously alternate the 2 elements, or an integer for a set number of repeats)
If you want staggered / alternating animations:
Use an animation-delay (matching the animation-duration) on the second element so it doesn't appear until the first element animation has completed
Build a delay onto the end of your animation (revert to original state # 50%) so that the first element stays hidden while the second animates.