Scroll to the bottom doesn't work due to font link - javascript

Can someone please explain what's going on here?
As you can see in the example, the scroll does not go all the way down to the bottom
This is of course a problem as it does not behave according to the instructions, which is:
scrollIntoView() or target.scroll (0, target.scrollHeight - target.clientHeight);
Strangely enough, it has something to do with the "font link" in "<head>", because if I use any font other than the one that has been downloaded (Poppins), it works
var html_1 = '<div class="chat_window"><div class="messages"></div></div>';
var html_2 = '<div>hello buddy</div>';
document.body.insertAdjacentHTML('beforeend', html_1);
var target = document.querySelector('.chat_window').querySelector('.messages');
for(var i = 0; i < 9; i++) {
target.insertAdjacentHTML('beforeend', html_2);
//target.scroll(0, target.scrollHeight - target.clientHeight);
target.lastElementChild.scrollIntoView();
}
body
{
font-family: Poppins; /*here, because of this the problem arise*/
}
.chat_window
{
height: 113px;
width: 339px;
border: 1px solid black;
}
.chat_window .messages
{
height: 100%;
overflow: auto;
}
<head>
<link href="http://fonts.googleapis.com/css?family=Poppins:400,300,500,600,700" rel="stylesheet">
</head>
<body></body>

The problem is the time needed to dynamically render the HTML and load the font. There are a few options, but might be seen as a little hacky.
Make sure you are using the same font somewhere else on the page. This will cause the browser to load the font (otherwise the browser may ignore the font until it is needed)
Delay the scroll a little after you render the HTML with JavaScript.
A minor change like this could work:
var html_1 = '<div class="chat_window"><div class="messages"></div></div>';
var html_2 = '<div>hello buddy</div>';
document.body.insertAdjacentHTML('beforeend', html_1);
var target = document.querySelector('.chat_window').querySelector('.messages');
for(var i = 0; i < 9; i++) {
target.insertAdjacentHTML('beforeend', html_2);
}
// A short delay, then jump to last item.
setTimeout(function(){
target.scroll(0, target.scrollHeight - target.clientHeight);
target.lastElementChild.scrollIntoView();
},500);
body{
font-family: Poppins;
}
.chat_window{
height: 113px;
width: 339px;
border: 1px solid black;
}
.chat_window .messages{
height: 100%;
overflow: auto;
}
<head>
<link href="http://fonts.googleapis.com/css?family=Poppins:400,300,500,600,700" rel="stylesheet">
</head>
<body>(forcing the font to load)</body>

Related

children of element with column-width move around when clicked with a <body> of a certain size

I cannot manage to reproduce the problem in fiddle.
The problem occurs when is exactly 1286px wide (in the inspector), but it might also happen at other widths.
Clicking the elements changes the height of the body, from 86 to 85.9833.
https://i.imgur.com/rGJPFyW.png
https://gfycat.com/acidicmarvelousabyssiniancat
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
body {font-family: monospace; background: #222; color:#aaa;}
html{scrollbar-color: grey black;}
#ui_tags{
column-width: 80px;
margin: 1em;
padding: 1em;
background-color: #181818;
/*width: 90%;*/
}
.tag_select {
cursor:pointer;
color:#aaa;
}
.tag_select:hover {
background: #222;
}
.tag_select:active {
background: #f00;
}
p {margin-bottom:1px;margin-top:1px;}
</style>
<body>
<div id="ui">
<div id="ui_tags"><p class="tag_select">4ch:114</p><p class="tag_select">avtr:54</p><p class="tag_select">awe:53</p><p class="tag_select">btfl:211</p><p class="tag_select">cat:319</p><p class="tag_select">charc:19</p><p class="tag_select">cmc:145</p><p class="tag_select">dung:15</p><p class="tag_select">frnc:53</p><p class="tag_select">fun:5</p><p class="tag_select">inspr:192</p><p class="tag_select">lego:16</p><p class="tag_select">lndsc:63</p><p class="tag_select">mchn:5</p><p class="tag_select">meh:42</p><p class="tag_select">mnstr:87</p><p class="tag_select">pgrmh:62</p><p class="tag_select">pltc:239</p><p class="tag_select">ppl:22</p><p class="tag_select">pxlr:72</p><p class="tag_select">shrlt:79</p><p class="tag_select">txl:145</p><p class="tag_select">urbn:6</p><p class="tag_select">vlgr:135</p><p class="tag_select">wrd:23</p>
</div>
</div>
<div id="gallery">
</div>
<script type="text/javascript">
window.onload = function(){
var tag_selects = document.getElementsByClassName("tag_select");
for(var i = 0, size = tag_selects.length; i < size ; i++){
// var elem = tag_selects[i].children[1];
var elem = tag_selects[i];
elem.addEventListener("click", function(event){
char = this.innerHTML;
document.getElementById('gallery').innerHTML = char;
});
}
}
</script>
</body>
</html>
I don't know if I'm using bad practices, or how to avoid this problem. I think column-width is not really stable and should be avoided but I'm not sure.
I modified the <p> to <span> and the problem went away.

