Unexpected top space when li element text is overflowing after ::before - html

I have a list component with a custom bullet defined as a before pseudoelement:
li:before {
display: inline-flex;
width: .8rem;
height: .8rem;
margin-right: 1.5rem;
margin-left: -2.9rem;
background-color: #00c878;
border-radius: .375rem;
content: "";
}
It all works fine as long as the li content doesn't overflow the container. Then, the whole content just jumps down a few pixels and leaves a weird top margin between the bullet and the content.
I have recreated it here.
I have managed to make it disappear using work-break: break-all, but that is of course not a susteinable solution.
Any tips?

So many solutions. but this one worked best
Please Set position to absolute on the pseudo element and remove margin. My solution uses positioning to get wrapped lines automatically line up correctly.
Advantages:
very compact code
works with any font size (no absolute pixel values contained)
aligns rows perfectly (no slight shift between first line and following lines)
.container {
width:170px;
border:1px solid red;
}
ul {
margin: 0;
padding: 0;
}
li {
padding-left: 35px;
margin-bottom: 24px;
margin-top: 0;
font-size: 16px;
line-height: 24px;
list-style-type: none;
position:relative;
word-break: break-all;
}
li::before {
width: 4px;
height: 4px;
background-color: #00c878;
border-radius: 375px;
content: "";
position: absolute;
left: 10px;
top: 9px;
}
<div class="container">
<div class="list unordered">
<h3 class="text-grey-150 h5 "> Branchen ETFs </h3>
<ul class="">
<li>Technologie ETF
<br>
</li>
<li style="/* word-break: break-all; */">Finanzdienstleistungen ETF</li>
<li>Gesundheitswesen ETF
<br>
</li>
<li>Immobilien ETF
<br>
</li>
<li>Industrie ETF</li>
</ul>
</div>
</div>

When doing custom pseudo-elements it's better to position them absolute and relative to the li. See example below, this has fixed your issue:
li {
padding-left: 35px;
margin-bottom: 24px;
margin-top: 0;
font-size: 16px;
line-height: 24px;
list-style-type: none;
position: relative;
}
li::before {
display: inline-flex;
width: 4px;
height: 4px;
margin-right: 15px;
margin-left: -29px;
background-color: #00c878;
border-radius: 375px;
content: "";
position: absolute;
top: 9px;
}
You can use top and left properties to re-position as per your needs.

Related

Dynamic horizontal list with variable width lines and content between nodes

