Button border on hover moves the text inside - html

I have created a border-like keyframe CSS style. When I hover the button the border-like animation should start from top-right to top-left then to bottom-left then after to bottom-right and finally to top-right again. When I hover the button the previous sequence should happen and is already created. However; when hovered, the text inside the button moves, which makes the button looks weird.
I looked at the answer to this question, but it's not applicable in my case as I am not using border styling on hover. Instead, I am changing the background color, width, and height of the three spans, not borders.
How can I prevent this shake with the method the animation is created?
CodePen: https://codepen.io/Tes3awy/pen/ZZRpBW
HTML
<div class="wrapper">
<a class="custom-btn" href="https://mince.34way.com/about/" title="About">
About Us
<span class="border-top"></span>
<span class="border-right"></span>
<span class="border-bottom"></span>
<span class="border-left"></span>
</a>
</div>
CSS
body {
position: relative;
height: 100vh;
}
.wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.custom-btn {
position: relative;
width: 183px;
height: 55px;
line-height: 55px;
display: inline-block;
text-align: center;
text-transform: uppercase;
margin: 0 auto;
border: 2px solid #77a942;
color: #77a942;
text-decoration: none;
}
span[class^="border-"] {
opacity: 0;
}
.border-top {
position: absolute;
top: -2px;
right: 0;
width: 100%;
height: 3px;
background-color: transparent;
}
.border-left {
position: absolute;
top: 0;
left: -2px;
width: 3px;
height: 100%;
background-color: transparent;
}
.border-bottom {
position: absolute;
left: 0;
bottom: -2px;
width: 100%;
height: 3px;
background-color: transparent;
}
.border-right {
position: absolute;
bottom: 0;
right: -2px;
width: 3px;
height: 100%;
background-color: transparent;
}
.custom-btn:hover .border-top {
animation: animateTop .2s 1 alternate ease forwards;
}
.custom-btn:hover .border-left {
animation: animateLeft .2s 1 alternate ease forwards;
animation-delay: .2s;
}
.custom-btn:hover .border-bottom {
animation: animateBottom .2s 1 alternate ease forwards;
animation-delay: .4s;
}
.custom-btn:hover .border-right {
animation: animateRight .2s 1 alternate ease forwards;
animation-delay: .6s;
}
#keyframes animateTop {
0% {
width: 0;
height: 0;
opacity: 0;
background-color: #77a942;
}
50% {
width: 50%;
height: 3px;
opacity: 1;
background-color: #77a942;
}
100% {
width: 100%;
height: 3px;
opacity: 1;
background-color: #77a942;
}
}
#keyframes animateLeft {
0% {
width: 0;
height: 0;
opacity: 0;
background-color: #77a942;
}
50% {
width: 3px;
height: 50%;
opacity: 1;
background-color: #77a942;
}
100% {
width: 3px;
height: 100%;
opacity: 1;
background-color: #77a942;
}
}
#keyframes animateBottom {
0% {
width: 0;
height: 0;
opacity: 0;
background-color:#77a942;
}
50% {
width: 50%;
height: 3px;
opacity: 1;
background-color:#77a942;
}
100% {
width: 100%;
height: 3px;
opacity: 1;
background-color:#77a942;
}
}
#keyframes animateRight {
0% {
width: 0;
height: 0;
opacity: 0;
background-color: #77a942;
}
50% {
width: 3px;
height: 50%;
opacity: 1;
background-color: #77a942;
}
100% {
width: 3px;
height: 100%;
opacity: 1;
background-color: #77a942;
}
}

When you translate things by 50%, they may end up in-between pixels. When you use a transition, CSS tends to change its mind on what pixel it rounds to. Try to make sure that the button you're centering text in has height/width that CSS has a definite position it can settle on when you divide it by half.

Related

I can't make the 3/4 circle and i have to use one div only so how can i make it as the example in the link below

