skip to Main Content

I’ve written a function for my little JavaScript project that prints text to a div akin to a dialog in an old-school game. I’ve included the code for this function in the snippet below, although I believe it’s not really crucial for my question:

When I use this function, when a word is too long to fit in a line, the first few letters often are printed in the current line. Then the word jumps to another line and is finished there. This causes a rather unpleasant effect.

My question is, can I prevent this kind of behaviour through JS or CSS? Is there a way for the function to know in advance that the new word won’t fit in the current line and start printing it in a new line from the beginning, thus avoiding the jump?

I tried various word-wrap settings for the target div, but to no avail. I don’t really know which CSS property is responsible for this kind of behaviour. Thanks for your help.

I want to get rid of word jumping in words like ‘demonstrates’ or ‘effect’. I would like them to be printed to a new line from the beginning.

Code Snippet
(also on JSFiddle)

async function echo(targetId, msg) {
  let txtTarget = document.getElementById(targetId);
  for (let i = 0; i < msg.length; i++) {
    txtTarget.innerHTML += msg[i];
    txtTarget.scrollTop = txtTarget.scrollHeight;
    await this.sleep(55);
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const myMsg = 'This is a test message. I hope it clearly demonstrates what I'm asking for. I want to get rid of the words jumping to new line effect. Instead, I want the words to be printed in a new line from the very beginning, if they're not going to fit in the current line.';

echo('message-box', myMsg);
body {
  background: black;
  color: ghostwhite;
}

#message-box {
  width: 300px;
  height: 200px;
  border: 2px solid ghostwhite;
}
<div id="message-box"></div>

2

Answers


  1. This method utilizes two elements. One is pre-filled with the entire message but uses transparent text. As each character is added to the "visible" element, the first character of the "invisible" element is removed. This back-fill prevents would-be-wrapped words from appearing on the wrong line.

    async function echo(targetId, msg) {
        let txtTarget = document.getElementById(targetId);
        
        let visible = document.createElement('span');
        let invisible = document.createElement('span');
        
        invisible.style.color = 'transparent';
        
        txtTarget.appendChild(visible);
        txtTarget.appendChild(invisible);
        
        invisible.innerHTML = msg;
    
        for (let i = 0; i < msg.length; i++) {
            visible.innerHTML += msg[i];
            invisible.innerHTML = invisible.innerHTML.substring(1);
            txtTarget.scrollTop = txtTarget.scrollHeight;
            await this.sleep(55);
        }
    }
    
    function sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    const myMsg = 'This is a test message. I hope it clearly demonstrates what I'm asking for. I want to get rid of the words jumping to new line effect. Instead, I want the words to be printed in a new line from the very beginning, if they're not going to fit in the current line.';
    
    echo('message-box', myMsg);
    body {
      background: black;
      color: ghostwhite;
    }
    
    #message-box{
      width: 300px;
      height: 200px;;
      border: 2px solid ghostwhite;
    }
    <div id="message-box"></div>
    Login or Signup to reply.
  2. A simple (simplistic?) way would be to have just one instance of the string, in place, but in a span with opacity 0. Then on each clock tick move the span one character along.

    const div = document.querySelector('div');
    const string = "This is a test message. I hope it clearly demonstrates what I'm asking for. I want to get rid of the words jumping to new line effect. Instead, I want the words to be printed in a new line from the very beginning, if they're not going to fit in the current line.";
    const l = string.length;
    div.innerHTML = '<span>' + string + '</span>';
    let i = 0;
    const interval = setInterval(function() {
        i++;
        if (i >= l) clearInterval(interval);
        div.innerHTML = string.substring(0, i) + '<span>' + string.substring(i, string.length) + '</span>';
      },
      55);
    #message-box span {
      opacity: 0;
    }
    
    body {
      background: black;
      color: ghostwhite;
    }
    
    #message-box {
      width: 300px;
      height: 200px;
      border: 2px solid ghostwhite;
    }
    <style>
      #message-box span {
        opacity: 0;
      }
      
      body {
        background: black;
        color: ghostwhite;
      }
      
      #message-box {
        width: 300px;
        height: 200px;
        border: 2px solid ghostwhite;
      }
    </style>
    <div id="message-box"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search