I have a system that generates a list of nodes which may or may not have additional elements between the nodes. I want to visualize this list horizontally with lines connecting the nodes as shown in the example below.
The content between two nodes is variable and can even contain more complex elements like images and tables. The nodes themselves are labeled with only text (Point A, Point B, etc.).
Code & What I have tried so far
In my first attempt at trying to visualize the nodes I simply used a vertical list with the :before and :after CSS pseudo-elements to draw the lines between the nodes. I am however having difficulty translating this approach to a horizontal list.
Horizontal approach: (updated thanks to Mayank Gupta's answer below)
h1, h2 {
margin: 0;
padding: 0;
}
ul {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
flex-direction: row;
text-align: center;
list-style-type: none;
font-size: 1.5em;
}
ul li {
display: flex;
justify-content: flex-start;
flex: 2;
position: relative;
border-bottom: 2px solid #000;
padding-bottom: 10px;
}
ul li:after {
position: absolute;
bottom: -5px;
left: 0;
font-family: "Font Awesome 5 Free";
font-weight: 300;
content: "\f111";
height: 17px;
width: 23px;
background: #fff;
}
ul h2 {
margin: 0 0 0 -1em;
padding: 0;
}
ul li:last-of-type {
border: none;
}
ul li > div {
flex: 0 0 auto;
position: absolute;
left: 50%;
transform: translateX(-50%);
}
<link href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" rel="stylesheet"/>
<ul>
<li>
<h2>Node A</h2>
<div>Content</div>
</li>
<li>
<h2>Node B</h2>
<div>Content</div>
</li>
<li>
<h2>Node C</h2>
</li>
</ul>
Problems with this method:
All nodes are equal width causing the last node to take up space needlessly (last node never has any content to show), in effect this prevents the list from using all available horizontal space (or at least seemingly);
The line is sensitive to font-size changes causing it to misalign;
The node labels are centered using a negative offset, this probably isn't the best method;
The content div is taken out of the document flow in order to center it between the nodes, this potentially allows it to overlap the node labels as is the case in this example
How could I resolve these issues?
Constraints
I only support the latest version of modern browsers, so no compatibility is required for ancient browsers;
I prefer an HTML(5) and CSS only approach
Here is my answer - essentially you add display:flex to the ul list and make sure that the nodes have fixed size by using flex:0 0 auto and a fixed width. This would allow for the context between to be variable in size.
Concerning the connection of the nodes, although it could be done by using the :before and :after pseudo-elements, there's an easier way to do it; just use a pseudo-element for the whole list (the ul element) that goes side-by-side along the width of the element (in the example actually left and right have a value of 30px to compensate the arbitrary side padding I set).
HTML:
<ul>
<li class="node"><label>Point A</label></li>
<li class="context"><span>Content here Content here Content here</span></li>
<li class="node"><label>Point B</label></li>
<li class="context"><span>Content here</span></li>
<li class="node"><label>Point C</label></li>
</ul>
CSS:
ul {
list-style-type: none;
display: flex;
width: 100%;
margin: 50px 0 0 0;
padding: 0 30px;
position: relative;
}
ul:before {
content: "";
display: block;
position: absolute;
left: 30px;
right: 30px;
top: 50%;
margin-top: -1px;
height: 2px;
background: steelblue;
}
.node {
flex: 0 0 auto;
display: block;
width: 12px;
height: 12px;
border-radius: 12px;
border: 2px solid steelblue;
position: relative;
background: #fff;
}
.node label {
position: absolute;
top: -30px;
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
}
.context {
flex: 1 1 auto;
}
.context span {
display: block;
margin-top: -15px;
text-align: center;
}
Here is a working fiddle:
https://jsfiddle.net/8ksxtz60/
Try this code
h1, h2 {
margin: 0;
padding: 0;
}
ul {
display: flex;
align-items: center;
}
ul li {
position: relative;
width: 33%;
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
border-bottom: 1px solid #ddd;
padding-bottom: 10px;
}
ul li:after {
position: absolute;
bottom: -10px;
left: 0;
font-family: "Font Awesome 5 Free";
font-weight: 300;
content: "\f111";
height: 17px;
width: 17px;
background: #fff;
}
<link href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" rel="stylesheet"/>
<ul>
<li>
<h2>Node A</h2>
<div>Content</div>
</li>
<li>
<h2>Node B</h2>
<div>Content</div>
</li>
<li>
<h2>Node C</h2>
<div>Content</div>
</li>
</ul>
This somewhat answers your question[*] [* = however I wrote most of this code before I read on seeing your first image, without seeing the h2/div content].
The bulk of the answer is HTML/CSS, but there is a small bit of javascript to set the li class [of the nodes up to the point selected] to active.
Run the snippet and click on the node items in turn to see the lines being drawn.
EDIT: Re. your questions:
With regard to the last node, you could choose to give it a different width, remove border-width/margin/padding or display:none. If you use the :last-child selector, you can give the last item different property values as required, using CSS.
Regarding different fonts/misalignment, I'd say the same is true of most code using different fonts. Try to stick use one font consistently (I'd regard it as better practice in this instance). As for misalignment, if it's varying image sizes that are mostly causing it to misalign, try using a fixed width with
object-fit (contain/scale-down should display best for you) You can set an overflow to divs, and don't forget wrap
Label-centering: have you tried simply adding text-align: center; ? Not sure what suggest regarding the negative offset, as this is dependent/relative to other css. Would have to see full css/html layout.
Re. potentially overlapping divs: set a max-width for your content and overflow/overflow-y to auto if necessary.
Hope this helps!
var nodelist1 = document.getElementById("connect");
var mynodes = nodelist1.getElementsByTagName("li");
for (var i = 0; i < mynodes.length; i++) {
mynodes[i].addEventListener("click", function() {
var currNode = document.getElementsByClassName("active");
currNode[0].className = currNode[0].className.replace("active", "");
this.className += "active";
});
}
body {
font-family: "Font Awesome 5 Free";
/* padding: 2em;*/
}
#connect {
font-weight: 300;
content: "\f111";
}
h1,
h2 {
margin: 0;
padding: 0;
}
li {
vertical-align: middle;
display: inline-block;
position: relative;
color: white;
width: 4em;
height: 4em;
text-align: center;
margin: 0em .8em;
line-height: 4em;
border-radius: 1em;
background: navy;
}
li::before {
content: '';
position: absolute;
top: 2em;
left: -3em;
min-width: 4em;
/*width of connecting line*/
height: .2em;
background: maroon;
z-index: -1;
}
li:first-child::before {
display: none;
/*at pos 1, other nodes are 'disabled' line is light blue*/
}
.active {
background: navy;
}
.active~li {
background: lightgray;
}
.active~li::before {
background: lightblue;
}
.content {
display: none;
width: 5em;
max-height: 6em;
overflow-y: scroll;
overflow-x: none;
line-height: 1em;
color: red;
padding: 0;
margin: 0;
}
.active .content {
display: block;
}
<link href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" rel="stylesheet" />
<ul id="connect">
<li>1</li>
<li class="active">2</li>
<li>
<h2>Node A</h2>
<div class="content">Manuel: hello how are you I speak English I learn it from a book</div>
</li>
<li>4</li>
<li>5</li>
</ul>

