Loading css file across pages takes a fraction of a second



I started using the multi pages feature to create a streamlit app, so far its been nice. However I have encountered a sort of bug (Although I understand this is a expected behavior, because of my approach) . I am loading a custom css file to change the font of the app, I am doing this in every page .py file, now while it works, every time I switch between pages it takes a fraction of a second for the page to load the custom css and its quite noticeable and annoying.

I tried wrapping the code to load the css file with a st.cache decorator, but was greeted with a CachedStFunctionWarning.

This is the code to load the css file.

    with open(file_name) as f:
        st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)

The css file:

@import url('https://fonts.googleapis.com/css2?family=Azeret+Mono&display=swap');

html, body, [class*="css"] {
    font-family: 'Azeret Mono', monospace;

Expected behavior:

Ideally I would want the css to load instantly on all pages upon app launch without it refreshing every time i switch to a different page, and being able to configure it globally would also be nice.

Are there any ways of accomplishing this? Could we have the option to include custom fonts on the config.toml file instead of just the current available ones?

Debug info

  • Streamlit version: 1.15.0
  • Python version: 3.8.0
  • Browser version: Up to date chrome

Have you tried playing directly with Streamlit theming?

I don’t know how you wrote in the caching attempt, so if you could share how you structured it as a function that might shed some light. Also, have you tried the new st.experimental_memo? There can be some fiddly bits with caching, but if you cache the actual css to inject as a string to load on the page, I don’t think there should be a problem.

Unfortunately streamlit theming only has a few font types. I went with the css approach to use a custom one.

And essentially what I did with the st.cache is this

def load_css(file_name = "path/to/file.css"):
   with open(file_name) as f:
      st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)

And then on each page I would call load_css()

How would st.experimental_memo be implemented? Would it be similar to what I tried with st.cache?

Caching stores the output of a function, so try it as some variation like this:

def load_css(file_name = "path/to/file.css"):
    with open(file_name) as f:
        css = f'<style>{f.read()}</style>'
    return css
css = load_css()
st.markdown(css, unsafe_allow_html=True)

I tried your approach, but Im still having the same issues.

You can see what I mean here:

If you are really determined to get this done you could try injecting the custom stylesheet into the base HTML page of the installed Streamlit package. I would be hesitant to suggest a specific implementation but you can look here for inspiration. In one of my apps I adapted some of this code to be run at Docker image build time. Or just use that package’s API but try to understand what it does first and that it could break easily with changes in Streamlit.

Alright, thanks for the suggestion.

Ill leave it as it is. I just hope we get more ways to customize natively in the future.