"Learn how to create a scrolling div using a combination of CSS and JavaScript with absolute and relative

After relying solely on "pre-made" components like Mui or TailWind, I decided to create a component using only CSS and maybe JavaScript. However, I encountered some difficulties when attempting to position a div inside an image using relative and absolute positions. I am aware that absolute positioning disrupts the natural flow... and I need to find a way to make this scrollable div work.

The issue at hand: when the page width is less than the combined width of all images, the images overflow into the next div, disregarding the margins set by another div.

I am considering a solution where I use useRef to retrieve the width from the 'a' tag and calculate the left position to create a gap. For example, left: 0, left: 580*funcGetWidthFromRef(), left: funcGetWidthFromRef().

Is there another alternative solution?

Here is my code:

import Image from "next/image";
import styles from "../../styles/Card.module.css";
export default function Card() {
    const listArticles = [1, 2, 3, 4];
    const textTitle = ["Vant", "Vam", "Puits", "JUmpP"];
    return (
        <>
            {" "}
            <section className={`${styles.scrollableCategoryContent}`}>
                {listArticles.map((art, index) => {
                    return (
                        <article key={index} className={`styles.Game${art}`}>
                            <a
                                href=""
                                className={`${styles.cardAnchorConteirner}`}
                                style={{
                                    left: `${170 * index}px`,
                                }}
                            >
                                <Image
                                    className={`${styles.cardImage}`}
                                    width={580}
                                    height={480}
                                    objectFit="cover"
                                    objectPosition="top left"
                                    src={
                                        "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Postgres_Query.jpg/1920px-Postgres_Query.jpg"
                                    }
                                    alt="test"
                                ></Image>
                                <div
                                    className={`${styles.textCardBackGround}`}
                                >
                                    <h2
                                        className={`${styles.cardTitleText}`}
                                    >{`${textTitle[index]}`}</h2>
                                </div>
                            </a>
                        </article>
                    );
                })}
            </section>
        </>
    );
}

.scrollableCategoryContent{
  display: grid;
  grid-auto-flow: column;
  background-color: black;
  max-width: 700;
  height: 480px;
  overflow-x: scroll;
}

Game1, .Game2, .Game3, .Game4 {
  
}

.cardAnchorConteirner{
  width: 100%;
  height: 100%;
  position: relative;
}

.cardImage{
  position: absolute;
}

.textCardBackGround {
 position: absolute;
 background-color: aqua;
 width: 100%;
 height: 20%;
 left: 0px;
 right: 0px;
 bottom: 20%;
}

.cardTitleText{
  color: white;
}

Answer №1

Here is a simple solution: place a div outside all relative and absolute positioned divs. This div without positions can utilize Grid and allow the normal flow to be followed. However, problems may arise if the div or other component has zero width or height. I previously attempted to use UseRef with good results, but the code became excessively large when implementing additional solutions such as resizing images.

import Image from "next/image";
import styles from "../../styles/CardAlt.module.css";

export default function CarCompAlt() {
    const games = [1, 2, 3, 4];
    const titles = ["Valorant", "Mw2", "RPGs", "Actions"];

    return (
        <>
            <section className={`${styles.trywarp}`}>
                {games.map((value, index) => {
                    return (
                        <article
                            key={index}
                            className={`${styles.thisJustWork}`}
                        >
                            <a
                                href=""
                                className={`${styles.cardArchorContainer}`}
                            >
                                <Image
                                    className={`${styles.imageContainer}`}
                                    src={
                                        "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Postgres_Query.jpg/1920px-Postgres_Query.jpg"
                                    }
                                    width={584}
                                    height={480}
                                    alt={`${2265}`}
                                    objectFit="cover"
                                    objectPosition="center"
                                ></Image>
                                <h3 className={`${styles.titleContainer}`}>
                                    {titles[index]}
                                </h3>
                            </a>
                        </article>
                    );
                })}
            </section>
        </>
    );
}

CSS

.trywarp{
    display: grid;
    grid-auto-flow: column;
    gap: 100px;
    overflow-x: scroll;
    overflow-y: clip;
}

.thisJustWork{
    width: 500px;
    height: 500px;
    background-color: brown;
}