Applying pseudo class "before" and "after" to multi-line text

I am trying to add a pseudo before and after vertical line to a textfield for styling purposes. These elements need to be flush to the text -20px left and -20px right.
This works fine when the text is on one line as an inline-block, but as soon as the text spans multiple lines the width expands to that of the parent and the pseudo elements are no longer just 20px from the text.
Is there a way in which I can accomplish this using CSS?
.container {
width: 500px;
background-color: red;
text-align: center;
margin-left: 40px;
}
h2 {
position: relative;
display: inline-block;
margin: 0;
padding: 0;
background-color: blue;
color: white;
}
span {
position: relative;
background-color: green;
}
h2::before,
h2::after {
content: '';
position: absolute;
top: 0;
width: 4px;
height: 20px;
background: black;
}
h2::before {
left: -20px;
}
h2::after {
right: -20px;
}
<!-- Single line example works as the black bars are 20px away from the start/end of text-->
<div class="container">
<h2><span>This is a title</span></h2>
</div>
<br> <br>
<!-- double line doesn't work because the h2 is now the full width of the container -->
<div class="container">
<h2><span>This is loooonnggggggggggggggggggggggeeeeerrr</span></h2>
</div>
Edit: Here is a working version using tables, but if anyone has a better solution I'd love to hear it: https://codepen.io/anon/pen/MqveLQ
So from what i can see is the issue here is where you are applying the borders with before and after. You need to alter where you apply your borders. Remove them from the h2, and add in a new html element that wraps the h2 and apply there.
eg:
<div class="container">
<div class="headerwrap">
<h2><span>This is loooonnggggggggggggggggggggggeeeeerrr</span></h2>
</div>
</div>
<div class="container">
<div class="headerwrap">
<h2><span>This is a title</span></h2>
</div>
</div>
CSS
.headerwrap::before,
.headerwrap::after {
content: '';
position: absolute;
top: 0px;
bottom:0;
margin:auto;
width: 4px;
height: 20px;
background: black;
}
.headerwrap::before {
left: 10px;
}
.headerwrap::after {
right: 10px;
}
Here is a working example: https://codepen.io/FEARtheMoose/pen/VGbJjO?editors=1100#0
Edit: altered example after comments - https://codepen.io/FEARtheMoose/pen/VGbJjO
I have moved your code to this fiddle: https://jsfiddle.net/n2Lr6xy5/13/ and removed position: absolute along with stripping out some of the other styles as they seemed unnecessary and I think I have created what you're after.
Here is the updated CSS:
.container {
width: 500px;
background-color: red;
text-align: center;
margin-left: 40px;
}
h2{
display: inline-block;
}
h2:after,
h2:before {
content: "";
width: 4px;
height: 20px;
background: #000000;
display: inline-block;
margin: 0 10px;
}

