How to change colors of RangeSlider in CSS depending on value?

Hi, I think this is a CSS question, but here goes.

I am trying to make an interactive bar chart where the user can drag two range slider handles to change the bar heights:


The purpose is to guess the breakdown of a budget by category.
I am tryin to figure out how I can change the CSS such that the range slider has three different colors:
Values 0 to left handle = blue
values left handle to right handle = red
Values right handle to 100 = green.

Below is my code. Any help would be much appreciated as I am not an expert in CSS or JS.

import plotly.express as px
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

# dummy global var for total $$
TOTAL = 45034567

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = JupyterDash(__name__,external_stylesheets=external_stylesheets)

            
app.layout = html.Div([
                html.P('Total Spending: '+str(TOTAL)),
                dcc.RangeSlider(id='range-slider',
                      min=0,
                      max=100,
                      step=0.5,
                      value=[33.3,66.6],
                      ),
                html.Div(id='range-slider-drag-output'),
                dcc.Graph(id='guess-spending')
            ])

@app.callback(Output('guess-spending','figure'),
              Output('range-slider-drag-output','children'),
              Input('range-slider','value'))
                
    
def make_guess(value):
    # percents
    a = value[0]
    b = value[1]-value[0]
    c = 100-value[1]
    
    # dollar amounts
    A = a/100*TOTAL
    B = b/100*TOTAL
    C = c/100*TOTAL
    guess_dict = {'Category':['A','B','C'],
                'Dollar Amount':[A,B,C]
                 }
    guessFig = px.bar(guess_dict,
                     x='Category',
                     y='Dollar Amount',
                     color='Category',
                     title='Spending by Category, Your Estimate')
    return guessFig, 'Your estimate: A: {}%, B: {}%, C: {}%'.format(round(a),round(b),round(c))


app.run_server(mode='external',port=8051) ```

Hi @syrup

It would be cool if you could make each segment of the slider a different color, but with this slider, there is one color for the track and one for the rail, so there is not an easy way to do this with CSS.

However, you could update the labels based on the slider. Here’s how that looks:

import dash
import plotly.express as px
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

# dummy global var for total $$
TOTAL = 45034567

external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div(
    [
        html.P("Total Spending: " + str(TOTAL)),
        dcc.RangeSlider(
            id="range-slider", min=0, max=100, step=0.5, value=[33.3, 66.6],
        ),
        html.Div(id="range-slider-drag-output"),
        dcc.Graph(id="guess-spending"),
    ]
)


@app.callback(
    Output("guess-spending", "figure"),
    Output("range-slider-drag-output", "children"),
    Output("range-slider", "marks"),
    Input("range-slider", "value"),
)
def make_guess(value):
    # percents
    a = value[0]
    b = value[1] - value[0]
    c = 100 - value[1]

    color = {
        i: "blue" if i <= a else "red" if (a < i <= (a + b)) else "green"
        for i in range(101)
    }
    marks = {
        i: {"label": str(i), "style": {"color": color[i]}}
        for i in range(0, 101, 5)
    }

    # dollar amounts
    A = a / 100 * TOTAL
    B = b / 100 * TOTAL
    C = c / 100 * TOTAL
    guess_dict = {"Category": ["A", "B", "C"], "Dollar Amount": [A, B, C]}
    guessFig = px.bar(
        guess_dict,
        x="Category",
        y="Dollar Amount",
        color="Category",
        title="Spending by Category, Your Estimate",
    )
    return (
        guessFig,
        "Your estimate: A: {}%, B: {}%, C: {}%".format(round(a), round(b), round(c)),
        marks,
    )


if __name__ == "__main__":
    app.run_server(debug=True)
1 Like

Thank you very much @AnnMarieW ! This is great. Do you know how to change the colors for the track and the rail? It may be more visually understandable if they are the same color.

Making the rail and the track the same color is a great idea! Here are some selectors that I commonly use to customize the slider. This can be included in a .css file in the assets folder.

.rc-slider-handle {
  border: 0;
  background-color: red
}

.rc-slider-rail {
   background-color: #ededed;  /* grey */
}

.rc-slider-track {
  background-color: red
}

.rc-slider-dot {
  border: 0;
  background-color: #ededed; /* grey */
}

.rc-slider-dot.rc-slider-dot-active {
  background-color: red
}
1 Like

Hi @AnnMarieW

I have another slider CSS question and I was wondering if you might be able to help.

I am trying to create a color gradient slider representing an index value on a range from -1 to 1. I would like the marks (-1, -0.5, 0, 0.5, 1) to appear below the background image, but adjusting the height of the rail and track doesn’t appear to work. I’ve made the track, rail, and dots transparent because I only want to see the handle and the marks. I also tried changing background-position but it didn’t change anything.

Here is the version where track, rail, and dots are transparent:


And here is a version where they are white so you can see the positioning of the slider relative to the background:

Here is my css code for the first image:

.rc-slider{
background-image: linear-gradient(to right, darkblue, lightgreen);
height: 50px;
}

.rc-slider-rail {
background-color: transparent;
}

.rc-slider-track {
background-color: transparent;
}

.rc-slider-handle{
height: 50px;
width: 15px;
border-radius: 10px;
border-color: black;
background-color: white;
}

.rc-slider-dot.rc-slider-dot-active{
background-color: transparent;
border-color: transparent;
}

.rc-slider-dot{
background-color: transparent;
border-color: transparent;
}

Hi @syrup

That looks like a cool slider. To move the markers, try:

.rc-slider-mark {
    margin-top:25px;
}