/* REGULAR SCANLINES SETTINGS */ // width of 1 scanline (responsive units to prevent banding) $scan-width: 1px; $scan-width-scaled: 0.15vh; // viewport-relative unit for better scaling // 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 1s 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 6s 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); } // the scanlines, so! - with responsive scaling for low-res displays &: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); // 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: 1200px) and (max-height: 900px) 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: 1024px) and (max-height: 768px) { &:before { height: calc($scan-width * 2); } &:after { background-size: 100% calc($scan-width * 4); } } // Very low resolution displays @media (max-width: 800px) and (max-height: 600px) { &:before { height: calc($scan-width * 3); } &:after { background-size: 100% calc($scan-width * 6); } } } /* 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%; } } }