CSS image and pseudo element transition out-of-sync - html

I'm trying to create a transition for both an image and a pseudo element of its container, but for some reason, these transitions appear to be out of sync with each other, resulting in the pseudo element reaching a opacity: 0 state before the image does.
I've tried various combinations of style rules, but I never managed to accomplish an ease-in-out transition to work correctly.
Here's some context for the current code: the image is padded on purpose, to provide a better visual (centered) of its content. The images that'll be used are always guaranteed to have a white background. That's why I'm using a pseudo-element with a white background color to fill the vertical spaces that the image does not cover.
The background-image should take the full width/height of the container and there are not guarantees of its background being white.
The desired effect is for both the pseudo-element and image to reach opacity: 0 at the same making it look like its a single element.
I'm also considering using an ::after pseudo element to provide a "loading skeleton" while the image is not retrieved from the server, but that's not a concern for now.
Here's the code, and the respective fiddle: https://jsfiddle.net/rjk2z31d/1/
*,
*::before,
*::after {
box-sizing: border-box;
}
.box {
width: 248px;
height: 320px;
}
.image-box {
position: relative;
display: block;
background-repeat: no-repeat;
background-size: cover;
line-height: 0;
background-color: #FFFFFF;
&::before {
display: block;
content: "";
width: 100%;
padding-top: (100% + (100% / 3));
}
img {
z-index: 1;
position: absolute;
top: 50%;
left: 0;
width: 100%;
transform: translate3d(0, -50%, 0);
padding: 16px 16px;
}
&::before, img {
background-color: #FFFFFF;
opacity: 1;
transition: all 1.5s ease-in-out;
}
&:hover {
&::before, img {
opacity: 0;
}
}
}
<div class="box">
<div class="image-box" style="background-image: url('https://via.placeholder.com/248x320/FF0000/000000?text=Background')">
<img src="https://via.placeholder.com/248x320/FFFFFF/000000?text=Image">
</div>
</div>

Actually, they both fade at the same speed.
The out-of-sync effect you're talking about is an illusion due to the opacities overlapping.
If you set the initial opacity of both elements, it's easier to understand what's going on.
The image's faded white added to the pseudo element's faded white looks less transparent than the pseudo element's faded white alone.
See it in effect with the below image:
If you need to be convinced of their synchronization, add a transform rule to the :hover handler. the result is synced as it is supposed to be.
As a workaround, I would suggest you to try figuring out a better approach than fading overlapping elements.
You could use the <picture> tag with css object-fit property to get rid of those blank spaces.
picture doc
object-fit doc

Related

Background overlay on hover