CSS - making symbol stay always on second line

I want to that symbol -> (text element) would only appear in second line. For example if text would be one line
John
->
and if there would be two lines of text symbol would still be on second line.
John and
Tom ->
is it possible?
Currently how it is:
HTML
<div class="inner-box">
<span class="inner-box-text">Category<i class="icon-font icon-long-arrow"></i></span>
</div>
CSS
.inner-box {
bottom: 16%;
left: 10%;
right: 25%;
text-align: left;
position: absolute;
z-index: 3;
height: 51px;
}
.inner-box span {
display: inline-block;
text-align: left;
text-transform: uppercase;
text-decoration: none;
color: white;
line-height: 25px;
max-width: 270px;
padding-right: 5px;
}
.inner-box i {
padding-top: 5px;
}
first of all the span should be closed as well like so:
<div class="inner-box">
<span class="inner-box-text">Category<i class="icon-font icon-long-arrow"></i></span>
</div>
What you are likely looking for is CSS selector :after
<style>
.inner-box-text:after {
content: " --- whatever should come after";
}
</style>
Sadly the :after selector does not support HTML, only text.
Another possibility would be the use of jQuery to append something.
Alex
you can use below code
<div class="inner-box">
<span class="inner-box-text">Category</span><i class="icon-font icon-long-arrow"></i>
</div>
and below css
.vip-inner-box {
bottom: 16%;
left: 10%;
right: 25%;
text-align: left;
position: absolute;
z-index: 3;
height: 51px;
span {
display: inline-block;
text-align: left;
text-transform: uppercase;
text-decoration: none;
font: $font-weight-light 24px $font-custom;
color: white;
line-height: 25px;
max-width: 270px;
padding-right: 5px;
}
}
i {
padding-top: 5px;
display:block;
}

How to fill horizontal space with a div responsively

I've been trying to create a feed page and I want it to be totally responsive. The layout is a score on the right with a fixed width and a link on the left which should take up the rest of the horizontal space.
The code I have so far has the link just taking up the whole line and passing underneath the score div.
This will be a problem if the link title is so long that it gets cut off by the score as I can't stop the link div's width once it collides in which case I'd like to use the text-overflow: ellipsis feature.
My code is below along with a jsfiddle link
HTML
<body>
<ul id="tracklist">
<li class="trackwrap"> <a class="tracklink" href="#">Link 1</a>
<p class="trackscore">x score</p>
</li>
</ul>
</body>
CSS
#tracklist {
margin: 0;
position: relative;
list-style-type: none;
background: white;
padding: 10px 20px 10px 20px;
}
.trackwrap {
position: relative;
margin: 0;
width: 100%;
height: 24px;
transition: 1s;
margin-bottom: 2px;
transition: 1.5s;
}
.tracklink {
background: red;
margin: 0;
display: inline;
position: absolute;
left: 3px;
width: 100%;
max-height: 24px;
font-size: 16px;
line-height: 24px;
}
.trackscore {
background: blue;
margin: 0;
display: inline;
position: absolute;
right: 52px;
font-size: 14px;
color: white;
text-align: right;
line-height: 24px;
}
http://jsfiddle.net/4Lf8v9tn/
This needs to be responsive so I'd prefer it if answers could use width: 100% for the link div
Thanks
Add a min-width on your .trackwrap like so: http://jsfiddle.net/4Lf8v9tn/1/

vertical-align:middle for a span element

