I'm working on my portfolio website so, I was trying some animation for the landing page. Everything is working fine but the animation takes very long time to load. I was generating a matrix of divs using JS and appling CSS and animation to each one of them. Please suggest something to decrease the load time.
My Website
Javascript
let holder = document.getElementById("hero");
let gs = 25;
window.onload = () => {
for (let i = 0; i < gs; i++) {
for (let j = 0; j < gs; j++) {
let dot = document.createElement("div");
dot.classList.add("dot");
dot.style.animationDelay = `${Math.sin(i * j) / 2}s`;
holder.appendChild(dot);
}
}
};
CSS
.hero {
/* background-image: url(media/Background.jpg); */
height: 100vh;
position: absolute;
width: 100%;
display: grid;
grid-template-columns: repeat(50, 90px);
grid-template-rows: repeat(50, 90px);
overflow: hidden;
text-align: left;
}
.dot {
width: 2px;
height: 2px;
animation-name: wavyDots;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate-reverse;
z-index: -1;
}
.dot:nth-child(odd) {
background-color: #0cf5d5;
}
.dot:nth-child(even) {
background-color: #e0017a;
}
#keyframes wavyDots {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(30px, 30px);
}
}
I tried decreasing the matrix size but didn't help much, if I decrease more then I don't have enough divs to cover my entire page.
My goal is to (upon clicking a button) spin a wheel multiple times, then end on a specific rotation value (0...360) while easing out the animation. I can currently 'smoothly' spin to a specific point on the wheel without any full revolutions. My problem is trying to spin the wheel multiple times and then landing on a specific point to make it look more realistic. Is this achievable with the CSS animaton property or anything else?
Here is my code...
const wheelEl = document.getElementById("wheel");
const sliceSize = 360 / 3;
function spinWheel(index) {
// Reset animation
wheelEl.style.transition = "none";
wheelEl.style.transform = "rotate(0deg)";
// Play animation on the next frame
setTimeout(() => {
wheelEl.style.transition = "all ease 1s";
// Target rotation margin
let rotMin = (sliceSize * (index))+(sliceSize/15);
let rotMax = (sliceSize * (index + 1))-(sliceSize/15);
// Target rotation
let rot = Math.floor(Math.random() * (rotMax - rotMin + 1) + rotMin);
wheelEl.style.transform = `rotate(-${rot}deg)`;
}, 0);
}
#container {
position: absolute;
text-align: center;
}
#arrow {
position: absolute;
top: -5px;
left: 50%;
transform: translateX(-50%);
border-top: 10px solid black;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
z-index: 1;
}
#wheel {
width: 100px;
height: 100px;
border-radius: 50%;
background-image: conic-gradient(lightpink 0 120deg, lightblue 0 240deg, lightsalmon 0 360deg);
}
<div id="container">
<div id="arrow"></div>
<div id="wheel"></div>
<br />
<button onclick="spinWheel(2)">Spin wheel</button>
</div>
You can stick to using transform.
This snippet does two things: adds a random (within bounds) number of 360 degrees to the rotation value and sets the easing function to ease-out so that the rotation slows down towards the end only.
So that the effect can be seen, the time of the full rotation is set to 5 seconds but of course alter this to whatever you want. You could for example make that random within some bounds too if desired.
You could also play with the Beziere function that represents ease-out if say you wanted a longer stretch of it seeming to slow down.
const wheelEl = document.getElementById("wheel");
const sliceSize = 360 / 3;
function spinWheel(index) {
// Reset animation
wheelEl.style.transition = "none";
wheelEl.style.transform = "rotate(0deg)";
// Play animation on the next frame
setTimeout(() => {
wheelEl.style.transition = "all ease-out 5s";
// Target rotation margin
const rotMin = (sliceSize * (index)) + (sliceSize / 15);
const rotMax = (sliceSize * (index + 1)) - (sliceSize / 15);
// Target rotation
const fullRots = Math.floor(Math.random() * 5) + 5; // minimum 5 rotations max 9
const rot = (fullRots * 360) + Math.floor(Math.random() * (rotMax - rotMin + 1) + rotMin);
wheelEl.style.transform = `rotate(-${rot}deg)`;
}, 0);
}
#container {
position: absolute;
text-align: center;
}
#arrow {
position: absolute;
top: -5px;
left: 50%;
transform: translateX(-50%);
border-top: 10px solid black;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
z-index: 1;
}
#wheel {
width: 100px;
height: 100px;
border-radius: 50%;
background-image: conic-gradient(lightpink 0 120deg, lightblue 0 240deg, lightsalmon 0 360deg);
}
<div id="container">
<div id="arrow"></div>
<div id="wheel"></div>
<br />
<button onclick="spinWheel(2)">Spin wheel</button>
</div>
I want to make a flutter timer app which will fill the screen from bottom to top with a color. I think i can do that by incrementing the size of the container with respect to time but i want the text as shown in the image. Please someone help me with this.
It changes the color of the text as the size of the container, which fills the screen, increases.
I can offer a solution for css. The timer counter will be displayed with rule content: '', with a cycle of 10 seconds and a delay of 1 second before this animation starts.
.timer:after {
content: "0";
animation: timer 10s 1s forwards;
}
The complete css code shows how 10 seconds are distributed over a percentage of 100%.
#keyframes timer {
10% {
content: "1";
}
...
100% {
content: "10";
}
}
I used rule mix-blend-mode: difference to invert the background color.
The mix-blend-mode CSS property sets how an element's content should blend with the content of the element's parent and the element's background.
I changed the height of the dynamic background element using rule top, and animated it in a similar way using rule animation and #keyframes.
#keyframes background_top {
from {
top: 100%;
}
to {
top: 0%;
}
}
The #keyframes rule sets keyframes when animating an element. A keyframe is an element's properties (transparency, color, position, etc.) that should be applied to an element at a given moment in time. Thus, animation is a smooth transition of style properties from one keyframe to another. The calculation of intermediate values between such frames is taken over by the browser.
body {
margin: 0;
}
.wrapper {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: lightgrey;
position: relative;
}
.background {
position: absolute;
left: 0;
right: 0;
bottom: 0;
background: brown;
mix-blend-mode: difference;
animation: background_top 10s 1s forwards;
}
.timer:after {
content: "0";
animation: timer 10s 1s forwards;
font-size: 10em;
color: lightseagreen;
}
#keyframes timer {
10% {
content: "1";
}
20% {
content: "2";
}
30% {
content: "3";
}
40% {
content: "4";
}
50% {
content: "5";
}
60% {
content: "6";
}
70% {
content: "7";
}
80% {
content: "8";
}
90% {
content: "9";
}
100% {
content: "10";
}
}
#keyframes background_top {
from {
top: 100%;
}
to {
top: 0%;
}
}
<div class="wrapper">
<div class="timer"></div>
<div class="background"></div>
</div>
There is a simple way of doing this in flutter with CustomPaint.
The only thing you have to change is the StatelessWidget to a StatefulWidget so that the animation is possible, however I would recommend using something like hooks this package can make animation pretty simple.
class TextWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: TimerPainter(text: "6", height: 500),
));
}
}
class TimerPainter extends CustomPainter {
TimerPainter({required this.text, required this.height});
final String text;
final double height;
#override
void paint(Canvas canvas, Size size) {
// ========================================== TextPainter
final TextPainter textPainter = TextPainter(
textDirection: TextDirection.ltr,
text: TextSpan(
text: text,
style: TextStyle(
color: Colors.greenAccent,
fontSize: 500,
),
))
..layout();
textPainter.paint(
canvas,
Offset(size.width / 2 - textPainter.width / 2,
size.height / 2 - textPainter.height / 2));
// ============================================== Rect
final rectPaint = Paint()
..color = Colors.greenAccent
..blendMode=BlendMode.difference;
canvas.drawRect(
Offset(0, size.height / 2) & Size(size.width, height), rectPaint);
final rectPaint2 = Paint()
..color = Colors.white
..blendMode=BlendMode.difference;
canvas.drawRect(
Offset(0, size.height / 2) & Size(size.width, height), rectPaint2);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
this is how it looks
I'd like to make both .quote-container and #new-quote elements in the same line even if the window width is very small. For example 83pixels. Using min-width on the .quote-container element worked, however, using the same technique on the #new-quote element didn't work.
Maybe that's because #new-quote isn't the children of .quote-container? I even tried to make it a child and it was even worse (picture was taken on the desktop window size):
What I'd like to achieve in visual:
var getNewQuote = function(callback) {
var quote = {};
quote.text = 'Example';
quote.author = 'Example';
$(".loading").hide();
callback(quote);
};
var quoteContainerStartingPadding,
quoteContainerEndingPadding,
newQuoteEndingPadding;
if ($(window).width() > 648) {
quoteContainerStartingPadding = "0 2.5rem";
quoteContainerEndingPadding = "2.5rem";
newQuoteEndingPadding = "2.5rem .75rem";
} else {
quoteContainerStartingPadding = "0 1.5em";
quoteContainerEndingPadding = "1.5rem";
newQuoteEndingPadding = "1.5rem .75rem";
}
$(".quote-container").css("padding", quoteContainerStartingPadding);
getNewQuote(function(quote) {
var getRandomColor = function() {
var colors = ["#ff9966", "#7f00ff", "#396afc", "#0cebeb", "#06beb6", "#642b73", "#36d1dc", "#cb356b", "#3a1c71", "#ef3b36", "#159957", "#000046", "#007991", "#56ccf2", "#f2994a", "#e44d26", "#4ac29a", "#f7971e", "#34e89e", "#6190e8", "#3494e6", "#ee0979"],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + quote.text + '" ';
twitter += quote.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += quote.author;
tumblr += "&content=";
tumblr += quote.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>").prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, quote.text);
$t.find(".quote-author").html("- " + quote.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append("<style id='modStyle'>#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}</style>");
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}");
}
};
var getQuote = function() {
var nc, nh = 0;
nc = getRandomColor();
nh = calcNewHeight(quote);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh / 16 + "rem",
}, {
duration: 1000,
queue: false
});
$(".quote-container").animate({
padding: quoteContainerEndingPadding
}, {
duration: 1000,
queue: false
});
$("#new-quote").animate({
padding: newQuoteEndingPadding
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), quote);
$(".quote-container").children().not($(".loading")).fadeTo(750, 1);
};
$(".quote-container, #new-quote").css({
visibility: "visible",
height: 0
});
$("#new-quote").css("padding", "0 .75rem");
getQuote();
}
);
var two = function() {
$(".quote-container").children().not($(".loading")).hide();
$(".loading").show();
getNewQuote(function(quote) {
var getRandomColor = function() {
var colors = ["#ff9966", "#7f00ff", "#396afc", "#0cebeb", "#06beb6", "#642b73", "#36d1dc", "#cb356b", "#3a1c71", "#ef3b36", "#159957", "#000046", "#007991", "#56ccf2", "#f2994a", "#e44d26", "#4ac29a", "#f7971e", "#34e89e", "#6190e8", "#3494e6", "#ee0979"],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + quote.text + '" ';
twitter += quote.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += quote.author;
tumblr += "&content=";
tumblr += quote.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>").prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, quote.text);
$t.find(".quote-author").html("- " + quote.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append("<style id='modStyle'>#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}</style>");
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";} .lds-eclipse {box-shadow: 0 .25rem 0 0 " + newColor + ";}");
}
};
var getQuote = function() {
var nc = getRandomColor(),
nh = calcNewHeight(quote);
$(".quote-container").children().not($(".loading")).css("opacity", 0);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh / 16 + "rem",
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), quote);
$(".quote-container").children().not($(".loading")).fadeTo(750, 1);
};
getQuote();
});
}
;
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
background: #333;
color: #333;
font-family: sans-serif;
}
.quote-container {
width: 35%;
background: #fff;
margin: 0;
display: inline-block;
vertical-align: middle;
border-radius: 0.1875rem;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
visibility: hidden;
min-width: 15rem;
}
.quote-text {
font-size: 1.625rem;
}
.quote-text i {
margin-right: 0.6rem;
}
.quote-text p {
display: inline;
}
.quote-author {
font-size: 1rem;
margin: 0 0.4rem 2rem 0;
text-align: right;
}
.button {
padding: 0.75rem;
text-align: center;
font-size: 1rem;
color: #fff;
border-radius: 0.1875rem;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.button:not(#new-quote):hover {
opacity: 0.8 !important;
}
.button:not(#new-quote) {
min-width: 1rem;
min-height: 1rem;
}
.button i {
vertical-align: middle;
}
#new-quote {
white-space: nowrap;
writing-mode: vertical-lr;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
vertical-align: middle;
background: #fff !important;
margin: 0;
position: relative;
right: 0.25625rem;
color: #333;
visibility: hidden;
}
#new-quote:before {
content: "";
position: absolute;
height: 100%;
width: 0.0625rem;
bottom: 0;
left: 0;
visibility: hidden;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
#new-quote:hover:before {
visibility: visible;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
.v-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.text-center {
text-align: center;
}
footer {
font-size: 0.85rem;
margin-bottom: 1rem;
}
footer a {
text-decoration: none;
color: #fff;
position: relative;
}
footer a:before {
content: "";
position: absolute;
width: 100%;
height: 0.0625rem;
bottom: 0;
left: 0;
background: #fff;
visibility: hidden;
-webkit-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: all 0.3s ease-in-out 0s;
transition: all 0.3s ease-in-out 0s;
}
footer a:hover:before {
visibility: visible;
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
/* Loading animation */
#keyframes lds-eclipse {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
50% {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
#-webkit-keyframes lds-eclipse {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
50% {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.loading {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.lds-eclipse {
-webkit-animation: lds-eclipse 1s linear infinite;
animation: lds-eclipse 1s linear infinite;
width: 10rem;
height: 10rem;
border-radius: 50%;
margin: auto;
}
#media (max-width: 62.5em) {
.quote-container {
width: 50%;
}
}
#media (max-width: 50em) {
.quote-container {
width: 65%;
}
}
#media (max-width: 17.96875em) {
.quote-container {
width: 40%;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="v-align text-center">
<div class="quote-container">
<div class="quote-text">
</div>
<div class="quote-author"></div>
<a id="tweet-quote" class="button"><i class="fa fa-twitter"></i></a>
<a id="tumblr-quote" class="button"><i class="fa fa-tumblr"></i></a>
<div class="loading">
<div class="lds-eclipse"></div>
</div>
</div>
<div id="new-quote" class="button">New quote</div>
<footer>
Created by LukasLSC
</footer>
</div>
EDIT 1: Codepen: https://codepen.io/Kestis500/pen/KZvXgB?editors=0110
If you want to align things in CSS you usually have two different positioning concepts you can use for this purpose:
display (flex)
float
Usually it is a good idea to put all elements you want to align in a wrapping container like a div. In this manner you can just focus on your aligning issue and forget about the general layout - means where you want to have your aligned elements in the layout eventually. You can later on just position the wrapper and do not have to worry about the elements inside.
Another best practice is to give all your elements that this container inherits from a dimension (at least width). A common mistake is that elements that should be aligned break just because the parent element does not have enough space to fit all elements on one line. If you want to know why I provide an example at the end, just follow the *.
But lets go back to the two concepts that you can use. Which one you should use depends on one hand what other attributes you need to give the respective elements and what browsers you need to support. If you only want to support newer browser versions you can go with flexbox, the more secure way to do this is use percentages for widths and float.
Flexbox
.container {
display: flex;
flex-direction: row; // this makes your elements align horizontally
}
.child1 {
flex: 1 1 auto;
}
.child2 {
flex: 0 1 auto;
}
The flex attribute determines the dimension of a child. So consider the parent as width: 100%; and the numbers you give as a first parameter to flex is the ratio of the child's dimension compared to the other children.
Float
.container {
overflow: hidden;
width: 100%; // this must be relative to the containers parent of course
}
.child1 {
width: 75%;
float: left;
}
.child2 {
width: 25%;
float: left;
}
Mind that float takes effect on the elements following in the document flow AFTER the element that you give the float attribute. Also take into account that you might need to calculate margins, paddings or borders in additionally to the elements' widths (except for paddings when using box-sizing: border-box) and that elements containing only floated elements lose their "automatic" dimensions as floated elements lose their information about height and width as well. (overflow: hidden on the container solves this issue for you)
*In a responsive design e.g. you should give the highest parent a width of 100%. If you provide to a child width: 50%; it will now have exactly 50% of the entire width. If you now give the child of the child width: 50% it will be 25% of the entire width. This is less error prone then giving the child's child directly 25%. Let's assume later on you give the child a width of 50% the width of the child's child (25%) will relate to the childs width instead of the parent. So you will end up with a width of 12.5% for the child's child relative to the entire width.
I'm trying to build a webpage for a comic studio and I want one of the characters to come in from the side every so often. So far I have this in the css
.charc {
animation:peek 20s infinite;
left:-500px
}
#-webkit-keyframes peek{
1% {transform:translateX(-500px)}
10%{transform:translateX(100px)}
20% {transform:translateX(-200px)}
100% {transform:translateX(-500px)}
}
and the html
<img src="character.jpg" class="charc"/>
This means the character comes on over and over again. I don't know whether it is possible to get random figures in CSS but I thought if it is, You guys would know
p.s. I know this will only work in chrome but I will be changing that soon.
You need to use js/jQuery for that.
function move() {
$('.charc')
.animate({
left: '-500px'
}, 200)
.animate({
left: '100px'
}, 400)
.animate({
left: '50px'
}, 400)
.animate({
left: '-500px'
}, 100, function() {
var nextIn = Math.floor(Math.random() * 1000);
setTimeout('move()', nextIn);
})
}
$(document).ready(function() {
move();
});
#scene {
width: 500px;
height: 100px;
border: 2px solid black;
margin: 20px;
}
.charc {
position: absolute;
left: -500px;
top: 20px;
width: 20px;
height: 20px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scene">
<div class="charc"></div>
</div>
It is possible with js :
var divElement = document.getElementsByClassName("charc")[0];
var maxValue = 20; //the random value won't exceed 20s
function randomTime(maxvalue){
return Math.round(Math.random() * maxvalue );
}
function changeAnimationTime(maxValue){
var random = randomTime(maxValue);
divElement.style.animation = "peek "+randomTime+"s infinite";
setTimeout(function(){
changeAnimationTime(maxValue);
},random);
}
changeAnimationTime(maxValue);
The advantage of this methode is that you won't use js for animation but just for generating values. So it consumes less ressources.
Not a random delay but you can use a tool I created called WAIT! Animate to add a pause between animations. Here's your animation with a 2 second pause between animations:
.peek.wait2.animated {
animation: peek-wait2 22s linear infinite;
transform-origin: 50% 50%
}
#keyframes peek-wait2 {
0% { transform:translateX(-500px) }
9.09091% { transform:translateX(100px) }
18.18182% { transform:translateX(-200px) }
90.90909% { transform:translateX(-500px) }
100% { transform:translateX(-500px) }
}
Use WAIT! Animate to change the pause duration.
PS. I suggest starting at 0% to avoid a flicker in the animation.