.cardAnchorContainer{
    position: relative;
}

.imageContainer{
    position: absolute;
}

.titleContainer{
    position: absolute;
    z-index: 50;
    color: aliceblue;
}

The solution using useRef involves giving a width to "scrollableCategoryContent" to prevent an increase in gap.

import Image from "next/image";
import { HtmlHTMLAttributes, useEffect, useRef, useState } from "react";
import styles from "../../styles/Card.module.css";

export default function Card() {
    const refScrollableCategoryContent = useRef<any>();
    const [pixelGain, setPixelGain] = useState<number>(0);
    const [widthScrollable, setWidthScrollable] = useState<any>(
        refScrollableCategoryContent.current?.getBoundingClientRect().width
    );
    const listArticles = [1, 2, 3, 4];
    const textTitle = ["Vant", "Vam", "Puits", "JUmpP"];

    function resizeScrollable() {
        const widthRefScroll =
            refScrollableCategoryContent.current?.getBoundingClientRect().width;
        setWidthScrollable(widthRefScroll);
    }

    useEffect(() => {
        window.addEventListener("resize", resizeScrollable);
        resizeScrollable();

        return () => {
            window.removeEventListener("resize", resizeScrollable);
        };
    }, []);

    return (
        <>
            <div>
                <div>Window size: {widthScrollable}</div>
                <button
                    onClick={() => {
                        setWidthScrollable(
                            refScrollableCategoryContent.current?.getBoundingClientRect()
                        );
                    }}
                >
                    refScrollableCategoryContent
                </button>
            </div>
            
            <section
                className={`${styles.scrollableCategoryContent}`}
                ref={refScrollableCategoryContent}
            >

                {listArticles.map((art, index) => {
                    return (
                        <article key={index} className={`styles.Game${art}`}>
                            <a
                                href=""
                                className={`${styles.cardAnchorConteirner}`}
                                style={{
                                    left: `${(425 + pixelGain) * index}px`,
                                }}
                            >
                                <Image
                                    className={`${styles.cardImage}`}
                                    width={584}
                                    height={480}
                                    objectFit="cover"
                                    objectPosition="center"
                                    src={
                                        "https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Postgres_Query.jpg/1920px-Postgres_Query.jpg"
                                    }
                                    alt="test"
                                ></Image>

                                <div
                                    className={`${styles.textCardBackGround}`}
                                >
                                    <h2
                                        className={`${styles.cardTitleText}`}
                                    >{`${textTitle[index]}`}</h2>
                                </div>
                            </a>
                        </article>
                    );
                })}
            </section>
        </>
    );
}

CSS

.scrollableCategoryContent{
    display: grid;
    grid-auto-flow: column;
    background-color: black;
    width: 1000px;
    height: 480px;
    overflow-x: scroll;
    overflow-y: clip;
}

.cardAnchorConreiner{
    position: relative;
}

.cardImage{
    position: absolute;
}

.textCardBackground {
    position: absolute;
    background-color: aqua;
    width: 100%;
    height: 20%;
    bottom: 20%;
}

