skip to Main Content

I’m creating a terminal-like app with JS. I want to be able to change the color of individual characters, so I decided to use a lot of spans to display them. Each span contains only one character. This is what I ended up with. It works fine, but I want the "span screen" (green outline) to fit the screen as much as it can. It should scale but keep ascpect ratio. I posted the code on CodePen.

I tried changing the size of the div that contains spans, but it didn’t help. Then I tried changing the font size of spans, but it didn’t help either. Maybe there’s a better way to accomplish it all.

UPDATE: This is how it is now, and this is how it should be.

Here’s the code:

document.addEventListener("DOMContentLoaded", draw);

function draw() {
  game = document.getElementById("game");
  for (y = 0; y <= 25; y++) {
    for (x = 0; x <= 100; x++) {
      cell = document.createElement("span");
      cell.innerText = "1";
      game.appendChild(cell);
    }
    game.appendChild(document.createElement("br"));
  }
}
* {
  margin: 0;
  padding: 0;
  border: 0;
}

html {
  min-height: 100vh;
}

body {
  min-height: 100vh;
  box-shadow: 0px 0px 0px 10px red inset;
  display: flex;
  justify-content: center;
  align-items: center;
}

#game {
  box-shadow: 0px 0px 0px 10px green inset;
}

span {
  font-family: Cascadia Code;
}
<div id='game'></div>

3

Answers


  1. I am struggling to understand your issue, but I think you are trying to lay out the numbers in a grid of 101 by 25 inside a container of unknown width. If you set the width of each span to calc(100%/101), you should be able to accomplish it.

    #game {
      box-shadow: 0px 0px 0px 10px green inset;
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
    }
    
    span {
      font-family: Cascadia Code;
      width: calc(100%/101);
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    Login or Signup to reply.
  2. Could you use a grid?
    If it’s a game the good thing is after you can address each cell by row and col.

    let str = '';
    for (let i = 0; i < 25; i++) {
      for (let j = 0; j < 100; j++) {
        str += '<div>1</div>';
      }
    }
    document.querySelector('#game').innerHTML = str;
    *,
    *:before,
    *:after {
      box-sizing: border-box;
    }
    
    body {
      margin: 0;
      padding: 0;
    }
    
    #gameWrapper {
      position: relative;
      width: 100vw;
      height: 100vh;
    }
    
    #game {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      display: grid;
      grid-template-rows: repeat(25, auto);
      grid-template-columns: repeat(100, 1fr);
      gap: 0;
      width: 100%;
    }
    
    #game {
      box-shadow: 0px 0px 0px 10px green inset;
    }
    <div id="gameWrapper">
      <div id="game">
      </div>
    </div>
    Login or Signup to reply.
  3. Getting HTML elements to scale exactly can be tricky.

    But SVG’s are designed to be scaled, so if yo build your terminal inside an SVG things become much easier.

    Below is a working snippet, I’ve adjusted the Row & Cols to just fit nicer inside a SO Snippet. You can also make the SVG scale X & Y with the preserveAspectRatio attribute, click the SVG to see the difference.

    const tw = 10;
    const th = 12;
    
    const numCols = 40;
    const numRows = 20;
    
    
    function getNode(n, v) {
      n = document.createElementNS("http://www.w3.org/2000/svg", n);
      for (var p in v)
        n.setAttributeNS(null, p, v[p]);
      return n
    }
    
    function draw() {
      const svg = getNode('svg', {
        viewBox: `0 0 ${tw*numCols} ${th*numRows}`});
      svg.style.display = 'block';
      for (y = 0; y <= numRows; y++) {
        for (x = 0; x <= numCols; x++) {
          cell = getNode('text', {
            alignmentAaseline:"hanging",
            textAnchor:"start",
            x: x * tw,
            y: y * th,
            class: 'cell',
           });
          cell.innerHTML = (x+y)%10;
          svg.appendChild(cell);
        }
      }
      game.appendChild(svg);
      
      svg.addEventListener('click', () => {
        const p = svg.getAttribute('preserveAspectRatio');
        svg.setAttribute('preserveAspectRatio', 
           p === 'none' ? '' : 'none');
      });
    }
    
    draw();
    * {
      margin: 0;
      padding: 0;
      border: 0;
    }
    
    .cell {
      font-family: courier;
    }
    
    svg {
      display: block;
      width: 100vw;
      height: 100vh;
    }
    <div id='game'>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search