Creating CSS3 Circles connected by lines

CssCss FloatSass

Css Problem Overview


I have to implement the following circle and line combination in CSS and I am looking for pointers on how to implement this effectively. The circles and lines should look like this:

Ideal image prototype

I am able to implement the circles as such:

span.step {
  background: #ccc;
  border-radius: 0.8em;
  -moz-border-radius: 0.8em;
  -webkit-border-radius: 0.8em;
  color: #1f79cd;
  display: inline-block;
  font-weight: bold;
  line-height: 1.6em;
  margin-right: 5px;
  text-align: center;
  width: 1.6em; 
}

but the lines are tricky for me to understand.

The size of the circle changes depending on whether it is the active step or not, and the color of the line connecting the circles changes as well depending on status. How would I accomplish this?

Css Solutions


Solution 1 - Css

You can achieve this effect with no additional markup using pseudo-elements and the adjacent sibling selector (~):

css3 circles connected by lines

li {
  width: 2em;
  height: 2em;
  text-align: center;
  line-height: 2em;
  border-radius: 1em;
  background: dodgerblue;
  margin: 0 1em;
  display: inline-block;
  color: white;
  position: relative;
}

li::before{
  content: '';
  position: absolute;
  top: .9em;
  left: -4em;
  width: 4em;
  height: .2em;
  background: dodgerblue;
  z-index: -1;
}


li:first-child::before {
  display: none;
}

.active {
  background: dodgerblue;
}

.active ~ li {
  background: lightblue;
}

.active ~ li::before {
  background: lightblue;
}

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li class="active">4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
</ul>  

Demo on CodePen

Solution 2 - Css

Flexbox timeline with steps


Working off of the excellent answer from @bookcasey I found myself doing it the opposite way to get it responsive;

  • I put the circles as ::before pseudo selectors (with automatic css counter).
  • The lines between are the li elements so they can be stretched by flexbox.

It now stretches to fill parent, and deals with different number of steps automatically. You can also do things like adjust font-size on parent ul and have the whole thing adapt.

I'm sure it can be improved so feel free to contribute :)


Interactive CodePen: Flexbox Timeline with steps: http://codepen.io/ccondrup/pen/bqbGWB?editors=1100


ul {
  align-content: center;
  align-items: center;
  counter-reset: stepCount;
  display: flex;
  justify-content: space-around;
  margin: 10vh auto 20vh;  /* for codepen */
}

li {
  background: dodgerblue;
  color: white;
  content: ' ';
  display: flex;
  flex-grow: 1;
  height: .3em;
  line-height: 1em;
  margin: 0;
  position: relative;
  text-align: right;
  z-index: -1;
}

li::before {
  background: dodgerblue;
  border-radius: 50%;
  color: white;
  content: counter(stepCount);
  counter-increment: stepCount;
  height: 2em;
  left: -2em;
  line-height: 2em;
  position: absolute;
  text-align: center;
  top: -.85em;
  width: 2em;
}

li.active {
  background-color: lightblue;
}

li.active~li {
  background-color: lightblue;
}

li.active~li::before {
  background-color: lightblue;
}

li:last-child {
  flex-grow: 0;
  flex-shrink: 1;
  flex-basis: 0;
/* Shorthand: flex: 0 1 0; */
}

ul.bigger {
  font-size: 1.3em;
}

ul.highlight-active li.active::before {
  font-size: 1.6em;
  background: navy;
}

ul.roman li::before {
  content: counter(stepCount, upper-roman);
}

ul.triangle li::before {
  width: 0;
  height: 0;
  border-radius: 0;
  border-left: 1em solid white;
  border-right: 1em solid white;
  border-bottom: .8em solid dodgerblue;
  content: '';
  top: -.65em;
}

ul.triangle li:first-child::before {
  left: 0;
}

ul.triangle li.active~li::before {
  border-bottom-color: lightblue;
}

<ul>
  <li></li>
  <li></li>
  <li class="active"></li>
  <li></li>
  <li></li>
  <li></li>
</ul>


<ul class="bigger highlight-active">
  <li></li>
  <li></li>
  <li class="active"></li>
  <li></li>
</ul>


<ul class="roman">
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li class="active"></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>


<ul class="triangle">
  <li></li>
  <li></li>
  <li class="active"></li>
  <li></li>
  <li></li>
</ul>

Solution 3 - Css

It is not my own but it works quite well and looks elegant, only works with css and you can perzonalize it more. Source http://jsfiddle.net/Misiu/y1Lo3qh1/

var i = 1;
$('.progress .circle').removeClass().addClass('circle');
$('.progress .bar').removeClass().addClass('bar');
setInterval(function () {
    $('.progress .circle:nth-of-type(' + i + ')').addClass('active');
    $('.progress .circle:nth-of-type(' + (i - 1) + ')').removeClass('active').addClass('done');
    $('.progress .circle:nth-of-type(' + (i - 1) + ') .label').html('&#10003;');
    $('.progress .bar:nth-of-type(' + (i - 1) + ')').addClass('active');
    $('.progress .bar:nth-of-type(' + (i - 2) + ')').removeClass('active').addClass('done');
    i++;
    if (i == 8) {
        $('.progress .circle').removeClass().addClass('circle');
        $('.progress .bar').removeClass().addClass('bar');
        i = 1;
    }
}, 1000);