here is the shape i want to do enter link description here
P.S.I am still learning the front-end stuff so could you pls help me with this assignment.
Here is the HTML code <div>Elzero</div>
here is the CSS code i tried to do with
* {
box-sizing: border-box;
}
div {
width: 200px;
height: 200px;
background-color: #eee;
margin: 80px auto;
color: black;
font-size: 50px;
font-weight: bold;
text-align: center;
line-height: 200px;
border-radius: 50%;
}
::after {
content: "";
width: 200px;
height: 200px;
background-color: #03a9f4;
margin: 80px auto;
border-radius: 50%;
position: absolute;
transform: translate(-190px, -80px);
z-index: -1;
}
::before {
content: "";
width: 200px;
height: 200px;
background-color: #e91e63;
margin: 80px auto;
border-radius: 50%;
position: absolute;
top: 0px;
z-index: -2;
}
div:hover {
transition: all 0.5s;
transform: rotate(180deg);
}
As you are constrained to use just one div, this snippet builds on your idea of having the pseudo elements but creating them with conic-gradient backgrounds and the 'main' div having the light gray circular background created using a radial gradient. That way it creates these 3 shapes.
and overlays them to give the impression of 3/4 circles. It then uses CSS animation to rotate them on hover.
Obviously you will want to play with the dimensions, the animations timings and directions to get exactly what you want but this should give a start.
* {
box-sizing: border-box;
}
div {
width: 200px;
height: 200px;
background-image: radial-gradient(#eee 0 55%, transparent 55% 100%);
margin: 80px auto;
color: black;
font-size: 50px;
font-weight: bold;
text-align: center;
line-height: 200px;
border-radius: 50%;
position: relative;
}
div::after {
content: "";
width: 200px;
height: 200px;
border-radius: 50%;
position: absolute;
top: 0;
left: 0;
z-index: -2;
background-image: conic-gradient(#03a9f4 0deg 45deg, white 45deg 135deg, #03a9f4 135deg 360deg);
}
div::before {
content: "";
width: calc(100% - 10%);
height: calc(100% - 10%);
position: absolute;
border-radius: 50%;
position: absolute;
top: 5%;
left: 5%;
z-index: -1;
background-image: conic-gradient(#e91e63 0, #e91e63 225deg, white 225deg, white 315deg, #e91e63 315deg, #e91e63 360deg);
}
div:hover::after {
animation: rot .4s linear;
}
div:hover::before {
animation: rot .4s linear;
animation-delay: .1s;
animation-direction: reverse;
}
#keyframes rot {
0% {
transform: rotate(0);
}
25% {
transform: rotate(180deg);
}
50% {
transform: rotate(180deg);
}
75% {
transform: rotate(0);
}
100% {}
}
<div>Elzero
</div>
also here is example in less:
https://codepen.io/nikitahl/pen/XooBXd
if you want to use css here is a converter:
https://jsonformatter.org/less-to-css

Masking an object to make it appear as if it goes behind the item it's rotating around

I'm trying to make a 'dot' orbit around another object (circle) but due to the z-index the dot always appears above the circle it is meant orbiting around.
CodePen link: https://codepen.io/moy/pen/ROVZXd?editors=1100
Ideally the 2nd half of the animation would take place behind the object so it's not seen until it comes out the other side - is that possible?
I thought about fading out the object that is moving around but I don't think that would give a smooth/masked effect?
A bit stuck as to how I'd mask this area as I can't see a way the CSS would know it's meant to be hidden. I thought maybe I could change the z-index 50% though the animation it and reset it at 0%/100% but that doesn't appear to do anything.
Any ideas? Thanks in advance!
.earth {
background: white;
border: 1px solid black;
border-radius: 50%;
display: block;
height: 100px;
margin: 30px auto;
position: relative;
width: 100px;
z-index: 20;
}
.orbit {
border: 2px #eee transparent;
border-radius: 50%;
height: 140px;
margin: auto;
position: absolute;
top: -20px;
left: -20px;
transform: rotateZ(60deg) rotateY(60deg);
transform-style: preserve-3d;
width: 140px;
z-index: 10;
}
.orbit .moon {
animation: move ease-in-out infinite;
animation-duration: 2s;
background: black;
border-radius: 50%;
height: 15px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 15px;
z-index: 10;
}
#keyframes move {
0% {
transform: rotateZ(-90deg) translateX(70px) rotateZ(90deg) rotateY(-70deg); z-index: 20;
}
50% {
z-index: -20;
}
100% {
transform: rotateZ(270deg) translateX(70px) rotateZ(-270deg) rotateY(-70deg); z-index: 20;
}
}
<div class="earth">
<div class="orbit">
<div class="moon"></div>
</div>
</div>
I seem to have solved this by adding a negative z-index to an animation applied to the parent .orbit
Link: https://codepen.io/moy/pen/wZdpRw?editors=1100
I initially applied this at 50% through the animation as that should be the furthest away the dot is before it comes back behind the larger circle. However this didn't work, setting it on 100% did work. Not entirely sure why but it seems to work!
The initial issue was due to the fact that you are applying z-index to the parent element and doing so it will impossible to make the child to move behind it (Why elements with any z-index value can never cover its child?) thus changin z-index is useless
Even if you remove the z-index from the parent you still have the transform that is also creating a stacking context making impossible to the child element to move behind so you cannot make the .moon to move behind the .earth.
The only way to do it (like you already noticed) is to remove z-index from the .earth to avoid the earth creating a stacking context and animate z-index of orbit to make the orbit AND the moon moving behind the earth (not only the moon).
Add some coloration to better see this:
.earth {
background: white;
border: 1px solid black;
border-radius: 50%;
display: block;
height: 100px;
margin: 60px auto;
position: relative;
width: 100px;
}
.orbit {
animation: hide ease-in-out infinite;
animation-duration: 2s;
background:red;
border-radius: 50%;
height: 140px;
margin: auto;
position: absolute;
top: -20px;
left: -20px;
transform: rotateZ(60deg) rotateY(60deg);
transform-style: preserve-3d;
width: 140px;
}
.orbit .moon {
animation: move ease-in-out infinite;
animation-duration: 2s;
background: black;
border-radius: 50%;
height: 15px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 15px;
}
#keyframes move {
0% {
transform: rotateZ(-90deg) translateX(70px) rotateZ(90deg) rotateY(-70deg);
}
100% {
transform: rotateZ(270deg) translateX(70px) rotateZ(-270deg) rotateY(-70deg);
}
}
#keyframes hide {
0% {
z-index: 20;
}
100% {
z-index: -20;
}
}
<div class="earth">
<div class="orbit">
<div class="moon"></div>
</div>
</div>
Now if you add back z-index to earth it will stop working because of the stacking context:
.earth {
background: white;
border: 1px solid black;
border-radius: 50%;
display: block;
height: 100px;
margin: 60px auto;
position: relative;
width: 100px;
z-index:2;
}
.orbit {
animation: hide ease-in-out infinite;
animation-duration: 2s;
background:red;
border-radius: 50%;
height: 140px;
margin: auto;
position: absolute;
top: -20px;
left: -20px;
transform: rotateZ(60deg) rotateY(60deg);
transform-style: preserve-3d;
width: 140px;
}
.orbit .moon {
animation: move ease-in-out infinite;
animation-duration: 2s;
background: black;
border-radius: 50%;
height: 15px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 15px;
}
#keyframes move {
0% {
transform: rotateZ(-90deg) translateX(70px) rotateZ(90deg) rotateY(-70deg);
}
100% {
transform: rotateZ(270deg) translateX(70px) rotateZ(-270deg) rotateY(-70deg);
}
}
#keyframes hide {
0% {
z-index: 20;
}
100% {
z-index: -20;
}
}
<div class="earth">
<div class="orbit">
<div class="moon"></div>
</div>
</div>
You can try key-framing the opacity:
.earth {
background: white;
border: 1px solid black;
border-radius: 50%;
display: block;
height: 100px;
margin: 30px auto;
position: relative;
width: 100px;
z-index: 20;
}
.orbit {
border: 2px #eee transparent;
border-radius: 50%;
height: 140px;
margin: auto;
position: absolute;
top: -20px;
left: -20px;
transform: rotateZ(60deg) rotateY(60deg);
transform-style: preserve-3d;
width: 140px;
z-index: 10;
}
.orbit .moon {
animation: move ease-in-out infinite;
animation-duration: 2s;
background: black;
border-radius: 50%;
height: 15px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 15px;
z-index: 10;
}
#keyframes move {
0% {
transform: rotateZ(-90deg) translateX(70px) rotateZ(90deg) rotateY(-70deg); opacity: 1;
}
56% {
opacity: 1;
}
58% {
opacity: 0;
}
77% {
opacity: 0;
}
78% {
opacity: 1;
}
100% {
transform: rotateZ(270deg) translateX(70px) rotateZ(-270deg) rotateY(-70deg); opacity: 1;
}
}
<div class="earth">
<div class="orbit">
<div class="moon"></div>
</div>
</div>

