Mouse-movement image-layer effect - css

I'd like to create the following effect:
There are two full-screen images on top of each other, but only one is visible. When you move the mouse, the second one is revealed within a circle where the mouse is.
I know how to create the circle that follows the mouse using JS. As for the image overlays, I'm stumped. I fiddled with pseudo-elements, with clip-path and opacity, with radial-gradient, with multiple backgrounds -- to no avail.
Radial-gradient would actually be ideal here, but as far as I know it only accepts colors, not images.
Perhaps a third overlay layer? Any ideas? (If there's already a CodePen that does this and that I've missed, please link to it).
Thanks y'all!

short answer: (and all the code below is commented)
I used background property in a <div> instead of using a <img> tag...
the trick is when you use background-attachment: fixed;
in this example, I used 2 backgrounds from Windows 11 OS and you can see really the trick! one dark and one light...
detailed explanation:
so the a <div> and assigned a background-image to the URL of the light-image
the problem here is: when the div is moving with JS, also the image move...
but I find a solution
make the image fixed, which make the image be always in the same position, also if the image is moving
#circle {
background-attachment: fixed;
/* your code */
}
the problem here is: the image isn't responsive,
but I find solution:
make the image size to cover so it will auto-adjust the size and height of the image automatically to the viewport of the device.
#circle {
background-size: cover;
/* your code */
}
for moving is simple... because we can use Javascript, with an eventListener of mousemove
document.addEventListener('mousemove', (e) => {
/* your code */
});
now solved all the problems, however, I will put some documentations below
documentation that can help you:
CSS background-image MDN
CSS background-attachment MDN
CSS background-size MDN
JS mousemove event MDN
here the code
the code can seem to be long,
but not really because I added a lot of comments so everyone can understand
let circle = document.getElementById('circle');
// on mouse move move the circle
document.addEventListener('mousemove', (e) => {
// make the image move relative to the mouse (make sure that in css you applied position: relative; to the div)
circle.style.left = e.pageX - 100 + 'px'; // 100 is half height of circle, so the cursor is in the middle
circle.style.top = e.pageY - 100 + 'px';
});
body {
margin: 0;
overflow: hidden;
}
#bg-image {
position: fixed;
height: 100vh;
width: 100vw;
/*make the background responsive*/
object-fit: cover;
/* under the circle div*/
z-index: -1;
}
#circle {
height: 200px;
width: 200px;
/* make the the div circle */
border-radius: 50%;
/* important using relative for using top and left in javascript */
position: relative;
/* change the url with the link of image you want */
background-image: url(https://laaouatni.github.io/w11CSS/images/0light.jpg);
/*center the background */
background-position: center;
background-repeat: no-repeat;
/* TRICK: making the background responsive*/
background-size: cover;
/* TRICK: the MAGIC is HERE make the image fixed, so is not moving */
background-attachment: fixed;
}
<!-- background image -->
<img id="bg-image" src=" https://laaouatni.github.io/w11CSS/images/1dark.jpg" alt=" ">
<!-- the circle, and moved with javascript -->
<div id="circle"></div>
please see in full mode,
for better results... you can change the values to something like vh or vw for making this more responsive.
I hope this will help you.

You can use a radial gradient as a mask in CSS.
This snippet has an 'underneath' element which is in fact above the background on the body element.
The mask-image cuts out all but the part of its background which is underneath the non-transparent part.
Obviously you will want to alter the dimensions to fit your use case.
Also, the mousemove does literally that (not looking to see whether mousedown for example) just to give a simple demonstration.
Note that some browsers still require a -webkit- prefix for masks.
<!doctype html>
<html>
<head>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
margin: 0;
background-image: url(https://picsum.photos/id/1016/1024/768);
width: 100vw;
height: 100vh;
background-size: cover;
background-position: center;
}
.underneath {
position: absolute;
width: 100%;
height: 100%;
--x: 50vw;
--y: 50vh;
background-image: url(https://picsum.photos/id/1015/1024/768);
background-size: cover;
background-position: center;
-webkit-mask-image: radial-gradient(black 0 15vmin, transparent 15vmin 30vmin);
-webkit-mask-size: 30vmin 30vmin;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: calc(var(--x) - 15vmin) calc(var(--y) - 15vmin);
mask-image: radial-gradient(black 0 15vmin, transparent 15vmin 30vmin);
mask-size: 30vmin 30vmin;
mask-repeat: no-repeat;
mask-position: calc(var(--x) - 15vmin) calc(var(--y) - 15vmin);
}
</style>
</head>
<body>
<div class="underneath"></div>
<script>
const underneath = document.querySelector('.underneath');
document.body.addEventListener('mousemove', function() {
underneath.style.setProperty('--x', event.clientX + 'px');
underneath.style.setProperty('--y', event.clientY + 'px');
});
</script>
</body>

Related

backdrop-filter: opacity() does not seem to work

I am making an website on which, I am looking for an effect that I can not reproduce. I might be making it all wrong so I am going to explain the effect how I am planning on doing it but I am open for other perspectives of course.
The effect:
I have a background image (whole screen) I covered it with a dark grayish color. I also have a 100 by 100 pixels round div following my mouse pointer. My goal is to make this round div a kind of "window" that could see through the dark gray and so reveling the background image on mouse movement.
My method :
styled the background image to be z-index: 1, height: 100vh and width: 100vw.
styled the background gray color to be z-index: 2, height: 100vh, width 100vw and background-color: gray;
styled the div following my pointer to be z-index: 3, height: 100px, width:100px, border-radius: 50% and backdrop-filter: opacity(0);
Of course I have simplified everything and I can tell the backdrop-filter is working with other options like blur or grayscale... But I don't know why the opacity options seems to do nothing at all. I have read that backdrop-filter: opacity() would require other CSS settings like mix-blend-mode. But I have tried quite a few without success.
I know I am thinking only in CSS right now, hence I am open to other suggestions with or without CSS. If you need more details do not hesitate. I am going to make an example on codeSandBox and edit my post to make it easier to understand.
If you can use Js this will work
let image = document.querySelector('#image');
document.body.addEventListener('mousemove', e => {
image.style.clipPath =
`circle(100px at ${e.pageX}px ${e.pageY}px)`;
});
body {
margin: 0;
}
#background {
width: 100vw;
height: 100vh;
background: rgba(24, 24, 24);
position: fixed;
}
#image {
width: 100vw;
height: 100vh;
background: url("https://images.unsplash.com/photo-1542831371-29b0f74f9713") no-repeat;
background-size: contain;
background-position: center;
position: fixed;
clip-path: polygon(0 0);
cursor: none;
}
<div id="background"></div>
<div id="image"></div>
It works basically by updating the clip-path property when the mousemove event is fired.
Edit:
I'll assume you don't know Js, so I'll add that you can play with the circle size (and even its shape) by changing this line:
circle(100px at ${e.pageX}px ${e.pageY}px)
to
circle(75px at ${e.pageX}px ${e.pageY}px)
or even this
polygon(${e.pageX}px ${e.pageY + 25}px, ${e.pageX - 25}px ${e.pageY - 25}px, ${e.pageX + 25}px ${e.pageY - 25}px)
Be sure that the z-index is effective. Remember that it only applies on positioned elements, which mean that if your background-image and div do not have a "position" attribute it will not take the z-index into consideration.

how to achieve blurry parallax background

My objective is to have a full-screen parallax background that is blurred.
The problem is that when you blur an element it no longer spans the full size of the container (because the edges are blurry). I found an example that suggested using transform:scale in order to stretch it just a little bigger than the size required for 'cover', although now this now makes it so that when you scroll down the page the background slowly moves down as well (once again exposing the blurred edges).
HTML
<div class="viewport"></div>
CSS
.viewport {
background-image: url("images/img1.jpg");
background-attachment: fixed;
filter: blur(7px);
position: relative;
transform: scale(1.1);
background-size: cover;
background-position: center;
height: 130vh;
z-index: -1;
}
Consider putting the viewport in a viewport-wrapper with hidden overflow?
HTML
<div class="viewport-wrapper"><div class="viewport"></div></div>
CSS
.viewport-wrapper {
overflow: hidden;
}
Codepen

background-image doesn't appear if <div> is empty?

I created a <div> first thing in the <body> to draw a top line at the top of the page:
<body>
<div class="bordertop"></div>
.....
</body>
and the style:
body {
font-family: Helvetica, Arial, sans-serif;
-webkit-text-size-adjust: 100%;
margin:0;
}
.bordertop {
background-image: url(../images/top_border.png);
background-repeat: repeat-x;
}
However, the top_border image doesn't appear unless I write some text inside the <div> but I don't want to. How could I fix this?
Since the div is empty, there's no content to push it "open" leaving the div to be 0px tall. Set explicit dimensions on the div and you should see the background image.
.bordertop
{
background-image: url(../images/top_border.png);
background-repeat: repeat-x;
height: 100px;
width: 100%; /* may not be necessary */
}
You might need to set the css width and height of your <div> element to whatever size you want
.bordertop {
background-image: url(../images/top_border.png);
background-repeat: repeat-x;
width: 200px;
height: 100px;
}
Give the div a height:1px. That should work. Otherwise your div is 0px high, meaning you won't see anything.
You could also give it padding-top:1px
Another thing you could do is to set the background-image of the line on the body in your CSS. This is assuming the line is the entire width of the body.
See demo
As the answers above me suggest ^^' it's because it has virtually no size, you need either to put content inside to resize it or to set width/height or padding in css bordertop class, or you can put another empty inside it with set size. I was going to skip this answer since there are already answers but I just wanted to add that width/height is not your only option.
On a side note, oh man, people here posting so fast I sometimes wonder if its a race and what is the prize, there must be some, I guess helping other is itself great prize. :) When I was starting to type this there was no answer yet.
The best way I have found is:
for landscape:
width:100%;
height:0;
padding-top:[ratio]%;
for portrait:
width:[ratio]%;
height:0;
padding-top:100%;
You need to determine which side is longer and accept this dimension as 100%
then calculate [ratio] - percentage of shorter dimension in relation to 100% longer dimension. Then use the one of solutions above.
I had the same problem for quite some time, my solution was giving the style lines of: min-height. This opens the div to the height given if there is no elements inside. The height can get bigger with the more elements inside, but not smaller.
Example code:
.fixed-bg {
/* The background image */
background-image: url("img_tree.gif");
/* Set a specified height, or the minimum height for the background image */
min-height: 500px;
/* Set background image to fixed (don't scroll along with the page) */
background-attachment: fixed;
/* Center the background image */
background-position: center;
/* Set the background image to no repeat */
background-repeat: no-repeat;
/* Scale the background image to be as large as possible */
background-size: cover;
}
code gotten from https://www.w3schools.com/cssref/pr_background-attachment.asp
If it is the only div element in the body use the following style to to make it occupy the full-width.
.bordertop {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-image:
url('../images/top_border.png');
}
I couldn't get my background showing in the div even with the width set up. Turns out i had to put "../" in the url section then it showed the picture i was struggling for quite a while.
left {
width: 800px;
height: auto;
min-height: 100%;
position: relative;
background-image: url("../img/loginpic.jpg");
background-size: cover;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
background-color: crimson;
}
Otherwise, you can just open a <p></p> and in styles, remove the default margin length, that's margin: 0; and add height: 0.1px which doesn't consume much space, so it'll work.
Note: it'll work properly until it's not zoomed out more than 50%, so make sure of the use case before you apply it to the body.

CSS Sprite Full Page Background: background-position

I have an image, the top 80px of which I want to use for some other purpose, and remaining image, I want to set as a full page background image.
I tried setting:
background-position: 0px -80px
but it does not work.
How to properly use css sprite (background position) and full page background image?
Either of these (link or link) will generate a sprite for you and the corresponding css.
Once you have that completed use the css classes for their corresponding areas like:
.image1Background {
background-image: url("thesprite.png"),
left: -80px;
top: 0px;
}
.image2Background {
background-image: url("thesprite.png"),
left: 0px;
top: 0px;
}
<body class="image1Background">
<div class="image2Background">
</div>
</body>
Sprites are generally used for a lot of little icons to reduce the number of requests needed to download them to the client.
i would use a div for the 80px image and the background img as body background.. something like:
body { background-image: url(background.gif) }
#imgtop { height: 100%; width: 100%; background-image: url(80px_image.gif) }

Using background-attachment:fixed in safari on the ipad

I'm looking to recreate an effect similiar to the popular science app. Basically have one big background image and then have HTML/CSS layer on top of that. When the user scrolls the content, then background-position of the image should remain in place, and not scroll.
Obviously in a 'regular' browser I would use background-attachment:fixed, but this doesn't seem to work on the ipad. I know position:fixed doesn't work as you might expect according to safari spec - but is there any way of achieving this?
You can use this code to make a fixed background layer to hack into this problem.
#background_wrap {
z-index: -1;
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-size: 100%;
background-image: url('xx.jpg');
background-attachment: fixed;
}
And put <div id="background_wrap"></div> into <body></body>
<body>
<div id="background_wrap"></div>
</body>
Expanding on Anlai's answer above, I found that solution was repeating my image as I was scrolling rather than keeping it fixed. If anyone else had this problem my CSS for the background_wrap ID is as follows:
#background_wrap {
z-index: -1;
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-size: cover;
background-image: url('../images/compressed/background-mobile.png');
background-repeat: no-repeat;
background-attachment: scroll;
}
Just changed the background size and background attachment to make the image static.
Mobile safari scales your whole site down to it's viewport size, including the background image. To achieve the correct effect, use the -webkit-background-size CSS property to declare your background size:
-webkit-background-size: 2650px 1440px;
(hat tip to commenter Mac)
I believe you can place the background image in a div and set the z-index to appear behind other content. Afterwards you can use javascript to fix the position of the div which contains the background image.
I'm not that profi one, but I've solved this problem usin' jquery.
It's quite simple)
Here is the code:
jQuery(window).scroll(function(){
var fromtop = jQuery(window).scrollTop();
jQuery(" your element ").css({"background-position-y": fromtop+"px"});
});
next solution in Css:
body {
background-image: url( ../images/fundobola.jpg );
background-position: top center;background-repeat:no-repeat;
background-size: 1900px 1104px;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
--- not use---- (cause: scroll disable )
position: fixed
Resolved in Ipad and iPhone
Similar to Ig365, I found that Angolao's solution causes image repeat, depending on image proportions; however, Ig365's image doesn't mimic the placement of background-fixed . To do this, add a background-position-x: 50%;. (Depending on your image dimensions, you may also need background-position-y: 50%.)
#background_wrap {
z-index: -1;
position: fixed;
top: 0;
background-position-x: 50%;
height: 100%;
width: 100%;
background-size: cover;
background-image: url('imageURL');
background-repeat: no-repeat;
}

Resources