DEV Community

Cover image for Follow Mouse on Hover in SCSS with Responsive. No JS!
Prahalad S
Prahalad S

Posted on • Edited on

Follow Mouse on Hover in SCSS with Responsive. No JS!

Follow Mouse on Hover in SCSS with Responsive. No JS!

So Let's create hover follow mouse using scss without using JavaScript. Below is the gif image for final output. Its also responsive.

Image description

Let's create list elements in html like below code. Also add <span class="item"></span> at the bottom of last <li>. This item span will follow the mouseover.

<ul id="list">
        <li class="box"><img src="img/1.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/2.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/3.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/4.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/5.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/6.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/7.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/8.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/9.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/10.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/11.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/12.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/13.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/14.jpg" alt=""><span>caption</span></li>
        <li class="box"><img src="img/15.jpg" alt=""><span>caption</span></li>
     <span class="item"></span>
</ul>
Enter fullscreen mode Exit fullscreen mode

Let's create scss variables $w, $h for width and height of <li>. Assign width, height to 100% to img and span(which has text: caption) tags which are inside <li> like below code. span will appear on hover of <li> and also <span class="item"></span> will follow on hover with our for loop logic.

$w: 150px;
$h: 100px;

body {
    margin: 0;
    padding: 0;
    background: #5b5b5b;
    font-family: monospace;
}

#list {
    display: flex;
    flex-wrap: wrap;
    margin: 50px auto;
    // width:750px;
    padding: 0;
    list-style-type: none;
    position: relative;

    li {
        &.box {
            box-sizing: border-box;
            -moz-box-sizing: border-box;
            -webkit-box-sizing: border-box;
            width: $w;
            height: $h;
            position: relative;
            overflow: hidden;
            border: 1px solid rgb(255, 255, 255);
            z-index: 1;
            margin: 0;
            padding: 0;
            cursor: pointer;

            img {
                width: 100%;
                height: 100%;
                opacity: 0.5;
            }

            span {
                font-size: 15px;
                opacity: 0;
                z-index: 2;
                position: absolute;
                color: white;
                width: 100%;
                height: 100%;
                left: 0;
                top: 0;
                z-index: 2;
                text-shadow: none;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            &:hover {
                img {
                    opacity: 0.15;
                }
                span {
                    opacity: 1;
                    animation: fade 0.5s;
                }   
            }
        }
    }

    .item {
        position: absolute;
        width: $w;
        height: $h;
        left: unset;
        top: unset;
        background: rgb(0, 0, 0);
        opacity: 0;
        z-index: 0;
        transition: 0s ease;
        pointer-events: none;
    }
}

@keyframes fade {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

Enter fullscreen mode Exit fullscreen mode

Output:

Image description

Now, I have two methods to do this. First lets go with first method. Please comment which method is better. Feedback is much appreciated.

Method 1:

@mixin responsive-styles($width, $col, $multiplier, $max-nth-child) {
    #list {
        width: $width;

        // Calculate the maximum range for the loop
        $limit: min($col * $multiplier, $max-nth-child);

        @for $i from 1 through $limit {
            li:nth-child(#{$i}):hover~.item {
                    $row: ceil($i / $col); // determine the row number
                    $rowOffset: ($row - 1) * $col * $w; // adjust based on row
                    left: #{$i * $w - $rowOffset - ($w)};
                    top: #{($row - 1) * $h};
                    transition: 0.25s ease;
                    opacity: 0.7;
              }
        }
    } 
}

// media queries
@media only screen and (max-width: 1920px) { 
   @include responsive-styles(750px, 5, 3, 15);
}

@media only screen and (max-width: 768px) { 
    @include responsive-styles(600px, 4, 4, 15);
 }

 @media only screen and (max-width: 600px) { 
    @include responsive-styles(450px, 3, 5, 15);
 }

 @media only screen and (max-width: 450px) { 
    @include responsive-styles(300px, 2, 8, 15);
 } 
Enter fullscreen mode Exit fullscreen mode

Output:

Image description
Method 2:

$max-nth-child: 15;
$breakpoints: (1920px:(col: 5, numOfRows: 3, width: 750px),
    768px: (col: 4, numOfRows: 4, width: 600px),
    600px: (col: 3, numOfRows: 5, width: 450px),
    450px: (col: 2, numOfRows: 8, width: 300px));

#list {
    @each $breakpoint,
    $settings in $breakpoints {
        @media only screen and (max-width: $breakpoint) {
            width: map-get($settings, width);
            $col: map-get($settings, col);
            $numOfRows: map-get($settings, numOfRows);
            $limit: min($col * $numOfRows, $max-nth-child);

            @for $i from 1 through $limit {
                li:nth-child(#{$i}):hover~.item {
                    $row: ceil($i / $col);
                    $rowOffset: ($row - 1) * $col * $w;
                    left: #{$i * $w - $rowOffset - ($w)};
                    top: #{($row - 1) * $h};
                    transition: 0.25s ease;
                    opacity: 0.7;
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:
Image description

Thank you for watching...Please subscribe to my youtube channel

Click here for demo

Top comments (0)

Cloudinary image

Optimize, customize, deliver, manage and analyze your images.

Remove background in all your web images at the same time, use outpainting to expand images with matching content, remove objects via open-set object detection and fill, recolor, crop, resize... Discover these and hundreds more ways to manage your web images and videos on a scale.

Learn more