Building a Progress Meter which aligns Steps and a Meter - javascript

I'm working to create a progress meter which has 4 steps:
25%, 50%, 75%, and 100% completion.
The goal is to pass the component the percentageComplete and then have the component render the progress meter where the width of the bar represents percentage complete and the step bubbles are activated based on if the percentage completion matches the 25, 50, 75 and 100% thresholds.
The above is what I would eventually expect to see if we passed ~80% to the component.. Currently this is what is rendering for 75% which is not desired. It should be:
Here is my current code:
.container {
position: relative;
width: 288px;
padding: 12px 0;
margin: 0 auto;
box-sizing: border-box;
display: flex;
-webkit-box-pack: justify;
justify-content: space-between;
}
.container:before {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 12px;
background: #E6E6E7;
margin-top: -6px;
border-radius: 50px;
}
.container:after {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 4px;
background: blue;
margin-top: -2px;
width: 75%;
border-radius: 50px;
transition: width .2s ease;
}
.step {
position: relative;
width: 24px;
height: 24px;
box-sizing: border-box;
}
.step:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 24px;
height: 24px;
border-radius: 50%;
background: #ececec;
}
.p25:after,
.p50:after,
.p75:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 24px;
height: 24px;
background: blue;
border-radius: 50%;
}
<div class="container">
<div class="step p25"></div>
<div class="step p50"></div>
<div class="step p75"></div>
<div class="step 100p"></div>
</div>
If you play with the snippet, you'll notice changing the width of
.container:after {
width: ___%;
}
does not render as desired.
Any suggestions on how I can get this ui component to render as desired by simply passing a percentage?

Since you're starting at 25% instead of zero, you need need start at -25% and add to that. You also need to take into account the width of the step.
width: calc(-25% + xx% + (24px * yy));
xx is the percent desired
yy is the step offset
.container {
position: relative;
width: 288px;
padding: 12px 0;
margin: 0 auto;
box-sizing: border-box;
display: flex;
-webkit-box-pack: justify;
justify-content: space-between;
}
.container:before {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 12px;
background: #E6E6E7;
margin-top: -6px;
border-radius: 50px;
}
.container:after {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 4px;
background: blue;
margin-top: -2px;
width: calc(-25% + 50% + (24px * 1));
border-radius: 50px;
transition: width .2s ease;
box-sizing: border-box;
}
.step {
position: relative;
width: 24px;
height: 24px;
box-sizing: border-box;
}
.step:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 24px;
height: 24px;
border-radius: 50%;
background: #ececec;
}
.p25:after,
.p50:after,
.p75:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 24px;
height: 24px;
background: blue;
border-radius: 50%;
}
<div class="container">
<div class="step p25"></div>
<div class="step p50"></div>
<div class="step p75"></div>
<div class="step 100p"></div>
</div>

You could try this approach, where you can control in JS the width value of track.
.track{
position: absolute;
top: 21px;
height: 4px;
background-color: blue;
}
.container {
position: relative;
width: 288px;
padding: 12px 0;
margin: 0 auto;
box-sizing: border-box;
display: flex;
-webkit-box-pack: justify;
justify-content: space-between;
}
.container:before {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 12px;
background: #E6E6E7;
margin-top: -6px;
border-radius: 50px;
}
.step {
position: relative;
width: 24px;
height: 24px;
box-sizing: border-box;
}
.step:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 24px;
height: 24px;
border-radius: 50%;
background: #ececec;
}
.p:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 24px;
height: 24px;
background: blue;
border-radius: 50%;
}
<div class="container">
<div class="track" style="width: 80%"></div>
<div class="step p"></div>
<div class="step p"></div>
<div class="step p"></div>
<div class="step p"></div>
</div>