CSS3 animations not in sync on IE/Edge

I have a simple animation running on an element which loops moving a "star" element from place to place using absolute positioning. It fades in and out briefly using opacity before moving to the next location, then repeating. This works fine in Chrome and Firefox, but of course IE/Edge is having issues. It can best be seen here: Codepen
Issue: In IE/Edge the animation runs correctly through the first iteration, but as soon as the animation starts looping, the opacity and absolute position changes get out of sync to the point where the "star" is fading in/out WHILE it's moving which shouldn't be the case. Chrome shows the ideal animation steps: Fade In, Fade out, Move, Stop, Repeat.
Here's the code:
#import url(https://fonts.googleapis.com/css?family=Mr+Dafoe);
#-webkit-keyframes star-effect {
0% {
left: -7%;
top: 44%;
opacity: 0;
}
5% {
opacity: 1;
}
10% {
left: -7%;
top: 44%;
opacity: 0;
}
35% {
left: 44%;
top: 0%;
opacity: 0;
}
40% {
opacity: 1;
}
45% {
left: 44%;
top: 0%;
opacity: 0;
}
70% {
left: 90%;
top: 6%;
opacity: 0;
}
75% {
opacity: 1;
}
80% {
left: 90%;
top: 6%;
opacity: 0;
}
100% {
left: -7%;
top: 44%;
opacity: 0;
}
}
body{
background: #000;
margin: 0;
padding: 50px;
font-size: 16px;
width: 100%;
font-family: "Helvetica Neue",helvetica,Arial,sans-serif;
overflow-x: hidden;
}
h1{
position: relative;
height: 1.35em;
line-height: 1;
font-size: 10rem;
margin: 0;
transition: font-size .2s linear;
}
h1 > span:nth-child(1){
position: absolute;
padding-left: 30px;
padding-right: 50px;
top: 0px;
font-family: 'Mr Dafoe', cursive;
font-size: .87em;
margin-top: 0px;
margin-bottom: 0;
color: #fd5afa;
text-shadow: -2px -2px 0 #FFBAF2;
-webkit-filter: drop-shadow(3px 3px 1px #441F62);
-webkit-transform: skew(-5deg,-5deg);
font-weight: normal;
z-index: 2;
-webkit-backface-visibility: hidden;
}
h1 span.star{
position: absolute;
display: block;
left: -7%;
top: 44%;
width: 80px;
height: 80px;
z-index: 4;
opacity: 0;
-webkit-animation-name: star-effect;
animation-name: star-effect;
-webkit-animation-duration: 6s;
animation-duration: 6s;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
h1 span.star:before{
position: absolute;
content: '';
background-image: -webkit-radial-gradient(#fff 20%, transparent 80%);
width: 100%;
height: 2px;
display: block;
top: 50%;
}
h1 span.star:after{
position: absolute;
content: '';
background-image: -webkit-radial-gradient(#fff 0%, transparent 90%);
width: 2px;
height: 100%;
display: block;
left: 50%;
}
<body>
<h1>
<span>Word<span class="star"></span></span>
</h1>
</body>

How to make concave animation with CSS

So, I have sidebar that just display some of its content, when it hovered it will display all the sidebar width.
.sidenav {
height: 100%;
width: 100px;
position: fixed;
z-index: 2;
top: 0;
left: 0;
background-color: #fff;
overflow: hidden;
padding-top: 20px;
transition: 0.8s;
opacity: 0.8;
box-shadow: 0px 20px 50px black;
border-radius: 0;
background: black;
}
.sidenav:hover {
width: 215px;
overflow: hidden;
animation-name: roundborder;
animation-duration: 1s;
animation-iteration-count: 1;
}
#keyframes roundborder {
0% { border-radius: 0; }
50% { border-radius: 0 50% 50% 0; }
100% { border-radius: 0; }
}
<div class="sidenav"></div>
my question is how to make concave animation if the sidebar is not hover? so after it hovered and the pointer not in sidebar again, it will back to the initial state but with concave animation, I cant use the negative percent, so what do I use for it? thanks
I guess that you have to do with SVG you create a normal square and then two
animation the first when it's out with rounded corner then the second is with
concave corner.
Maybe I am misunderstanding the question but can you not just put the same animations on the div (without :hover). Like this:
.sidenav {
height: 100%;
width: 100px;
position: fixed;
z-index: 2;
top: 0;
left: 0;
background-color: #fff;
overflow: hidden;
padding-top: 20px;
transition: 0.8s;
opacity: 0.8;
box-shadow: 0px 20px 50px black;
border-radius: 0;
background: black;
animation-name: roundborder2;
animation-duration: 1s;
animation-iteration-count: 1;
}
.sidenav:hover {
width: 215px;
overflow: hidden;
animation-name: roundborder;
animation-duration: 1s;
animation-iteration-count: 1;
}
#keyframes roundborder {
0% { border-radius: 0; }
50% { border-radius: 0 50% 50% 0; }
100% { border-radius: 0; }
}
#keyframes roundborder2 {
0% { border-radius: 0; }
50% { border-radius: 0 50% 50% 0; }
100% { border-radius: 0; }
}
<div class="sidenav"></div>

CSS animations transitioning from behind other elements broken in Firefox

Here's a simple example of what I mean.
HTML
<div class="main-container">
<div class="ht-tx1"></div>
<div class="headtest"></div>
<div class="ht-tx2"></div>
</div>
CSS
.main-container {
width: 100%;
height: 200px;
margin: 250px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
}
.ht-tx2 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
}
#keyframes test-ani1 {
100% {
transform: translateY(-20px);
}
}
#keyframes test-ani2 {
100% {
transform: translateY(20px);
}
}
-
If you view in Chrome, both black bars slide out perfectly. The one transitioning from behind, and the one in front.
If you view it in Firefox, the bar transitioning from behind is broken. It sometimes works, but mostly it ignores the slide animation and just appears at the end of the animation duration.
I've re-created this a number of times and it seems that items that transition from behind another element are broken in firefox.
I've tried using -moz- which doesn't work. IS there anything else you can think of?
I've tried it without the absolute positioning, with z-indexs. and nothing seems to work.
EDIT ----
I appreciate work-around ideas, but I'd really like to know the route cause of this if anyone knows?
Thanks very much.
It seems Firefox is inconsistent when animate the transform property, and I can't say why (yet), most likely a bug though.
Here is 2 workarounds to achieve the same effect
.main-container {
width: 100%;
height: 200px;
margin: 50px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
}
.ht-tx2 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
}
#keyframes test-ani1 {
0% {
transform: translateY(-1px);
}
0.1% {
transform: translateY(0px);
}
100% {
transform: translateY(-20px);
}
}
#keyframes test-ani2 {
100% {
transform: translateY(20px);
}
}
<div class="main-container">
<div class="ht-tx1"></div>
<div class="headtest"></div>
<div class="ht-tx2"></div>
</div>
.main-container {
width: 100%;
height: 200px;
margin: 50px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
}
.ht-tx2 {
width: 100%;
height: 0px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
}
#keyframes test-ani1 {
100% {
top: -20px;
}
}
#keyframes test-ani2 {
100% {
height: 20px;
bottom: -20px;
}
}
<div class="main-container">
<div class="ht-tx1"></div>
<div class="headtest"></div>
<div class="ht-tx2"></div>
</div>
The solution relies on the z-index property of your elements: if you don't specify it the elements lay out one on top of the others, following the flow of the HTML document, when their "position" is set to "absolute". So "ht-txt1" is underneath "headtest" and "ht-tx2" is on top of "headtest".
To correct this "ht-tx1" and "ht-tx2" should take a "z-index" value of -1, so they are hidden underneath "headtest".
As for FF compatibility you need to prefix your "transform" effect with -moz-, check http://caniuse.com/#feat=transforms2d for more details.
Here's the CSS style code:
.main-container {
width: 100%;
height: 200px;
margin: 250px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
z-index: -1;
}
.ht-tx2 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
z-index: -1;
}
#keyframes test-ani1 {
100% {
-ms-transform: translateY(-20px);
-webkit-transform: translateY(-20px);
-moz-transform: translateY(-20px);
transform: translateY(-20px);
}
}
#keyframes test-ani2 {
100% {
-ms-transform: translateY(20px);
-webkit-transform: translateY(20px);
-moz-transform: translateY(20px);
transform: translateY(20px);
}
}