I am trying to get the text in a span to align vertically in the middle relative to adjacent text. This is easily achieved, however when the text in the span takes up two lines, the text is cut-off.
To solve this problem the span either needs to expand in height when the text takes up two lines, or to somehow align the text to the middle..
A working example of the problem is here http://jsfiddle.net/BxLnN/
Any suggestions or solutions would be greatly appreciated.
The current dimensions of the containing elements must remain the same.
Cheers!
the html
<div class="divisions_container">
<div class="division">
<div class="div_head">
DIVISION 1 <span>SIX WINNING NUMBERS</span>
</div>
<div class="div_head">
DIVISION 2
<div>
<span>FIVE WINNING NUMBERS PLUS ONE OF THE TWO SUPPLEMENTARY NUMBERS</span>
</div>
</div>
</div>
</div>
the css
/* division winnings */
.divisions_container {
font-size: 13px;
padding: 0 10px;
width: 7.4cm;
height: 8.5cm;
}
.div_head {
margin-top: 20px;
text-align: left;
padding-left: 5px;
position: relative;
background-color: #000;
color: #fff;
max-height: 6mm;
font-weight: bold;
font-size: 1.2em;
}
/* # winning numbers */
.div_head span {
font-size: 0.5em;
vertical-align: middle;
font-weight: 200;
border: 1px solid red;
display: inline-block;
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 100px;
}
You have got the span with position: absolute;. When you make an element absolutely positioned, it becomes a block element without any margins, and you cannot use vertical-align on them, as it works only on inline and inline-block elements.
So I suggest this CSS:
/* division winnings */
.divisions_container {
font-size: 13px;
padding: 0 10px;
width: 7.4cm;
height: 8.7cm;
}
.div_head {
margin-top: 20px;
text-align: left;
padding-left: 5px;
position: relative;
background-color: #000;
color: #fff;
max-height: 6mm;
font-weight: bold;
font-size: 1.2em;
}
/* # winning numbers */
.div_head span {
font-size: 0.5em;
vertical-align: middle;
font-weight: 200;
border: 1px solid red;
display: inline-block;
}
.div_head div {position: absolute;
right: 0;
top: -2px;
bottom: 0;
left: 100px;
}
Fiddle: http://jsfiddle.net/praveenscience/BxLnN/1/
If it's possible for you to set a fixed height to your span, like 20px or so, then you could use: line-height: 20px in your .div_head span style. That would then center the text in your span automatically.
You also don't need to set a display: inline-block and vertical-align: middle that way.
Example: http://jsfiddle.net/BxLnN/2/
Try this works...
You must specify width of span and position to relative and increase or decrease the value of top and left;
.div_head span {
font-size: 0.5em;
vertical-align: middle;
font-weight: 200;
border: 1px solid red;
display: inline-block;
position: relative;
right: 0;
top: -20px;
bottom: 0;
left: 100px;
text-align: left;
width: 200px;
}
Try this works...
You must specify width of span and position to relative and increase or decrease the value of top and left;
.div_head span {
font-size: 0.5em;
vertical-align: middle;
font-weight: 200;
border: 1px solid red;
display: inline-block;
position: relative;
right: 0;
top: -20px;
bottom: 0;
left: 100px;
text-align: left;
width: 200px;
}
The Nice One Is Here
HTML
<div class="Division_Container">
<span>Division 1</span>
<span class="Inner_Container">
six winning numbers
</span>
</div>
<div class="Division_Container">
<span>Division 2</span>
<span class="Inner_Container">
five winning numbers and rest of the nubmers to be displayede winning numbers and rest of the nubmers to be displayed
</span>
</div>
<div class="Division_Container">
<span>Division 2</span>
<span class="Inner_Container">
five winning numbers and rest of the nubmers to be displayede winning n
</span>
</div>
CSS
.Division_Container{display: block; width: 300px; background: #000; color: #fff; margin: 10px;}
.Inner_Container{display: inline-block; vertical-align: middle; left: 200px; width: 200px; margin-left: 20px; border: 1px solid red;}
/* If you want to specify height add following */
.Division_Container:before{content: "."; display: inline-block; height: 100px; vertical-align: middle; visibility: hidden;}