Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Arcade Pixel Font - CRT Scanlines!
/*
* Inspired by Arcade Game Typography
* https://www.itsnicethat.com/articles/toshi-omagari-arcade-game-typography-publication-graphic-design-231019
*/
/* scanlines - Creates a repeating-linear-gradient over text
*
* @param $font-size (Required) in px
* @param $line-height (Required) in px
* @param $colors (Required) at least one color, each color makes a scanline
*/
@mixin scanlines($font-size, $line-height, $colors...) {
display: inline-block;
font-size: $font-size;
line-height: $line-height;
// Check and see if browser supports text-fill-color
@supports (-webkit-text-fill-color: transparent) {
$colors-count: length($colors);
$scanline-above: ($line-height - $font-size) / 2; // Where top of letters start. The line height above
$scanline-height: $font-size / $colors-count; // height of each scanline
// Build the scanline gradient
$stops: ();
@for $i from 1 through $colors-count {
$color: nth($colors, $i);
$new-stops: ();
@if $i == 1 { // First line
$new-stops: $color 0px,
$color ($scanline-above + $scanline-height);
} @else if $i == $colors-count { // Last line
$new-stops: $color ($scanline-above + $scanline-height * ($i - 1)),
$color $line-height;
} @else { // All others
$new-stops: $color ($scanline-above + $scanline-height * ($i - 1)),
$color ($scanline-above + $scanline-height * $i);
}
$stops: join($stops, $new-stops, comma);
}
background: repeating-linear-gradient(($stops));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
/* scanlines-crt - Creates a repeating-linear-gradient with transparent gaps between each line (like a CRT display!) over text
*
* @param $font-size (Required) in px
* @param $line-height (Required) in px
* @param $gap (Required) a number for a percent
* @param $colors (Required) at least one color, each color makes a scanline
*/
@mixin scanlines-crt($font-size, $line-height, $gap, $colors...) {
// May need to adjust font-size or line-height by a pixel to help scanlines align
display: inline-block;
font-size: $font-size;
line-height: $line-height;
// Check and see if browser supports text-fill-color
@supports (-webkit-text-fill-color: transparent) {
$colors-count: length($colors);
$scanline-above: ($line-height - $font-size) / 2; // Where top of letters start. The line height above
$scanline-height: $font-size / $colors-count; // height of each scanline
$scanline: $scanline-height * (1 - $gap); // height of color
$scanline-gap: $scanline-height * $gap; // height of gap
// Build the scanline gradient
$stops: ();
@for $i from 1 through $colors-count {
$color: nth($colors, $i);
$new-stops: ();
@if $i == 1 { // First Line
$new-stops: $color 0px,
$color ($scanline-above + $scanline-height - $scanline-gap),
transparent ($scanline-above + $scanline-height - $scanline-gap),
transparent ($scanline-above + $scanline-height);
} @else if $i == $colors-count { // Last line
$new-stops: $color ($scanline-above + $scanline-height * ($i - 1)),
$color ($scanline-above + $scanline-height * $i) - $scanline-gap,
transparent ($scanline-above + $scanline-height * $i) - $scanline-gap,
transparent $line-height;
} @else { // All in between
$new-stops: $color ($scanline-above + $scanline-height * ($i - 1)),
$color ($scanline-above + $scanline-height * $i) - $scanline-gap,
transparent ($scanline-above + $scanline-height * $i) - $scanline-gap,
transparent ($scanline-above + $scanline-height * $i);
}
$stops: join($stops, $new-stops, comma);
}
background: repeating-linear-gradient(($stops));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
/* scanlines-shadow - Creates a text-shadow behind the scanline text with a before pseudo-element
*
* @HTML data-text (Required) attribute on the element with a copy of the scanline text
* @param $font-size (Required) in px
* @param $line-height (Required) in px
* @param $color (Required) color for the shadow
* @param $distance-x (Optional) in px to offset the x-axis, defaults to 10px
* @param $distance-y (Optional) in px to offset the y-axis, defaults to 7px
* @param $blur (Optional) in px for the blur-radius of the shadow, defaults to 0
*/
@mixin scanlines-shadow($font-size, $line-height, $color, $distance-x: 10px, $distance-y: 7px, $blur: 0) {
// Drop shadow
position: relative;
&:before {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
z-index: -1;
text-shadow: $distance-x $distance-y $blur $color;
}
}
/* scanlines-outline - Creates an outline on the text behind the scanline text with an after pseudo-element
*
* @HTML data-text (Required) attribute on the element with a copy of the scanline text
* @param $font-size (Required) in px
* @param $line-height (Required) in px
* @param $color (Required) color for the shadow
* @param $thickness (Optional) in px for the line thickness, defaults to 10px
* @param $distance-x (Optional) in px to offset the x-axis, defaults to 0
* @param $distance-y (Optional) in px to offset the y-axis, defaults to 0
*/
@mixin scanlines-outline($font-size, $line-height, $color, $thickness: 10px, $distance-x: 0, $distance-y: 0) {
// Outline
position: relative;
&:after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
z-index: -1;
transform: translate($distance-x, $distance-y);
-webkit-text-fill-color: $color;
-webkit-text-stroke: $thickness $color;
}
}
<div class="container">
<h1 class="scanlines-head" data-text="Arcade Game Typography">
Arcade Game Typography
</h1>
<p class="scanlines-subhead" data-text="The Art of Pixel Type">
The Art of Pixel Type
</p>
<div class="book">
<a target="_blank" href="https://www.itsnicethat.com/articles/toshi-omagari-arcade-game-typography-publication-graphic-design-231019">Inspired by the book by Toshi Omagari</a>
</div>
</div>
// Scanline styles applied
// Play with the arguments to see various options. Check the mixin docs above to see what args are available.
// Font size and line height may need adjusting by a pixel or two for scanlines to perfectly align at different sizes.
// A pixel font - 8 scanlines works well with this font
@import url("https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap");
.scanlines-head {
$scanlines-head-colors: #bf34ff, #bf34ff, #bf34ff, #ff00d0, #ff8500, #d0ff00, #50ff00, #50ff00;
$scanlines-head-shadow: darken(#af00ff, 60%);
$scanlines-gap: .35;
font-weight: 400; // Weight matters for scanline alignment and browser consistancy!
@include scanlines-crt(100px, 119px, $scanlines-gap, $scanlines-head-colors...);
@include scanlines-shadow(100px, 119px, $scanlines-head-shadow, 10px, 7px);
@media (max-width: 1300px) {
@include scanlines-crt(64px, 72px, $scanlines-gap, $scanlines-head-colors...);
@include scanlines-shadow(64px, 72px, $scanlines-head-shadow, 8px, 5px);
}
@media (max-width: 1000px) {
@include scanlines-crt(48px, 60px, $scanlines-gap, $scanlines-head-colors...);
@include scanlines-shadow(48px, 60px, $scanlines-head-shadow, 7px, 4px);
}
@media (max-width: 700px) {
@include scanlines-crt(32px, 48px, $scanlines-gap, $scanlines-head-colors...);
@include scanlines-shadow(32px, 48px, $scanlines-head-shadow, 6px, 4px);
}
@media (max-width: 400px) {
@include scanlines-crt(28px, 32px, $scanlines-gap, $scanlines-head-colors...);
@include scanlines-shadow(28px, 32px, $scanlines-head-shadow, 5px, 4px);
}
}
.scanlines-subhead {
$color-base: #d0ff00;
$scanlines-subhead-colors:
adjust-hue($color-base, -20deg),
adjust-hue($color-base, 0deg),
adjust-hue($color-base, 0deg),
adjust-hue($color-base, -20deg),
adjust-hue($color-base, -20deg),
adjust-hue($color-base, -30deg),
adjust-hue($color-base, -30deg),
adjust-hue($color-base, -35deg);
$scanlines-subhead-shadow: darken(#af00ff, 60%);
font-weight: 400; // Weight matters for scanline alignment and browser consistancy!
text-transform: uppercase;
@include scanlines(32px, 48px, $scanlines-subhead-colors...);
@include scanlines-outline(32px, 48px, $scanlines-subhead-shadow, 8px);
@media (max-width: 1300px) {
@include scanlines(20px, 24px, $scanlines-subhead-colors...);
@include scanlines-outline(20px, 24px, $scanlines-subhead-shadow, 6px);
}
@media (max-width: 1000px) {
@include scanlines(16px, 18px, $scanlines-subhead-colors...);
@include scanlines-outline(16px, 18px, $scanlines-subhead-shadow, 6px);
}
@media (max-width: 700px) {
@include scanlines(14px, 16px, $scanlines-subhead-colors...);
@include scanlines-outline(14px, 16px, $scanlines-subhead-shadow, 5px);
}
}
// Layout CSS
body {
font-family: "Press Start 2P", sans-serif;
color: rgba(255, 255, 255, .6);
background-color: #371d3a;
padding: 0;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.container {
padding: 40px;
@media (max-width: 700px) {
padding: 10px;
}
text-align: center;
h1,
p {
margin: 0 0 .4em 0;
}
.book {
a {
display: inline-block;
font-size: 12px;
background-color: rgba(255, 255, 255, .1);
color: rgba(255, 255, 255, .6);
text-decoration: none;
margin-top: 4em;
padding: .75em 1.5em .6em;
line-height: 1.3;
border-radius: 2em;
&:hover {
background-color: rgba(255, 255, 255, .2);
color: rgba(255, 255, 255, .9);
}
@media (max-width: 700px) {
font-size: 9px;
letter-spacing: 1px;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment