Span text pushes other elements (buttons) to the right and left - javascript

I am trying to create an voting system for my website but am currently struggling with upvote and downvote counters styling. Here is how it looks right now:
As you can see, the problem is that whenever the number on the right or left side of the buttons gets large, it pushes other elements. I want the two buttons to stay in the center and the upvote counter to grow to the left, and downvote to the right. This way, everything will be centered.
Here is my current CSS code:
.upvoteButtonsContainer{
display: flex;
justify-content: center;
margin-top: 15px;
}
.upvoteButton{
margin-right: 2px;
border: none;
background-color: transparent;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
border-radius: 5px;
font-size: 25px;
}
.downvoteButton{
margin-left: 2px;
border: none;
background-color: transparent;
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
border-radius: 5px;
font-size: 25px;
}
.upvoteCounterContainer{
display: block;
direction: rtl;
text-align: right;
}
.downvoteCounterContainer{
display: block;
direction: ltr;
text-align: left;
}
.upvoteCounter{
margin-right: 5px;
}
.downvoteCounter{
margin-left: 5px;
}
And my HTML code:
<div className="homePage">
{imageLists.map((image) => {
return (
<div className="container">
<div className="meme">
<img src={image} className="meme-img"></img>
</div>
<div className="upvoteButtonsContainer">
<div className="upvoteCounterContainer">
<span className="upvoteCounter">120</span>
</div>
<button type="button" className="upvoteButton">
👍
</button>
<button type="button" className="downvoteButton">
👎
</button>
<div className="downvoteCounterContainer">
<span className="downvoteCounter">1241123123310</span>
</div>
</div>
</div>
);
})}
</div>
Thank you!

If you always want the buttons to be center and dont care about the numbers breaking into new lines for exceptionally large numbers, you can solve this by position: absolute quite easily:
.upvoteButton{
position: relative;
}
.downvoteButton{
position: relative;
}
.upvoteCounterContainer{
position: absolute;
top: 50%;
transform: translateY(-50%);
right: calc(100% + 5px);
}
.downvoteCounterContainer{
position: absolute;
top: 50%;
transform: translateY(-50%);
left: calc(100% + 5px);
}
And then wrapping the counters inside the buttons:
<div className="upvoteButtonsContainer">
<button type="button" className="upvoteButton">
👍
<div className="upvoteCounterContainer">
<span className="upvoteCounter">120</span>
</div>
</button>
<button type="button" className="downvoteButton">
👎
<div className="downvoteCounterContainer">
<span className="downvoteCounter">1241123123310</span>
</div>
</button>
</div>
Extra changes:
You can remove all text align/direction styles
If this doesnt work properly you can try putting the icons in specific containers (Divs/spans)
If the counters dont get an auto width (their width doesnt grow based on their content) you can calculate and give them a fixed value.

Related

Child div background-color does not fit parent div when zooming

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;
}

Dynamic css content

Today I have a tab bar that looks like this :
https://codepen.io/cdemez/pen/WNrQpWp
stuffs like width: 400px; etc...
If you look at the code, all the sizes are static :-(
So, I have several sizing issues:
Sometimes I have 4 buttons, sometimes 5
On some mobiles (ie. iPhone 5/SE) the bar is going out of the screen :-(
So, I wish to know if there is a way to fix this.
Mainly the second issue, when the screen is too small for the bar, then everything should by dynamically resized to match the screen size.
Any idea ?
I made a couple of changes to your code pen to get this to work. Mainly setting the width and max-width of each menu item width: 10vw; max-width: 65x;. So when the screen is small it will use the visual width "vw" up to when it hits 65px, then it will use that.
$(".mobilebar-tab-item").click(function () {
$(".mobilebar-tab-item").removeClass("active");
$(this).addClass("active");
$(".mobilebar-tab-overlay").css({
left: $(this).prevAll().length * 65 + "px"
});
});
.mobilebar-container {
position: fixed;
bottom: 15px;
z-index: 12;
left: 50%;
transform: translateX(-50%);
}
.mobilebar-tab {
height: 40px;
width: fit-content;
background-color: #fff;
box-shadow: 0 10px 6px 0 rgba(0, 0, 0, 0.175);
border-radius: 6px;
overflow: hidden;
border: 10px solid #fff;
display: flex;
position: relative;
flex-shrink: 0;
bottom: 0px;
}
.mobilebar-tab-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 5vw;
max-width: 65px;
flex-shrink: 0;
cursor: pointer;
transition: 0.3s;
position: relative;
z-index: 2;
}
.mobilebar-tab-item.active {
width: 10vw;
max-width: 105px;
}
.mobilebar-tab-overlay {
border-radius: 6px;
background-color: #f0f0f0;
height: 100%;
width: 10vw;
max-width: 105px;
position: absolute;
left: 0;
top: 0;
transition: 0.3s;
}
.mobilebar-tab__icon {
display: block;
color: #F96972;
transition-duration: 0.3s;
line-height: 1;
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css">
<div class="mobilebar-container mobile-layout">
<nav class="mobilebar-tab">
<div class="mobilebar-tab-item active">
<span class="mobilebar-tab__icon">
<i class="fas fa-home"></i>
</span>
</div>
<div class="mobilebar-tab-item">
<span class="mobilebar-tab__icon">
<i class="fas fa-search"></i>
</span>
</div>
<div class="mobilebar-tab-item">
<span class="mobilebar-tab__icon">
<i class="fab fa-themeco"></i>
</span>
</div>
<div class="mobilebar-tab-item">
<span class="mobilebar-tab__icon">
<i class="fas fa-bell"></i>
</span>
</div>
<div class="mobilebar-tab-item">
<span class="mobilebar-tab__icon">
<i class="fas fa-user"></i>
</span>
</div>
<div class="mobilebar-tab-overlay"></div>
</nav>
</div>
You could use max/min width properties instead, that way it changes size of that entire bar depending on screen. You can also set a media query so that once it hits, say 700px it will change the size of that button. You can then use flexbox in the parent container itself and try setting it to flex-wrap: wrap; so the items drop to a new row.
If none of that works the way you want, then you can set the size of the font/icons using vw instead, while using max/min width on the bar. Experiment with those and see if they help give the results you need.

scrollTop returns 0

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.

How to make link clickable when using z-index without turning all other elements z-index negative?

I'm trying to make a drop-down box with a button and a toolbar so that my drop-down will be behind the toolbar but in front of my main element. The problem is that to do this I use z-index with negative value because using positive value on the toolbar will cause it to get behind my drop-box due to positioning and hierarchy.
I know that if I'll go and change the z-index of elements in my DOM to smaller negative values (as suggested here) it will make my links clickable again, but this seems to be a very inefficient way of solving the issue. Plus, I'd rather not mess with the toolbar and break it different elements for each button as this can cause a lot of issues with responsiveness in the future. Please take a look at the JFiddler link below.
Here is my code:
$('#btn2').on('click', function() {
console.log('Click!');
var element = document.getElementById("sub-memu");
element.classList.toggle("show");
})
body {
background-color: gray;
height: 100vh;
padding: 0px;
margin: 0px;
}
.toolbar {
height: 40px;
background-image: linear-gradient(white, red);
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.35);
position: relative;
}
.buttons {
display: flex;
flex-direction: row;
}
button {
margin-right: 5px;
}
#sub-memu {
position: absolute;
display: flex;
flex-direction: column;
background-color: white;
padding: 10px;
min-width: 100px;
z-index: -1;
transform: translate(0px, -140%);
transition: transform 1s;
}
main {
padding: 10px;
margin: 10px;
background-color: yellow;
height: calc(100% - 40px - 20px - 20px);
position: relative;
z-index: -2;
}
.show {
transform: translate(0px, 25px) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class='toolbar'>
<div class='buttons'>
<button id='btn1'>
Button 1
</button>
<div class='btn-wrapper'>
<button id='btn2'>
Button 2
</button>
<div id='sub-memu' class='subMenu'>
<a href='#'>Can you click me?</a>
<a href='#'>Can you click me?</a>
<a href='#'>Can you click me?</a>
<a href='#'>Can you click me?</a>
</div>
</div>
</div>
</div>
<main>
This is my main element.
You should be able to click me.
</main>
</body>
https://jsfiddle.net/atb8yq6e/1/
What I'm trying to achieve is the same behavior as can bee seen in my JSFiddle link (drop-down box lowering from behind the navigation bar but in front of my main content) but with active links, without going through my DOM tree and changing every overlapping element's z-index to lower number.
Thank you all in advance,
Lior.
Add z-index to body element to make sure you create a stacking context and avoid having the element going behind it:
$('#btn2').on('click', function() {
console.log('Click!');
var element = document.getElementById("sub-memu");
element.classList.toggle("show");
})
body {
background-color: gray;
height: 100vh;
padding: 0px;
margin: 0px;
position:relative;
z-index: 0;
}
.toolbar {
height: 40px;
background-image: linear-gradient(white, red);
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.35);
position: relative;
}
.buttons {
display: flex;
flex-direction: row;
}
button {
margin-right: 5px;
}
#sub-memu {
position: absolute;
display: flex;
flex-direction: column;
background-color: white;
padding: 10px;
min-width: 100px;
z-index: -1;
transform: translate(0px, -140%);
transition: transform 1s;
}
main {
padding: 10px;
margin: 10px;
background-color: yellow;
height: calc(100% - 40px - 20px - 20px);
position: relative;
z-index: -2;
}
.show {
transform: translate(0px, 25px) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class='toolbar'>
<div class='buttons'>
<button id='btn1'>
Button 1
</button>
<div class='btn-wrapper'>
<button id='btn2'>
Button 2
</button>
<div id='sub-memu' class='subMenu'>
<a href='#'>Can you click me?</a>
<a href='#'>Can you click me?</a>
<a href='#'>Can you click me?</a>
<a href='#'>Can you click me?</a>
</div>
</div>
</div>
</div>
<main>
This is my main element.
You should be able to click me.
</main>
</body>
Related: Why can't an element with a z-index value cover its child?
add this codes to your css:
html{
pointer-events:none;
}
body *{
pointer-events:initial;
}
body {
background-color: gray;
height: 100vh;
padding: 0px;
margin: 0px;
pointer-events:none;
}
https://jsfiddle.net/hL32e6cz/
Simply set z-index to 1 instead on your #sub-memu (should probably be menu?), and remove the z-index value on main.

Fixed pop up for scrollable elements displays where an element is at the moment

I didn't find the right answer to my question.
using Angular, I'm displaying file names in a scrollable div. I need to hover over a file name and see some info in a pop up.
The problem is that pop up shows based on where file name was positioned before user started scrolling. I.e. if I scroll all the way down and hover over a filename, pop up will be displayed somewhere on the bottom of the page.
Another detail is that right after a scrollable div I have a non-scrollable div. I think because of that I can't use position absolute because pop up won't be rendered on top of the second component.
<div style="display:table;" class="upload-item" *ngFor="let f of files; let i = index;">
<span class="filenameblock">
<span class="file-name">{{ f.name}</span>
<span class="tooltiptext">{{f.info}}</span>
</span>
<span style="width:30%;" class="progress">
<span class="bar" [style.width]="f?.progress?.data?.percentage + '%'"></span>
</span>
</div>
<div>Non scrollable div here</div>
css:
.upload-items .upload-item {
width: 100%;
display: block;
margin-bottom: 5px;
height: 5vh;
line-height: 4.9vh;
border: 2px solid #CBCBCB;
border-radius: 3px;
position: relative;
}
.filenameblock {
display: inline-block;
position: relative;
padding: 0 0 5px 5px;
color: #74809D;
margin-left: 5px;
max-width: 300px;
}
.tooltiptext {
visibility: hidden;
width: auto;
padding: 0 15px 0 15px;
background-color: #E7F5FC;
color: #6A6A6A;
text-align: center;
border-radius: 6px;
left: 10vw;
margin-top: 3vw;
position: fixed;
/*z-index: 1000;*/
}
.file-name:hover + .tooltiptext {
visibility: visible;
}
I tried to add 'top' to pop up styling but in this case pop up displayed on the same height all the time.

Categories