I want to expand the div on click. An idea is for the div to start expanding until its full-page height and width starting from the position of the div before it starts expanding.
I know I didn't explain that to you clearly but I hope my current code will help you understand.
I want to the div to expand from its current position to fill the full page. It almost works but it works from the position I set in the animation.
Do you have any idea how can I receive the div's current position in Javascript and set that value as animation's starting point?
$(document).ready(function() {
$('.about').click(function() {
$('.about').addClass('active');
$('.about').removeClass('border');
})
$('.projects').click(function() {
$('.projects').addClass('active');
$('.projects').removeClass('border');
})
})
.hero {
position: relative;
width: 100%;
height: calc(100vh - 150px);
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 1.5em;
}
.border {
border-radius: 15px;
border: 1px solid #000;
cursor: pointer;
}
.about {
grid-row: 1/2;
background-color: chocolate;
}
.projects {
grid-row: 1/3;
grid-column: 2/3;
background-color: cyan;
}
#grid-split {
grid-row: 2/3;
grid-column: 1/2;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5em;
}
#keyframes expand {
0% {
width: 0vw;
height: 0vh;
top: 20%;
left: 20%;
}
100% {
width: 100vw;
height: 100vh;
top: 0;
left: 0;
}
}
.about.active {
position: fixed;
top: 0;
left: 0;
z-index: 100;
animation: expand .5s ease-in;
width: 100vw;
height: 100vh;
}
.projects.active {
position: fixed;
top: 0;
left: 0;
z-index: 100;
animation: expand .5s ease-in;
width: 100vw;
height: 100vh;
}
<div class="hero">
<div class="about border"></div>
<div class="projects border"></div>
<div id="grid-split">
<div class="contact border"></div>
<div class="process border"></div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Related
After adding a position: fixed; to my header everything was in front of my header because they were using a position: absolute or position: relative I deleted them, and problem solved but now I want to change the position of price since I can not use a relative or absolute position because of this:
in this image price uses a relative position and header uses a fixed position but price is infront of the header so i decided to delete the position from price:
How can I change the position of price in the following code? For example I want to put it in bottom right without setting a position: absolute or position: relative.
Or if there is a better solution that can help me to put my content behind the fixed header without deleting the position property of contents what is it?
.header {
width: 100%;
height: 200px;
position: fixed;
background-color: darkcyan;
top: 0;
left: 0;
right: 0;
margin-top: 0;
margin-right: 0;
}
body {
margin-top: 333px;
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
margin-right: 0;
margin-left: 0;
margin-bottom: 0;
}
.footer {
background: darkslateblue;
margin-top: 100px;
height: 100px;
margin-right: 0px;
width: 100%;
}
.card {
max-width: 400px;
margin: auto;
text-align: center;
font-family: arial;
border-style: solid;
border-width: 6px;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 1em;
}
.card img {
height: 400px;
width: 400px;
vertical-align: middle;
}
.price {
background-color: #f44336;
font-size: 22px;
border-radius: 3px;
width: 131px;
padding: 5px;
}
.card button {
border: none;
color: white;
background-color: #000;
cursor: pointer;
width: 100%;
height: 100px;
font-size: 44px;
align-items: center;
}
.card button:hover {
opacity: .5;
background-color: #330;
}
#id {
background-color: saddlebrown;
color: white;
margin: 0;
font-size: 30px;
height: 310px;
}
.number {
width: 50px;
height: 50px;
background-color: #330;
color: yellow;
border-radius: 50%;
position: absolute;
top: -22px;
right: -22px;
justify-content: center;
align-items: center;
display: flex;
font-size: 22px;
}
#media (max-width: 1864px) {
.card {
max-width: 300px;
}
.price {
font-size: 20px;
}
.card img {
height: 300px;
width: 300px;
}
}
#media (max-width: 1319px) {
.grid {
grid-template-columns: 1fr 1fr 1fr;
}
}
<head>
<!-- <link rel="stylesheet" href="{% static 'main.css' %}"> -->
<div class="header">
<h1>header</h1>
</div>
</head>
<body style="background-color: #36454F;">
<div class="grid">
<!-- {% for i in p%} -->
<div class='card'>
<div class="number">{{i.Number}}</div>
<img src="{{i.image}}"></img>
<p id="id">{{i.description}}</p>
<a href="{{i.buy}}" target='_blank' rel='noopener noreferrer'>
<button><span class="price"> ${{i.price}}</span> buy</button>
</a>
</div>
<!-- {%endfor%} -->
</div>
<div class="footer">
<h1>hello</h1>
</div>
</body>
Add a z-index property in the header class.
.header{
width: 100%;
height: 200px;
position: fixed;
background-color: darkcyan;
top: 0;
left: 0;
right: 0;
z-index: 100;
margin-top: 0;
margin-right: 0;
}
Hello I have several javascript files, I want to put them on the site but place them using grid in css.
I'll share the code with you, I do not understand:
Where do I need to write columns and rows so that after I add columns and rows to the .box-1 class it will change its position?
I have several more javascript files for which I want to change the position, my question, is it advisable to leave each javascript file separately and link it to HTML or is it recommended to merge all the javascript files into one file and then link to HTML?
Thanks.
const panels = document.querySelectorAll('.panel')
panels.forEach(panel => {
panel.addEventListener('click', () => {
removeActiveClasses()
panel.classList.add('active')
})
})
function removeActiveClasses() {
panels.forEach(panel => {
panel.classList.remove('active')
})
}
#import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
* {
box-sizing: border-box;
}
body {
font-family: 'Muli', sans-serif;
display: grid;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
margin: 0;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr 1fr;
}
.box-1 {
display: flex;
width: 30vw;
height: auto;
flex-direction: row;
}
.container {
display: flex;
width: 90vw;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr 1fr;
}
.box-1 {
grid-column: 3/4;
grid-row: 2/3;
}
.panel {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
height: 80vh;
border-radius: 50px;
color: #fff;
cursor: pointer;
flex: 0.5;
margin: 10px;
position: relative;
-webkit-transition: all 700ms ease-in;
}
.panel h3 {
font-size: 24px;
position: absolute;
bottom: 20px;
left: 20px;
margin: 0;
opacity: 0;
}
.panel.active {
flex: 5;
}
.panel.active h3 {
opacity: 1;
transition: opacity 0.3s ease-in 0.4s;
}
#media (max-width: 480px) {
.container {
width: 100vw;
}
.panel:nth-of-type(4),
.panel:nth-of-type(5) {
display: none;
}
}
<div class="box 1">
<div class="container">
<div class="panel active" style="background-image: url('https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Explore The World</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Wild Forest</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80')">
<h3>Sunny Beach</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80')">
<h3>City on Winter</h3>
</div>
<div class="panel" style="background-image: url('https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
<h3>Mountains - Clouds</h3>
</div>
</div>
</div>
I succeeded:
I added 2 queues so that they could take up space and the JavaScript file I reduced its width-
enter code here #import
url('https://fonts.googleapis.com/css?family=Muli&display=swap');
* {
box-sizing: border-box;
}
body {
font-family: 'Muli', sans-serif;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
margin: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.container {
display: flex;
width: 30vw;
justify-items: center;
grid-column: 2/3;
}
.card{
grid-column: 1/2;
width: 80vh;
margin: 30px;
}
.card2{
grid-column: 3/4;
width: 80vh;
margin: 30px;
}
.panel {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
height: 30vh;
border-radius: 50px;
color: #fff;
cursor: pointer;
flex: 0.5;
margin: 10px;
position: relative;
-webkit-transition: all 700ms ease-in;
grid-column: 3/4;
width: 30vh;
}
.panel h3 {
font-size: 24px;
position: absolute;
bottom: 20px;
left: 20px;
margin: 0;
opacity: 0;
}
.panel.active {
flex: 5;
}
.panel.active h3 {
opacity: 1;
transition: opacity 0.3s ease-in 0.4s;
}
#media (max-width: 480px) {
.container {
width: 100vw;
}
.panel:nth-of-type(4),
.panel:nth-of-type(5) {
display: none;
}
}
I have a sticky header that utilizes the process found here (https://www.w3schools.com/howto/howto_js_sticky_header.asp). This works great. However, this does not account for variable heights of the hero element above the header. When you resize the window vertically, the sticky header breaks until you refresh the browser. What do I need to add to the script so that it detects the new height upon resizing?
Here is a codepen displaying my dilemma: https://codepen.io/JKDESIGN44/pen/VwYBqBV
Here is the javascript:
// STICKY HEADER
document.addEventListener('DOMContentLoaded', function () {
// When the event DOMContentLoaded occurs, it is safe to access the DOM
// When the user scrolls the page, execute myFunction
window.addEventListener('scroll', myFunctionForSticky);
// Get the navbar
var navbar = document.getElementById("c3Header");
// Get the offset position of the navbar
var sticky = navbar.offsetTop;
// Add the sticky class to the navbar when you reach its scroll position.
// Remove "sticky" when you leave the scroll position
function myFunctionForSticky() {
if (window.pageYOffset >= sticky) {
console.log("window.pageYOffset >= sticky");
} else {
console.log("Not window.pageYOffset >= sticky");
}
if (window.pageYOffset >= sticky) {
navbar.classList.add("sticky");
} else {
navbar.classList.remove("sticky");
}
}
})
You don't need any JS to accomplish this. All you need are two lines of css to be able to accomplish the same, with way less complexity.
Take a look at this:
html, body, header{
margin: 0px;
padding: 0px;
}
.full-height-section{
height: 100vh;
width: 100%;
position: relative;
}
a{
text-decoration: none;
font-family: 'Montserrat', sans-serif;
color: inherit;
}
li{
list-style-type: none;
text-transform: uppercase;
font-size: 15px;
letter-spacing: 2px;
transition: all 0.1s ease;
}
.bg-aqua{
background-color: #073038;
}
.text-white{
color: #FFFFFF;
transition: all 0.1s ease;
font-family:
}
.text-hover-blue:hover{
color: #7DD2EF;
transition: all 0.1s ease;
}
/* --------------HEADER---- */
/* ----HERO---- */
.hero{
height: 100vh;
width: 100vw;
min-height: 500px;
position: relative;
display: flex;
justify-content: center;
align-content: center;
align-items: center;
}
.hero-text{
font-size: 40px;
text-transform: uppercase;
z-index: 20;
}
.content-hero{
height: 25vh;
width: 100vw;
min-height: 500px;
position: relative;
display: flex;
justify-content: center;
align-content: center;
align-items: center;
}
.hero-bg{
display: block;
object-fit: cover;
z-index: -1;
position: absolute;
min-height: 500px;
}
.hero-logo-wrap{
align-self: center;
height: 30vw;
max-height: 50vh;
min-height: 200px;
z-index: 10;
}
.hero-logo{
height: 100%;
}
.down-arrow-wrapper{
height: 50px;
width: 50px;
position: absolute;
margin: auto;
left: 0;
right: 0;
bottom: 40px;
border-radius: 999px;
background-color: rgba(125,210,239,0.0);
transition: all 0.5s ease;
z-index: 10;
}
.down-arrow-wrapper:hover{
background-color: rgba(125,210,239,1.0);
transition: all 0.5s ease;
transform: scale(1.2)
}
.down-arrow-rel-wrapper{
height: 50px;
width: 50px;
position: relative;
}
.down-arrow{
height: 20px;
width: 20px;
position: absolute;
margin: auto;
left: 0;
right: 0;
top: 8px;
transform: rotate(45deg);
border-right: solid #fff 3px;
border-bottom: solid #fff 3px;
}
.img-overlay{
height: 100%;
width: 100%;
position: absolute;
margin: auto;
top: 0;
mix-blend-mode: overlay;
background: rgb(3,31,36);
background: -moz-linear-gradient(148deg, rgba(3,31,36,1) 0%, rgba(125,210,239,1) 100%);
background: -webkit-linear-gradient(148deg, rgba(3,31,36,1) 0%, rgba(125,210,239,1) 100%);
background: linear-gradient(148deg, rgba(3,31,36,1) 0%, rgba(125,210,239,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#031f24",endColorstr="#7dd2ef",GradientType=1);
}
/* ----HERO END---- */
.header{
height: 150px;
width: 100%;
z-index: 100;
display: flex;
justify-content: center;
position: sticky;
top: 0;
}
.content-header{
width: 100%;
z-index: 100;
display: flex;
flex-direction: column;
}
.sticky{
position: fixed;
top: 0;
width: 100%;
}
.sticky + .page-wrapper{
padding-top: 150px;
}
.nav-flexbox{
height: 150px;
width: 80%;
max-width: 1500px;
min-width: 1000px;
position: relative;
/*
position: absolute;
margin: auto;
left: 0;
right: 0;
*/
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.nav-left{
display: flex;
flex-direction: row;
justify-content: space-between;
text-transform: uppercase;
letter-spacing: 2px;
width: 100%;
}
.nav-center{
width: 70%;
display: flex;
justify-content: center;
align-items: center;
}
.header-logo{
height: 80px;
z-index: 999;
}
.header-logo-link{
transition: all 0.5s ease;
}
.header-logo-link:hover{
transform: scale(1.2);
transition: all 0.5s ease;
}
.nav-right{
display: flex;
flex-direction: row;
justify-content: space-between;
text-transform: uppercase;
letter-spacing: 2px;
width: 100%;
}
.tab-nav-center{
display: none;
}
.tab-nav-right{
display: none;
}
.content-sub-nav{
height: 50px;
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-content: center;
}
.sub-nav-arrow {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 30px solid #031F24;
position: absolute;
margin: auto;
bottom: 0;
left: 10px;
}
/* ---------------HEADER END---- */
.content-section{
height: calc(100vh - 150px);
display: flex;
justify-content: center;
align-items: center;
}
<head>
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,500,700&display=swap" rel="stylesheet">
</head>
<header>
<!----------------
HERO
------------------>
<div class="hero full-height-section">
<div class="hero-logo-wrap">
<img src="http://c3.abettermancc.com/wp-content/uploads/2019/09/Primary-Logo_Vertical.png" class="hero-logo">
</div>
<a href="#c3Header">
<div class="down-arrow-wrapper">
<div class="down-arrow">
</div>
</div>
</a>
<img src="http://c3.abettermancc.com/wp-content/uploads/2019/09/audience-black-and-white-black-and-white-2014773.jpg" class="hero-bg full-height-section">
<!--------------Overlay -->
<div class="bg-aqua" style="width: 100%; height: 100%; position: absolute;
margin: auto; top: 0; opacity: 0.7; z-index: 9;">
</div>
<div class="img-overlay" style="z-index: 9;">
</div>
<!--------------Overlay END -->
</div>
<!----------------
HERO END
------------------>
</header>
<!----------------
NAVIGATION
------------------>
<nav class="header bg-aqua text-white" id="c3Header">
<div class="nav-flexbox">
<div class="nav-left">
<li>who we are</li>
<li>ministries</li>
<li>sermons</li>
</div>
<div class="nav-center">
<a href="#" class="header-logo-link">
<img src="http://c3.abettermancc.com/wp-content/uploads/2019/09/Primary-Icon-01.png" class="header-logo">
</a>
</div>
<div class="nav-right">
<li>get connected</li>
<li>events</li>
<li>give online</li>
</div>
</div>
</nav>
<!----------------
NAVIGATION END
------------------>
<div class="content-section" style="background-color: #888888;">
<p>SECTION 1</p>
</div>
<div class="content-section" style="background-color: #999999;">
<p>SECTION 2</p>
</div>
<div class="content-section" style="background-color: #888888;">
<p>SECTION 3</p>
</div>
The trick was adding:
position: sticky;
top: 0;
To the .header class. The top:0 states that this class content will only get sticky when it reaches 0 offset from the top (meaning, just at the top of the page).
I am trying to animate width on my fixed element using calc simply because I can't make it relative. It's one of those nav bars that hide when scrolling down and appear back on the top when scrolling up.
For some reason the animation isn't smooth and the 'Settings' div jumps between the transitions. The weird or maybe not that weird bit is that it works fine in Chrome but not in IE...
I know having a div with a calculated width isn't the best idea here but I simply can't make it relative due to its constant disappearance on scroll. I have spent hours trying to figure it out for nothing. Try running it in IE and compare it with Chrome.
const sideMenu = document.querySelector('.side-menu');
sideMenu.addEventListener('click', function() {
sideMenu.classList.toggle('collapse');
});
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.side-menu {
width: 160px;
height: 100vh;
background-color: #ccc;
transition: ease-in-out 0.3s;
float: left;
cursor: pointer;
}
.side-menu.collapse {
width: 50px;
}
.side-menu.collapse + .right-panel > .top {
width: calc(100% - 50px);
}
.right-panel {
position: relative;
background-color: yellow;
display: flex;
flex-direction: column;
}
.top {
position: fixed;
height: 70px;
width: calc(100% - 160px);
background-color: #c3c3c3;
transition: ease-in-out 0.3s;
display: flex;
align-items: center;
}
.banner {
width: calc(100% - 20vw);
}
.settings {
width: 20vw;
display: flex;
justify-content: center;
}
<div class="side-menu">Click</div>
<div class="right-panel">
<div class="top">
<div class="banner">Banner</div>
<div class="settings">Settings</div>
</div>
</div>
I'm not certain why IE has those stuttering issues, but you can simplify your layout to not use calc, which appears to solve the problem.
As you're using fixed and want to cover the full width of the page, instead of the calc() you can use left and right.
E.g. In .top we change calc(100% - 160px); this to
right: 0;
left: 160px;
And in .side-menu.collapse + .right-panel > .top
width: calc(100% - 50px); becomes left: 50px;
const sideMenu = document.querySelector('.side-menu');
sideMenu.addEventListener('click', function() {
sideMenu.classList.toggle('collapse');
});
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.side-menu {
width: 160px;
height: 100vh;
background-color: #ccc;
transition: ease-in-out 0.3s;
float: left;
cursor: pointer;
}
.side-menu.collapse {
width: 50px;
}
.side-menu.collapse + .right-panel > .top {
left: 50px;
}
.right-panel {
position: relative;
background-color: yellow;
display: flex;
flex-direction: column;
}
.top {
position: fixed;
height: 70px;
right: 0;
left: 160px;
background-color: #c3c3c3;
transition: ease-in-out 0.3s;
display: flex;
align-items: center;
}
.banner {
width: calc(100% - 20vw);
}
.settings {
width: 20vw;
display: flex;
justify-content: center;
}
<div class="side-menu">Click</div>
<div class="right-panel">
<div class="top">
<div class="banner">Banner</div>
<div class="settings">Settings</div>
</div>
</div>
I think this will be a problem really difficult to solve...
I created a speedometer that shows number of earthquakes occured in my city.
I want to animate this speedometer in two way:
background-color (green when there aren't quakes and red when there are 3000 quakes) and width of this colored div (the div where i animate background-color).
So the width will be 0 when there aren't quakes and will be 100% when there are 3000 quakes.
The animation is 2 seconds, so for example if i have 1500 quakes:
Add the class for animate speedometer
$('#first').addClass('first-start');
And using setTimeout i add a class to stop the animation after 1 second
setTimeout(function() {
$('#first').addClass('first-pause');
}, 1000);
This code almost always works great.
Now i add a snippet:
$('#first').addClass('first-start');
setTimeout(function() {
$('#first').addClass('first-pause');
}, 1000);
#page {
margin-top: 50px;
width: 300px;
height: 300px;
background-color: #000;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
z-index: 4;
overflow: hidden;
}
#box-first{
width: 200px;
height: 100px;
background-color: #fff;
border-radius: 200px 200px 0 0;
margin-top: 10px;
margin-bottom: 10px;
position: relative;
display: flex;
justify-content: flex-end;
align-items: flex-start;
z-index: 3;
overflow: hidden;
}
#first{
border-radius: 200px 200px 0 0;
margin: 0;
background: red;
width: 200px;
height: 100px;
transform: rotate(180deg);
transform-origin: 50% 100%;
position: absolute;
top: 0px;
right: 0px;
border: 0;
z-index: 1;
}
#n1{
font-size: 20px;
color: #fff;
font-weight: bold;
position: absolute;
left: 50px;
right: 0;
text-align: center;
top: 50px;
bottom: 0;
display: flex;
align-items: flex-end;
justify-content: center;
width: 100px;
height: 50px;
background: #000;
border-radius: 100px 100px 0 0;
z-Index: 1;
overflow: hidden;
}
#keyframes first {
0% {
background-color: green;
transform: rotate(180deg);
}
33% {
background-color: yellow;
transform: rotate(240deg);
}
66% {
background-color: orange;
transform: rotate(300deg);
}
100% {
background-color: red;
transform: rotate(360deg);
}
}
.first-start {
animation: first 2s linear;
}
.first-pause {
animation-play-state: paused;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="page">
<div id="box-first">
<div id="first">
</div>
<div id="n1">
1500
</div>
</div>
</div>
https://jsfiddle.net/hoymds97/
The problem is that i use this code in a big file (4000 lines) with a lot of events and in the same function there are 8 speedometers.
I noticed that sometimes (when there are more events) setTimeout not start immediately after added class for animate speedometer.
As a result, the animation will stop after ...
In our case, for example, it is as if it blocked after 1700 milliseconds and not 1000 seconds. Sometimes it stops even after 2 seconds.
I think the problem is the many events in the queue.
So how can i solve this problem ?
Is possible to solve using always setTimeout or without it?
I hope you can help me and sorry for my english.
Here is a complete new idea that relies on transition instead of animation and where you can easily adjust the state without synchronization issue.
The main trick is to use a gradient for the background coloration and adjust its position in order to have the needed color.
Here is a simple code to illustrate the coloration:
.box {
background: linear-gradient(to right, green, yellow, orange, red);
background-size: 2000% 100%;
transition:1s;
background-repeat: no-repeat;
background-position: 0 0;
height: 200px;
}
.box:hover {
background-position: 100% 0;
}
<div class="box">
</div>
As you can see, I defined a gradient with the 4 colors and we simply need to adjust the background-size in order to have the coloration (0% for green and 100% for red). This won't be exactly the same visually because we will not have a solid color like with animation and for this reason I made the background-size big enough to create the illusion of a solid color.
Now, we simply need to find the values of the background-position and the degree which is pretty easy. The backround-position is a value between 0% and 100% and the degree is a value between 180deg and 360deg. For the state 50% we will logically use 50% for the background-position and 270deg for the transformation and for an x% state we will use respectively x% and x%*(360deg - 180deg) + 180deg = x%*180deg + 180deg = 180deg(x% + 1)
Here is an example with 50% (hover to see)
#page {
margin-top: 50px;
width: 300px;
height: 300px;
background-color: #000;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
z-index: 4;
overflow: hidden;
}
#box-first{
width: 200px;
height: 100px;
background-color: #fff;
border-radius: 200px 200px 0 0;
margin-top: 10px;
margin-bottom: 10px;
position: relative;
display: flex;
justify-content: flex-end;
align-items: flex-start;
z-index: 3;
overflow: hidden;
}
#first{
border-radius: 200px 200px 0 0;
margin: 0;
background: linear-gradient(to right, green, yellow, orange, red);
background-size: 2000% 100%;
background-repeat:no-repeat;
background-position:0% 0%;
transition:1s;
width: 200px;
height: 100px;
transform: rotate(180deg);
transform-origin: 50% 100%;
position: absolute;
top: 0px;
right: 0px;
border: 0;
z-index: 1;
}
#box-first:hover #first{
transform: rotate(270deg);
background-position:50% 0%;
}
#n1{
font-size: 20px;
color: #fff;
font-weight: bold;
position: absolute;
left: 50px;
right: 0;
text-align: center;
top: 50px;
bottom: 0;
display: flex;
align-items: flex-end;
justify-content: center;
width: 100px;
height: 50px;
background: #000;
border-radius: 100px 100px 0 0;
z-Index: 1;
overflow: hidden;
}
<div id="page">
<div id="box-first">
<div id="first">
</div>
<div id="n1">
1500
</div>
</div>
</div>
In order to make this dynamic, we need to adjust the values using JS and the transition will do the job. For this we can define a data-attribute for the state that we convert to the needed value.
Here is an example where I also simplified the html and used pseudo element and CSS variables
setTimeout(function() {
$('.box').each(function() {
var d = $(this).data('state');
$(this).attr("style", "--s:" + d);
});
}, 1000);
body {
margin: 0;
background: #000;
}
.box {
width: 200px;
height: 100px;
background-color: #fff;
border-radius: 200px 200px 0 0;
margin: 10px;
position: relative;
display: inline-flex;
z-index: 0;
overflow: hidden;
}
.box:before {
content: "";
position: absolute;
z-index: -1;
border-radius: 200px 200px 0 0;
background: linear-gradient(to right, green, yellow, orange, red);
background-size: 2000% 100%;
background-repeat: no-repeat;
background-position: calc(var(--s, 0) * 1%) 0%;
transition:2s linear;
width: 200px;
height: 100px;
transform: rotate(calc((var(--s, 0)/100 + 1)*180deg));
transform-origin: 50% 100%;
top: 0px;
right: 0px;
}
.box:after {
content: attr(data-number);
font-size: 20px;
color: #fff;
font-weight: bold;
text-align: center;
margin: auto auto 0;
width: 100px;
height: 50px;
line-height: 50px;
background: #000;
border-radius: 100px 100px 0 0;
z-Index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-number="1500" data-state="50"></div>
<div class="box" data-number="1000" data-state="20"></div>
<div class="box" data-number="3000" data-state="80"></div>
<div class="box" data-number="6000" data-state="100"></div>
You may notice that all will have the same duration since the transition is the same for all. In case you want a different duration and keep the same speed, simply use the CSS variable within the transition also.
setTimeout(function() {
$('.box').each(function() {
var d = $(this).data('state');
$(this).attr("style", "--s:" + d);
});
}, 1000);
body {
margin: 0;
background: #000;
}
.box {
width: 200px;
height: 100px;
background-color: #fff;
border-radius: 200px 200px 0 0;
margin: 10px;
position: relative;
display: inline-flex;
z-index: 0;
overflow: hidden;
}
.box:before {
content: "";
position: absolute;
z-index: -1;
border-radius: 200px 200px 0 0;
background: linear-gradient(to right, green, yellow, orange, red);
background-size: 2000% 100%;
background-repeat: no-repeat;
background-position: calc(var(--s, 0) * 1%) 0%;
transition: calc(2s * var(--s, 0)/100) linear;
width: 200px;
height: 100px;
transform: rotate(calc((var(--s, 0)/100 + 1)*180deg));
transform-origin: 50% 100%;
top: 0px;
right: 0px;
}
.box:after {
content: attr(data-number);
font-size: 20px;
color: #fff;
font-weight: bold;
text-align: center;
margin: auto auto 0;
width: 100px;
height: 50px;
line-height: 50px;
background: #000;
border-radius: 100px 100px 0 0;
z-Index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-number="1500" data-state="50"></div>
<div class="box" data-number="1000" data-state="20"></div>
<div class="box" data-number="3000" data-state="80"></div>
<div class="box" data-number="6000" data-state="100"></div>