Using css/js to force div to width of X chars?

I'm working on a page that recieves a large string, 500*500 characters (initially all spaces, ' '). I then render this with a monospace font into a <div>, with width and height set to 500ch.
let text = "";
let char = ' ';
for (var i = 0; i < 500 * 500; i++) {
if (!(i % 500)) {
char = '|'
}
text += char;
char = ' ';
}
document.getElementById('text').innerHTML = text;
:root {
--pwidth: 500ch;
}
body {
background-color: #111111;
}
div {
position: absolute;
left: 0;
top: 0;
padding: none;
font-family: "Lucida Console", "Courier New", monospace;
font-size: 14;
margin: none;
width: var(--pwidth);
color: #EEEEEE;
resize: none;
display: block;
white-space: break-spaces;
overflow-wrap: anywhere;
border: none;
}
<div id="text"></div>
The result is odd. The string index of every line should be an even number: 0, 500, 1000 (...)
However the rendered result is something like this:
|0
|500
|1000
|1500
|2000
|2500
|3000
|3500
|4000
|4500
This doesn't happen in Firefox, but on Chrome and Edge it does. It is as if the browsers decide to break the line prematurely. Is there any way to achieve the desired effect on atleast the popular browsers?
The problem does not occur when run as a SO snippet apparently.
My suspicion therefore is that the code as run elsewhere does not correctly set up a Doctype. SO snippets tend to have such 'missing bits' added automatically.
I have run the following code on Chrome/Edge/Firefox on Windows 10 and all give a 'vertical straight line' of As down the left hand side, ie the expected result.
However, if I remove the <!DOCTYPE html> Chrome and Edge layout mainly diagonally, with the odd 'blip' of two As vertically above each other. I suspect in those cases you are getting some additive rounding errors, but I can't prove it.
In the StackOverflow environment, a doctype will be added so you don't see the problem.
Here's the code that runs OK outside the SO environment. Note the original given code has several errors ('none' is not OK value for padding or margin for example) but these did not affect the final result.
<!DOCTYPE html>
<html>
<head>
<style>
:root {
--pwidth: 500ch;
--pheight: 500ch;
}
body {
background-color: #111111;
top: 0;
padding: 0;
font-family: Courier, monospace;
font-size: 14;
margin: 0;
width: var(--pwidth);
height: var(--pheight);
height: auto;
resize: none;
display: block;
white-space: break-spaces;
overflow-wrap: anywhere;
border: none;
}
#text {
background: pink;
}
</style>
</head>
<body>
<div id="text"></div>
<script>
const textEl = document.querySelector('#text');
let str = '';
for (let i = 0; i< 500; i++) { str += 'A'; for (j = 0; j<499 ; j++) {str +=' '; }}
textEl.innerHTML = str;
</script>
</body>
</html>

DOM nodes styles which have been manually fiddled with get invalidated if any parent style changes

