Safari Only CSS Hover Event Not Triggered on Drag - css

There seems to be something wrong with Safari registering the hover event with css. If you run the snippet below and drag the cursor from blue to green, two things should happen. On all browsers, the green div will turn red on hover. On non-Safari browsers (firefox and chrome, both latest), when dragging from blue to green, the green div will turn red when the cursor enters. On Safari (also latest), the green div does not turn red when the cursor is dragged from the blue div to the green div. It seems to be a problem with recognizing the hover when the mouse was already down. I have tried many different variations and other solutions, but they do not work (setting other css properties to make it repaint and so on). Can anyone explain this strange behavior and how to work around / fix it?
div {
position: fixed;
color: white;
-webkit-user-select: none;
user-select: none;
}
div.blue {
top: 0;
left: 0;
width: 50%;
height: 100%;
background-color: blue;
}
div.green {
top: 0;
left: 50%;
width: 50%;
height: 100%;
background-color: green;
}
.green:hover {
background-color: red !important;
}
<div class="blue">CLICK HERE</div>
<div class="green">AND DRAG HERE</div>

I discovered after much more searching that I have to use javascript mouse enter and mouse leave events to change the color. Safari hover seems to be purposefully made to not recognize a drag over as a hover.
document.getElementsByTagName('div')[1].onmouseenter = () => {
document.getElementsByTagName('div')[1].classList.add('hover')
}
document.getElementsByTagName('div')[1].onmouseleave = () => {
document.getElementsByTagName('div')[1].classList.remove('hover')
}
div {
position: fixed;
color: white;
-webkit-user-select: none;
user-select: none;
}
div.blue {
top: 0;
left: 0;
width: 50%;
height: 100%;
background-color: blue;
}
div.green {
top: 0;
left: 50%;
width: 50%;
height: 100%;
background-color: green;
}
.green:hover, .green.hover {
background-color: red !important;
}
<div class="blue">CLICK HERE</div>
<div class="green">AND DRAG HERE</div>

Related

Why is ::before pseudo element appearing on top of the element?

From my understanding, ::before should appear below the element, and ::after should appear above of the element (in terms of z-index).
In the following example I am trying to make just the background color darker (not the foreground color) when one hovers over the button. Even though I used ::before it still appears in front. Why? I know I could fix it with z-index, but according to this comment which has 6 upvotes:
I think it's better to use :before so you get the right stacking order without playing with z-index.
I should not have to, and the order should be correct?
.parent {
--my-color: red;
}
button {
color: blue;
background-color: var(--my-color);
padding: 8px 16px;
position: relative;
}
button:hover {
background-color: transparent;
}
button:hover::before {
display: block;
content: "";
position: absolute;
top: 0; left: 0; width: 50%; height: 100%; /* width is 50% for debugging (can see whats below) */
background-color: var(--my-color);
filter: brightness(80%);
}
<div class="parent">
<button type="button">CLICK ME</button>
</div>
There's no difference between ::before and ::after regarding the z-index or z-axis order. By default both will be placed in front of their parent, covering it (if their position is defined accordingly). To achieve z-axis layering beyond that, you need to actually use a z-index (besides a combination of relative and absolute position).
Addition after comment:
In the snippet below there are two variations of the situation. The only difference if that once ::after is used, once ::before, both times without a z-index, and both time with the same result, i.e. the pseudo element covering its parent:
.parent {
--my-color: red;
}
button {
color: blue;
background-color: var(--my-color);
padding: 8px 16px;
position: relative;
}
button:hover {
background-color: transparent;
}
.parent:nth-child(1) button:hover::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: var(--my-color);
filter: brightness(80%);
}
.parent:nth-child(2) button:hover::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: var(--my-color);
filter: brightness(80%);
}
<div class="parent">
<button type="button">CLICK ME</button>
</div>
<div class="parent">
<button type="button">CLICK ME</button>
</div>
So, to come back to your question in your second comment: Yes, they are wrong - you need to use a z-index to move the pseudo element behind the parent.
So your actual solution should look like this, using a negative z-index: -1; for the pseudo element (and you could as well use ::after here, it doesn't matter...).
.parent {
--my-color: red;
}
button {
color: blue;
background-color: var(--my-color);
padding: 8px 16px;
position: relative;
}
button:hover {
background-color: transparent;
}
button:hover::before {
content: '';
position: absolute;
z-index: -1;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: var(--my-color);
filter: brightness(80%);
}
<div class="parent">
<button type="button">CLICK ME</button>
</div>

CSS animation for hover effect flickers, not properly showing in FF

thanks for reading and offering help.
I assume my CSS code shouldn't be too complicated, however, it does not behave the way I want.
Expected result: when hovering over the button, there is a background area "folding up" (no background color to dark background color).
Actual results:
Works in Chrome (Version 88.0.4324.146), however, there is a flicker to it, like it is rebuilding again and again. This happens especially when hovering coming from the top. Looks alright when doing it from the bottom and rather slow.
I also saw that it seems to not really work in FF (Dev Edition 86.0b9). Sometimes it pops up, but if it does, it only does so once. Refreshing the browser window is not helping either.
I already tried to have a <div> around it and apply the hover animation to it, to fix it with prefixes... so far I couldn't make it work (smoothly), the issue always persisted.
So, this is the code now, which can also be found in this codepen example
html:
<button class="btn">
click
</button>
CSS:
.btn {
height: 48px;
width: 200px;
text-align: center;
text-transform: uppercase;
border: none;
border-bottom: 1px solid steelblue;
position: relative;
color: steelblue;
background: transparent;
::before {
bottom: 0;
content: "";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
right: 0;
z-index: -1;
}
&:hover,
&:focus {
animation: one 0.25s linear;
background-color: steelblue;
color: whitesmoke;
opacity: 1;
transform-origin: 50% 100%;
}
#keyframes one {
0% {
transform: perspective(1000px) rotateX(90deg);
}
100% {
transform: perspective(1000px) rotateX(0);
}
}
}
If this is a duplicate, it means I didn't find the helping answer yet, will be happy for any solutions and hints.
The problem also happens in Chrome. It happens because you are changing the perspective of the button, which will change its "bounding box".
So when you mouse over the bounding box the animation will change the bounding box, and then the mouse is not over the bounding box, so the animation stops, but then the mouse is over the bounding box again, so the animation starts, and so on.
To fix this, create a container around the button, and make the countainer change the button perspective, instead of the button changing the perspective itself. The container will retain its bounding box when yo do this:
.bcg {
display: flex;
justify-content: center;
align-items: center;
background: whitesmoke;
height: 100vh;
}
.btncontainer {
display: inline-block;
}
.btncontainer:hover .btn, .btncontainer:focus .btn {
animation: one 0.25s linear;
background-color: steelblue;
color: whitesmoke;
opacity: 1;
transform-origin: 50% 100%;
}
#keyframes one {
0% {
transform: perspective(1000px) rotateX(90deg);
}
100% {
transform: perspective(1000px) rotateX(0);
}
}
.btn {
height: 48px;
width: 200px;
text-align: center;
text-transform: uppercase;
border: none;
border-bottom: 1px solid steelblue;
position: relative;
color: steelblue;
background: transparent;
}
.btn::before {
bottom: 0;
content: "";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
right: 0;
z-index: -1;
}
<div class="bcg">
<div class="btncontainer">
<button class="btn">
click
</button>
</div>
</div>