Is it possible to have markup like this but also background overlay on hover?
<figure class="gallery-item">
<div class="gallery-icon landscape">
<a href="www.google.com">
<img src="http://placehold.it/300x300" />
</a>
</div>
</figure>
I tried placing background-color: #333 on .gallery-icon on hover, but only something like border-bottom appears?
http://codepen.io/filaret/pen/NRpVyr
You are definitely on the right track. Since you are using an :after element for the icon, you should leave that element alone since it's already positioned and defining its own width+height (based off the icon).
The reason the :after selector positions itself correctly is because it's not relying on its parent containers dimensions. You only have it as absolute from the top and left, which is fine. But it doesn't know about how tall it should be, because its parent has no defined height! If you use absolute positioning, you need to define the parent containers dimensions so that the child knows where its bounds are.
So first off, .gallery-icon is already a block element, so you don't need to define its width (its already 100% by nature), just the height:
.gallery-icon {
position: relative;
height: 100%;
}
Second, you should use a :before element to define a background, so that you don't have to mess with the :after icon:
&:before {
content: '';
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
background-color: #333;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
Now, you just have to add the opacity change on hover!
&:hover {
.gallery-icon {
&:before {
opacity: .5;
}
&:after {
opacity: 0.6;
}
}
Hope that helps, here is a codepen forked off your original: http://codepen.io/anon/pen/JRWqxX
Edit: I also noticed that your img tag is causing it to go below the visual bottom of the container, a quick fix is just to add:
.gallery-icon {
img {
display: block;
}
You need to understand your markup works. Your image will be displayed on top of everything, and when you put a background colour on .gallery-icon that background colour will be under the image, and since the anchor link doesn't has a width and height, it only take a little bit of portion, that's why it showing a border bottom.
To create a background overlay on hover, you need to position it to be on top of the image.
Using pseudo element to create a background overlay:
&:hover .gallery-icon {
&::before {
content: '';
background-color: #333;
display: block;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
opacity: 0.2;
}
}
The pseudo element has a position absolute so it will displayed on top of the image. top, left, right and bottom 0 to tell the pseudo element to stretch it self as tall and as wide as the parent element.
Hope this helps.
I've tried to simplify the code a little bit. I hope it's what you've tried to achieve.
The trick is to place a as a independent element to img.
<figure class="gallery-item">
<img src="http://placehold.it/300x300">
</figure>
http://codepen.io/anon/pen/LRWoaR
The image (http://placehold.it/300x300) has a solid background colour, no?
That will block anything happening behind itself.

how to change only one item in a class

I just want the background image's opacity to be changed. Not the whole items like p.
css:
#home{
background-image: url('../img/main.jpg');
background-position: center;
background-size: cover;
background-repeat: no-repeat;
position: relative;
height:100%;
opacity: .8;
}
html:
<section id="home">
<p>hi</p>
<p>hi</p>
<p>hi</p>
<p>hi</p>
<p>hi</p>
</section>
The rule opacity is for the element. Not for the background. If you need to do that way, you have two options:
Fake the background by using another div and use opacity on it.
Use two different images with one having lesser opacity.
There are a lot of hacks available:
CSS Opacity on Child Element
Using :after and styling it.
while there isnt any way to change the background opacity directly, there is hacky way of doing it.
div {
width: 200px;
height: 200px;
display: block;
position: relative;
}
div::after {
content: "";
background: url(image.jpg);
opacity: 0.5;
top: 0;
left: 0;
bottom: 0;
right: 0;
position: absolute;
z-index: -1;
}
taken from here
I don't think there's any property for CSS background transparency.
What you could do is create a child element that fills the space, and apply the background and transparency to that element.
If you want to pure CSS solution, you can create the child element using the :before pseudo selector with an empty content field.
If you're only wanting to change the opacity of a background image, it may be easier to actually save the image with a lower opacity, to avoid writing extra markup.
However, there are hacky work arounds that involve moving the 'child' elements over the top of the background using absolute positioning - there's a really useful article here.

Div Backgrounds That Overlap At The Corner

There are several separate background images, displayed top to bottom. Is it possible to make them overlap slightly and clip a transparent triangular area in the bottom-right corner revealing the image below?
Is this possible with CSS?
Here is the desired look:
Yes, this is very possible with CSS.
Here is a technique using a rotated div and :before pseudo element. This looks like a long explanation, but the basic principal is pretty straight forward once you start poking around.
Compatibility: IE9 + and all modern browsers — The transform property in IE9 requires the -ms- prefix and Safari requires the -webkit- prefix. They should be placed before the unprefixed property.
The wrapper
The wrapper is used to clip the slanted corners of each div.
Provide a suitable max and min width
Clip its children with overflow: hidden
The div
The div is used to create the slant by clipping its childrens bottom right corner.
Rotate with transform: rotate()
Clip its children with overflow: hidden
Blow the width out with width: 200% so that the corners are clipped by the wrapper
Move every div (except the first div) up with a negative margin
Change the z-order with z-index so that each div is overlapped by the div before it
The :before pseudo element
The :before provides the actual background image without any extra markup.
Counter the div parents rotation by the same number of degrees
Provide the background image
Shift as needed with transform-origin
The straight edge is provided by the bottom edge of the image and the corner is cut off by the parent. The image must be quite large to overlap the width of its parent.
Full Example
Example with prefixes.
.wrap {
margin: 0 auto;
max-width: 1000px;
min-width: 660px;
overflow: hidden;
background: #EEE;
}
.wrap > div {
transform: rotate(-15deg);
height: 700px;
width: 200%;
overflow: hidden;
transform-origin: 0 90%;
position: relative;
z-index: 10;
}
.wrap > div:before {
content: '';
display: block;
width: 100%;
height: 100%;
background: url(http://lorempixel.com/output/food-q-c-1500-1000-2.jpg) no-repeat;
transform: rotate(15deg);
position: absolute;
transform-origin: 30% 0;
}
.wrap > div:nth-child(n+2) {
margin-top: -140px;
}
.wrap > div:nth-child(2):before {
background-image: url(http://lorempixel.com/output/people-q-c-1500-1000-10.jpg);
}
.wrap > div:nth-child(3):before {
background-image: url(http://lorempixel.com/output/technics-q-c-1500-1000-3.jpg);
}
.wrap > div:nth-child(2) {
z-index: 9;
}
.wrap > div:nth-child(3) {
z-index: 8;
}
<div class="wrap">
<div></div>
<div></div>
<div></div>
</div>

CSS image hover pushes other elements in the page?

When the image grows in hover to 350px it pushes everything around.
This code is working except that when I hover and the picture grows it pushes the menu or what ever is around downwards.
How can I stop this?
#displaycar img
{
height: 200px;
}
#displaycar img:hover
{
height: 350px;
}
BTW I'm using twitter bootstrap and I have tried position: absolute;.
Is there any way to still increase size when hover but don't push nothing don't move nothing.
Set the height of #displaycar (the presumed parent div) to 200px and add overflow: visible;
#displaycar {
height: 200px;
overflow: visible;
}
I would use z-index on the elements. keep the values equal on the initial layout, but make it a stronger (bring to front) value when hovering
#displaycar img:hover
{
z-index:[stronger value];
height: 350px;
position :[relative, absolute, fixed];
}
note: to use z-index, you have to use one of the position values
Z-index gives priority to overlapping elements (bring to front / bring to back)
here is a bit more info on the subject
It's possible, but to avoid affecting surrounding content the element itself has to be removed from the flow of the document; this is easiest to achieve using position: absolute, though unfortunately this requires using a wrapping element, with position: relative (or any other non-static position value). The wrapping element has to have a width and height defined, which could be done automatically (with JavaScript, or PHP (amongst many other options)).
For example, the HTML:
<span>
<img src="http://placekitten.com/400/400/" />
</span>
<p><!-- generic dummy content, excised for brevity --></p>
And the CSS:
span {
display: inline-block;
position: relative;
width: 150px;
height: 150px;
}
span img {
position: absolute;
top: 0;
left: 0;
height: 150px;
width: 150px;
/* Vendor-prefixes removed, for brevity */
transition: all 1s linear;
}
span:hover img {
width: 400px;
height: 400px;
/* Vendor-prefixes removed, for brevity */
transition: all 1s linear;
}
JS Fiddle demo.

Is there a foreground equivalent to background-image in css?

I want to add some shine to an element on webpage. I would prefer if I don't have to add additional html to the page. I want the image to appear in front of the element rather than behind. What's the best way to do this?
To achieve a "foreground image" (without extra HTML code), you can use a pseudo-element (::before / :before) plus the CSS pointer-events. The last property is needed so that the user can actually click through the layer "as if it did not exist".
Here's an example (using a colour whose alpha channel is 50% so that you can see that the real elements can actually be focused). http://jsfiddle.net/JxNdT/
#cont {
width: 200px;
height: 200px;
border: 1px solid #aaa;
/*To show the boundaries of the element*/
}
#cont:before {
position: absolute;
content: '';
background: rgba(0, 0, 0, 0.5);
width: 200px;
height: 200px;
pointer-events: none;
}
<div id="cont">
Test<br>
<input type="text" placeholder="edit">
</div>
​
PS. I picked the ::before pseudo-element, because that naturally leads to the correct positioning. If I pick ::after, then I have to add position:relative; to the real element (#cont), and top:0;left:0; to the pseudo-element (::after).
PPS. To get the foreground effect on elements without a fixed size, an additional element is needed. This wrapper element requires the position:relative;display:inline-block; styles. Set the width and height of the pseudo-element to 100%, and the pseudo-element will stretch to the width and height of the wrapper element. Demo: http://jsfiddle.net/JxNdT/1/.
If you need a white-transparent foreground
This is for future visitors like me who are considering adding a white-transparent foreground to an element to communicate that it's hidden / disabled for instance. You can often achieve your goal by simply lowering the opacity below 1:
.is-hidden {
opacity: 0.5;
}
visible
<span class="is-hidden">hidden</span>
visible
You can use this css
#yourImage
{
z-index: 1;
}
NOTE
Set the z-index to index greater the the z-index of the element over which you are putting the image.
If you have not specified any z-index then 1 would do the work.
You can also set z-index to -1,in that case the image would always be at background!
A neat solution: box-sizing + padding-left, see more at css-tricks
Somewhere in your HTML:
<img id="test_replacement" src="test.png" alt="test" />
The CSS for replacing the image (on hovering)
#test_replacement {
width: 200px; //must be the size of your image (and the replacement one)
height: 200px; //idem
display: block;
}
#test_replacement:hover {
box-sizing: border-box;
background-image: url('somewhere/other_image.png');
padding-left: 200px; //at least the size of the width
}
Use an absolutely positioned <img> element:
img {
position: absolute;
opacity: 0.3;
pointer-events: none;
}
iframe {
width: 500px;
height: 300px;
border: 0;
}
<img src="https://i.stack.imgur.com/rET57.jpg" alt="Foreground image">
<iframe src="https://example.com/"></iframe>