Please, take a look at this fiddle (I am using Vue.js to generate lots of DOM nodes here, but my question doesn't seem to be a Vue related issue): https://jsfiddle.net/dmaevsky/kswj23r1/117/ .
When I am monitoring performance using Chrome's performance tool while pressing the button in a rapid succession, I am seeing 42ms 'Update Layer Tree' rendering delay, which makes sense, since the stuff is moving on page, so why not (I am still wondering btw whether there's a way to eliminate this).
However, things get awry when I uncomment the line 30, thus manually setting the td's styles in Javascript:
//nr = 50, nc = 50;
for (let i = 0; i < nr; i++) {
for (let j = 0; j < nc; j++) {
this.$refs[i + ':' + j][0].style.color = 'blue';
}
}
When I now monitor the performance I see all 2500 TD nodes added to the "Recalculating styles" in Chrome when 'Shift down' button is pressed. I just cannot see why that would make any sense ? Using a class instead of setting styles manually does not cause this to happen.
This is just an attempt to understand the browser's style invalidation logic, not a real application, so the number of DOM nodes here is intentionally kept higher than one would reasonably need in a real world application, though close enough.
UPDATE:
This actually DOES seem to be a Vue.js issue finally. I have re-written the code in pure JS (complete HTML below), and I do not observe the same effect anymore.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Create table test</title>
<style>
body {
font-family: Helvetica;
}
#app {
background: #fff;
padding: 20px;
}
#app {
position: relative;
}
#pane {
position: absolute;
}
.table {
table-layout: fixed;
border-collapse: collapse;
margin: 0;
padding: 0;
border: hidden;
width: 8000px;
height: 1600px;
}
.cell {
width: 100px;
height: 20px;
line-height: 16px;
box-sizing: border-box;
padding: 2px;
background: white;
overflow: hidden;
}
</style>
</head>
<body>
<noscript>
<strong>Need JS</strong>
</noscript>
<button onclick="shift()">Shift down</button>
<div id="app">
<div id="pane"></div>
</div>
</body>
</html>
<script>
var pos = 0;
function shift() {
pos++;
document.getElementById('pane').style.top = pos + 'px';
}
function createTable(nr, nc) {
let table = document.createElement('table');
table.className = 'table';
for (let i = 0; i < nr; i++) {
let tr = document.createElement('tr');
for (let j = 0; j < nc; j++) {
let td = document.createElement('td');
let span = document.createElement('span');
span.innerHTML = i + j;
td.className = 'cell';
td.style.color = 'blue';
td.appendChild(span);
tr.appendChild(td);
}
table.appendChild(tr);
}
return table;
}
document.getElementById('pane').appendChild(createTable(80, 80));
</script>
Question to Vue.js experts then: what does Vue do to DOM to warrant the observed behavior in the first fiddle???

How to stop an element to touch screen border?