Change appearance of sticky element when it reaches sticky position

I have create a bottom div that is present all the time when scrolling the site. Its "natural" stop is right after the footer. When I do scroll, and it's not at the footer, it is a bit transparent. However, what I would like to do is when the sticky div reaches the bottom (i.e. its "true" position), then the background changes or something like that.
Is that possible WITHOUT using JS or something like that ?
Updated with a fiddle:
https://jsfiddle.net/octvg6mn/
HTML:
<div class="largeDiv"></div>
<div class="stickyDiv">Test</div>
CSS:
.largeDiv {
height: 1500px;
width: 100%;
background: #cccccc;
}
.stickyDiv {
position: sticky;
bottom: 0px;
text-align: center;
background: blue;
color: white;
opacity: 0.8;
padding: 25px;
}
.stickyDiv:hover {
opacity: 1.0;
}
So as you can see in the fiddle, the sticky has a light opacity while scrolling, but when I reach the bottom, where it is supposed to be, I would like it to turn the opacity into 1.0 or something like, just like when hovering the mouse.
You can apply an opaque background to the container to simulate this. When the sticky element will reach the bottom that background will hide the transparency:
.largeDiv {
height: 1500px;
width: 100%;
background: #cccccc;
}
.container {
background:rgba(0,0,255,1);
}
.stickyDiv {
position: sticky;
bottom: 0px;
text-align: center;
background:rgba(0,0,255,0.5);
color: white;
padding: 25px;
}
.stickyDiv:hover {
background:rgba(0,0,255,1);
}
<div class="container">
<div class="largeDiv"></div>
<div class="stickyDiv">Test</div>
</div>

Changing transparent background-image on hover in front of background colour

I've had a search on here and can't seem to find anyone thread addressing the issue I'm having. If I've missed something though I apologise!
I'm doing work for a client who want a logo to change on hover state, with a background color to be assigned on hover at the same time. The logo is partially transparent, so the background color is intended to show through the logo.
I've got something working but I'm getting an annoying result whereby on the first mouseover, the background color appears to cover the whole image as a colored square. Subsequent hovers work as intended.
This made me wonder if the issue was a delay in the server providing the images. I tried preloading them but no luck.
I've got a prototype in Codepen, source code below! http://codepen.io/JD1990/pen/mPagaz
HTML
<div class="test">
<img src="http://dummyimage.com/318x318/ffffff/ffffff.png">
</div>
CSS
#preload-01 {
background: url(http://new-site-jd-5-5-16.new-site-fa.appspot.com/static/content/client-logo-bbc-inverse.png) no-repeat -9999px -9999px;
}
.test {
display: inline-block;
position: relative;
}
.test:after {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0,0,0,0);
background-image: url(http://new-site-jd-5-5-16.new-site- fa.appspot.com/static/content/client-logo-bbc-inverse.png);
background-image: url(http://new-site-jd-5-5-16.new-site-fa.appspot.com/static/content/client-logo-bbc.png);
}
.test:hover:after {
background-image: url(http://new-site-jd-5-5-16.new-site-fa.appspot.com/static/content/client-logo-bbc-inverse.png);
background-color: black;
}
Very grateful for any hints, I'm still quite inexperienced with CSS so thank you in advance :)
I'm not sure I got the question correctly, is this what you're going for?
If you change the url to a background image it will load the image only when it's hovered, while having it in the html will make the browser to load it immediately. An even better option would be to position those images one next to the other in photoshop and combine them into a sprite, then on hover you just change the background position to show one or the other.
body {
background-color: #BADA55;
}
.test {
position: relative;
}
.wt {
background-color: white;
}
.blk {
background: black;
display: none;
}
img {
position: absolute;
}
.test:hover img {
display: none;
}
.test:hover .blk {
display: block;
}
<div class="test">
<img class="wt" src="http://new-site-jd-5-5-16.new-site-fa.appspot.com/static/content/client-logo-bbc.png">
<img class="blk" src="http://new-site-jd-5-5-16.new-site-fa.appspot.com/static/content/client-logo-bbc-inverse.png" alt="" />
</div>
Added very quick transition to the background color and removed the original background color as it wasn't necessary.
Additionally, since the image isn't being changed I removed it from the :hover rule since it wasn't required. I think this might have been the issue.
body {
background: pink;
}
.test {
display: inline-block;
position: relative;
}
.test:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-image: url(http://new-site-jd-5-5-16.new-site-fa.appspot.com/static/content/client-logo-bbc.png);
transition: background-color 0.1s ease;
}
.test:hover:before {
background-color: #000;
}
<div class="test">
<img src="http://dummyimage.com/318x318/ffffff/ffffff.png">
</div>

Adding colored bar to image with CSS

I have the css code below along with an image to show it's output. I need help though 2 things.
This code works pretty good to show the username on the photo, however I noticed today while using chrome all day often when I would click a link that would take me to the page that has images with this code, it would not show the name on the image, it would just show the name below the image and the transparent black div would not be visible at all and the name would not even be on the image, I would then refresh the page and it would work fine, what could cause this, this was while my PC was acting like it was short on memory, could that be part of the issue?
I would like to make a bar show at
the top of the image that is the
width of the image and like maybe
2-3 pixels tall and have a
background color of like blue. What
I am wanting to accomplish is for
femail users there will be a pink
bar over there image and a different
color for males. Can someone who
knows css help me modify this to do
that the best please
<style type="text/css">
div.imageSub { position: relative; }
div.imageSub img { z-index: 1; }
div.imageSub div {
position: absolute;
left: 0px;
right: 0px;
bottom: 0;
padding: 5px;
height: 5px;
line-height: 4px;
text-align: center;
overflow: hidden;
}
div.imageSub div.blackbg {
z-index: 2;
background-color: #000;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
filter: alpha(opacity=70);
opacity: 0.5;
}
div.imageSub div.label {
z-index: 3;
color: white;
}
</style>
<div class="imageSub" style="width: 90px;"> <!-- Put Your Image Width -->
<img src="http://cache2.mycrib.net/images/image_group66/0/43/t_6871399b0962b5fb4e29ce477541e165950078.jpg" alt="Something" width="90"/>
<div class="blackbg"></div>
<div class="label">Sara</div>
</div>
Since I've written this code for you, seems logical that I also try to fix it...
It seems that Chrome is struggling since it doesn't know the height of the element. Let's use margins instead of positioning
Also, since you are using a set height, you could drop positioning all together and use the following CSS (In which case you shouldn't need the above code):
div.imageSub img { z-index: 1; margin: 0; display: block; }
div.imageSub div {
position: relative;
margin: -15px 0 0;
padding: 5px;
height: 5px;
line-height: 4px;
text-align: center;
overflow: hidden;
}
div.imageSub div.blackbg {
z-index: 2;
background-color: #000;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
filter: alpha(opacity=70);
opacity: 0.5;
}
div.imageSub div.label {
z-index: 3;
color: white;
}
EDIT: You've asked for a top colored bar for the gender. You can use the following HTML:
<div class="imageSub" style="width: 90px;"> <!-- Put Your Image Width -->
<img class="female" src="http://cache2.mycrib.net/images/image_group66/0/43/t_6871399b0962b5fb4e29ce477541e165950078.jpg" alt="Something" width="90"/>
<div class="blackbg"></div>
<div class="label">Sara</div>
</div>
With the following CSS:
div.imageSub img.female { border-top: 10px solid red; }
div.imageSub img.male { border-top: 10px solid blue; }

Resources