I have animated my navigation buttons that expand upon hover, but they keep on disrupting the flow of the rest of the page. I've tried using z-index to take them out of the flow, but that isn't working, either. Is there a way to do this with out the buttons shoving everything out of whack? Here's my relevant code so far:
.btn-group .button {
background-color: teal;
border: 2px solid orange;
color: orange;
padding: 2px 15px;
text-align: center;
text-decoration: none;
display: inline-block;
cursor: pointer;
float: left;
font-size: 1em;
border-radius: 50%;
margin: 5px 0 5px 5px;
padding-left: 30px;
position: relative;
z-index: 1; }
.btn-group .button:hover {
background-color: cadetblue; }
.button span {
cursor: pointer;
display: inline-block;
position: relative;
transition: 0.5s; }
.button span:after {
content: '\00bb';
opacity: 0;
top: 0;
right: -20px;
transition: 0s;
padding-left: 10px; }
.button:hover span {
padding: 10px;
color: black;
font-size: 1.5em; }
.button:hover span:after {
opacity: 1;
right: 0;
color: black; }
Thanks for your help!
You have to limit your animations to properties that do not interfere with object's position and dimensions in the document flow.
Those are: transform, left, right, bottom and top. For the last 4, in order to work, you also need position:relative on the button. When using any of these, even though you see the element moving, its place is kept in the flow, just like it would still be there. Only its projected image is moved/transformed.
Example with transform:
.button {
margin: 1rem;
transition : transform .3s cubic-bezier(.4,0,.2,1);
display: inline-block;
border: 1px solid black;
padding: 1rem;
}
.button:hover {
transform: scale(1.1);
}
.red {
background-color: red;
padding: 1rem;
color: white;
}
<a class="button">Example with transform</a>
<div class="red">see? I'm not moving</div>
That's how the vast majority of web animations are done (using transforms).
As an alternative, if you really want to animate properties that would normally affect the rest of the document, you will need to remove your element from document flow. For that, you need to:
wrap your element in a wrapper (placeholder) of desired dimensions (which will never move and keep everything in place), and give the wrapper position:relative,
set position:absolute on the button.
Now you can animate anything on the button without affecting the rest of the document.
But remember, the wrapper needs to have proper dimensions, as the button, now being absolutely positioned, will no longer occupy any space in the document flow. Also, note that your button is now relative to its placeholder. If the placeholder moves, the button moves too.
Example with absolute positioning and wrapping:
.wrapper {
height: 5rem;
position: relative;
}
.button {
position: absolute;
top: 1rem;
padding: 1rem;
transition: all .3s cubic-bezier(.4,0,.2,1);
border: 1px solid black;
}
.button:hover {
top: .5rem;
padding: 1.5rem;
}
.red {
background-color: red;
padding: 1rem;
color: white;
}
<div class="wrapper">
<a class="button">Example with absolute positioning and wrapping</a>
</div>
<div class="red">see? I'm not moving</div>
That's the basics.
As a side note, best practices require you to limit animations to a very select and limited bunch or properties which do not hit browser performance: the bunch is made of exactly two items:
transforms
and opacity.
You animate anything else... boom!, your scroll begins to stagger on devices with limited resources. There is quite a lot to read on the subject, but here's a good one.
Setting a high z-index does not take the element out of the document flow, you need to use absolute positioning for your button.
i.e.
.btn-group{
position: relative;
}
.button{
position: absolute;
}
Related
I decided to write a basic blackjack card game using HTML, CSS, and JS, and I'm having a problem where a card oscillates up and down because I'm changing the top margin of the card.
.card {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
border: 5px solid black;
width: 60px;
height: 100px;
background-color: #F0F0F0;
transition-duration: 0.3s;
transition-property: margin-top, border;
}
.card:hover {
margin-top: 0px;
border: 5px solid #3000A0;
z-index: 0 !important;
transition-duration: 0.3s;
transition-property: margin-top, border;
}
<div class="card">Card</div>
So when I hover over the card, the top margin of 50px is removed and the card slides up. However, if I hover over the bottom 50px of the card, the card will slide up (out of the selection of :hover, and the card starts to slide back down. The card will then become selected, slide up, become unselected, slide down... repeat.
I tried to fix this by adding
.card::after {
content: "";
width: 60px;
height: 50px;
}
but it didn't seem to do anything.
I considered a solution by adding <div>s before and after the card element and changing their heights, but I'd rather use a CSS solution before JS for this scenario. What could I do to fix this?
When animating elements based on mouse position it's best to delegate the location of the event to another element (in this case, a parent) and animate the transform property as it is only a visual transform (padding, margin, etc. affect the document flow).
For example:
.card-wrapper {
display: inline-block;
margin-top: 50px;
border: 1px solid #ccc;
padding: 5px;
}
.card-wrapper:hover .card {
z-index: 0 !important;
border: 5px solid #3000A0;
transform: translateY(-50px);
}
.card {
display: flex;
flex-direction: column;
align-items: center;
border: 5px solid black;
width: 60px;
height: 100px;
background-color: #F0F0F0;
transition: all 300ms ease;
}
<div class="card-wrapper">
<div class="card">Card</div>
</div>
I added a border and padding to the parent to show you the bounds of the parent. As the mouse enters/exits the parent the child card animates without affecting other elements.
Note that the bounds of the parent includes the child as it transforms to extend beyond the top of the parent.
You can use :after to make an extension of the :hover area on the card. Make the card relative and then absolute position the :after below the card. You can set a background-color on the :after to see where your psudo hover state covers.
.card {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
border: 5px solid black;
width: 60px;
height: 100px;
background-color: #F0F0F0;
transition-duration: 0.3s;
transition-property: margin-top, border;
position: relative;
}
.card:hover:after {
content: '';
height: 50px;
position: absolute;
top: 100%;
left: -5px;
right: -5px;
}
.card:hover {
margin-top: 0px;
border: 5px solid #3000A0;
z-index: 0 !important;
transition-duration: 0.3s;
transition-property: margin-top, border;
}
<div class="card"></div>
This question already has answers here:
Keep width when using letter-spacing on hover
(2 answers)
Closed 2 years ago.
i try something when i hover my button. Currenttly that's my code
.btn {
border:solid 1px purple;
color:purple;
background: white;
padding:10px 15px;
text-align: center;
transition: .5s;
}
.btn:hover{
letter-spacing: 1px;
}
<button class="btn">My bouton</button>
The problem is, when i hover my button, the text expand, the button expand too on the right.
I want to make button not expand (keep original size), only text inside expand and centerized, without put a width size, because i want it as component (I would never know the size of the text.)
ALL in css only.
The only one way i've find is to add a data attribute who come over, but i don't like this way because i reapt my text 2 times.
For you it's possible only CSS ? if yes how ? Thanks a lot
Hide the original button text and use it inside the after/before using below CSS rules.
.btn {
border: solid 1px purple;
color: white;
background: white;
padding: 10px 15px;
text-align: center;
position: relative;
}
.btn:hover::after{
letter-spacing: 1px;
}
.btn::after{
content: 'My Button';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
color: purple;
transition: 0.5s;
}
<button class="btn">My bouton</button>
use absolute positioning on the text element and set it relative to the button element
edit:
.btn {
position: relative;
border: solid 1px purple;
color: purple;
background: white;
padding: 10px 15px;
text-align: center;
transition: .5s;
width: 5em;
}
.btn:hover {
letter-spacing: 1px;
}
span {
//position: absolute;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
<button class="btn">
<span>My button</span>
</button>
Most easy solution would be to give the button a width... but you don't want that.
As an alternative, you can play with the padding-left and padding-right.
In normal state, you give it some more padding, on hover state, bring it back to 15px.
Note: changing the text length will affect the width, the padding then needs to be adjusted too...
.btn {
border:solid 1px purple;
color:purple;
background: white;
padding:10px 20px 10px 19px;
text-align: center;
transition: .5s;
}
.btn:hover{
letter-spacing: 1px;
padding-right: 15px;
padding-left: 15px;
}
<button class="btn">My bouton</button>
As long as the button width is determined by the text width you can only try to manipulate the padding so it fits again.
If its no problem to give the button a width depending on its parent or a fixed width you can try this:
.btn {
border:solid 1px purple;
color:purple;
background: white;
padding:10px 15px;
text-align: center;
transition: .5s;
width: 95px;
}
.btn:hover{
letter-spacing: 1px;
}
<button class="btn">My bouton</button>
how can I create a button animation like this using css?
what I want to achieve
I want to display only first letter of button, and when hover it expands and shows rest of letters.
maybe something like:
<button>h<span>ello</span></button>
and css:
button {
width: 40px;
height: 40px;
border-radius: 50%;
}
button span {
display: none: /* maybe hide it first? */
}
but when I change the width it looks like a stretched circle because the radius. Whats the best approach to modify the width but keep the same border radius?
Thanks,
AH.
Firstly, you shouldn't use border-radius of 50%, that would make an oval when the width is larger than its height, you should use a fixed value, such as 30px.
Secondly, you shouldn't fix height and width, you should set the padding, so that the text won't run out of the button.
Thirdly, to change the content, you could use the content property.
In the code, I used :after, which adds "ello" after "H" on :hover.
button {
padding: 15px;
border-radius: 30px;
}
button:hover:after {
content: "ello";
}
<button>H</button>
Instead of using a nested <span>, I recommend using the :after CSS selector, to show the rest of the button's label. You will want to use CSS3 transitions for a smooth hover animation. I combined the :after selector with the transition, and a :hover opacity of 1, so that the button text appears simultaneously as the button expands.
button {
width: 50px;
height: 50px;
border-radius: 10px;
padding:6px;
background-color:black;
color:white;
font-size:1.03em;
box-shadow:3px 3px red;
}
button:hover {
width:100px;
height:50px;
border-radius: 10px;
padding:6px;
background-color:black;
color:white;
transition:all 0.4s ease 0s;
font-size:1.02em;
box-shadow:3px 3px blue;
}
button span {
opacity: 0;
}
button:hover span {
opacity: 1;
transition: all 0.3s ease 0s;
}
button:hover span:after {
content:"ello!";
}
<button>H<span></span></button>
You can define a border-radius value in px, em, or rem. Using % will create an ellipse.
You can avoid additional markup by using the ::first-letter attribute.
Example...
button {
background: black;
color: transparent;
font-size: 3rem;
border: 0;
border-radius: 2.5rem;
width: 5rem;
height: 5rem;
padding: .5rem 1.5rem;
}
button::first-letter {
color: white;
}
button:hover {
width: auto;
color: white;
}
<button>Hello</button>
Simple Use of the :hover tag below /
CSS:
.button {
background-color: pink;
}
.button:hover {
background-color: blue;
}
HTML:
<h3 class="button"> Hello, World! </h3>
I have two buttons, that I was hoping to have side by side, however their right on top of each that I can't figure out why.. here's what i'm looking at.
here's my code.
CSS:
button {
position: absolute;
top: 250px;
left: -15px;
z-index: 9999;
color:white;
display: block;
margin: 30px;
padding: 7px 35px;
font: 300 150% langdon;
background: transparent;
border: 3px solid white;
cursor: pointer;
}
button:hover {
background: black;
border: 1px solid black;
}
button:active {
background: #2e2e2e;
border: 1px solid black;
color: white;
}
Any ideas?
position:absolute removes the elements from the normal document flow. Thus, they will be positioned on top of each other where specified (top: 250px;, left: -15px;) since they share the same position styles.
For your scenario, it would probably be better to use floats and margins:
button {
float:left;
margin-top:250px;
}
In general, position: absolute; should be avoided; you're taking an element out of the standard flow (which means no more side by side or top to bottom reflowing).
If you insist on using it, you need two different positioning rules for your buttons so you can assign them to different places.
Try position:static; I read that it renders elements in order as they appear in the document flow.
I am just getting back into coding and I would like to know what is the best method for adding heigh to my btn.
Here is the code -
Padding method
.nav-main li a {
display: block;
padding: 70px 10px 70px 10px;
color: #6CF784;
border-bottom: 10px solid white;
text-decoration: none;
}
Line-height method
.nav-main li a {
display: block;
padding: 0 10px 0 10px;
line-height: 150px;
color: #6CF784;
border-bottom: 10px solid white;
text-decoration: none;
}
I like to use line-height because it positions the baseline correctly to make the text appear in the middle of the element (whereas with padding it may be off-centre one way or the other based on the font)
Of course, this relies on you using a pixel value for line-height (as you are doing in your question) - using a numeric value like 1.5 may produce different results depending on the font.
I personally use padding as it gives me more control across browsers, as line height can vary on which font you are using, along with what fonts are installed/not installed on the clients' browser.
.link {
text-decoration: none;
color: aqua;
border: 2px solid aqua;
margin: 30px auto;
display: block;
width: 160px;
height: 40px;
line-height: 35px;
text-align: center;
position: relative;
overflow: hidden;
}
.link::before {
content: attr(data-text);
position: absolute;
width: 100%;
top: 0;
left: 0;
transform: translateX(-100%);
transition: 0.5s;
}
You will show the difference between the padding and line height
when you use pseudo element (before and aftere) =>
with line height the pseudo element take the same height of his parent
with padding the pseudo element do not take the height of his parent