main
.phone
ul.message-list(aria-label='A list of random messages from a simulated server, styled to resemble a smartphone.' aria-live='polite' aria-relevant='additions')
.text
h1 408 — Request Timeout
p The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.
View Compiled
body
font-family 'space mono', monospace
font-size 16px
color #333
background-color ghostwhite
.phone
max-width 15em
margin 3em auto
background-color currentcolor
padding 1em 0.5em
border-radius 1em
box-shadow 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)
.message-list
height 20em
overflow hidden
background white
margin 1em auto
list-style none
padding 0.5em
border-radius 0.1em
display flex
flex-direction column
justify-content flex-end
.message
display flex
align-items flex-end
flex-shrink 0
margin-bottom 1em
animation fadein 400ms
.message__text
background-color dodgerblue
padding 0.5em 1em
color rgba(255, 255, 255 0.9)
border-radius 1em
.message__avatar
flex-shrink 0
width 2em
height 2em
text-align center
margin-right 0.5em
border-radius 2em
display flex
flex-direction column
justify-content center
background-color lavender
.text
width 27em
margin 0 auto
.visually-hidden
clip rect(1px, 1px, 1px, 1px)
height 1px
overflow hidden
position absolute
white-space nowrap
width 1px
@media (prefers-reduced-motion: reduce)
*
animation none !important
transition none !important
@keyframes fadein
0%
opacity 0
50%
opacity 0
100%
opacity 1
View Compiled
const messages = [
'hey',
'heyy',
'heyyy',
"what's up?",
'you there??',
"how's it going?",
'so...',
'anybody home?',
'just checking in',
"what's going on?",
'you around?',
'let me know when you get this',
'did you get my message?',
'knock knock',
];
const messageList = document.querySelector('.message-list');
function randomMessage() {
const i = Math.floor(Math.random() * messages.length);
return messages[i];
}
function buildMessage(message) {
const li = document.createElement('li');
li.classList.add('message');
const avatar = document.createElement('div');
avatar.classList.add('message__avatar');
avatar.setAttribute('aria-hidden', 'true');
avatar.appendChild(document.createTextNode('🖥️'));
const messageEl = document.createElement('div');
messageEl.classList.add('message__text');
const hiddenText = document.createElement('span');
hiddenText.classList.add('visually-hidden');
hiddenText.appendChild(document.createTextNode('Message from server: '));
messageEl.appendChild(hiddenText);
messageEl.appendChild(document.createTextNode(message));
li.appendChild(avatar);
li.appendChild(messageEl);
return li;
}
function scrollToBottom(animate) {
if (animate) {
const distance = messageList.scrollHeight - messageList.scrollTop;
const steps = 10;
const step = distance / steps;
for (let i = 0; i <= steps; i++) {
setTimeout(() => {
messageList.scrollTop = messageList.scrollTop + (i * step);
}, 50 * i);
}
}
else {
messageList.scrollTop = messageList.scrollHeight;
}
}
function showMessage(infinite) {
const message = randomMessage();
messageList.appendChild(buildMessage(message));
scrollToBottom(infinite);
if (infinite) {
const delay = Math.random() * 2000 + 2000;
setTimeout(() => showMessage(true), delay);
}
}
const motionQuery = matchMedia('(prefers-reduced-motion: reduce)');
function handleReduceMotionChanged() {
const animate = !motionQuery.matches;
if (animate) {
showMessage(true);
}
else {
showMessage(false);
showMessage(false);
showMessage(false);
showMessage(false);
showMessage(false);
showMessage(false);
showMessage(false);
}
}
handleReduceMotionChanged();
motionQuery.addListener(handleReduceMotionChanged);
This Pen doesn't use any external JavaScript resources.