Причина, по которой это происходит, заключается в том, что вы не учитываете случайный размер ребенка.
var size = Math.floor(Math.random() * 101) + 50;
Эта строка может иметь размер до 150.
var top = Math.floor(Math.random() * 301);
В этой строке можно установить максимум 300.
Родительский div имеет высоту только 400px, поэтому, если размер вычисляется на 150, а верхний на 300, дочерний элемент переполняет родительский на нижний на 50px. Аналогичная ситуация возникает при установке left, что приведет к переполнению дочернего элемента справа от родительского элемента. Вам нужно ограничить сверху и слева. Пример ниже.
function makeShapeAppear() {
var size = Math.floor(Math.random() * 101) + 50;
var top = Math.min(Math.floor(Math.random() * 101), 180 - size);
var left = Math.min(Math.floor(Math.random() * 301), 400 - size);
document.getElementById("shape").style.display = "block"
document.getElementById("shape").style.top = top + "px";
document.getElementById("shape").style.left = left + "px";
document.getElementById("shape").style.width = size + "px";
document.getElementById("shape").style.height = size + "px";
document.getElementById("shape").style.backgroundColor = "red";
setTimeout(function() { makeShapeAppear(); }, 1000);
}
makeShapeAppear();
#box {
width: 400px;
height: 180px;
background-color: grey;
margin: 0;
padding: 0;
}
#shape {
display: none;
position: relative;
}
<div id="box">
<div id="shape"></div>
</div>