Search code examples
pythonhtmlcssstreamlit

Only the top part of div is clickable - why?


I am making a website in Streamlit. With HTML and CSS, I’m trying to put a clickable logo on the top left corner, and text dead center on the same line, regardless of the logo placement. I have managed to make the logo clickable when it is not located on the same line of the logo with base64 encoding. However, when I try to use div tricks to put logo and title on the same line without affecting placement of the title, only the top of the logo is clickable. Can someone explain where my code went wrong?

import base64
from typing import Final
from pathlib import Path

import streamlit as st


HOME_DIR: Final = Path(__file__).parent.resolve()
TITLE: Final = "Example page"


@st.cache_data(persist="disk")
def clickable_image(img_path: str, link: str) -> str:
    """By default, st.image doesn't support adding hyperlinks to a local image, so I
    have to decode a local image to base64 and pass it to HTML markdown instead.

    Parameters:
    -----------
    img_path : str
        Path to where your image is stored.
    link : str
        URL which you would like to open when the image is clicked on.
    Returns:
    -----------
    str
        A cached hyperlink where your local image is stored inside via base64 encoding.
    """
    img_path = HOME_DIR / img_path
    img_bytes, ext = img_path.read_bytes(), img_path.suffix
    encoded_img = base64.b64encode(img_bytes).decode()

    return (
        f'<div style="display: inline-block;">'
        f'<a href="{link}" target="_blank">'
        f'<img src="data:image/{ext};base64,{encoded_img}" width="100"></a>'
        f"</div>"
    )


def pretty_title(title: str, img_path: str, link: str) -> None:
    """Make a centered title, and give it a red line. Adapted from
    'streamlit_extras.colored_headers' package.

    Parameters:
    -----------
    title : str
        The title of your page.
    img_path : str
        Path to where your image is stored.
    link : str
        URL which you would like to open when the image is clicked on.
    """
    # Define the logo and text
    logo_html = clickable_image(img_path, link)
    text_html = "<h2 style='text-align: center; margin-top: 0;'>" f"{title}</h2>"

    # Define the HTML for the logo and text side by side
    html = (
        "<div style='position: relative;'>"
        f"<div style='position: absolute; top: 0; left: 0;'>{logo_html}</div>"
        f"<div style='text-align: center;'>{text_html}</div>"
        "</div>"
        "<hr style='background-color: #ff4b4b; margin-top: 0;"
        " margin-bottom: 0; height: 3px; border: none; border-radius: 3px;'></hr>"
    )

    # Render the HTML in the Streamlit app
    st.markdown(html, unsafe_allow_html=True)


def main() -> None:
    st.set_page_config(
        page_title=TITLE,
        page_icon="📖",
        layout="wide"
    )

    pretty_title(TITLE, "logo.png", "https://www.google.com/")


main()

Solution

  • I solved this by setting a higher z-index priority to the image div:

    "<div style='position: relative; z-index: 1'>"
    f"<div style='position: absolute; top: 0; left: 0; z-index: 2'>{logo_html}</div>"