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>
Related
I would like to allow my user to click on the card to "cancel it". I can take care of the JS, but I am wondering what's the best way to add a "red opaque overlay" on top of the card after the user clicks it.
So ideally I can write a css class such as but also make it that it's not simply transparent at 40% but also slightly "red". And I don't want to create another dive that wraps the whole card if possible.
.card-deactivated{
opacity:40%
}
.card{
max-width:300px;
min-width:200px;
height: 350;
display: flex;
flex-direction: column;
padding: 0px 0px 20px;
gap: 10px;
background: #FFFFFF;
/* Gray/4px */
box-shadow: 0px 4px 8px rgba(41, 41, 41, 0.08);
border-radius: 10px;
overflow:hidden;
}
.card-img{
order: 0;
display:block;
margin-bottom:2rem;
}
.card-title{
align-self:center;
margin-bottom:1rem;
}
.card-description{
align-self:center;
margin:0px 20px 1rem;
text-align:center;
}
<div class='card'>
<img class='card-img' alt='Card Image' src='data:image/jpeg;base64,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'>
<h3 class='card-title'>Name Surname</h3>
<p class='card-description'>This is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long description </p>
</div>
Edit
I am achieving some sort of result by leveraging this css but I don't think I am doing it "right"...or at least in the best possible way.
.card{
max-width:300px;
min-width:200px;
height: 350;
display: flex;
flex-direction: column;
padding: 0px 0px 20px;
gap: 10px;
background: #FFFFFF;
/* Gray/4px */
box-shadow: 0px 4px 8px rgba(41, 41, 41, 0.08);
border-radius: 10px;
overflow:hidden;
position:relative;
}
.overlay-selected::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: .3;
background-image: linear-gradient(90deg, #eaee44, #eaee44);
}
You can achieve this by using one of the pseudo-elements, either ::before or ::after, that will act as an overlay when the user clicks on the .card element.
Basically, we'll initially style that overlay, we'll use the ::after pseudo-element, and place it behind the .card element using z-index of -1 so that the overlay is hidden initially. When a click occurs, we add a class, let's call it is-canceled, to the .card element that simply sets the z-index of the overlay to a higher value (like 2 or 999) so that the overlay appears on top of the .card element and act as the intended overlay.
To make the overlay transition smoothly, we'll initially set its background-color to transparent and override that when the is-canceled class is attached to the .card element. When the is-canceled class is attached to the .card element, we'll set the background-color to a reddish background (something like rgba(255, 0, 0, .7). Using the transition property we can instruct the browser to have a smooth transition when the is-canceled is added/removed from the .card element.
To illustrate, here's alive demo that allows you to toggle the overlay when you click on the .card element:
const card = document.querySelector('.card');
card.addEventListener('click', () => card.classList.toggle('is-canceled'));
.card {
position: relative; /* required to correctly position the overlay */
max-width: 300px;
min-width: 200px;
display: flex;
flex-direction: column;
padding: 0px 0px 20px;
gap: 10px;
box-shadow: 0px 4px 8px rgba(41, 41, 41, 0.08);
border-radius: 10px;
overflow: hidden;
}
/* initial overlay styles */
.card::after {
content: "";
position: absolute;
width: 100%;
height: 100%;
inset: 0;
background-color: transparent;
transition: all .4s 0s ease;
z-index: -1;
}
/* styles to be applied to the overlay when the "is-canceled" class is added */
.card.is-canceled::after {
background-color: rgba(255, 0, 0, .7);
z-index: 999;
}
.card-img {
order: 0;
display: block;
margin-bottom: 2rem;
}
.card-title {
align-self: center;
margin-bottom: 1rem;
}
.card-description {
align-self: center;
margin: 0px 20px 1rem;
text-align: center;
}
<div class="card">
<img class="card-img" alt="Card Image" src="https://via.placeholder.com/250">
<h3 class="card-title">Name Surname</h3>
<p class="card-description">This is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long descriptionThis is a long description </p>
</div>
The above demo is just for demonstration purposes and you're invited to build upon it and customize it the way you see fit.
I have a styled checkbox that is the child of a container along with some text. The reason the checkbox and text are children of a parent is so that they can sit next to each other and be centered vertically on the UI. This has worked fine for me; however, I've noticed that the checkbox starts to change from a perfect circle into more of an oval as text starts to wrap into multiple lines (on mobile the text is two lines long and on desktop it is only one line). How could I fix this so that the checkbox does not stretch as the text wraps into multiple lines? Below is my html and styling, thank you.
.opt-in {
display: flex;
align-items: center;
color: #f4a11e;
}
input[type='checkbox'] {
position: relative;
margin: 17px 15px 0 0;
cursor: pointer;
width: 20px;
height: 20px;
-webkit-appearance: none;
background: transparent;
border: 1px solid #f4a11e;
outline: none;
border-radius: 50%;
transition: 0.5s;
}
input[type='checkbox']:before {
content: '';
position: absolute;
top: 45%;
left: 50%;
width: 4px;
height: 10px;
opacity: 0;
border-right: 1px solid #f4a11e;
border-bottom: 1px solid #f4a11e;
transform: translate(-50%, -50%) rotateZ(40deg);
transition: 0.2s;
}
input:checked[type='checkbox']:before {
opacity: 1;
}
<div class="opt-in">
<input type="checkbox" v-model="optIn" id="checkbox" />
<label for="checkbox">Opt-in to receive the latest cloud insights and industry deep dives.</label>
</div>
In the CSS code in the input[type='checkbox'] {} section, try using min-width: 20px; rather than width: 20px;.
Worked for me in a test implementation with copy/pasted code although I had to set max-width in the properties of the opt-in div to test it.
I don't have a technical explanation but I believe it has something to do with the relative position or the display: flex overriding the specified width/height in pixels.
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>
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;
}
I'm new to flexbox and trying to make a menu using it.
I want links to have a nice border on the bottom when user hovers on them. But even if I set box-sizing: border-box; flex keeps recalculating text position and element 'jumps' instead of predicted behaviour.
I have an example with the problem. I don't want content inside my element to jump when I hover.
Is there any simple solution/edition to my code to make it work as expected? I know other ways of achieving what I want: set baseline, use relative/absolute positioning...
.item {
display: flex;
width: 200px;
height: 100px;
background: #123;
color: #fff;
text-align: center;
justify-content: center;
flex-direction: column;
}
.item:hover {
border-bottom: 10px solid lightgreen;
box-sizing: border-box;
}
<div class="item">
Content
</div>
By adding a 10px border on hover, you are changing the size of the box on hover. That will reposition surrounding elements... on hover.
One solution is to reserve the space for the border at all times. In other words, have the 10px border factored into the element in a normal state.
This border gets the element's background color (or transparent) so it is not visible. On hover, you only change the color.
.item {
display: flex;
width: 200px;
height: 100px;
background: #123;
color: #fff;
text-align: center;
justify-content: center;
flex-direction: column;
position: relative;
}
.item::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
border-bottom: 10px solid #123;
}
.item:hover::after {
border-bottom: 10px solid lightgreen;
}
<div class="item">Content</div>
I would use an inset box-shadow for this feature.
I managed to recreate the effect by changing the :hover css to:
.item:hover {
box-shadow: inset 0 -10px lightgreen;
}
example here
What if you just set a bottom border by default using the same colour which is on its background? Once you hover over your item, you will need just to change the colour.