Jack Guy
Jack Guy

Reputation: 8523

Pixel filter HTML elements CSS

I'm creating a game using WebGL. I'm currently working on menu design, and it occured to me that one of the great advantages I have in using web technologies is that I can use HTML for the GUI.

The game uses pixel art, so in keeping with that art style I want the menu to have pixelated buttons and text as well. I'm wondering if using CSS filters or something similar I'm able to pixelate my rendering of DOM elements, or if I'll need to create full button images beforehand (much less appealing).

Thanks!

Upvotes: 1

Views: 1371

Answers (1)

Quinn Keaveney
Quinn Keaveney

Reputation: 1604

You can use SVG filters to achieve this.

image showing pixelation effect

<svg>
  <filter id="pixelateStr4" x="0" y="0" width="100%" height="100%">

    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="16" height="16"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="8" result="dilatedPixelation"></femorphology>

    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="8" height="16"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="8" result="dilatedFallbackX"></femorphology>

    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="16" height="8"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="8" result="dilatedFallbackY"></femorphology>

    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
</svg>

and apply it to an overlay with CSS

.overlay{
    backdrop-filter: url(#pixelateStr3);
}

Bellow is the full snippit

.imgAni {
  -webkit-animation: pixelAni 5s;
          animation: pixelAni 5s;
}
.img1 {
  -webkit-backdrop-filter: url("#pixelateStr1");
          backdrop-filter: url("#pixelateStr1");
}
.img2 {
  -webkit-backdrop-filter: url("#pixelateStr2");
          backdrop-filter: url("#pixelateStr2");
}
.img3 {
  -webkit-backdrop-filter: url("#pixelateStr3");
          backdrop-filter: url("#pixelateStr3");
}
.img4 {
  -webkit-backdrop-filter: url("#pixelateStr4");
          backdrop-filter: url("#pixelateStr4");
}
.img5 {
  -webkit-backdrop-filter: url("#pixelateStr5");
          backdrop-filter: url("#pixelateStr5");
}
.img6 {
  -webkit-backdrop-filter: url("#pixelateStr6");
          backdrop-filter: url("#pixelateStr6");
}
.img7 {
  -webkit-backdrop-filter: url("#pixelateStr7");
          backdrop-filter: url("#pixelateStr7");
}
.filter {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  pointer-events: none;
}
.content {
  position: relative;
  width: 25vw;
  height: 50vh;
  float: left;
  background: #ff0;
}
.content h1 {
  font-size: 4.5vw;
  padding: 2vw;
  z-index: 2;
  position: relative;
  color: #00f;
  font-family: monospace;
  margin: 0;
}
.content span {
  background: #f00;
  border-radius: 50%;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 50%;
  height: 50%;
  z-index: 1;
}
@-webkit-keyframes pixelAni {
  99.9% {
    -webkit-backdrop-filter: url("#pixelateAni");
            backdrop-filter: url("#pixelateAni");
  }
}
@keyframes pixelAni {
  99.9% {
    -webkit-backdrop-filter: url("#pixelateAni");
            backdrop-filter: url("#pixelateAni");
  }
}


html,body{padding:0;margin:0;}
<div class="content">
  <div class="filter imgAni"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<div class="content">
  <div class="filter img1"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<div class="content">
  <div class="filter img2"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<div class="content">
  <div class="filter img3"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<div class="content">
  <div class="filter img4"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<div class="content">
  <div class="filter img5"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<div class="content">
  <div class="filter img6"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<div class="content">
  <div class="filter img7"></div>
  <h1 contenteditable="true">HOW Pixel ATED?</h1><span></span>
</div>
<svg>
  <filter id="pixelateAni" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="2" height="2"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="1" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="1" height="2"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="1" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="2" height="1"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="1" result="dilatedFallbackY"></femorphology>
    <animate calcmode="discrete" xlink:href="#composite" attributename="width" values="128; 64; 32; 16; 8; 4; 2" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#composite" attributename="height" values="128; 64; 32; 16; 8; 4; 2" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#morphology" attributename="radius" values="64; 32; 16; 8; 4; 2; 1" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#compositeX" attributename="width" values="64; 32; 16; 8; 4; 2; 1" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#compositeX" attributename="height" values="128; 64; 32; 16; 8; 4; 2" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#morphologyX" attributename="radius" values="64; 32; 16; 8; 4; 2; 1" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#compositeY" attributename="width" values="128; 64; 32; 16; 8; 4; 2" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#compositeY" attributename="height" values="64; 32; 16; 8; 4; 2; 1" dur="5s" fill="freeze" repeatcount="once"></animate>
    <animate calcmode="discrete" xlink:href="#morphologyY" attributename="radius" values="64; 32; 16; 8; 4; 2; 1" dur="5s" fill="freeze" repeatcount="once"></animate>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
  <filter id="pixelateStr7" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="128" height="128"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="64" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="64" height="128"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="64" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="128" height="64"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="64" result="dilatedFallbackY"></femorphology>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
  <filter id="pixelateStr6" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="64" height="64"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="32" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="32" height="64"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="32" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="64" height="32"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="32" result="dilatedFallbackY"></femorphology>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
  <filter id="pixelateStr5" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="32" height="32"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="16" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="16" height="32"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="16" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="32" height="16"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="16" result="dilatedFallbackY"></femorphology>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
  <filter id="pixelateStr4" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="16" height="16"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="8" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="8" height="16"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="8" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="16" height="8"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="8" result="dilatedFallbackY"></femorphology>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
  <filter id="pixelateStr3" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="8" height="8"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="4" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="4" height="8"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="4" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="8" height="4"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="4" result="dilatedFallbackY"></femorphology>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
  <filter id="pixelateStr2" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="4" height="4"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="2" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="2" height="4"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="2" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="4" height="2"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="2" result="dilatedFallbackY"></femorphology>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
  <filter id="pixelateStr1" x="0" y="0" width="100%" height="100%">
    <!-- First layer: Normal pixelation effect-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="composite" in2="SourceGraphic" operator="in" width="2" height="2"></fecomposite>
    <fetile result="tiled"></fetile>
    <fecomposite in="SourceGraphic" in2="tiled" operator="in"></fecomposite>
    <femorphology id="morphology" operator="dilate" radius="1" result="dilatedPixelation"></femorphology>
    <!-- Second layer: Fallback with full-width tiling-->
    <feflood x="1" y="1" height="1" width="1" result="floodFallbackX"></feflood>
    <fecomposite id="compositeX" in2="SourceGraphic" operator="in" width="1" height="2"></fecomposite>
    <fetile result="fullTileX"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileX" operator="in"></fecomposite>
    <femorphology id="morphologyX" operator="dilate" radius="1" result="dilatedFallbackX"></femorphology>
    <!-- Third layer: Fallback with full-height tiling-->
    <feflood x="1" y="1" height="1" width="1"></feflood>
    <fecomposite id="compositeY" in2="SourceGraphic" operator="in" width="2" height="1"></fecomposite>
    <fetile result="fullTileY"></fetile>
    <fecomposite in="SourceGraphic" in2="fullTileY" operator="in"></fecomposite>
    <femorphology id="morphologyY" operator="dilate" radius="1" result="dilatedFallbackY"></femorphology>
    <!-- Combine all three layers-->
    <femerge>
      <femergenode in="dilatedFallbackX"></femergenode>
      <femergenode in="dilatedFallbackY"></femergenode>
      <femergenode in="dilatedPixelation"></femergenode>
    </femerge>
  </filter>
</svg>

Here is a codepen showing this in practice (https://codepen.io/QuiteQuinn/pen/KKOVvrN)

Upvotes: 0

Related Questions