Skip to content

Instantly share code, notes, and snippets.

@panstav
Last active October 21, 2023 11:45
Show Gist options
  • Save panstav/8d4fb38f9f0e6dfbe94b0074f0c9b7af to your computer and use it in GitHub Desktop.
Save panstav/8d4fb38f9f0e6dfbe94b0074f0c9b7af to your computer and use it in GitHub Desktop.
bulma-o-steps.sass with RTL support
$steps-default-color: $grey-lighter !default
$steps-completed-color: $success !default
$steps-active-color: $success !default
$steps-horizontal-min-width: 10em !default
$steps-vertical-min-height: 4em !default
$steps-marker-size: 2 !default
$steps-divider-size: .4em !default
$steps-gap-size: .3rem !default
$steps-hollow-border-size: .3em !default
$steps-thin-divider-size: 1px !default
$steps-thin-marker-size: .8em !default
=steps-horizontal
+tablet
&:not(.is-vertical)
@content
&.is-horizontal
@content
=steps-vertical
+mobile
&:not(.is-horizontal)
@content
&.is-vertical
@content
=steps-all-segments
&.steps .steps-segment
@content
=steps-active-segment
&.steps .steps-segment.is-active
@content
=steps-inactive-segments
&.steps .steps-segment.is-active ~ .steps-segment
@content
.steps
+block
.steps-segment
position: relative
&:not(:last-child):after
// This will contain the horizontal or vertical divider
content: " "
display: block
position: absolute
+steps-vertical
.steps-segment
display: block
&:not(:last-child)
min-height: $steps-vertical-min-height
&.is-short
.steps-segment
flex-grow: 0
&:not(:last-child)
//this is commented because text would be running perpendicular to the line, so we won't need as much room
// min-height: $steps-horizontal-min-width
&.is-short.is-centered
justify-content: center
&.is-short.is-bottom
justify-content: flex-end
&:not(.is-short)
height: 100%
display: flex
flex-direction: column
.steps-segment:not(:last-child)
flex-grow: 1
+steps-horizontal
display: flex
.steps-segment:not(:last-child)
flex-basis: 1rem
flex-grow: 1
flex-shrink: 1
&.is-narrow
.steps-segment
flex-grow: 0
&:not(:last-child)
min-width: $steps-horizontal-min-width
&.is-narrow.is-centered
justify-content: center
&.is-narrow.is-right
justify-content: flex-end
&.has-content-centered
text-align: center
&.is-balanced, &.has-content-centered
.steps-segment:last-child
flex-basis: 1rem
flex-grow: 1
flex-shrink: 1
&.is-narrow.has-content-centered
.steps-segment:last-child
flex-grow: 0
min-width: $steps-horizontal-min-width
.steps-content.is-divider-content
text-align: center
// Marker style
.steps-marker
align-items: center
display: flex
border-radius: 50%
font-weight: $weight-bold
justify-content: center
// Position & z-index are needed to put it above the divider
position: relative
z-index: 5
// Use a mixin to define all ratios in the same spot
=steps-size($size)
font-size: $size
.steps-marker
height: $size * $steps-marker-size
width: $size * $steps-marker-size
overflow: hidden
+steps-vertical
// Draw a vertical divider
display: flex
flex-direction: column
.steps-segment:not(:last-child):after
// top and bottom position is almost touching the inner side of a hollow border marker
bottom: -$steps-gap-size * 0.8
inset-inline-start: calc(#{$size * ($steps-marker-size * 0.5)} - (#{$steps-divider-size * 0.5}))
top: ($size * $steps-marker-size) - ($steps-gap-size * 0.8)
width: $steps-divider-size
// Align the content with the marker
.steps-content
margin-inline-start: calc(#{$size * $steps-marker-size * 0.5} + .5em)
margin-top: -$size * $steps-marker-size
padding-inline-start: 1em
padding-bottom: 1em
.steps-content.is-divider-content
margin-top: 0
padding-bottom: 0
&.has-content-centered
+tablet
.steps-content
padding-top: calc(#{$size * $steps-marker-size * 0.5} - .5em)
&:not(.is-thin)
&.has-gaps .steps-segment, .steps-segment.has-gaps
&:not(:last-child):after
top: ($size * $steps-marker-size) + $steps-gap-size
bottom: $steps-gap-size
+steps-horizontal
// Draw a horizontal divider
.steps-segment:not(:last-child):after
height: $steps-divider-size
// top and bottom position is almost touching the inner side of a hollow border marker
inset-inline-start: ($size * $steps-marker-size) - ($steps-gap-size * 0.8)
inset-inline-end: -$steps-gap-size * 0.8
top: calc(#{$size * ($steps-marker-size * 0.5)} - (#{$steps-divider-size * 0.5}))
&.has-content-above .steps-segment:not(:last-child)::after
bottom: calc(#{$size * $steps-marker-size * 0.5} - (#{$steps-divider-size * 0.5}))
top: auto
// extra data
.extra-data
inset-inline-start: calc(50% + #{($size * $steps-marker-size * 0.5) + $steps-gap-size})
inset-inline-end: calc(-50% + #{($size * $steps-marker-size * 0.5) + $steps-gap-size})
bottom: 100%
position: absolute
&.has-overflow-right
overflow: visible
inset-inline-end: auto
white-space: nowrap
min-width: calc(100% - #{$size * $steps-marker-size * 0.5} - (#{$steps-divider-size * 0.5}))
&.has-overflow-left
overflow: visible
inset-inline-start: auto
white-space: nowrap
min-width: calc(100% - #{$size * $steps-marker-size * 0.5} - (#{$steps-divider-size * 0.5}))
&.has-overflow-centered
overflow: visible
inset-inline-start: auto
white-space: nowrap
min-width: calc(100% - #{$size * $steps-marker-size * 0.5} - (#{$steps-divider-size * 0.5}))
&.has-content-above .extra-data
top: 100%
bottom: auto
// Align the content with the marker
.steps-content
margin-inline-start: $size * $steps-marker-size * 0.5
&:not(:last-child)
margin-inline-end: -$size * $steps-marker-size * 0.5
&.is-divider-content
margin-inline-end: -$size * $steps-marker-size * 0.5
padding-inline-start: 2em
padding-inline-end: 2em
&.has-content-centered
.steps-segment:not(:last-child):after
inset-inline-start: 50%
inset-inline-end: -50%
.steps-marker
position: absolute
inset-inline-start: calc(50% - #{$size * $steps-marker-size * 0.5})
.steps-content
margin-top: $size * $steps-marker-size
margin-inline-start: .5em
margin-inline-end: .5em
padding-top: .2em
&.has-content-above.has-content-centered .steps-content
margin-bottom: $size * $steps-marker-size
padding-bottom: .2em
&:not(.is-thin)
&.has-gaps .steps-segment, .steps-segment.has-gaps
&:not(:last-child):after
inset-inline-start: ($size * $steps-marker-size) + $steps-gap-size
inset-inline-end: $steps-gap-size
&.has-content-centered
&.has-gaps .steps-segment, .steps-segment.has-gaps
&:not(:last-child):after
inset-inline-start: calc(50% + #{($size * $steps-marker-size * 0.5) + $steps-gap-size})
inset-inline-end: calc(-50% + #{($size * $steps-marker-size * 0.5) + $steps-gap-size})
.steps
+steps-size($size-normal)
.steps.is-small
+steps-size($size-small)
.steps.is-medium
+steps-size($size-medium)
.steps.is-large
+steps-size($size-large)
// Divider Default Colors
.steps-segment
&:after
background-color: $steps-completed-color
&.is-active
&:after
background-color: $steps-default-color
&.is-active ~ .steps-segment
&:after
background-color: $steps-default-color
// Marker Default Colors
.steps:not(.is-hollow)
.steps-marker:not(.is-hollow)
background-color: $steps-completed-color
color: findColorInvert($steps-completed-color)
.steps-segment.is-active
.steps-marker:not(.is-hollow)
background-color: $steps-active-color
color: findColorInvert($steps-active-color)
.steps-segment.is-active
& ~ .steps-segment .steps-marker:not(.is-hollow)
background-color: $steps-default-color
color: findColorInvert($steps-default-color)
// Hollow style
.steps.is-hollow .steps-marker,
.steps-marker.is-hollow
border: $steps-hollow-border-size solid $steps-completed-color
.steps.is-hollow .is-active .steps-marker,
.steps .is-active .steps-marker.is-hollow
border-color: $steps-active-color
.steps.is-hollow .steps-segment.is-active ~ .steps-segment .steps-marker,
.steps-segment.is-active ~ .steps-segment .steps-marker.is-hollow
border-color: $steps-default-color
// Override marker color per step
@each $name, $pair in $colors
$color: nth($pair, 1)
$color-invert: nth($pair, 2)
.steps:not(.is-hollow) .steps-marker:not(.is-hollow)
&.is-#{$name}
background-color: $color !important
color: $color-invert !important
.steps.is-hollow .steps-marker,
.steps .steps-marker.is-hollow
&.is-#{$name}
border-color: $color !important
// Divider dashed style
=steps-divider-background($angle, $color, $size)
background: repeating-linear-gradient($angle, $color, $color $size, transparent $size, transparent #{$size * 2})
.steps
+steps-vertical
&.is-dashed .steps-segment, .steps-segment.is-dashed
&:after
+steps-divider-background(0deg, $steps-completed-color, 5px)
&.is-dashed .steps-segment.is-active,
&.is-dashed .steps-segment.is-active ~ .steps-segment,
.steps-segment.is-active.is-dashed,
.steps-segment.is-active ~ .steps-segment.is-dashed
&:after
+steps-divider-background(0deg, $steps-default-color, 5px)
+steps-horizontal
&.is-dashed .steps-segment,
.steps-segment.is-dashed
&:after
+steps-divider-background(90deg, $steps-completed-color, 10px)
// the active segment and any subsequent segment get the default colot
&.is-dashed .steps-segment.is-active,
&.is-dashed .steps-segment.is-active ~ .steps-segment,
.steps-segment.is-active.is-dashed,
.steps-segment.is-active ~ .steps-segment.is-dashed
&:after
+steps-divider-background(90deg, $steps-default-color, 10px)
// Thin modifier
.steps.is-thin
.steps-marker
width: $steps-thin-marker-size
height: $steps-thin-marker-size
&.is-hollow .steps-marker,
.steps-marker.is-hollow
border-width: $steps-thin-divider-size
height: calc(#{$steps-thin-marker-size} + #{$steps-thin-divider-size})
width: calc(#{$steps-thin-marker-size} + #{$steps-thin-divider-size})
+steps-vertical
.steps-segment
&:not(:last-child):after
bottom: 0
inset-inline-start: calc(#{$steps-thin-marker-size * 0.5} - #{$steps-thin-divider-size * 0.5})
top: $steps-thin-marker-size
width: $steps-thin-divider-size
.steps-content
margin-top: -$steps-thin-marker-size * 1.5
margin-inline-start: $steps-thin-marker-size
&.has-gaps .steps-segment, .steps-segment.has-gaps
&:not(:last-child):after
bottom: $steps-thin-marker-size * 0.5
top: $steps-thin-marker-size * 1.5
&.has-content-centered
.steps-content
padding-top: $steps-thin-marker-size * 2
+steps-horizontal
.steps-segment
&:not(:last-child):after
inset-inline-start: $steps-thin-marker-size
inset-inline-end: 0
top: calc(#{$steps-thin-marker-size * 0.5} - #{$steps-thin-divider-size * 0.5})
height: $steps-thin-divider-size
&.has-content-above .steps-segment:not(:last-child)::after
bottom: calc(#{$steps-thin-marker-size * 0.5} - #{$steps-thin-divider-size * 0.5})
top: auto
.steps-content
margin-top: $steps-thin-marker-size
&.has-content-centered
.steps-segment
&:not(:last-child):after
inset-inline-start: calc(50% + #{$steps-thin-marker-size * 0.5})
inset-inline-end: calc(-50% + #{$steps-thin-marker-size * 0.5})
.steps-marker
position: absolute
inset-inline-start: calc(50% - #{$steps-thin-marker-size * 0.5})
&.has-gaps .steps-segment, .steps-segment.has-gaps
&:not(:last-child):after
inset-inline-start: $steps-thin-marker-size * 1.5
inset-inline-end: $steps-thin-marker-size * 0.5
&.has-content-centered.has-gaps .steps-segment, &.has-content-centered .steps-segment.has-gaps
&:not(:last-child):after
inset-inline-start: calc(50% + #{($steps-thin-marker-size * 0.5) + ($steps-thin-marker-size * 0.5)})
inset-inline-end: calc(-50% + #{($steps-thin-marker-size * 0.5) + ($steps-thin-marker-size * 0.5)})
//.has-content-above
.steps:not(.is-vertical).has-content-above
.steps-segment
+tablet
display: flex
flex-direction: column-reverse
.steps-content
margin-top: 0
padding-top: 0
display: flex
flex-direction: column-reverse
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment