I am trying to make my portfolio website better looking by adding throwing some images in the background at random positions but is is not working as expected. This is what I have:
//This is the index.html page:
<!-- header and navbar above of the webpage above-->
<body>
<!--==================== Background Random Images ====================-->
<div class="image-container">
<img src="https://shorturl.at/T8cGm"
alt="Image 1">
<img src="https://shorturl.at/T8cGm"
alt="Image 2">
<img src="https://shorturl.at/T8cGm"
alt="Image 3">
<img src="https://shorturl.at/T8cGm"
alt="Image 1">
<img src="https://shorturl.at/T8cGm"
alt="Image 2">
<img src="https://shorturl.at/T8cGm"
alt="Image 3">
</div>
<!-- hero, cta, footer sections of the webpage below-->
</body>
//This is the css:
.image-container {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.image-container img {
position: absolute;
transition: width 0.2s, height 0.2s;
width: 100px;
height: 100px;
}
//and this is the js:
document.addEventListener("DOMContentLoaded", function () {
const imageNodeList = document.querySelectorAll(".image-container img");
const imageArray = Array.from(imageNodeList);
const maxAttempts = 100; // Maximum number of attempts to find a non-overlapping position
const resizeFactor = 0.9; // Factor by which to reduce the size on each resize attempt
function setPositions(images, positions) {
images.forEach((img, index) => {
img.style.left = `${positions[index].left}px`;
img.style.top = `${positions[index].top}px`;
});
}
function getRandomPos(maxWidth, maxHeight, imgWidth, imgHeight) {
const randomX = Math.floor(Math.random() * (maxWidth - imgWidth));
const randomY = Math.floor(Math.random() * (maxHeight - imgHeight));
return { left: randomX, top: randomY };
}
function isOverlapping(pos, positions, imgWidth, imgHeight) {
return positions.some(p => {
return !(
pos.left + imgWidth < p.left || // Right of new image is left of existing image
pos.left > p.left + p.width || // Left of new image is right of existing image
pos.top + imgHeight < p.top || // Bottom of new image is above existing image
pos.top > p.top + p.height // Top of new image is below existing image
);
});
}
function positionImages(images) {
const newPositions = [];
images.forEach(img => {
let pos;
let attempts = 0;
let resized = false;
while (attempts < maxAttempts) {
pos = getRandomPos(window.innerWidth, window.innerHeight, img.width, img.height);
if (!isOverlapping(pos, newPositions, img.width, img.height)) {
newPositions.push({ ...pos, width: img.width, height: img.height });
break;
}
attempts++;
}
if (attempts >= maxAttempts) {
// Resize and retry positioning
img.width *= resizeFactor;
img.height *= resizeFactor;
console.warn('Resizing image due to overlapping');
positionImages([img]); // Retry positioning this image
}
});
setPositions(images, newPositions);
}
positionImages(imageArray);
});
What I intended to do:
- Scatter these images in the background at random positions without them interfering with elements of the webpage.
- Scatter them to the whole page from "hero section" to "contact section"
Here is the github of the repo if you want to look into it in detail:
[https://github.com/faizalkhan99/Portfolio]
When all this is isolated, it works perfectly as shown below:
BUT when I merge this into my main file, it just sits at the top of the page:
2
Answers
You just need to set the position of your .image-container to fixed, so that no space is allocated for it in the DOM and it stays at the top of the window (does not scroll with the content).
After trying it on your actual webpage, I noticed that the images cover some of your content. Setting the z-index to -10 fixed that.
As you want the images to always cover the full background, change the position of image-container to absolute and add top and left to 0 to define from where the component should start.
The below css works fine when adding the image rendering tags at the last of the DOM, if the tags are at the start of the DOM then you need to change the css for the other content to position absolute.