CSS border bottom only on one side - html

I am trying to use the css border-bottom property with a circle in between. Something like this :
what I want
But, for the first and last circles I only want it to line to be inclusive within the borders but its extending to the ends like this.
result of what I tried with normal css
This is the css I used:
.horizontalLineComplete{
width: 100%;
border-bottom: 4px solid #26890D;
height:20px;
}
.horizontalLineCurrent{
width: 70%;
border-bottom: 4px solid #63666A;
height:20px;
}
I tried using the li:: before and ::after selector classes as well but that also hasn't worked it just shows up the lines between the circles but the colors I assign aren't working accurately. It takes black color by default like this: result for what I tried with selector classes
This is the css I gave:
li.circleComplete::before
{
content: "";
flex: 1 1;
border-bottom: 2px solid #26890D;
margin: auto;
}
li.circleComplete::after {
content: "";
flex: 1 1;
border-bottom: 2px solid #26890D;
margin: auto;
}
li.circleNext::before
{
content: "";
flex: 1 1;
border-bottom: 2px solid #63666A;
margin: auto;
}
li.circleNext::after {
content: "";
flex: 1 1;
border-bottom: 2px solid #63666A;
margin: auto;
}
Can someone help me out on how I can adjust this or let me know if I am making any mistakes in the code? I am using react and typescript for my front end with scss.

This is one of solution how to fix your code.
$('.active').html("&#10003");
$('#goNext').on('click', function() {
$('ul>li.active').removeClass('active').next('li').addClass('active');
$("ul>li.active").html("&#10003")
});
li {
width: 2em;
height: 2em;
text-align: center;
line-height: 2em;
border-radius: 1em;
background: #45ad66;
margin: 0 1em;
display: inline-block;
color: white;
position: relative;
}
li::before{
content: '';
position: absolute;
top: .9em;
left: -4em;
width: 4em;
height: .2em;
background: #45ad66;
z-index: -1;
transition: all 1s;
}
li:first-child::before {
display: none;
}
.active {
background: #3f995b;
transition: all 1s;
}
.active ~ li {
background: gray;
}
.active ~ li::before {
background: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li class="active">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
<button id="goNext">
Go to next
</button>
UPDATED code

I find it easier to put the central line as a background image (via linear-gradient) on the ul element itself.
This snippet sets the ul to display inline-flex and gets the circles (the li elements) spaced out evenly with the first at the left side and the last at the right side by using the space-between justification property.
This way you don't have to do lots of positioning.
The tick is put on via a content in a pseudo element for each li as I assume it is just for decoration rather than as actual content.
ul {
margin: 0;
padding: 0;
list-style-type: none;
display: inline-flex;
width: 100%;
background-image: linear-gradient(#45ad66, #45ad66);
background-size: 100% 2px;
background-position: center center;
background-repeat: no-repeat;
justify-content: space-between;
}
li::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
content: '✔';
color: white;
font-size: 3vmin;
}
li {
display: inline-block;
position: relative;
background-color: #45ad66;
width: 6vmin;
height: 6vmin;
border-radius: 50%;
transition: all 1s;
}
li.active,
li:hover {
background-color: #3f995b;
}
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Note: dimensions are in terms of vmin so that the whole thing is responsive but of course you are free to change those if required.
Just so you can see the 'active' effect transitioning I've put the active color as the color for a hover on an li element as well. Also moved the transition to the element itself so the color transitions both in and out.

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>

With a z-index of -1, the after pseudo element is hidden behind background

I made a simple progress bar for an online form. It worked fine, until I added a background color on the containing div. It seems that when z-index is set to -1, it hides behind the background of the parent's parent's parent.
The following JS Fiddle shows the error above what is expected.
https://jsfiddle.net/h2e52oux/
What can I do to make the top one work the same as the bottom when there is a background color?
div {
height: 100px;
}
div.bg {
background-color: white;
}
ul {
counter-reset: step;
}
li {
list-style-type: none;
width: 25%;
text-align: center;
font-style: italic;
color: #999;
float: left;
position: relative;
}
li::before {
content: counter(step);
counter-increment: step;
width: 1.5em;
text-align: center;
display: block;
background: white;
border: 1px solid #999;
color: #999;
margin: 0 auto 5px auto;
}
li:not(:first-child)::after {
content: '';
width: 100%;
height: 3px;
background: white;
border: 1px solid #999;
position: absolute;
top: 0.5em;
left: -50%;
z-index: -1;
}
li.active {
color: #222;
font-style: normal;
}
li.active::before,
li.active::after {
background: #b05d68;
color: white;
border: 0;
}
<div class="bg">
<ul>
<li class="active">One</li>
<li class="active">Two</li>
<li>Three</li>
<li>Four</li>
</ul>
</div>
<div>
<ul>
<li class="active">One</li>
<li class="active">Two</li>
<li>Three</li>
<li>Four</li>
</ul>
</div>
In your case it turns out that no matter what number you give to the z-index, adding the lines below are enough to do the work. I set it to the value of -2 on purpose to make it 1 layer below lis but that can be changed as desired. Just the z-index property alone takes no effect because it needs to be accompanied by the position property with the value of anything different than the default static. Setting it to the value of relative is a logical choice since I don't want to break your layout.
div.bg {
position: relative;
z-index: -2;
}
Try:
div.bg {
position: relative;
z-index: -2;
}
z-index only works on positioned elements (position:absolute, position:relative, or position:fixed).
Setting the z-index to -2 means the background div will be stacked below your other content.

Why is there whitespace separating list items from its parentr?

This is my first time implementing the standard html nav. However, the list elements inside nav are not positioned inside nav the way I want them to be, and although I've changed most of the obvious properties that come to mind, I haven't been able to:
Center the li elements inside nav
Make the width of the li elements fit perfectly inside nav
I don't understand why they are by default positioned so awkwardly to the right of their parent container, or why setting 'width: 100%' isn't the solution. When I set the positioning on the li elements to absolute, it seems to mucks up everything since I need each list element to be positioned relative to where the element before it is placed.
There seems to be a few possible ways I could go about solving this problem, but they seem sort of hackish, and I'm wondering if there's a more obvious solution I lack the experience to see.
nav {
width: 40%; height: 500px;
left: 50%;
transform: translateX(-50%);
position: relative;
border: 2px solid black;
}
nav ul li {
list-style: none; text-align: center;
width: 99%; height: 100%;
position: inherit;
padding: 1%;
border: 2px solid black;
border-top: none;
margin: 0;
display: block;
background: blue;
}
<nav><!--
--><ul><!--
--><li class="user">WelcomeVids</li>
<li class="user">Diablo</li>
<li class="user">FreeCodeCamp</li>
<li class="user">OtherStuff</li>
<li class="user">Dota2</li><!--
--></ul><!--
--></nav>
To see the output, view my Codepen: http://codepen.io/sentedelviento/full/grzrgR/
This is because most browsers default to adding a padding-left to <ul>. You can override that:
/* Added */
ul {
padding-left: 0;
}
nav {
width: 40%; height: 500px;
left: 50%;
transform: translateX(-50%);
position: relative;
border: 2px solid black;
}
nav ul li {
list-style: none; text-align: center;
/* width: 99%; height: 100%; */
position: inherit;
padding: 1%;
border: 2px solid black;
border-top: none;
margin: 0;
display: block;
background: blue;
}
<nav><!--
--><ul><!--
--><li class="user">WelcomeVids</li>
<li class="user">Diablo</li>
<li class="user">FreeCodeCamp</li>
<li class="user">OtherStuff</li>
<li class="user">Dota2</li><!--
--></ul><!--
--></nav>
I'd recommend the following changes to your CSS:
nav ul {
margin: 0;
padding: 0;
}
nav ul li {
box-sizing: border-box;
width: auto;
}

multiple words break on absolute positioned element

I'm building out a tooltip feature for our site, it's what should be a simple highlight over an icon image and some text appears next to it. the problem I'm having is the words that should be inside of that tooltip bubble breaks into a new line for each. when the code is on its own it works fine.
ul { list-style-type: none; margin: 0; }
li { width: 50px; height: 50px; background: #000; color: #fff; position: relative; }
li:hover { background: #eee; color: #000; }
li:hover #z { display: block; }
#z { position: absolute; left: 50px; height: 50px; background: orange; color: #fff; display: none; }
<ul>
<li>
<div id="z">
some word that shouldn't break
</div>
</li>
</ul>
http://jsfiddle.net/emqLnmo8/1/
Use white-space: nowrap; to stop the words from wrapping.
So with your example: fiddle.

Visual grouping of HTML elements by CSS background with rounded corners

I'm looking for a solution to group html elemts with a background. The real problems are the rounded corners highlighted in the picture. Is there a way to achieve this?
This solution still needs some work, but it's pretty close.
FIDDLE
Basically, I add a pseudo element before each list item using nth-child to group them with a particular color.
Also I set a lower z-index for each group.
I might be possible to play with the clip property to perfect this.
Markup
<ul>
<li></li><li></li><li class="last"></li>
<li></li><li></li><li></li><li></li><li></li><li class="last"></li>
<li></li><li></li><li></li><li class="last"></li>
</ul>
CSS
ul
{
list-style:none;
width: 350px;
}
li:before
{
content: '';
border-radius: 10px;
display: inline-block;
position: absolute;
top: -10px;
left: -10px;
height:70px;
width: 80px;
z-index:-1;
}
li:nth-child(-n+3):before
{
background: brown;
z-index: -2;
}
li:nth-child(n+4):nth-child(-n+9):before
{
background: green;
z-index: -3;
}
li:nth-child(n+10):nth-child(-n+13):before
{
background: pink;
z-index: -4;
}
li
{
width: 50px;height: 50px;
background: black;
border-radius: 10px;
margin: 5px 5px 10px 5px;
display: inline-block;
position:relative;
}
.last:before
{
z-index: -1!important;
width: 70px;
}
.last + li:before
{
border-radius: 10px 10px 10px 0;
}
/* clip the last item in each row */
li:nth-child(5n):before
{
width: 70px;
}