Here is another idea with less of code:
.container {
position: relative;
margin:20px;
width: 288px;
height:50px;
--i:100%;
--p:calc(var(--i) - 56px);
background:
/*The 4 circles*/
radial-gradient(circle at center,#E6E6E7 50%,transparent 53%) 100% 0/ 40px 100%,
radial-gradient(circle at center,blue 50%,transparent 53%) calc(2*100% / 3) 0/ 40px 100%,
radial-gradient(circle at center,blue 50%,transparent 53%) calc(100% / 3) 0/ 40px 100%,
radial-gradient(circle at center,blue 50%,transparent 53%) 0 0/ 40px 100%,
/*The progress bar*/
linear-gradient(blue,blue) 20px 50%/var(--p) 20% no-repeat,
/*The bottom Bar*/
linear-gradient(#E6E6E7,#E6E6E7) center/calc(100% - 20px) 30% no-repeat;
background-repeat:no-repeat;
}
<div class="container">
</div>
<div class="container" style="--i:75%">
</div>
<div class="container" style="--i:50%">
</div>
<div class="container" style="--i:25%">
</div>

Related

space-between not working on loading page

I have created a loading page with css and html. I would like to display a loading bar to display when the page is loading, between 0% to 100%.I have used justify-content:space-between to solve this but I can't seem to make this work. I have read previous posts on this in the forum but am still stuck. here is my code, both html and css
<body>
<div class="loading">
<div class="loading__box">
<div class="loading__text">
<div class="loading__text--border"></div>
L
<div class="loading__text--dot"></div>
OADING EXPERIENCE
</div>
<div class="loading__bar">
<div class="loading__bar--inner"></div>
</div>
<div class="loading__counter">
<span>0%</span>
<div class="loading__counter--number">100%</div>
</div>
</div>
</div>
</body>
base.scss
body {
margin: 0;
box-sizing: border-box;
&::after,
&::before {
box-sizing: border-box;
}
}
html, body {
overflow-x: hidden;
}
body{
font-family: 'Poppins', sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
```
loader.scss
```
.loading {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100vh;
width: 100%;
z-index: 99;
background: #0b134f;
place-items: center;
display: grid;
font-family: "Orbitron", sans-serif;
&__box {
position: relative;
width: 500px;
height: 200px;
border: 3px solid #6cff8d;
border-top: 3px solid #6cff8c7a;
border-bottom: 3px solid #6cff8c7a;
}
&__bar {
width: 90%;
height: 10%;
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%);
background: #ccc;
border-radius: 2px;
&--inner {
height: 100%;
width: 50%;
border-radius: 2px;
background: #6cff8d;
}
}
&__text {
position: relative;
color: #fff;
padding: 1rem;
font-size: 20px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
&--dot {
width: 15px;
height: 15px;
margin: 0 3px;
border-radius: 50%;
animation: pulse 1s infinite;
background: #fff;
#keyframes pulse {
from {
opacity: 0;
background: #6cff8d;
}
to {
opacity: 1;
}
}
}
&--border {
width: 85%;
height: 1px;
background: #6cff8c7a;
position: absolute;
bottom: 0;
left: 50px;
transform: translateY(-50%);
}
}
&__counter {
position: absolute;
top: 70%;
left: 0;
color: #fff;
font-size: 20px;
font-weight: 700;
width: 100px;
display: flex;
justify-content: space-between;
padding-left: 10px;
}
}
```
you need to edit you .loading__counter:
width: 100%;
box-sizing: border-box;
padding: 0 10px;
See the working example below:
body {
margin: 0;
box-sizing: border-box;
&::after,
&::before {
box-sizing: border-box;
}
}
html, body {
overflow-x: hidden;
}
body{
font-family: 'Poppins', sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
.loading {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100vh;
width: 100%;
z-index: 99;
background: #0b134f;
place-items: center;
display: grid;
font-family: "
Orbitron"
, sans-serif;
}
.loading__box {
position: relative;
width: 500px;
height: 200px;
border: 3px solid #6cff8d;
border-top: 3px solid #6cff8c 7a;
border-bottom: 3px solid #6cff8c 7a;
}
.loading__bar {
width: 90%;
height: 10%;
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%);
background: #ccc;
border-radius: 2px;
}
.loading__bar--inner {
height: 100%;
width: 50%;
border-radius: 2px;
background: #6cff8d;
}
.loading__text {
position: relative;
color: #fff;
padding: 1rem;
font-size: 20px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
}
.loading__text--dot {
width: 15px;
height: 15px;
margin: 0 3px;
border-radius: 50%;
animation: pulse 1s infinite;
background: #fff;
}
#keyframes pulse {
from {
opacity: 0;
background: #6cff8d;
}
to {
opacity: 1;
}
}
.loading__text--border {
width: 85%;
height: 1px;
background: #6cff8c 7a;
position: absolute;
bottom: 0;
left: 50px;
transform: translateY(-50%);
}
.loading__counter {
position: absolute;
top: 70%;
left: 0;
color: #fff;
font-size: 20px;
font-weight: 700;
width: 100%;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding: 0 10px;
}
<body>
<div class="loading">
<div class="loading__box">
<div class="loading__text">
<div class="loading__text--border"></div>
L
<div class="loading__text--dot"></div>
OADING EXPERIENCE
</div>
<div class="loading__bar">
<div class="loading__bar--inner"></div>
</div>
<div class="loading__counter">
<span>0%</span>
<div class="loading__counter--number">100%</div>
</div>
</div>
</div>
</body>

position: fixed won't keep the elements fixed to the bottom of an element

With the following styles:
#fullpage-menu > .gradient {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 0.3rem;
}
where #fullpage-menu has the styling:
#fullpage-menu {
height: 100%;
width: 100%;
background-color: var(--secondary-button-color);
left: 0;
position: absolute;
top: 0;
animation: expand-fullpage-menu 500ms cubic-bezier(0.42, 0, 0.07, 1.43);
z-index: 1001;
animation-fill-mode: both;
padding: 1rem;
box-sizing: border-box;
overflow: hidden;
transform: translate(-100%);
overflow-y: auto;
}
and
.apply-for-org .apply-button {
background-color: var(--dark-secondary-button-color);
padding: 0.5rem 1rem;
border-radius: 10rem;
border: none;
cursor: pointer;
color: var(--title-color);
transition: all 300ms ease-out;
user-select: none;
display: block;
clear: left;
font-size: 1.3rem;
text-transform: capitalize;
font-family: bahnschrift;
letter-spacing: 0.05em;
margin: 1rem 0 0 1rem;
position: fixed;
bottom: 1rem;
left: 50%;
transform: translate(-50%);
font-weight: lighter;
}
Where .gradient is displayed on the bottom of each fullscreen menu, and .apply-button is displayed at the bottom of the .apply-for-org <div>, which also has the id #fullpage-menu.
In other words, the .apply-for-org menu should have a gradient bar at the bottom, which should stay there when scrolling through the div if the content height exceeds the screen height.
In addition, the HTML would look like this for a fullpage-menu:
<div id="fullpage-menu" class="apply-for-org">
<!--Content and other cool stuff-->
<button class="apply-button">Apply for Organisation</button>
<div class="gradient"></div>
</div>
So why does this not work? Why doesn't the gradient bar and the apply button stick to the bottom of the screen when scrolling through the content?
EDIT 15/04/2021:
#fullpage-menu {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #121a21;
overflow-y: auto;
}
#fullpage-menu > button.close {
padding: 0.5rem 1rem;
position: absolute;
top: 1rem;
right: 1rem;
border-radius: 10rem;
font-family: bahnschrift;
background-color: #070b0e;
border: none;
color: white;
}
#fullpage-menu .gradient {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 0.2rem;
background: rgb(131,58,180);
background: linear-gradient(41deg, rgba(131,58,180,1) 0%, rgba(181,73,227,1) 28%, rgba(253,29,29,1) 83%, rgba(252,145,69,1) 100%);
}
.apply-for-org .apply-button {
position: fixed;
bottom: 1rem;
left: 50%;
transform: translate(-50%);
background-color: #070b0e;
border-radius: 10rem;
border: none;
color: white;
padding: 0.5rem 1rem;
font-family: bahnschrift;
cursor: pointer;
}
/*Styling exclusive for this example*/
#example-content {
height: 100rem;
width: 70%;
margin: auto;
background: rgb(238,174,202);
background: radial-gradient(circle, rgba(238,174,202,1) 0%, rgba(148,187,233,1) 100%);
opacity: 0.5;
}
<div id="fullpage-menu" class="apply-for-org">
<button class="close">Close</button>
<div id="example-content"></div>
<button class="apply-button">Apply for Organisation</button>
<div class="gradient"></div>
</div>
I also noticed that it works just fine in the code snippet that I posted, but apparently it doesn't work as well on my locally hosted server..
If it matters, I'm using .ejs instead of .html, but it shouldn't be of any importance (i believe)
For anyone having the same problem in the distant or near future, it can be fixed by wrapping all the content in another div with position:block attribute:
<div id="fullpage-menu" class="apply-for-org">
<div class="main-wrapper">
<!--Place all the fancy content here-->
<div class="gradient"></div>
<button class="apply-button">Apply for Organisation</button>
</div>
</div>
And then by giving these styles, everything will work :)
#fullpage-menu {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #121a21;
overflow-y: auto;
}
#fullpage-menu .gradient {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 0.2rem;
background: rgb(131,58,180);
background: linear-gradient(41deg, rgba(131,58,180,1) 0%, rgba(181,73,227,1) 28%, rgba(253,29,29,1) 83%, rgba(252,145,69,1) 100%);
}
.apply-for-org .apply-button {
position: fixed;
bottom: 1rem;
left: 50%;
transform: translate(-50%);
background-color: #070b0e;
border-radius: 10rem;
border: none;
color: white;
padding: 0.5rem 1rem;
font-family: bahnschrift;
cursor: pointer;
}
/*This part is important!*/
.apply-for-org > .main-wrapper {
height: 100%;
width: 100%;
overflow-y: auto;
}
I don't know why, apparently my CSS and HTML knowledge is too limited, or I am too stupid, but at least this works. It wouldn't work without the .main-wrapper element wrapping all of the content.
EDIT:
disinfor mentioned something that might just as well work, haven't tried it though:
A fixed element can be positioned against its parent, if you set a transform property on the parent. Try adding transform: translate(0,0) to the parent element.

How can I mask the visibility of the text with the overlapping element using CSS

If you see the GIF provided below the text only appears after it has crossed the Black Dot. Until then it is invisible. This was made using Flash but how can we achieve this using CSS?
Here is what I've got so far:
#import url("https://fonts.googleapis.com/css?family=Ubuntu+Mono");
body {
height: 100vh;
background: #222;
padding: 0;
margin: 0;
font-family: "Ubuntu Mono";
}
.ypn-logo {
background: green;
display: flex;
flex-direction: row;
position: relative;
align-items: center;
justify-content: center;
padding: 10px;
width: 220px;
height: 220px;
border-radius: 220px;
z-index: 1;
}
.ypn-text {
font-size: 3.5em;
color: white;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
margin-left: -80px;
z-index: 0;
}
.ypn-text:before {
background: red;
content: "";
position: absolute;
width: 180px;
height: 180px;
border-radius: 180px;
z-index: -1;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
top: 30px;
left: 10px;
}
.ypn-logo:hover>.ypn-text:before {
left: 50px;
}
.ypn-text:after {
background: #222;
content: "";
position: absolute;
width: 50px;
height: 50px;
border-radius: 180px;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
top: 95px;
left: 130px;
z-index: 1;
}
.ypn-logo:hover>.ypn-text:after {
left: 60px;
}
.ypn-logo:hover>.ypn-text {
margin-left: 80px;
}
<div class="ypn-logo">
<div class="ypn-text">RUN</div>
</div>
I thought of making a div and locking its right border with the central axis of the dot in the middle but this hides the Green and Red elements also. Is there a way to just block the text element but not other elements?
#import url("https://fonts.googleapis.com/css?family=Ubuntu+Mono");
body {
height: 100vh;
background: #222;
padding: 0;
margin: 0;
font-family: "Ubuntu Mono";
}
.ypn-logo {
background: green;
display: flex;
flex-direction: row;
position: relative;
align-items: center;
justify-content: center;
padding: 10px;
width: 220px;
height: 220px;
border-radius: 220px;
z-index: 1;
}
.ypn-text {
font-size: 3.5em;
color: white;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
margin-left: -80px;
z-index: 0;
}
.ypn-before {
background: red;
content: "";
position: absolute;
width: 180px;
height: 180px;
border-radius: 180px;
z-index: -1;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
top: 30px;
left: 10px;
}
.ypn-logo:hover>.ypn-before {
left: 50px;
}
.ypn-after {
background: #222;
content: "";
position: absolute;
width: 50px;
height: 50px;
border-radius: 180px;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
top: 95px;
left: 130px;
z-index: 1;
}
.ypn-logo:hover>.ypn-after {
left: 60px;
}
.ypn-logo:hover>.ypn-text {
margin-left: 80px;
}
.ypn-after:after {
width: 130px;
background: black;
height: 3em;
content: '';
position: absolute;
left: -100px;
}
<div class="ypn-logo">
<div class="ypn-before"></div>
<div class="ypn-text">YPN</div>
<div class="ypn-after"></div>
</div>
You can make the text the child of an element with a background color. Then make the mask by creating an element with a dot and a div set to the background color of the parent. Make the parent's overflow:hidden so the colored area isn't seen as it moves to uncover the text.
$('.overlay').on('click', function() {
$(this).toggleClass('hidden');
});
$(window).on('load', function() {
$('.overlay').removeClass('hidden');
});
body {
background: red;
}
.container {
width: 80%;
height: 60px;
border-radius: 60px;
background: white;
overflow: hidden;
margin: 20px auto;
position: relative;
}
.overlay {
width: 100%;
height: 100%;
background: white;
transition: left 2s ease-out;
position: absolute;
top: 0;
left: calc( -100% + 60px);
}
.overlay.hidden {
left: 0;
}
.overlay::after {
content: '';
background: black;
height: 60px;
width: 60px;
border-radius: 60px;
position: absolute;
right: 0;
top: 0;
}
.text {
font-size: 50px;
line-height: 60px;
width: 100%;
text-align: center;
}
p {
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="text">ezoom</div>
<div class="overlay hidden"></div>
</div>
<p> click the circle to toggle the animation</p>
EDIT :
After using the above principle, here's the final code for the effect you need:
#import url("https://fonts.googleapis.com/css?family=Ubuntu+Mono");
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
padding: 0;
margin: 0;
background: #222;
font-family: "Ubuntu Mono";
}
.ypn-logo {
background: green;
display: flex;
flex-direction: row;
position: relative;
align-items: center;
justify-content: center;
padding: 10px;
width: 220px;
height: 220px;
border-radius: 220px;
}
.ypn-before {
background: red;
content: '';
overflow: hidden;
width: 180px;
height: 180px;
border-radius: 180px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: relative;
left: -20px;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
}
.ypn-text {
background: none;
position: absolute;
left: 20px;
font-size: 3.2em;
color: #ddd;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
}
.ypn-dot {
width: 200px;
height: 200px;
position: relative;
background: red;
left: -35px;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
}
.ypn-dot:after {
content: '';
position: absolute;
background: #222;
width: 60px;
height: 60px;
border-radius: 60px;
top: 70px;
right: -25px;
transition: all 1s cubic-bezier(0.86, 0, 0.07, 1);
}
.ypn-logo:hover>.ypn-before {
left: 20px;
}
.ypn-logo:hover>.ypn-before .ypn-dot {
left: -135px;
}
.ypn-logo:hover>.ypn-before .ypn-text {
left: 80px;
}
<div class="ypn-logo">
<div class="ypn-before">
<div class="ypn-text">RUN</div>
<div class="ypn-dot"></div>
</div>
</div>
Here is an idea where you can rely on one element and consider a width/margin animation:
.box {
font-size: 50px;
font-weight: bold;
line-height: 1em;
display: inline-flex;
justify-content:flex-end;
overflow:hidden;
white-space:nowrap;
border-radius:1em 0 0 1em;
background: radial-gradient(#000 0.48em, transparent 0.5em) left/1em 1em no-repeat;
width:0;
margin-left:200px;
padding: 5px 1em 5px 0;
transition:1s;
}
body:hover .box {
width:200px;
margin-left:0px;
padding: 5px 0 5px 1em;
}
<div class="box">
some text
</div>
To avoid setting a specific width you can adjust alignment and consider max-width:
.container {
text-align:right;
width:500px;
}
.box {
font-size: 50px;
font-weight: bold;
line-height: 1em;
display: inline-flex;
justify-content:flex-end;
overflow:hidden;
white-space:nowrap;
border-radius:1em 0 0 1em;
background: radial-gradient(#000 0.48em, transparent 0.5em) left/1em 1em no-repeat;
max-width:0;
padding: 5px 1em 5px 0;
transition:max-width 1s,padding 0s 1s;
}
body:hover .box {
max-width:100%;
padding: 5px 0 5px 1em;
transition:max-width 1s;
}
<div class="container">
<div class="box">
some text
</div>
</div>

Custom JQuery Slider doesn't work as expected

I tried to make a custom slider for my projects on my website.
It's important for me to use div tags to slide, because I want to include more information on it, like text and buttons.
It has a "next"- and "previous" button. The problem is that it doesn't slide back and it doesn't start at the beginning after it reached the last slide.
What's going wrong?
$(document).ready(function() {
projectSlider($('.projects').children('.project').first());
function projectSlider(projects) {
$(projects).show(function() {
$('.next').click(function() {
if (projects.next().hasClass('project')) {
projectSlider(projects.next());
} else {
projectSlider($('.projects').children('.project').first());
}
});
$('.previous').click(function() {
if (projects.prev().hasClass('project')) {
projectSlider(projects.prev());
} else {
projectSlider($('.projects').children('.project').first());
}
});
});
}
});
html,
body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
font-family: "Roboto Condensed", sans-serif;
}
/* */
a {
text-decoration: none;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
font-weight: normal;
}
.inline-list {
list-style-type: none;
padding: 0;
}
.inline-list>li {
display: inline-block;
}
/* */
header {
display: block;
position: relative;
top: 0;
left: 0;
width: 35%;
height: 100vh;
background: #fff;
}
.profile {
display: block;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.avatar {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
background: url("../img/avatar.jpg") no-repeat center center;
background-size: cover;
border-radius: 100%;
}
.socialmedia>li {
padding: 0 5px 0 0;
}
.socialmedia>li>a {
color: #212121;
}
/* */
main {
display: block;
position: absolute;
top: 0;
right: 0;
width: 65%;
height: 100%;
background: #EEEEEE;
}
.controls {
display: block;
position: absolute;
z-index: 100000;
top: 50%;
transform: translateY(-50%);
width: 100%;
}
.control {
display: inline-block;
position: absolute;
width: 36px;
height: 36px;
margin: 0 20px 0 20px;
background: #f5f5f5;
color: #212121;
border-radius: 100%;
cursor: pointer;
}
.backward {
left: 0;
float: left;
text-align: center;
}
.backward-arrow {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 18px;
height: 18px;
background: url("../img/icon/left-chevron.svg") no-repeat center center;
background-size: cover;
color: #212121;
}
.forward-arrow {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 18px;
height: 18px;
background: url("../img/icon/right-chevron.svg") no-repeat center center;
background-size: cover;
color: #212121;
}
.forward {
right: 0;
float: right;
}
.projects {
display: block;
position: relative;
width: 100%;
height: 100vh;
}
.project {
display: none;
position: absolute;
width: 100%;
height: 100vh;
}
.dog {
background: red;
}
.cat {
background: green;
}
.rabbit {
background: blue;
}
/* */
footer {
display: block;
position: relative;
bottom: 0;
padding: 0;
width: 100%;
height: 36px;
background: #fff;
}
.made {
display: inline-block;
position: absolute;
float: left;
left: 0;
top: 50%;
height: 38px;
transform: translateY(-50%);
}
.made>p {
display: inline-block;
}
.legal {
display: inline-block;
position: absolute;
float: right;
right: 0;
top: 50%;
height: 38px;
transform: translateY(-50%);
}
/* */
.envelope {
display: inline-block;
position: relative;
width: 18px;
height: 18px;
background: url("../img/icon/envelope.svg") no-repeat center center;
background-size: cover;
}
.twitter {
display: inline-block;
position: relative;
width: 18px;
height: 18px;
background: url("../img/icon/brands/twitter.svg") no-repeat center center;
background-size: cover;
}
.dribbble {
display: inline-block;
position: relative;
width: 18px;
height: 18px;
background: url("../img/icon/brands/dribbble.svg") no-repeat center center;
background-size: cover;
}
.github {
display: inline-block;
position: relative;
width: 18px;
height: 18px;
background: url("../img/icon/brands/github.svg") no-repeat center center;
background-size: cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed" rel="stylesheet">
<main>
<div class="project-slider">
<div class="controls">
<div class="control previous">
<div class="backward-arrow"><-</div>
</div>
<div class="control forward next">
<div class="forward-arrow">-></div>
</div>
</div>
<div class="projects">
<div class="project dog"></div>
<div class="project cat"></div>
<div class="project rabbit"></div>
</div>
</div>
</main>
JSFiddle
Your code seems to be unnecessarily recursive. Each time you click an arrow, the click handlers are bound again. Also, if you click "next", the object passed to projectSlider contains only a single project element, so there will be no "next" or "previous" in that object.
I suggest a different approach. In my example below, for each click, the appropriate project (based on a numeric index) is hidden, then appended to the project container (which stacks it on top of the others), and then re-shown (for animation purposes).
function refreshProjects(project_holder, projects, project_index) {
project_index = (project_index + projects.length) % projects.length;
var thisProject = projects.eq(project_index);
thisProject.hide().appendTo(project_holder).show(250);
}
$(function() {
var project_holder = $('.projects');
var projects = project_holder.children('.project');
var project_index = 0;
$('.control-next').click(function() {
refreshProjects(project_holder, projects, ++project_index);
});
$('.control-previous').click(function() {
refreshProjects(project_holder, projects, --project_index);
});
});
body {
padding: 0;
margin: 0;
font-size: 10px;
}
main {
position: absolute;
top: 0;
right: 0;
width: 65%;
height: 100%;
background: #EEEEEE;
}
.controls {
position: absolute;
z-index: 100000;
top: 50%;
transform: translateY(-50%);
width: 100%;
}
.control {
position: absolute;
background: #f5f5f5;
border: none;
color: #212121;
border-radius: 50%;
cursor: pointer;
width: 1.8em;
height: 1.8em;
padding: .5em;
box-sizing: content-box;
font-size: 1.4em;
outline: 0;
}
.control-previous {
left: 1em;
}
.control-next {
right: 1em;
}
.projects {
width: 100%;
height: 100vh;
}
.project {
position: absolute;
width: 100%;
height: 100%;
}
.project:not(:first-child) {
display: none;
}
.dog {
background: red;
}
.cat {
background: green;
}
.rabbit {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed" rel="stylesheet">
<main>
<div class="project-slider">
<div class="controls">
<button type="button" class="control control-previous"><-</button>
<button type="button" class="control control-next">-></button>
</div>
<div class="projects">
<div class="project dog"></div>
<div class="project cat"></div>
<div class="project rabbit"></div>
</div>
</div>
</main>

Create iOS style new message animation using CSS

My Existing Code...
I am in the process of writing the front end for a chat system that will be used in my application. I have completed the initial styling for the chat messages, see here:
body {
background: #6960b7;
}
/* FOR SO TESTING */
* {
font-family: Helvetica;
}
p {padding:0;margin:0}
/* Define the chat container */
#chat_container {
width: 470px;
height: 300px;
}
/* Define the messages */
#chat_container .chat_message {
position: relative;
padding: 15px 30px 25px;
overflow: hidden;
}
#chat_container .chat_message .chat_avatar {
position: absolute;
bottom: 15px;
left: 0;
width: 70px;
height: 70px;
border-radius: 50%;
z-index: 10;
}
#chat_container .chat_message.me .chat_avatar {
left: auto;
right: 0;
}
#chat_container .chat_message .message {
position: relative;
left: 60px;
max-width: 255px;
word-wrap: break-word;
padding: 10px 20px;
background: #bc6deb;
float: left;
border-radius: 20px;
}
#chat_container .chat_message.me .message {
background: #4fa9e1;
float: right;
left: auto;
margin-right: 60px;
}
#chat_container .chat_message .message p {
font-size: 20px;
font-weight: 300;
text-align: left;
color: #fff;
line-height: 150%;
margin: 0;
padding: 0;
}
#chat_container .chat_message .time {
position: absolute;
bottom: 0;
left: 100px;
font-size: 15px;
color: #fff;
}
#chat_container .chat_message.me .time {
left: auto;
right: 100px;
}
/* Define the message chat ticks */
#chat_container .chat_message .message:before {
content: '';
position: absolute;
bottom: -2px;
left: -7px;
height: 20px;
border-left: 20px solid #bc6deb;
border-bottom-right-radius: 16px 14px;
transform: translate(0, -2px);
z-index: 2;
}
#chat_container .chat_message .message:after {
content: '';
position: absolute;
bottom: -2px;
left: 4px;
width: 26px;
height: 20px;
background: #6960b7;
border-bottom-right-radius: 10px;
transform: translate(-30px, -2px);
z-index: 3;
}
#chat_container .chat_message.me .message:before {
left: auto;
right: -7px;
border-color: #4fa9e1;
border-bottom-right-radius: 0;
border-bottom-left-radius: 16px 14px;
z-index: 2;
}
#chat_container .chat_message.me .message:after {
left: auto;
right: -56px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 10px;
z-index: 3;
}
<div id="chat_container">
<div class="chat_message me">
<img src="http://s11.postimg.org/fq4w6nq8z/ben_carey.png" class="chat_avatar">
<div class="message">
<p>Where are you?</p>
</div>
<p class="time">2 mins ago</p>
</div>
<div class="chat_message">
<img src="http://s11.postimg.org/fq4w6nq8z/ben_carey.png" class="chat_avatar">
<div class="message">
<p>We are at the bar!</p>
</div>
<p class="time">20 secs ago</p>
</div>
<div class="chat_message">
<img src="http://s11.postimg.org/fq4w6nq8z/ben_carey.png" class="chat_avatar">
<div class="message">
<p>What time do you reckon you will get here? We should be sticking around for a bit...</p>
</div>
<p class="time">Just Now</p>
</div>
</div>
What I am Trying to Achieve...
On iOS, when receiving a new message it used to animate when appearing on the screen (it doesn't anymore). I believe this animation was a combination of opacity and scale, although, I am not 100% sure.
I am not very keen on using the transform:scale() method as this does not render particularly well on retina screens (regardless of the size of the the graphic). Excluding JavaScript/jQuery at this stage, as I can handle this, is anyone aware of a pre-existing 'Pure CSS' solution to replicate the animation of new messages on iOS?

Categories