DEV Community

Cover image for Pure CSS Salesforce-like progressbar control
Bohdan Stupak
Bohdan Stupak

Posted on

Pure CSS Salesforce-like progressbar control

This article was originally published at Codeproject
You can download the complete source code on Github.

Using LESS

LESS is CSS preprocessor which allows extending CSS with some useful features. You can learn more about it here. In this project, I use LESS variables and functions which as you can see later, allow me to work with colors in a cleaner way.

The stylesheet is attached to index.html file as usual CSS.

<link rel="stylesheet" href="stage-control.min.css"></link> 
Enter fullscreen mode Exit fullscreen mode

LESS file is compiled into stylesheet via:

$ lessc --clean-css stage-contro.less stage-contro.min.css
Enter fullscreen mode Exit fullscreen mode

Making Same Width Stage Items

Consider a container having a random number of items that should have the same width and occupy all available container space.

The solution would be:

.stage-wrapper {
    display: flex;
} 
.stage-item { 
    flex-basis: 100%; 
}

Enter fullscreen mode Exit fullscreen mode

display: flex allows the container to alter items size and is commonly used for dynamic layouts. flex-basis defines the default size of an element before the remaining space is distributed. 100% makes the same width items suitable for our case.

Drawing and Arrow

Every item box is decorated with an arrow.
arrow
The idea behind drawing an arrow is zero width and zero height box, which border serves as an arrow itself. The size of the arrow is determined by the size of the border. So for example, if you want to create an arrow pointing right, you fill the left border with some color and other borders you leave transparent.

.arrow-right { 
    width: 0; 
    height: 0; 
    border-top: 60px solid transparent; 
    border-bottom: 60px solid transparent; 
    border-left: 60px solid green; 
}
Enter fullscreen mode Exit fullscreen mode

To receive arrow after the item box and some white space between two boxes, we combine two arrows: one smaller with the color of the item box and the other one quite bigger white using :before and :after pseudo elements.

&:before,
&:after {
    border: solid transparent;
    content: " ";
    left: 100%;                
    position: absolute;
    top: 50%;
    z-index: 2
}

&:after {
    border-left-color: inherit;
    border-width: 12px;
    margin-top: -12px;
}

&:before {
    border-color: rgba(255, 255, 255, 0);
    border-left-color: #fff;
    border-width: 14px;
    margin-top: -14px;
}
Enter fullscreen mode Exit fullscreen mode

Hovering Items

Consider our progressbar has already some items passed. Let us introduce the class to mark those items.

&.stage-active {
    background-color: @active-color;

    &:after {
        border-left-color: @active-color;
    }
}
Enter fullscreen mode Exit fullscreen mode

Then how do we display intent to move to some next item and therefore mark this item and items before as passed? The idea is to mark all non-passed items that are before or hover with some lighter shade of @active-color.
hover control forward
As soon as in CSS, we can't just select all items before hover, we achieve our goal in two steps:

  1. Mark with a lighter shade of @active-color all non-passed children of our control wrapper:
.stage-wrapper:hover div:not(.stage-active) {
    background-color: lighten(@active-color, 20%);

    &:after {
        border-left-color: lighten(@active-color, 20%);
    }
}
Enter fullscreen mode Exit fullscreen mode

Please note how usage of LESS function lighten allows us not to hardcode lighter shade of active color.

  1. Mark all items after hovered with the default color.
&:hover ~ div:not(.stage-active) {
    background-color: @default-color;

    &:after {
        border-left-color: @default-color;
    }
}    
Enter fullscreen mode Exit fullscreen mode

Hovering Items Backward

Consider a similar logic for pointing item that was already passed to return backward.
hovering control backward
To achieve our goal, we just mark with accent of active color all items after hovered:

&:hover ~ div {
    background-color: lighten(@active-color, 20%);

    &:after {
        border-left-color: lighten(@active-color, 20%);
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
lluismf profile image
Lluís Josep Martínez

Replace("Khakriv", "Kharkiv")