crossfading div backgrounds on :hover - possible in CSS? - css

Is there a way to smooth the transition during a div background change? Ideally I'd like to do this within the css, and not use any js.
In my css I have:
.examplediv {
background: url(img_img.png);
}
.examplediv:hover{
background: url(brighter_img.png);
}
It's doing what I'd like it to do (changing pictures), but if there was a way to make the two backgrounds "dissolve" into one another, I'd start frothing at the mouth with gratitude.
Note: The effect I'm going for is essentially an opacity change, so if it's easier to code a dissolve with :opacity, I'm all ears!
Tanks!~

It's definitely possible using just CSS. See this Fiddle for an example: https://jsfiddle.net/ffqdmcws/
HTML:
<div class="crossfade">
<div class="static"></div>
<div class="hover"></div>
</div>
CSS:
.crossfade {
position: relative;
width: 300px;
height: 200px;
}
.static, .hover {
position: absolute;
width: 100%;
height: 100%;
transition: opacity 1s ease;
}
.static {
background: url('http://lorempixel.com/300/200/food');
opacity: 1;
}
.hover {
background: url('http://lorempixel.com/300/200/cats');
opacity: 0;
}
.crossfade:hover > .static {
opacity: 0;
}
.crossfade:hover > .hover {
opacity: 1;
}
In this case I've got a container div using the crossfade class, and a couple of other divs inside that, using classes static and hover.
The static class contains the background to be shown initially, and the hover class contains the background to fade to on hover. The initial opacities are 1 for the static class and 0 for the hover class, so you only see the div with class static.
Then, if you hook up the hover action on the container div using .crossfade:hover, in order to set opacity: 0; for static and opacity: 1; for hover, that hides static and shows hover, when you hover over the container div.
Finally, to make the backgrounds overlap use absolute positioning of the two internal divs, so they're on top of each other at all times. Additionally, for the true crossfade effect you need the transition: opacity 1s ease; rule, which says you want the opacity to transition over a period of 1 second instead of switching instantly. Both the divs changing opacity from 1->0 and from 0->1 give you the crossfade effect of the background images.

