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.
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>
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: #5e5e5e;
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;
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;
}
}
img {
width: 100%;
height: 100%;
opacity: 0.5;
}
&:hover {
span {
opacity: 1;
animation: fade 0.5s;
}
img {
opacity: 0.15;
}
}
}
.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;
}
}
Output:
Now, I have three methods to do this. First lets go with first method. Please comment which method is better. Feedback is much appreciated.
Method 1:
First we have to calculate columns & rows. Like how we want our images to display. I want to display 5x3(5 columns, 3 rows). 5 images in a row. Our total images are 15. So, we get 5 images in each row. Let's declare for columns as $col: 5; rows as $numOfRows: 3; Now, on hover on any <li>
. we will move the <span class="item"></span>
on it. Now lets write for loop. Lets also add for loop in media queries too.
#list {
$col: 5; // when we have 5 images in a row
$numOfRows: 3; // when we have 3 rows
width: 750px; // each <li> width is 150, 150x5=750;
$max-nth-child : 15; // total <li>'s are 15.
$limit: min($col * $numOfRows, $max-nth-child);
@for $i from 1 through $limit {
li {
&.box: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 only screen and (max-width: 768px) {
#list {
$col: 4; // when we have 5 images in a row
$numOfRows: 4; // when we have 3 rows
width: 600px; // each <li> width is 150, 150x4=600;
$max-nth-child : 15; // total <li>'s are 15.
$limit: min($col * $numOfRows, $max-nth-child);
@for $i from 1 through $limit {
li {
&.box: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 only screen and (max-width: 600px) {
#list {
$col: 3; // when we have 5 images in a row
$numOfRows: 5; // when we have 3 rows
width: 450px; // each <li> width is 150, 150x3=600;
$max-nth-child : 15; // total <li>'s are 15.
$limit: min($col * $numOfRows, $max-nth-child);
@for $i from 1 through $limit {
li {
&.box: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 only screen and (max-width: 450px) {
#list {
$col: 2; // when we have 5 images in a row
$numOfRows: 8; // when we have 3 rows
width: 300px; // each <li> width is 150, 150x2=300;
$max-nth-child : 15; // total <li>'s are 15.
$limit: min($col * $numOfRows, $max-nth-child);
@for $i from 1 through $limit {
li {
&.box: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;
}
}
}
}
}
That's it! We are done with responsive too.
Output default: max-width >= 1920px (5x3, col and rows) :
Output max-width: 768px (4x4, col and rows) :
Output max-width: 600px (3x5, col and rows) :
Output max-width: 450px (2x8, col and rows) :
Method 2:
@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 {
&.box: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;
}
}
}
}
}
/* Base styles */
/* uncomment below #list if you don't want to use media query for
(max-width: 1920px) and comment the below media query which has
[(max-width: 1920px), @include responsive-styles(750px, 5, 3);] */
// #list {
// $col: 5;
// width: 750px;
// $multiplier : 3;
// $max-nth-child: 15;
// // Calculate the maximum range for the loop
// $limit: min($col * $multiplier, $max-nth-child);
// @for $i from 1 through $limit {
// li {
// &.box: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);
}
Output:
$max-nth-child : 15; // total <li>'s are 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));
/* uncomment this below commented seection from 'width:750px to end of loop' if you want to
comment above first breakpoint(1920) */
#list {
// $default-col: 5;
// $default-numOfRows: 3;
// width: 750px;
// $col: $default-col;
// $numOfRows: $default-numOfRows;
// $limit: min($col * $numOfRows, $max-nth-child);
// @for $i from 1 through $col * $numOfRows {
// li {
// &.box: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;
// }
// }
// }
@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 {
&.box: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;
}
}
}
}
}
}
Thank you for watching...Please subscribe to my youtube channel
Click here for demo
Top comments (0)