Reputation: 21
On my current website, I am trying to render everything pixelated with sprite graphics and pixel fonts to make it look as close to a game as possible. The problem is that Chrome and Firefox like to render pixel fonts differently and there isn't a way to make them look consistent. This especially happens when trying to center the font or use css transform. It always defaults to anti-aliasing it.
Just for reference, here is the font I am trying to render dynamically:
Notice how it looks crystal clear on Firefox while blurry in Chrome.
I have attempted to try all sorts of css tricks to fix this with no luck, including some methods listed in this interesting Github repo. Then I came across some game development forums where they were discussing using a texture atlas to import their fonts in their games.
Here is an example. In the second half of the page, you can see they are using a sprite sheet with all the font letters laid out, then using code to assign each part to a letter and insert it into their WebGL example. I would like to do the same thing, except in my case have it dynamically reference what I typed and insert it where my example text is.
I'm sure there is a way this could be done in Javascript, or maybe there is another solution somebody else has already come up with that I just haven't thought of yet. Any ideas?
Here is an example of what the code looks like:
:root {
--multiplication-factor: 1;
--number-shadow: #002806;
--text-shadow: #4b4b54;
--font-size: 16px;
}
@font-face {
font-family: pixeltiny;
src: url(https://old.sgxp.me/example/PixelTiny.ttf);
}
body {
transform: translateZ(0);
}
.sprite-page-container {
margin: 20px 105px;
}
.sprite-container {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
padding: 10px;
min-height: 200px;
transition: 1s;
}
.sprite-box {
width: calc(117px * var(--multiplication-factor));
height: calc(188px * var(--multiplication-factor));
background-image: url('https://old.sgxp.me/example/icon_image.svg');
margin: 10px;
user-select: none;
transition: transform ease-in-out .2s;
text-decoration: none;
border-radius: 4px;
box-shadow: 10px 10px 0px rgba(0,0,0,0.7);
animation: fadein-top .7s;
}
.sprite-box:hover {
transform: translateY(calc(-5px * var(--multiplication-factor)));
animation: fadein-top .7s;
}
.sprite-page-container a {
color: white;
padding: 0;
}
.sprite-page-container a:hover {
padding: 0;
background-image: url("https://old.sgxp.me/example/icon_image.svg");
}
.sprite-page-container a:visited {
color: white;
}
.sprite-star-container {
display: flex;
margin-left: calc(6px * var(--multiplication-factor));
margin-top: calc(3px * var(--multiplication-factor));
margin-bottom: calc(-9px * var(--multiplication-factor));
width: calc(70px * var(--multiplication-factor));
}
.sprite-star {
height: calc(6px * var(--multiplication-factor));
width: calc(7px * var(--multiplication-factor));
}
.sprite-star:nth-child(n + 2) {
margin-left: calc(-1px * var(--multiplication-factor));
}
.sprite-number {
font-family: 'pixeltiny', monospace;
font-size: calc(var(--font-size) * var(--multiplication-factor));
color: white;
user-select: none;
display: flex;
justify-content: right;
line-height: 0;
margin-right: calc(6px * var(--multiplication-factor));
margin-top: calc(3px * var(--multiplication-factor));
text-shadow: calc(1px * var(--multiplication-factor)) 0px var(--number-shadow), 0px calc(1px * var(--multiplication-factor)) var(--number-shadow), calc(1px * var(--multiplication-factor)) calc(1px * var(--multiplication-factor)) var(--number-shadow);
}
.sprite-text {
font-family: 'pixeltiny', monospace;
user-select: none;
font-size: calc(var(--font-size) * var(--multiplication-factor));
line-height: calc(7px * var(--multiplication-factor));
text-align: center;
color:white;
}
.sprite-title {
display: flex;
justify-content: center;
align-items: center;
padding-top: calc(4px * var(--multiplication-factor));
margin-left: calc(5px * var(--multiplication-factor));
margin-right: calc(10px * var(--multiplication-factor));
height: calc(15px * var(--multiplication-factor));
width: calc(109px * var(--multiplication-factor));
overflow-wrap: anywhere;
}
.sprite-image {
display: flex;
justify-content: center;
align-items: center;
image-rendering: pixelated;
pointer-events: none;
height: calc(71px * var(--multiplication-factor));
width: calc(103px * var(--multiplication-factor));
margin-top: calc(5px * var(--multiplication-factor));
margin-left: calc(7px * var(--multiplication-factor));
margin-right: calc(6px * var(--multiplication-factor));
object-fit: cover;
overflow: hidden;
}
.sprite-image > img {
filter: drop-shadow(calc(10px * var(--multiplication-factor)) calc(10px * var(--multiplication-factor)) 0px rgba(0,0,0,0.7));
transform: scale(calc(1 * var(--multiplication-factor)));
}
.sprite-author {
display: flex;
justify-content: center;
align-items: center;
margin-top: calc(-2px * var(--multiplication-factor));
margin-left: calc(13px * var(--multiplication-factor));
margin-right: calc(12px * var(--multiplication-factor));
margin-bottom: calc(0spx * var(--multiplication-factor));
height: calc(26px * var(--multiplication-factor));
width: calc(93px * var(--multiplication-factor));
overflow-wrap: anywhere;
}
.sprite-stats {
display: flex;
justify-content: flex-start;
align-items: flex-start;
margin-top: calc(4px * var(--multiplication-factor));
margin-left: calc(24px * var(--multiplication-factor));
margin-right: calc(3px * var(--multiplication-factor));
width: calc(110px * var(--multiplication-factor));
}
.sprite-stats:nth-child(n+2) {
height: calc(5px * var(--multiplication-factor));
}
@keyframes fadein-top {
0% { opacity: 0; transform: translateY(-50px);}
50% { opacity: 0; transform: translateY(-50px);}
100% { opacity: 1; transform: translateY(0); }
}
<div class="sprite-container">
<a href="" class="sprite-box">
<div class="sprite-star-container">
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
<div class="sprite-star"></div>
</div>
<div class="sprite-number">001</div>
<div class="sprite-title">
<div id="author" class="sprite-text">Example</div>
</div>
<div class="sprite-image">
<img src="" alt="">
</div>
<div class="sprite-author">
<div class="sprite-text">Example</div>
</div>
<div class="sprite-stats">
<div class="sprite-text">Example</div>
</div>
<div class="sprite-stats">
<div class="sprite-text">Example</div>
</div>
<div class="sprite-stats">
<div class="sprite-text">Exmaple</div>
</div>
<div class="sprite-stats">
<div class="sprite-text">Exmaple</div>
</div>
</a>
</div>
As you can see, I am dynamically putting the example text over my svg image. Everything in the svg looks fine, but when I insert my text Chrome renders it with this weird font smoothing.
Upvotes: 1
Views: 168