*,
*:after,
*:before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Open Sans";
}
/* Form Progress */

.progress {

  margin: 20px auto;
  text-align: center;
  padding-bottom: 80px;
}
.progress .circle,
.progress .bar {
  display: inline-block;
  background: #fff;
  width: 40px;
  height: 40px;
  border-radius: 40px;
  border: 1px solid #d5d5da;
  vertical-align:top;
}
.progress .bar {
  position: relative;
  width: 80px;
  height: 6px;
  margin: 0 -5px 17px -5px;
  border-left: none;
  border-right: none;
  border-radius: 0;
  top:16px;
  vertical-align:top
}
.progress .circle .label {
  display: inline-block;
  width: 32px;
  height: 32px;
  line-height: 32px;
  border-radius: 32px;
  margin-top: 3px;
  color: #b5b5ba;
  font-size: 17px;
}
.progress .circle .title {
  color: #b5b5ba;
  font-size: 13px;
  line-height: 18px;
  margin-left: -30px;
  display: block;
  width: 100px;
  margin-top: 5px;
}
/* Done / Active */

.progress .bar.done,
.progress .circle.done {
  background: #eee;
}
.progress .bar.active {
  background: linear-gradient(to right, #EEE 40%, #FFF 60%);
}
.progress .circle.done .label {
  color: #FFF;
  background: #8bc435;
  box-shadow: inset 0 0 2px rgba(0, 0, 0, .2);
}
.progress .circle.done .title {
  color: #444;
}
.progress .circle.active .label {
  color: #FFF;
  background: #0c95be;
  box-shadow: inset 0 0 2px rgba(0, 0, 0, .2);
}
.progress .circle.active .title {
  color: #0c95be;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<div class="progress">
  <div class="circle done"> <span class="label">1</span>
    <span class="title">Order</span>

  </div> <span class="bar done"></span>

  <div class="circle done"> <span class="label">2</span>
    <span class="title">Address</span>

  </div> <span class="bar active"></span>

  <div class="circle active"> <span class="label">3</span>
    <span class="title">Payment</span>

  </div> <span class="bar"></span>

  <div class="circle"> <span class="label">4</span>
    <span class="title">Review</span>

  </div> <span class="bar"></span>

  <div class="circle"> <span class="label">5</span>
    <span class="title">Finish</span>

  </div>
</div>
<div class="progress">
  <div class="circle done"> <span class="label">1</span>
    <span class="title">Order informations</span>

  </div> <span class="bar active"></span>

  <div class="circle active"> <span class="label">2</span>
    <span class="title">Order review</span>

  </div> <span class="bar"></span>

  <div class="circle"> <span class="label">3</span>
    <span class="title">Finish</span>

  </div>
</div>

Solution 4 - Css

CSS3 only, Flex, Responsive, Dynamic, Customisable

example of breadcrumbs css

Ok... I went a bit overboard - here it is.

(Tested and working on Chrome, Firefox, Safari - as of July 2020)

/* custom stylings */
:root {
  --active-bg-color: #1975CF;
  --active-text-color: white;
  --inactive-bg-color: #C4DDF4;
  --inactive-text-color: #3480D2;
  --line-width: 5%;
  --active-circle-diam: 30px;
  --inactive-circle-diam: 20px;
}
ul {
  font-family: Arial;
  border: 1px solid magenta;
}


/* --- breadcrumb component --- */
ul {
  position:relative;
  display:flex;
  justify-content: space-between;
  align-items: center;
   padding: 0;
}
li:only-child {
  margin: auto;
}

/* lines */
li:not(:last-child):after {
  content: '';
  position: absolute;
  top: calc((100% - var(--line-width)) / 2);
  height: var(--line-width);
  z-index: -1;
}
/* circles */
li {
  overflow: hidden;
  text-align:center;
  border-radius: 50%;
  text-indent: 0;
  list-style-type: none;
}

/* active styling */
li,
li:not(:last-child):after {
  background: var(--active-bg-color);
  color: var(--active-text-color);
}

/* inactive styling */
li.active:after,
li.active ~ li,
li.active ~ li:not(:last-child):after {
  background: var(--inactive-bg-color);
  color: var(--inactive-text-color);
}

/* circle sizing */
li.active {
  width: var(--active-circle-diam);
  height: var(--active-circle-diam);
  line-height: calc(var(--active-circle-diam) + 0.1rem);
  font-size: calc(var(--active-circle-diam) / 1.6);
}
li:not(.active) {
  width: var(--inactive-circle-diam);
  height: var(--inactive-circle-diam);
  line-height: calc(var(--inactive-circle-diam) + 0.1rem);
  font-size: calc(var(--inactive-circle-diam) / 1.6);
}

/* 
Calculate ddynamic width using css3 only.
N.B. if you know the total count, hardcode away!
*/

li:first-child:nth-last-child(2):not(:last-child):after,
li:first-child:nth-last-child(2) ~ li:not(:last-child):after {
    width: calc((100% - 2rem) / 1);
}
li:first-child:nth-last-child(3):not(:last-child):after,
li:first-child:nth-last-child(3) ~ li:not(:last-child):after {
    width: calc((100% - 2rem) / 2);
}
li:first-child:nth-last-child(4):not(:last-child):after,
li:first-child:nth-last-child(4) ~ li:not(:last-child):after {
    width: calc((100% - 2rem) / 3);
}
li:first-child:nth-last-child(5):not(:last-child):after,
li:first-child:nth-last-child(5) ~ li:not(:last-child):after {
    width: calc((100% - 2rem) / 4);
}
li:first-child:nth-last-child(6):not(:last-child):after,
li:first-child:nth-last-child(6) ~ li:not(:last-child):after {
    width: calc((100% - 2rem) / 5);
}
li:first-child:nth-last-child(7):not(:last-child):after,
li:first-child:nth-last-child(7) ~ li:not(:last-child):after {
    width: calc((100% - 2rem) / 6);
}

li:first-child:nth-last-child(8):not(:last-child):after,
li:first-child:nth-last-child(8) ~ li:not(:last-child):after {
    width: calc((100% - 2rem) / 7);
}

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li class="active">4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
</ul> 
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li class="active">4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
</ul> 
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li class="active">4</li>
  <li>5</li>
  <li>6</li>
</ul> 
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li class="active">4</li>
  <li>5</li>
</ul> 
<ul>
  <li>1</li>
  <li class="active">2</li>
  <li>3</li>
  <li>4</li>
</ul> 
<ul>
  <li>1</li>
  <li class="active">2</li>
  <li>3</li>
</ul> 
<ul>
  <li class="active">1</li>
  <li>2</li>
</ul> 
<ul>
  <li class="active">1</li>
</ul>

Solution 5 - Css

Though this is possible with CSS3, I think SVG is a better tool for sophisticated interfaces.

I made this with SVG (styled with CSS):

enter image description here

And here's a Plunk to demonstrate.

Solution 6 - Css

Example I made based on the answer: https://codepen.io/Smakosh/pen/ZvvyMg

Pug
ul
  li.list.active 1
  li.list 2
  li.list 3
  li.list 4
Sass
ul
  list-style: none
    li
      display: inline-block
      width: 4rem
      height: 4rem
      line-height: 4rem
      border-radius: 100%
      background: #d8d8d8
      margin-right: 2rem
      position: relative
      &:first-child
        margin-left: unset
        &:before
          display: none
      &:before
        content: ''
        width: 2.4rem
        background-color: #d8d8d8
        height: 2px
        position: absolute
        top: 2rem
        right: 3.9rem
    .active
      background: #03A9F4
      color: #fff
      &:before
        background-color: #03A9F4

Solution 7 - Css

Well, it's a ton of markup, but you could do something like this:

Use display: table-cell; as it will automatically adjust the widths of items to fill spaces.

Then, have a set of circle elements, and a set of line elements. The line elements just have a bottom border on them, and the circle elements are just relatively positioned downwards to align with the line.

Note that the circles need to have an extra container, otherwise table-cell will stretch all the circles to the same height, and you don't want that that. This will require you to set the width of those containers to be 1px, which will force it to the size of it's child.

Check out this demo:

http://jsfiddle.net/Sjdm4/

Solution 8 - Css

I used Bootstrap 4 and FontAwesome to make my version of this.

Here's the code pen: [a link]https://codepen.io/tr4c355/pen/roBjWV

HTML & CSS:

<style>
.line-btw { 
  height:3px;
  width:100px;
  background-color: orange;
}
</style>

<div class="fa-stack fa-lg text-center">
  <i class="fa fa-circle-o fa-stack-2x"></i>
  <div class=""><b>1</b></div>
</div>
<div class="line-btw"></div>
<div class="fa-stack fa-lg text-center" style="">
  <i class="fa fa-circle-o fa-stack-2x"></i>
  <div style=""><b>2</b></div>
</div>
<div class="line-btw"></div>
<div class="fa-stack fa-lg text-center" style="">
  <i class="fa fa-circle-o fa-stack-2x"></i>
  <div class=""><b>3</b></div>
</div>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHGandhiView Question on Stackoverflow
Solution 1 - CssbookcaseyView Answer on Stackoverflow
Solution 2 - CssccondrupView Answer on Stackoverflow
Solution 3 - CssJhonatan Acelas ArevaloView Answer on Stackoverflow
Solution 4 - CssNick GrealyView Answer on Stackoverflow
Solution 5 - CssTyler EichView Answer on Stackoverflow
Solution 6 - CssSmakoshView Answer on Stackoverflow
Solution 7 - CssBlake MannView Answer on Stackoverflow
Solution 8 - CssTraceView Answer on Stackoverflow