You can do it with pseudo elements which are absolutely positioned. One is visible by default and another one on hover.
.examplediv {
height: 600px;
position: relative;
}
.examplediv:before, .examplediv:after {
content: '';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: -1;
transition: opacity 0.5s ease-out;
}
.examplediv:before {
background: url(https://pixabay.com/static/uploads/photo/2015/07/19/17/38/flower-851725_960_720.jpg)
}
.examplediv:after {
background: url(https://pixabay.com/static/uploads/photo/2015/12/07/23/56/pink-flower-1081646_960_720.jpg);
opacity: 0;
}
.examplediv:hover:before {
opacity: 0;
}
.examplediv:hover:after {
opacity: 1;
}
<div class="examplediv">
</div>
JSFIDDLE

Related

CSS: Show an element only when you hover over it

The following hides the element, but I cannot recover when I hover over it.
I've checked devtools to see that it is indeed rendered on the screen, I just can't see the contents of the div.
How do I make it so the div is visible only on hover?
.visible-on-hover {
visibility: hidden;
}
.visible-on-hover:hover {
visibility: visible !important;
}
Elements with visibility: hidden; don't receive any mouse events, so :hover never triggers on such an element.
Instead of visibility, you can work with opacity:
div {
background-color: orange;
height: 200px;
width: 400px;
padding: 50px;
}
.visible-on-hover {
opacity: 0;
transition: opacity .3s ease;
}
.visible-on-hover:hover {
opacity: 1;
}
<div class="visible-on-hover">visible only on hover</div>
you can not hover, focus or select a hidden element.
you can use opacity
.visible-on-hover {
opacity: 0;
}
.visible-on-hover:hover {
opacity: 1;
}

Change Colour Opacity When Dont know RGB values only Alpha

I am attempting to change a buttons colour to 50% opacity when hovered over. This is simple enough when I know what the colour is but it will change at runtime.
Any ideas how I can do this with CSS3? I know I could do this easily with LESS but its not available to me.
.my-btn {
background-color: rgba(255,0,0,1); /* Will change at run time to anything */
}
.my-btn:hover {
background-color: rgba(?,?,?,0.5); /* I dont know what the rgb values will be */
}
Problem
Using the opacity property on the button itself would affect the text of the button; not ideal.
Solution
Apply the background color to a pseudo-element instead and layer it underneath the text with negative z-index. When needed, use the opacity property on the pseudo-element to create your transparent background.
Example
Note: Pseudo-elements cannot be applied to the <input> element as it cannot have children. This will only work with elements that can have children, such as <button> and <a>.
button {
position: relative;
background: none;
border: solid 1px #EEE;
padding: 10px;
border-radius: 5px;
overflow: hidden;
}
button:before {
content: '';
position: absolute;
top: -1px;
right: -1px;
bottom: -1px;
left: -1px;
background: red;
z-index: -1;
opacity: .5;
}
button:hover:before {
opacity: .8;
}
button:active:before {
background: orange;
}
<button>Button</button>
It's a bit tricky because using a combination of a rgb background color and opacity sounds like it will work but the opacity will apply to everything inside the element - including the text. there are a number of ways of getting around this though so use a solution that will work for your situation.
Essentially you've got to separate the background element from the rest of the button so that only the background color gets effected by the opacity change on hover.
.my-btn:hover a {
background-color: rgb(255,0,0);
opacity:.5;
}
<div class="my-btn">
<span aria-hidden="true">whatever</span>
<span class="sr-only">whatever</span>
</div>
Here's a demo
Use the opacity attribute:
.my-btn:hover {
opacity: 0;
}
.my-btn:hover {
opacity: 0;
}
<input class="my-btn" type="submit"></input>

Jagged "border" showing due to background colour on wrapper element with border-radius: 50%;

As I was in the process of trying to make an animated figure (transitions on hover), I found out that the background of my <figure> is showing near the edges when I apply border-radius: 50% to it, even though my image should be taking up all available space.
For a quick demo that illustrates the problem, please look at http://codepen.io/anon/pen/KwMMKz
HTML
<figure>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
CSS
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover img {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}
Please note: I know that placing the background-color on figure:hover is a work-around, but I am more interested in the reason why this "jagged border"-like look is appearing.
My guess is that it has to do with AA rendering (or something related) of the browser and that it treats the <figure> element differently than a media element such as <img>, but I can't find any proof of this online. Is this a bug, is it a "feature", or is it something I can actually fix?
Lastly, I also know that I could have used transform: translateY(); here for the animation, but that's not part of my question so please don't provide it as an answer.
UPDATE 17/12 14:03
It appears that this issue is not exclusive to border-radius: 50%. The issue can occur when any wrapping element uses border-radius in combination with overflow: hidden, when the wrapper contains content that is equal or bigger than the wrapper's dimensions.
UPDATE 17/12 14:14
Neither the usage of overflow: hidden on the wrapper element, nor the usage of border-radius on the contained image (or any other child element) seem to be the cause of this as they can be interchanged and the pixelated edge will still appear.
This seems to indicate that this issue is solely caused by 2 DOM elements being in exactly the same place, when any sort of border-radius is applied to the wrapper element and the visible area of the child is limited to that of the parent's.
I've been having same issue and ended up using pseudo element instead of background, kinda like that:
figure::before {
content: '';
display: block;
background-color: red;
width: 400px;
height: 400px;
transform: scale(0.997);
border-radius: 50%;
}
This allowed me to create 'pseudo background' which I later shrinked a little bit with transform: scale(0.997); so it will be just the same size but a bit below visible edge. Of course in your case you would also need to position image absolutely so it is not pushed below by this ::before.
It appears that it is indeed a "feature" of how the browser handles border-radius to give a smooth edge to the rounded corners of a container. The image background is anti-aliased in the same way (but as it is transparent has no effect) as can be seen by setting the img background color.
When the border is anti-aliased it "bleeds" into the background to soften the edges and so you are seeing that around the image as a "jaggy" ring in much the same way you would see a corona around the moon during a full solar eclipse.
the issue is always there, whether the anti-aliased object is covered or not, if you were to draw a circle then anti-alias it, you would see the circle is marginally narrower than the anti-aliased version. Most anti-aliasing algorithms aggregate the surrounding pixels of the object rather than those contained within it.
To overcome it, you'd either need to make your image large enough to cover the space taken up by the anti-aliased edge or reduce the container such that the anti-aliased area is smaller than the image.
You could add a new tag with an opacity of 0 then have that fade in with the image fading out.
figure {
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
background {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
opacity: 0;
position: fixed;
z-index: 5;
transition: opacity 1s ease-out;
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
position: relative;
z-index: 100;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
z-index: 10000;
}
figure:hover img {
opacity: 0;
}
figure:hover background {
opacity: 1;
}
figure:hover figcaption {
top: 50%;
}
<figure>
<background></background>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
Notice I added the background tag and removed background-color from figure
http://codepen.io/marczking/pen/KwMgaR
So after playing around (used background-image and pseudo-elements, changes nothing...) you notice that this light border is only visible if you apply round corners. So I am assuming here it has to do how the Browser renders the CSS, nothing wrong with the CSS-rules ^^)
<figure>
<figcaption>Demo</figcaption>
</figure>
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 100px;
position: relative; /* For caption */
}
figure::before {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: url("http://placehold.it/400x400") no-repeat;
border-radius: 100px; /* Forced on image for smooth transition */
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover::before {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}

Change background from bottom to top on hover

How I can change the background-color on a:hover using a transition from the bottom to the top with a duration of 0.3s?
<ul>
<li><a></a></li>
<li><a></a></li>
<li><a></a></li>
</ul>
Is that possible?
Thanks
There is no way to (generically) apply a transition direction in CSS. However, we can work around that limitation by using a pseudo element (or other method like how this example uses gradients).
By using a pseudo element, which initially has a visible height of 0, we can transition the height from and to a desired direction when the link is hovered. It's best to use transform: scale for performance reasons, which means that we need to set our transform-origin to bottom center in this case to make sure it goes from bottom to top.
This approach is probably the most general, working with non-solid backgrounds and such, but does require a pseudo element or child element.
The CSS for that approach would be:
li {
background: red;
}
a {
position: relative;
z-index: 1;
}
a::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
transform: scaleY(0);
transform-origin: bottom center;
background: blue;
z-index: -1;
transition: transform 0.3s;
}
a:hover::after {
transform: scaleY(1);
}
Demo

Css Transition on hover for child element

Im trying to pause the display of a child element when it's parent is hovered over.
Html:
<span>
<div>This Is The Child</div>
Some Text in the span
</span>
Css:
span {
position: relative;
}
span div {
display: none;
width: 0px;
opacity: 0;
transition: width 5s;
-webkit-transition: width 5s;
transition: opacity 5s;
-webkit-transition: opacity 5s;
}
span:hover div {
display: inline-block;
width: 150px;
opacity: 1;
}​
As of right now, when the span is hovered, the div has no delay before it is shown. How would I go about fixing it so there is a pause?
Fiddle here: http://jsfiddle.net/SReject/vmvdK/
A few notes:
I originally tried to transition the display, but as Edward pointed out, that isn't possible, and have sense tried the above which, also, isn't working
SOLVED
It would appear that any "display" property in the "transition to" styling will stop any transition animations from happening. To work around this. I set the width of the child to be displayed to 0px and have it be completely transparent. Then in the "transition to" styling, I set the correct width, and make the div solid:
Html:
<span>
<div>This Is The Child</div>
Some Text in the span
</span>
Css:
span {
position: relative;
}
span div {
position: absolute;
width: 0px;
opacity: 0;
transition: opacity 5s;
-webkit-transition: opacity 5s;
}
span:hover div {
width: 150px;
opacity: 1;
}​
Fiddle here: http://jsfiddle.net/SReject/vmvdK/
According to this article on CSS transitions, which is referenced by the MDN page on CSS transitions, the display property is not one that can be transitioned:
There are several properties or values you’ll want to transition, but which are both unspecced and unsupported at the time of writing:
background-image, including gradients
...
display between none and anything else
So applying the transition: display 5s; property to your div has no effect.
EDIT:
Based on your updated code, you can achieve the effect you want with opacity and width as long as you don't specify the display property. Simply remove the line
display: none;
from the span div section, and the pop-up menu will use the transitions you specified when you hover over it.
Since the transition from display:none; to display:inline-block can't be animated, this property is probably changed only at the end of the transition - so the opacity animates while the div is still invisible.
Have you tried using -webkit-transition-delay: ;? If not, this might be something you are looking for?
Did some changes in the code:
span div {
position: absolute;
left: 5px;
top: 5px;
border: 1px solid #000;
background-color: #888;
width: 0px;
opacity: 0;
cursor: pointer;
}
span:hover div {
display: inline-block;
-webkit-transition-delay: 2s;
width: 150px;
opacity: 1;
}​
And here's a demo

Resources