2025-05-29 17:03:50 -05:00
/* REGULAR SCANLINES SETTINGS */
2025-06-24 22:38:25 -04:00
// width of 1 scanline (responsive units to prevent banding)
2025-05-29 17:03:50 -05:00
$scan-width : 1 px ;
2025-06-24 22:38:25 -04:00
$scan-width-scaled : 0 .15 vh ; // viewport-relative unit for better scaling
2025-05-29 17:03:50 -05:00
// emulates a damage-your-eyes bad pre-2000 CRT screen ♥ (true, false)
$scan-crt : false ;
// frames-per-second (should be > 1), only applies if $scan-crt: true;
$scan-fps : 20 ;
// scanline-color (rgba)
$scan-color : rgba ( #000 , .3 ) ;
// set z-index on 8, like in ♥ 8-bits ♥, or…
// set z-index on 2147483648 or more to enable scanlines on Chrome fullscreen (doesn't work in Firefox or IE);
$scan-z-index : 2147483648 ;
/* MOVING SCANLINE SETTINGS */
// moving scanline (true, false)
$scan-moving-line : true ;
// opacity of the moving scanline
$scan-opacity : .75 ;
/* MIXINS */
// apply CRT animation: @include scan-crt($scan-crt);
@mixin scan-crt ( $scan-crt ) {
@if $scan-crt == true {
animation : scanlines 1 s steps ( $scan-fps ) infinite ;
}
@else {
animation : none ;
}
}
// apply CRT animation: @include scan-crt($scan-crt);
@mixin scan-moving ( $scan-moving-line ) {
@if $scan-moving-line == true {
animation : scanline 6 s linear infinite ;
}
@else {
animation : none ;
}
}
/* CSS .scanlines CLASS */
. scanlines {
position : relative ;
overflow : hidden ; // only to animate the unique scanline
& : before ,
& : after {
display : block ;
pointer-events : none ;
content : ' ' ;
position : absolute ;
}
// unique scanline travelling on the screen
& : before {
// position: absolute;
// bottom: 100%;
width : 100 % ;
height : $scan-width * 1 ;
z-index : $scan-z-index + 1 ;
background : $scan-color ;
opacity : $scan-opacity ;
// animation: scanline 6s linear infinite;
@include scan-moving ( $scan-moving-line ) ;
}
2025-06-24 22:38:25 -04:00
// the scanlines, so! - with responsive scaling for low-res displays
2025-05-29 17:03:50 -05:00
& : after {
top : 0 ;
right : 0 ;
bottom : 0 ;
left : 0 ;
z-index : $scan-z-index ;
background : linear-gradient ( to bottom ,
transparent 50 % ,
$ scan-color 51 % ) ;
background-size : 100 % $scan-width * 2 ;
@include scan-crt ( $scan-crt ) ;
2025-06-24 22:38:25 -04:00
// Prevent sub-pixel aliasing on scaled displays
image-rendering : crisp-edges ;
image-rendering : pixelated ;
}
// Responsive scanlines for different display scenarios
// High DPI displays - use original sizing
@media ( -webkit-min-device-pixel-ratio : 2 ) ,
( min-resolution : 192dpi ) {
& : before {
height : $scan-width ;
}
& : after {
background-size : 100 % calc ( $scan-width * 2 ) ;
}
}
// Medium resolution displays (1024x768 and similar)
@media ( max-width : 1200 px ) and ( max-height : 900 px ) and ( - webkit-max-device-pixel-ratio : 1 .5 ) {
& : before {
height : calc ( $scan-width * 1 .5 ) ;
}
& : after {
background-size : 100 % calc ( $scan-width * 3 ) ;
}
}
// Low resolution displays - increase thickness to prevent banding
@media ( max-width : 1024 px ) and ( max-height : 768 px ) {
& : before {
height : calc ( $scan-width * 2 ) ;
}
& : after {
background-size : 100 % calc ( $scan-width * 4 ) ;
}
}
// Very low resolution displays
@media ( max-width : 800 px ) and ( max-height : 600 px ) {
& : before {
height : calc ( $scan-width * 3 ) ;
}
& : after {
background-size : 100 % calc ( $scan-width * 6 ) ;
}
2025-05-29 17:03:50 -05:00
}
}
/* ANIMATE UNIQUE SCANLINE */
@keyframes scanline {
0 % {
transform : translate3d ( 0 , 200000 % , 0 ) ;
// bottom: 0%; // to have a continuous scanline move, use this line (here in 0% step) instead of transform and write, in &:before, { position: absolute; bottom: 100%; }
}
}
@keyframes scanlines {
0 % {
background-position : 0 50 % ;
// bottom: 0%; // to have a continuous scanline move, use this line (here in 0% step) instead of transform and write, in &:before, { position: absolute; bottom: 100%; }
}
2025-06-24 22:38:25 -04:00
}