I am beginner to JS and I am trying to create a simple game in it. I am looking for a way to stop the player (20px x 20px) box causing the screen to scroll, i am looking for a fixed screen where the player cannot exceed the sides of the screen. Please see previous attempts below.
HTML :
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="Style.css">
</head>
<body>
<div id="player"></div>
<script type="text/javascript" src="Script.js"></script>
</body>
</html>
CSS:
body{
margin: 0;
padding: 0;
background-color: red;
}
#player{
border-radius: 30%;
padding: 0px;
margin: 0px;
background-color: white;
width: 20px;
height: 20px;
position: absolute;
}
JavaScript:
var player = document.getElementById("player")
var pros = {'top': 0, 'left': 0, 'speed': 10}
var ws = {'h': screen.height, 'w': screen.width}
document.addEventListener("keydown", function(event){
var keyP = event.key;
if(keyP === "ArrowDown"){
pros.top = pros.top + pros.speed;
}else if(keyP === "ArrowUp"){
pros.top = pros.top - pros.speed;
}else if(keyP === "ArrowLeft"){
pros.left = pros.left - pros.speed;
}else if(keyP === "ArrowRight"){
pros.left = pros.left + pros.speed;
}
if(pros.top < 0){
pros.top = 0;
}else if(pros.top > ws.h){
pros.top = ws.h;
}else if(pros.left < 0){
pros.left = 0;
}else if(pros.left > ws.w){
pros.left = ws.w;
}
player.style.top = `${pros.top}px`;
player.style.left = `${pros.left}px`;
});
Now, I want the element to never escape the given screen area. As you can see in the code that I have tried to use screen.height/screen.width to control it but still it escapes the area and the scroll bars get activated even in the full screen mode. It looks too messy for a game.
Here is picture of how it escapes the area:
In Full Screen Mode :
Without Full Screen Mode :
The most accurate position and dimensions measurements are available via the getBoundingClientRect() function.
So at the top of your keystroke callback I'd add two lines:
var screenRect = document.body.getBoundingClientRect();
var playerRect = player.getBoundingClientRect();
These need to be calculated at every iteration in order to make sure that the "game" adapts to every screen change. Also any position increments are better calculated in percents of the screen size rather than static pixel values.
Your screen edge check should be rewritten like this:
if(playerRect.top < 0){
pros.top = 0;
} else if(playerRect.top + playerRect.height > screenRect.height){
// make sure the bottom edge of the player doesn't go over the bottom edge of the screen
pros.top = screenRect.height - playerRect.height;
}
if(playerRect.left < 0){
pros.left = 0;
} else if(playerRect.left + playerRect.width + > screenRect.width){
// make sure the right edge of the player doesn't go over the right edge of the screen
pros.left = screenRect.width - playerRect.width;
}
On the CSS side, try the following:
body{
margin: 0;
padding: 0;
background-color: red;
width: 100vw;
height: 100vh;
overflow: hidden;
}
#player{
border-radius: 30%;
padding: 0px;
margin: 0px;
background-color: white;
width: 20px;
height: 20px;
position: fixed;
}
The height and width of your PLAYER object is 20px as concluded from the Stylesheet that you have provided.
If you place your element on a 2D plane, then it's coordinates will be the point where its TOP-LEFT corner lie. Focus here.
So, your JavaScript should change to this:
...
if(pros.top < 0){
pros.top = 0;
}else if(pros.top > ws.h-20){ // changed here
pros.top = ws.h-20; // try playing with the value here
}else if(pros.left < 0){
pros.left = 0;
}else if(pros.left > ws.w-20){ //changed here
pros.left = ws.w-20; // try playing with the value here
}
...
This would always place the #player element 20px inside on the horizntal axis and 20px on the vertical axis. I was successful in limiting the appearance of the horizontal scroll-bar but the vertical vanished only for a value of ws.h-40.
Hope this helps.
Hey :) Maybe this helps you:
<style type="text/css">
body {
overflow:hidden;
}
</style>
Setting the overflow: hidden will hide the scrollbar.

How to stack div elements using JavaScript

I am trying to create a checker board using pure JavaScript, not jQuery.
I have created the first row, but cannot seem to "stack" the rows to create a full board. If there is a better way to go about this than the road I'm going down, please enlighten me.
<!DOCTYPE html>
<html>
<head>
<title>Checkerboard</title>
<style>
.box {
height: 50px;
width: 50px;
border: 1px solid black;
display: inline-block;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
<script type="text/javascript">
var row = function (node, count) {
for (var i = 1; i < count; i++) {
if (i % 2 === 0) {
copy = node.cloneNode(true);
node.parentNode.insertBefore(copy, node).style.backgroundColor = "white";
} else {
copy = node.cloneNode(true);
node.parentNode.insertBefore(copy, node).style.backgroundColor = "red";
}
}
}
row(document.querySelector('.box'), 8);
</script>
</html>
Your code works fine, you just need to actually run the function you've created:
row(document.getElementsByClassName("box")[0], 50);
JSFiddle: http://jsfiddle.net/63dcjsk4/
Edit
If you're talking about the gap that appears between rows, fix this by using float and removing the inline-block display:
.box {
border: 1px solid black;
height: 50px;
float: left;
width: 50px;
}
JSFiddle: http://jsfiddle.net/63dcjsk4/1/

Categories