I have a fixed div in a vuejs app that i intend to use as a chat box. The div scrolls it's content within itself. I try to scroll to bottom automatically once chat box is open but it never works.
I have tried to assign scrollHeight to scrollTop but scrollTop always returns 0 even after assignment.
I have also emitted an event to the parent component that contains the scrollBar of the chat window to try to scroll but the problem is the same. scrollTop never gets assigned.
let msg = document.querySelector(".messanger .messanger-body");
msg.scrollTop = msg.scrollHeight;
console.log(msg.scrollTop);
console.log(msg.scrollHeight);
My problem is msg.scrollTop never gets assigned what msg.scrollHeight is. It remains 0.
<div class="messanger">
<div class="messanger-header text-center">
<div class="row h-100">
<div class="col-sm-12 my-auto">
<h2 class="ml-2 text-white">Chat</h2>
<div class="float-left">
<base-button size="sm" class="ml-1" type="primary" #click="returnToPrev">←</base-button>
</div>
<div class="float-right">
<base-button size="sm" class="mr-1" type="primary">Send message</base-button>
</div>
</div>
</div>
</div>
<div class="messanger-body">
<div>
<!-- child component -->
<message-thread :user="msgThread.user" #scrolltobtm="scrollViewToBtm"></message-thread>
</div>
</div>
</div>
I have a CSS like so for the parent component
.messanger {
background: white;
position: fixed;
top: 0;
width: 310px;
height: 70vh;
float: right;
right: 10px;
overflow-y: scroll;
overflow-x: hidden;
margin-top: 20vh;
border-top-left-radius: 20px;
border: 2px solid red;
}
.messanger .messanger-header {
position: fixed;
height: 60px !important;
width: 310px !important;
background: #25457a;
color: #ffffff;
z-index: 99999;
border-top-left-radius: 20px;
}
.messanger .messanger-body {
margin-top: 65px;
}
For my child component i have
<div class="message-history mt-2">
<div class="message-history-content">
<div class="text-center mb-4">
<span class="badge badge-info">Thread title : {{threadTitle}}</span>
</div>
<div v-for="(eachMessage, index) in messages" :key="index">
<div :class="messagePosition(eachMessage.added_by)[0]">
<!-- classes msg_container and msg_container_send are dynamically added here -->
<span>{{eachMessage.message}}</span>
</div>
</div>
</div>
<div class="message-input">
<form class="form m-1" #submit.prevent="sendMessage">
<textarea v-model="model.message" class="form-control"></textarea>
<div>
<button class="ni ni-send"></button>
</div>
</form>
</div>
</div>
Child component css
.msg_container {
margin-top: auto;
margin-left: 20%;
margin-right: 10px;
border-radius: 15px;
background-color: #82ccdd;
padding: 10px;
position: relative;
}
.msg_container_send {
margin-top: auto;
margin-right: 20%;
margin-left: 10px;
border-radius: 15px;
background-color: #25457a;
padding: 10px;
position: relative;
color: #ffffff;
}
.message-input {
position: fixed;
bottom: calc(100% - 90%);
background: #ffffff;
z-index: 99999;
}
.message-history {
overflow-x: hidden;
overflow-y: scroll;
margin-bottom: 40px;
}
.message-history .message-history-content {
overflow: scroll;
}
form {
display: flex;
width: 300px;
}
form button.ni.ni-send {
margin-top: 3px;
border-radius: 50%;
border: none;
height: 34px;
width: 34px;
background: #25457a;
color: #ffffff;
}
textarea {
flex-grow: 1;
resize: none;
border: 1px solid #25457a;
}
form button:focus {
outline: 0;
}
Thank you for help in advance.
I added overflow property to the .message-history class, it still doesn't work. I believe my mistake resides in my styles. I'm not much of a CSS person.
The chat window scrolls when the mouse is used to scroll though.
msg.scrollTop could stay with 0 value because of at least two things.
First .messanger-body don't have defined overflow property.
Second as it is initial phase content of .messanger-body have not enough content to make scroll appear on the right side of div.
Please check those options.
Related
Depending on the zoom-level of the browser, the background color of the child div has a strange behavior. Some white spaces appears.
See these examples:
Zoom 125%:
Zoom 150%:
Zoom 175%:
Zoom 200%:
Here is my code:
(JSFiddle: https://jsfiddle.net/3L4wfvyg/)
$(document).ready(function () {
document.getElementById("HeaderContainer").addEventListener("click", function (e) {
if (e.target.id != "FormContainer") {
document.getElementById("Container3").classList.toggle("clicked");
document.getElementById("HeaderContainer").classList.toggle("HeaderContainer3");
};
});
});
.Container1 {
background-color: white;
line-height: 30px;
font-size: 20px;
color: black;
border: none;
position: absolute;
}
.Container1 h3 {
font-size: 30px;
color: #142D41;
margin-top: 20px;
margin-bottom: 10px;
position: relative;
}
.Container1 .Container3 {
padding: 30px;
display: block;
border: 1px solid black;
border-radius: 5px;
margin-top: 15px;
font-size: 15px;
min-width: 100%;
background-color: white;
text-align: left;
height: 100px;
overflow: hidden;
}
.Container1 .Container3:hover {
text-decoration: none !important;
cursor: pointer;
}
.HeaderContainer3:hover {
color: white !important;
background-color: blue;
}
.HeaderContainer2 {
padding: 30px;
}
.HeaderContainer1 {
z-index: 10;
position: relative;
margin: -31px;
padding: 32px 30px 25px 30px;
width: auto;
}
.FormContainer {
font-size: 20px !important;
}
#Container3 {
height: 0px;
transition: height 300ms ease-in-out;
box-shadow: 0.1px 0.6px 2px 0px #8c8c8c;
}
#Container3.clicked {
height: 314px;
}
.Header {
position: relative;
padding-top: 6px;
overflow: hidden;
width: 100%;
height: 100%;
cursor: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="Container1" class="Container1">
<h3>Title
</h3>
<div class="Container2">
<div id="Container3" class="Container3">
<div id="HeaderContainer" class="HeaderContainer1 HeaderContainer2 HeaderContainer3">
<div class="Header">Header</div>
</div>
<div id="FormContainer" class="FormContainer">
<hr />
<div style="padding: 5px 0px 8px 0px;">
Form
</div>
<br />
<div id="FormElementsContainer" class="FormElementsContainer">
<div>
<b>First</b>
<br />
</div>
<div>
<b>Last</b>
<br />
</div>
<div>
<b>Third</b>
<br />
</div>
<div>
<br />
<button>
Submit
</button>
</div>
</div>
<br />
</div>
</div>
</div>
</div>
Why is this happening and how can I solve the problem?
When i remove the border from Container3 it seems like the problem does not occur anymore, but I do not know if this is because it gets hard to see if the problem is still there due to the white color.
There can be a sort of edge effect on zoom brought about by one CSS pixel not being just one screen pixel but 2 or more on high def/modern screens. If the system is trying to map several screen pixels to one CSS one and is asked to do a fraction it can sometimes 'leave behind' a screen pixel. Hence the white on occasion, and the variation at different zoom levels.
In the case in the question maybe doing a simple hack, making the parent element have background blue on hover, would be sufficient?
.Container1 .Container3:hover {
text-decoration: none !important;
cursor: pointer;
background-color: blue;
}
Inspired by A Haworth's answer: coloring the parent element instead is indeed less prone to rendering artifacts when dealing with different zoomlevels/screen densities. You could remove the background from the child element, and add a new :hover selector for the parent that only activates when it is not in the .clicked state.
.HeaderContainer3:hover {
color: white !important;
/** Background removed here **/
}
/** New block with a :not selector **/
.Container1 .Container3:hover:not(.clicked) {
background-color: blue;
}
Full working code example:
$(document).ready(function () {
document.getElementById("HeaderContainer").addEventListener("click", function (e) {
if (e.target.id != "FormContainer") {
document.getElementById("Container3").classList.toggle("clicked");
document.getElementById("HeaderContainer").classList.toggle("HeaderContainer3");
};
});
});
.Container1 {
background-color: white;
line-height: 30px;
font-size: 20px;
color: black;
border: none;
position: absolute;
}
.Container1 h3 {
font-size: 30px;
color: #142D41;
margin-top: 20px;
margin-bottom: 10px;
position: relative;
}
.Container1 .Container3 {
padding: 30px;
display: block;
border: 1px solid black;
border-radius: 5px;
margin-top: 15px;
font-size: 15px;
min-width: 100%;
background-color: white;
text-align: left;
height: 100px;
overflow: hidden;
}
.Container1 .Container3:hover {
text-decoration: none !important;
cursor: pointer;
}
.Container1 .Container3:hover:not(.clicked) {
background-color: blue;
}
.HeaderContainer3:hover {
color: white !important;
}
.HeaderContainer2 {
padding: 30px;
}
.HeaderContainer1 {
z-index: 10;
position: relative;
margin: -31px;
padding: 32px 30px 25px 30px;
width: auto;
}
.FormContainer {
font-size: 20px !important;
}
#Container3 {
height: 0px;
transition: height 300ms ease-in-out;
box-shadow: 0.1px 0.6px 2px 0px #8c8c8c;
}
#Container3.clicked {
height: 314px;
}
.Header {
position: relative;
padding-top: 6px;
overflow: hidden;
width: 100%;
height: 100%;
cursor: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="Container1" class="Container1">
<h3>Title
</h3>
<div class="Container2">
<div id="Container3" class="Container3">
<div id="HeaderContainer" class="HeaderContainer1 HeaderContainer2 HeaderContainer3">
<div class="Header">Header</div>
</div>
<div id="FormContainer" class="FormContainer">
<hr />
<div style="padding: 5px 0px 8px 0px;">
Form
</div>
<br />
<div id="FormElementsContainer" class="FormElementsContainer">
<div>
<b>First</b>
<br />
</div>
<div>
<b>Last</b>
<br />
</div>
<div>
<b>Third</b>
<br />
</div>
<div>
<br />
<button>
Submit
</button>
</div>
</div>
<br />
</div>
</div>
</div>
</div>
Here's a fix. It's similar to what someone else suggested, but takes into account the .clicked state.
Fix boils down to setting the background-color property on the container with border and border-radius properties instead of on the nested container. It achieves this by replacing .HeaderContainer3:hover selector with .Container3:not(.clicked):hover.
.Container3:not(.clicked):hover {
color: white !important;
background-color: blue;
}
Working fiddle: https://jsfiddle.net/2eqLb6go/
As for why this happens, I don't have a technical answer, but it does appear to have something to do with fractional pixel rendering with nested containers when parent has a border. Here's a demonstration of the same problem in a simplified form:
https://jsfiddle.net/0vje6k5w/
It seems like a rendering issue due to a rounding error with border. It appears that the clipping area and the border widths are calculated differently resulting in an inconsistent gap of transparent pixels which can be rounded to either 0 or 1. The background of the container with the border property is respected (hence the above-described fix), but anything nested inside of it will be clipped, and there doesn't appear to be any way to stop that from happening. E.g. the problem persists even if the child elements are absolutely positioned inside of it.
Honestly, I'd call this a buggy implementation of the box-model with regard to page zoom. It's odd that all major browsers in 2021 suffer from the same behavior.
I changed border size to 0.0125em. (It's weird but worked!).
.Container1 .Container3 {
border: 0.0125em solid black;
}
<nav>
</nav>
<div class="container">
<div class="wrapper row">
<div class="col-md-3 col-lg-3 left-side">
</div>
<div class="col-md-6 col-lg-6 middle-side">
</div>
<div class="col-md-3 col-lg-3 right-side">
</div>
</div>
</div>
</div>
<footer>
</footer>
CSS code
.wrapper {
width: 100%;
height: auto;
background-color: var(--main-bg2-color);
margin-top: 55.6px !important;
}
.wrapper.row {
margin: 0;
}
.left-side {
width: 10%;
background-color: var(--main-bg2-color);
color: var(--main-text-color);
height: auto;
padding-top: 41px;
padding-left: 0;
position: fixed;
overflow: hidden;
}
.middle-side {
padding-top: 40px;
width: 100%;
background-color: var(--main-bg2-color);
color: white;
height: auto;
overflow: hidden;
margin-left: 14%;
}
.right-side {
padding-top: 40px;
padding-left: 20px;
width: 100%;
background-color: var(--main-bg2-color);
height: auto;
position: fixed;
right: 0;
}
Here I have a container inside it the left-side class and right side class must remain fixed while the middle side class must be scrollable. My issue is that right side class is always on right with respect to the window when I give right:0. I want right-side class must be right:0 with respect to wrapper class
Is there anyway to fix this?
If I get you right, you want the child div to be fixed to it's parent...
in order to do so you have to set the parent to be positioned fixed and then all its children to be positioned absolute.
I need to go deep with Scroll Snap and your help.
I need to achieve 3 effects:
Able to be draggable
Able to scroll smoothly to an anchor
Able to Trigger a simple animation like changing color when content it's snapped
You can use CSS / JavaScript / jQuery / etc... to achieve the desired effects. Here's the snippet with no results so far:
a, span {
position: absolute
}
h1 {
font-size: 40px;
}
.child {
width: 400px;
height: 400px;
position: relative;
background-color: #F0F0F0;
display: inline-block;
margin-right: -4px;
border: 1px solid black;
}
.label {
width: 200px;
height: 200px;
border-radius: 25%;
background-color: white;
margin: 100px auto 0 auto;
}
.label > h1 {
font-size: 80px;
padding-left: calc(50% - 22px);
padding-top: calc(50% - 60px);
}
.container {
width: 402px;
height: 410px;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
margin: 10vh auto 0 auto;
}
#snap-scroll-container {
-webkit-scroll-snap-type: mandatory;
scroll-snap-type: mandatory;
-webkit-scroll-snap-points-x: repeat(100%);
scroll-snap-points-x: repeat(100%);
}
<div class="container" id="snap-scroll-container">
<div class="child">
<div class="label">
<h1>1</h1>
I must smooth scroll to 3!
</div>
</div>
<div class="child">
<div class="label">
<h1>2</h1>
<span>I must change color when snaps!</span>
</div>
</div>
<div id="3" class="child">
<div class="label">
<h1>3</h1>
<span>Scroll must be draggable too!</span>
</div>
</div>
</div>
Your help is really appreciated!
I want to make collapsible top boxes. but somehow I was not successful. I want to make objects such as cards on the links page materialize. but also bootstrap
card subject at this link: materializecss.com/cards.html
.card3 {
padding: 20px;
position: absolute;
background-color: #FFF;
width: 97.5%;
overflow-y: auto;
border-radius: 4px;
height: 92%;
z-index: 1;
overflow: hidden;
}
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="card3" class="card3">
.......
</div>
<div class="panel panel-default">
<div class="row">
<div class="col-md-6">
......
</div>
<div class="col-md-6">
.......
</div>
</div>
</div>
</div>
</div>
</div>
Have you tried styling the other divs? Because right now only one of the divs has styling, and that usually doesn't end up with a properly styled product.
you can try this one:
.container
{
background:gray;
padding: 20px;
}
.col-md-12 {
padding: 10px;
background-color: #FFF;
width: 97.5%;
overflow-y: auto;
border-radius: 4px;
height: 12%;
z-index: 1;
overflow: hidden;
}
.wrong
{
float:right;
top:0px;
margin-top:-70px;
cursor:pointer;
}
DEMO HERE
I need to hover this div on 2 more divs, and this div additionally should go on its position dynamically maybe playing with the $(document).width();
So, an example is the following:
<div id="store">
<div id="storeText">Store</div>
</div>
<div id="score">
<div id="money">Money earned: 0</div>
<div id="times">Bulbs charged: 0</div>
</div>
CSS
#score {
background-color: #aaaaaa;
width: 96%;
margin: 0;
padding: 10px 2% 10px 2%; }
#store {
float:right;
background-color: #c0c0c0;
width: 10%;
height: 200px;
margin: 0;
padding: 19px 2% 19px 2%; }
#storeText {
text-align: center; }
That's what I should do, but you need to consider I have one more div in the bottom and this is what happens:
JSFiddle
So my question is, how can I position that div '#store' dynamically on that position (right) noting that it should hover all the divs and not make them go away as it actually does right now.
If you didn't get how the result should be, this link will help you understand it carefully.
Please check this code: JSFiddle
What i understand from you i put here, please let me know if you want any more help.
#store {
background-color: #aaaaaa;
width: 96%;
margin: 0;
padding: 10px 2% 10px 2%;
}
#score {
float:right;
background-color: #c0c0c0;
width: 100%;
height: 300px;
margin: 0;
}
#storeText {
text-align: center;
}
#div3 {
float:right;
background-color: red;
width: 100%;
margin: 0;
height: 300px;
position: absolute;
left: 0px;
top: 0px;
z-index: 1;
opacity: 0.4;
padding: 10px 2% 10px 2%;
}
<div id="store">
<div id="storeText">Store</div>
</div>
<div id="score">
<div id="money">Money earned: 0</div>
<div id="times">Bulbs charged: 0</div>
</div>
<div id="div3"></div>