.cardTitleText{
    color: white;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to verify if an AJAX request calls HTML content?

Here is the HTML code for a mosaic of images. <div id="container"> <img id="1" /> ... <img id="20" /> </div> This script creates a mosaic layout from the images on the page after it has loaded or been resized. <script& ...

Is the flowplayer software free for use on a production server?

Here is the URL I am implementing to stream videos on my website: I would like to know if it is permissible and cost-free to use in a production environment. ...

MUI Gradient Tracked Button

Take a look at this Codepen example I created. It showcases a hover effect where the gradient follows the mouse cursor. In order to achieve this effect, I have defined two CSS variables - --x and --y, to keep track of the mouse position on the button. The ...

Working with Java to parse non-strict JSON data that does not have keys enclosed in quotes

I am currently facing the challenge of parsing a string in JSON format where keys are not enclosed in quotes. While I have successfully parsed this string in Javascript, I am struggling to find a Java API that can assist me with parsing. The APIs I have at ...

Eliminate the standard cell padding in nested HTML tables

In my setup, there is a parent table where each td tag in the tr tag contains a child table. Specifically, as shown in the example with Data WS-C3.... in the picture. [![<table class="table table--bordered table--nostripes table-top"> <thead& ...

How can the style of a div's :after pseudo-element be modified when hovering over its :before pseudo-element?

Here is some CSS code: .myDiv:before{ content:''; width:15px; height:15px; display:block; } .myDiv:after{ ... ... display:none; } And here is the corresponding HTML code: <div class='myDiv'></div> ...

Implementing onMouseEnter and onMouseLeave functionalities for music player

Currently facing a challenge while developing a music player app. I am trying to implement a feature where: Upon hovering over a song, a "play" button should appear in place of the song number. The currently playing song should display a "pause" ...

Formatting the numbers for an unordered list located outside of the content

Can the numbers of an ordered list be formatted using the list-position-style set to outside? I am looking for a solution using only CSS since I cannot edit the HTML. Essentially, I want styled numbers with round background to replace the outside numbers. ...

Encasing common functions within (function($){ }(jQuery) can help to modularize and prevent

As I was creating a global JavaScript function and made some errors along the way, I finally got it to work after doing some research. However, while searching, I came across an example using (function($){ code here }(jQuery); My question is, what exact ...

When attempting to add a variable using the next() function, I encountered an error with the BehaviorSubject. The error message displayed was "this.count.next is not a function"

In my Angular service, there is a variable called count that I need to monitor for updates. Whenever this count variable is updated, I want to assign its new value to another variable in a separate component. import {BehaviorSubject} from "rxjs/BehaviorSu ...

transmitting information using dataURL

Hey there! So I've got this code that does a neat little trick - it sends a dataURL to PHP and saves it on the server. In my JS: function addFormText(){ $('body').append('<input type="hidden" name="img_val" id="img_val" value="" /& ...

What is the best way to ensure my footer remains at the bottom of the page even when scrolled?

I'm struggling to get my footer to stay at the bottom of a page that requires scrolling. The code I have only seems to work on pages without scrolling, causing the footer to display in the middle of the page instead of at the bottom where it belongs. ...

Control the HTML button's state according to the information received from the server

I am currently working with datatable Jquery and using an ajax call to retrieve data from the server. Let's assume that the database consists of three attributes: "Attribute1, Attribute2, Status". Depending on the Status attribute, I need to enable or ...

Redirecting pages using an Ajax script in JavaScript

Unfortunately, I am unable to use a *.php extension for my page due to unforeseen circumstances. This has led me to consider using *.html instead and implementing conditional redirection using javascript/Ajax to call a PHP script that can evaluate the cond ...

Leveraging Angular2's observable stream in combination with *ngFor

Below is the code snippet I am working with: objs = [] getObjs() { let counter = 0 this.myService.getObjs() .map((obj) => { counter = counter > 5 ? 0 : counter; obj.col = counter; counter++; return view ...

Transmit information to the server via an AJAX request

$.ajax({ url:"http://192.168.0.74:8080/pimsdesign/JSONRequestHandler" , type: "POST", data: {name: "amit", id:1 }, dataType: "json", beforeSend: function(xhr) { if (xhr && xhr.overrideMimeType) { xhr.overrideMimeType("application/json;charset=UTF-8 ...

Sending the factory's response back to the controller in AngularJS

I operate a factory that uses an api call to request user data: angular.module('MyApp') .factory('UserApi', function($auth,Account){ return { getProfile: function() { Account.get ...

No Backend Detected for Tensorflow.js in Node

I've been attempting to develop a Discord bot that utilizes the @tensorflow-models/qna library, but I've hit a roadblock for the past 4 hours. Every time I run the script below: const qna = require('@tensorflow-models/qna'); (async () ...

Can Vue support recurring time slots?

I have configured a reproduction repository: https://github.com/devidwong/recurring-slot Using Vue runtime-only, I am unable to use Vue.extend (which requires template compiler) Vue 3 is quite new to me. I decided to use it for exploration purposes. Not ...

Encountered JSON array, unable to retrieve certain attributes in AngularJS

I have developed a web service that organizes my information into a list and then converts it to JSON format. Below is the JSON output: { GetEventLTResult: [ { eventID: 1, location: "Place A", type: "Communi ...