Reputation: 753
I'm trying to style a basic chat app, nothing too fancy or over the top, but I'm running into a few issues. There are three goals that I have with styling:
This is the code I have thus far:
const API_URL = "http://localhost:3000"
const form = document.querySelector("form")
const chatbox = document.querySelector(".chatbox")
const chatInput = document.querySelector(".message-input")
const socket = io.connect(API_URL)
socket.on("chat-message", (data) => {
console.log(data)
appendMessage("other-message", data)
})
socket.on("disconnect", (reason) => {
socket.emit("disconnect", reason)
});
form.addEventListener("submit", e => {
e.preventDefault()
console.log("message: ", chatInput.value)
const message = chatInput.value
appendMessage("message", message)
socket.emit("send-chat-message", message)
form.reset()
})
function appendMessage(className, message){
const div = document.createElement('div')
div.append(message)
div.className = className
chatbox.append(div)
}
.wrapper{
display: grid;
grid-template-columns: 1fr 2fr;
height: 100vh;
width: 100vw;
}
.side-bar{
background-color: blue;
color: gray;
text-align: left;
padding: 20px;
font-size: 50px;
}
.chat-room:hover{
cursor: pointer;
color: white;
}
.messages-container{
display: grid;
grid-template-columns: auto;
grid-template-rows: auto 40px;
}
.chatbox{
background-color: black;
border: 1px solid white;
overflow: scroll;
}
.chatbox > div{
border-radius: 15px;
padding: 10px;
margin: 20px;
color: white;
width: fit-content;
max-width: 50%;
}
.message{
background-color: blue;
}
.other-message{
background-color: gray;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>chat</title>
</head>
<body>
<div class = "wrapper">
<div class="side-bar">
<div class="name">
</div>
<div class="chat-room">
<h3>#chat room 1</h3>
</div>
<div class="chat-room">
<h3>#chat room 2</h3>
</div>
<div class="chat-room">
<h3>#chat room 3</h3>
</div>
<div class="chat-room">
<h3>#lifetime chat</h3>
</div>
</div>
<div class="messages-container">
<!-- Chat messages will be appended here! -->
<div class="chatbox">
</div>
<form>
<input type="text" class="message-input form-control" required name="send-message" placeholder="Send message" aria-label="Recipient's username" aria-describedby="basic-addon2">
</form>
</div>
</div>
<script src="https://cdn.socket.io/socket.io-3.0.1.min.js"></script>
<script src="sendMessage.js"></script>
</body>
</html>
The issues I'm having currently is that whenever I the amount of messages exceeds the height of the "chat" div in the HTML file, the div does not overflow, and instead grows indefinitely. I'm not sure what's causing this, even though I added the code for overflow: scroll;
in the css for that particular div. Also, I'm not sure how to push the messages to the bottom of the div as opposed to the top, and have each new one push the previous one up.
Are there any css tricks I can use to accomplish those three goals?
Upvotes: 3
Views: 1579
Reputation: 20944
CSS Grid has this little quirk that grid children have a min-height
and min-width
set to auto
. This will cause the grid to stretch whenever the content exceeds the container. Setting min-height: 0;
will prevent this behavior and allow the overflow to happen.
Read this SO answer for more details.
I've added an inner container to your chatbox
element. The chatbox
element now functions as an overflow wrapper. The inner element will be the wrapper of the chat messages. Since you want the messages to appear at the bottom you'll need to push this inner element down so that it will keep the messages at the bottom of the screen. The pushing down can be accomplished with display: grid;
and align-items: end;
. Flexbox seemed like a better candidate, but it disabled the ability to scroll. Grid does not.
Within the inner element use Flexbox to position a chat message either left or right and in a column formation.
Finally after appending each message use chatbox.scrollTo(0, chatbox.scrollHeight)
to force the chatbox
element to scroll down after each message that is appended to the document.
const API_URL = "http://localhost:3000"
const form = document.querySelector("form")
const chatbox = document.querySelector(".chatbox")
const chatboxInner = document.querySelector(".chatbox-inner")
const chatInput = document.querySelector(".message-input")
const socket = io.connect(API_URL)
socket.on("chat-message", (data) => {
console.log(data)
appendMessage("other-message", data)
})
socket.on("disconnect", (reason) => {
socket.emit("disconnect", reason)
});
form.addEventListener("submit", e => {
e.preventDefault()
console.log("message: ", chatInput.value)
const message = chatInput.value
appendMessage("message", message)
socket.emit("send-chat-message", message)
form.reset()
})
function appendMessage(className, message) {
const div = document.createElement('div')
div.append(message)
div.className = className
chatboxInner.append(div)
chatbox.scrollTo(0, chatbox.scrollHeight)
}
// Dummy messages for demo.
setInterval(() => {
appendMessage('other-message', 'Testing')
}, 4000)
.wrapper {
display: grid;
grid-template-columns: 1fr 2fr;
height: 100vh;
width: 100vw;
}
.side-bar {
grid-area: 1 / 1 / 2 / 2;
background-color: blue;
color: gray;
text-align: left;
padding: 20px;
font-size: 50px;
}
.chat-room:hover {
cursor: pointer;
color: white;
}
.messages-container {
grid-area: 1 / 2 / 2 / 3;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr 40px;
min-height: 0;
}
.chatbox {
display: grid;
align-items: end;
background-color: black;
border: 1px solid white;
overflow: scroll;
}
.chatbox-inner {
display: flex;
flex-direction: column;
justify-content: flex-end;
width: 100%;
padding: 10px 0;
}
.chatbox-inner > div {
border-radius: 15px;
padding: 10px;
color: white;
width: fit-content;
max-width: 50%;
}
.chatbox-inner > .message {
background-color: blue;
margin: 10px 20px 10px auto;
}
.chatbox-inner > .other-message {
background-color: gray;
margin: 10px auto 10px 20px;
}
.as-console-wrapper {
display: none !important;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>chat</title>
</head>
<body>
<div class="wrapper">
<div class="side-bar">
<div class="name">
</div>
<div class="chat-room">
<h3>#chat room 1</h3>
</div>
<div class="chat-room">
<h3>#chat room 2</h3>
</div>
<div class="chat-room">
<h3>#chat room 3</h3>
</div>
<div class="chat-room">
<h3>#lifetime chat</h3>
</div>
</div>
<div class="messages-container">
<!-- Chat messages will be appended here! -->
<div class="chatbox">
<div class="chatbox-inner">
</div>
</div>
<form>
<input type="text" class="message-input form-control" required name="send-message" placeholder="Send message" aria-label="Recipient's username" aria-describedby="basic-addon2">
</form>
</div>
</div>
<script src="https://cdn.socket.io/socket.io-3.0.1.min.js"></script>
<script src="sendMessage.js"></script>
</body>
</html>
Upvotes: 2
Reputation: 8368
For overflow: scroll
to work, you need to explicitly set the divs height. In this case, I used calc
to make it 100vh
and subtracted the height of the form.
For it to scroll from the bottom up, you can use element.scrollTo
and set it to the height of the .chatbox
div each time:
const API_URL = "http://localhost:3000"
const form = document.querySelector("form")
const chatbox = document.querySelector(".chatbox")
const chatInput = document.querySelector(".message-input")
const socket = io.connect(API_URL)
socket.on("chat-message", (data) => {
console.log(data)
appendMessage("other-message", data)
})
socket.on("disconnect", (reason) => {
socket.emit("disconnect", reason)
});
form.addEventListener("submit", e => {
e.preventDefault()
console.log("message: ", chatInput.value)
const message = chatInput.value
appendMessage("message", message)
socket.emit("send-chat-message", message)
form.reset()
chatbox.scrollTo(0, chatbox.scrollHeight)
})
function appendMessage(className, message) {
const div = document.createElement('div')
div.append(message)
div.className = className
chatbox.append(div)
}
.wrapper {
display: grid;
grid-template-columns: 1fr 2fr;
height: 100vh;
width: 100vw;
}
.side-bar {
background-color: blue;
color: gray;
text-align: left;
padding: 20px;
font-size: 50px;
}
.chat-room:hover {
cursor: pointer;
color: white;
}
.messages-container {
display: grid;
grid-template-columns: auto;
grid-template-rows: auto 40px;
}
.chatbox {
height: calc(100vh - 40px);
background-color: black;
border: 1px solid white;
overflow: scroll;
}
.chatbox>div {
border-radius: 15px;
padding: 10px;
margin: 20px;
color: white;
width: fit-content;
max-width: 50%;
}
.message {
background-color: blue;
}
.other-message {
background-color: gray;
}
input {
height: 40px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<div class="wrapper">
<div class="side-bar">
<div class="name">
</div>
<div class="chat-room">
<h3>#chat room 1</h3>
</div>
<div class="chat-room">
<h3>#chat room 2</h3>
</div>
<div class="chat-room">
<h3>#chat room 3</h3>
</div>
<div class="chat-room">
<h3>#lifetime chat</h3>
</div>
</div>
<div class="messages-container">
<!-- Chat messages will be appended here! -->
<div class="chatbox">
</div>
<form>
<input type="text" class="message-input form-control" required name="send-message" placeholder="Send message" aria-label="Recipient's username" aria-describedby="basic-addon2">
</form>
</div>
</div>
<script src="https://cdn.socket.io/socket.io-3.0.1.min.js"></script>
Upvotes: 2