Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blog: Hero images #6745

Open
4 tasks done
mathisgauthey opened this issue Feb 6, 2024 · 9 comments
Open
4 tasks done

Blog: Hero images #6745

mathisgauthey opened this issue Feb 6, 2024 · 9 comments
Labels
change request Issue requests a new feature or improvement

Comments

@mathisgauthey
Copy link

Context

I'm coming from Hugo with the theme hugo-theme-stack. Here's a demo page using it that looks like my old setup.

That's a blog template, with images for each posts.

@alexvoss recommended that I submit a feature request here.

Description

I'd like the blog index page to search for the first image linked inside the markdown document and use it as a thumbnail. That would allow for beautiful and easy projects portfolio inside blogs from mkdocs-material. But also a colorful blog index.

One could also overwrite it using a thumbnail: YAML key that gives the path to a file.

A default value could be the social card for that particular link maybe ?

Here's an example of my old theme :

image

Here's my current theme using mkdocs-material :

image

Related links

Use Cases

Apparently I wasn't the only one to ask for such a feature.

The image would allow us to build beautiful blogs without hassles, using the already existing blog chronological index. And we could also use it for generating projects portfolio index files automatically.

Visuals

Add the image above or below the blog post in a rectangular container, maybe ? Or just a thumbnail on the left of the blog post in the index file.

Before submitting

@mathisgauthey mathisgauthey changed the title Include images on blog post index files [FR] Include images on blog post index files Feb 6, 2024
@squidfunk
Copy link
Owner

Thanks for suggesting. Duplicate of #5736 (and some other issue I currently can't find). Please use customizations to include thumbnails in posts. It's likely that we eventually add this functionality, but we're still in the collection stage of requirements, so native support for this is not planed yet. It is, however, quite easy to do this functionality yourself.

You can post also ask for more support on our discussion board.

@squidfunk squidfunk closed this as not planned Won't fix, can't repro, duplicate, stale Feb 7, 2024
@alexvoss
Copy link
Collaborator

alexvoss commented Feb 7, 2024

That was my fault for not looking for the prior discussion of this (I suggested the FR). @squidfunk, how about I show how this can be done in the blog example that I need to pick up again? I'll post the necessary snippets here. @mathisgauthey, do you think it would be ok to have to put the image URL/path into the post meta-data? That is the most flexible option, I think, but requires some work by the post author.

@mathisgauthey
Copy link
Author

That was my fault for not looking for the prior discussion of this (I suggested the FR). @squidfunk, how about I show how this can be done in the blog example that I need to pick up again? I'll post the necessary snippets here. @mathisgauthey, do you think it would be ok to have to put the image URL/path into the post meta-data? That is the most flexible option, I think, but requires some work by the post author.

I think it could be a great start thanks !

One could then think about having a default behavior for handling thumbnails on modified Blog index pages such as using the first image found in the post or reverting to the social card of the post if the plugin is activated.

@squidfunk
Copy link
Owner

That was my fault for not looking for the prior discussion of this (I suggested the FR). @squidfunk, how about I show how this can be done in the blog example that I need to pick up again? I'll post the necessary snippets here. @mathisgauthey, do you think it would be ok to have to put the image URL/path into the post meta-data? That is the most flexible option, I think, but requires some work by the post author.

You know what, we'll reopen it, as this has been asked for a few times, so we'll see if others would find it useful as well. We could add functionality that extracts the image and allows for overriding via meta data, but I need to investigate. I'll try to come up with a general solution for this, but in the mean time the absolute simplest solution is #5406 (comment).

One could then think about having a default behavior for handling thumbnails on modified Blog index pages such as using the first image found in the post or reverting to the social card of the post if the plugin is activated.

IMHO, it's a hero image, not a thumbnail 😉 Using the social card image is not really a good idea, IMHO, because it has a completely different purpose. Thus, I'd say:

  1. Check front matter
  2. Check source of blog for first encounter, or for an image tagged with the data-hero attribute (or similar)
  3. No image

We could also allow to explicitly unset the image by using something like hero: null. I think those degrees of freedom allow for very precise control and good default behavior. We could also add setting to switch it on/off completely.

@squidfunk squidfunk reopened this Feb 7, 2024
@squidfunk squidfunk changed the title [FR] Include images on blog post index files Blog: Hero images Feb 7, 2024
@squidfunk squidfunk added the change request Issue requests a new feature or improvement label Feb 7, 2024
@Guts
Copy link
Contributor

Guts commented Feb 8, 2024

Definitely interested too! For now, I'm using a custom template to achieve this but not relying on blog plugin.

@pvdemael
Copy link

pvdemael commented Jun 6, 2024

I have a simple solution which works for me now. No doubt it can be improved much but it does the job. Some things are hardcoded but this can be changed by someone with much more dev skills. I must confess I used ChatGPT with a lot of prompts but hey, if it does the job...

In my case, only the home page must have a hero image. It needs to cycle every 4s between 4 available images with a fade effect.

The frontmatter of the home index.md page

---
hero:
  - assets/img/image1.png
  - assets/img/image2.png 
  - assets/img/image3.png
  - assets/img/image4.png

hide:
    - toc 
    - navigation

template: home.html
---

I override the home.html page with this code:

{% extends "main.html" %}

{% block hero %}
<div id="crossfade" class="hero-image">
  {% for image in page.meta.hero %}
    <div class="hero-image-inner {% if loop.first %}next{% endif %}" style="background-image: url('{{ image }}');"></div>
  {% endfor %}
  <div class="hero-text">
    <h1>Some text to add using variables</h1>
    <p>Here too</p>
    <button>And here too</button>
  </div>
</div>

<style>
  #crossfade {
    position: relative;
    width: 100%;
    height: 300px; /* Adjust height as needed */
    overflow: hidden;
  }

  .hero-image-inner {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    z-index: 0;
    background-position: center;
    background-repeat: no-repeat;
    background-size: cover;
    transition: opacity 2s ease-in-out; /* Transition for opacity */
  }

  .hero-image-inner.next {
    opacity: 1;
  }

  /* Place text in the middle of the image */
  .hero-text {
    text-align: left;
    position: absolute;
    top: 50%;
    left: 10%;
    transform: translateY(-50%);
    color: white;
    z-index: 2;
    transition: opacity 2s ease-in-out; /* Transition for opacity */
  }
</style>

<script>
document.addEventListener('DOMContentLoaded', () => {
  const images = document.querySelectorAll('.hero-image-inner');
  let index = 0;

  setInterval(() => {
    images[index].classList.remove('next');
    index = (index + 1) % images.length;
    images[index].classList.add('next');
  }, 4000);
});
</script>
{% endblock %}

@fertek
Copy link

fertek commented Feb 27, 2025

Using Customization, I added hero images to the blog:

Image

It's quite simple - just modify post.html and blog.html and add some CSS.

./overrides/partials/post.html:

{# https://github.com/squidfunk/mkdocs-material/blob/master/src/templates/partials/post.html #}

<!-- Post excerpt -->
<article class="md-post md-post--excerpt">
  <header class="md-post__header">
    <!-- Hero image (full width) -->
    <div class="hero-image">
      <a href="{{ post.url | url }}">
        {% if post.meta.hero %}
          <img src="{{ post.meta.hero }}" />
        {% else %}
          <img src="/images/default.jpg" />
        {% endif %}
      </a>
    </div>
    <!-- Post title below image -->
    <div class="md-typeset">
      <h2>
        <a href="{{ post.url | url }}">{{ post.title }}</a>
      </h2>
    </div>
    <!-- Post metadata -->
    <div class="md-post__meta md-meta">
      <ul class="md-meta__list">
        <!-- Post date -->
        <li class="md-meta__item">
          <time datetime="{{ post.config.date.created }}">
            {{- post.config.date.created | date -}}
          </time>
          {#- Collapse whitespace -#}
        </li>
        <!-- Post categories -->
        {% if post.categories %}
          <li class="md-meta__item">
            {{ lang.t("blog.categories.in") }}
            {% for category in post.categories %}
              <a href="{{ category.url | url }}" class="md-meta__link">{{- category.title -}}</a>
              {%- if not loop.last %},
              {% endif -%}
            {% endfor -%}
          </li>
        {% endif %}
        <!-- Post readtime -->
        {% if post.config.readtime %}
          {% set time = post.config.readtime %}
          <li class="md-meta__item">
            {% if time == 1 %}
              {{ lang.t("readtime.one") }}
            {% else %}
              {{ lang.t("readtime.other") | replace("#", time) }}
            {% endif %}
          </li>
        {% endif %}
      </ul>
      <!-- Draft marker -->
      {% if post.config.draft %}<span class="md-draft">{{ lang.t("blog.draft") }}</span>{% endif %}
    </div>
  </header>
</article>

./overrides/blog.html:

{# https://github.com/squidfunk/mkdocs-material/blob/master/src/templates/blog.html #}

{% extends "main.html" %}

<!-- Page content -->
{% block container %}
  <div class="md-content" data-md-component="content">
    <div class="md-content__inner">

      <!-- Header -->
      <header class="md-typeset">
        {{ page.content }}
      </header>

      <!-- Posts -->
      <div class="list-of-posts">
        {% for post in posts %}
          {% include "partials/post.html" %}
        {% endfor %}
      </div>

      <!-- Pagination -->
      {% if pagination %}
        {% block pagination %}
          {% include "partials/pagination.html" %}
        {% endblock %}
      {% endif %}
    </div>
  </div>

{% endblock %}

./docs/stylesheets/extra.css:

/*
Blog image and title with other information displayed in a column (not side by side).
Also left-aligned text.
*/
.md-post--excerpt .md-post__header {
  flex-direction: column;
  align-items: start;
}

/* Blog title without unnecessary space around it. */
.list-of-posts h2 {
  margin: 0;
}

/* Hero image container */
.hero-image {
  width: 100%;
  overflow: hidden;
  position: relative;
  padding-bottom: 100%; /* Creates a square aspect ratio */
}

/* Hero image styling */
.hero-image img {
  position: absolute;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.3s ease;
}

/* Hover effect for hero images */
.hero-image img:hover {
  transform: scale(1.03);
}

/* Two blog previews side by side */
@media (min-width: 45em) {
  .list-of-posts {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }
}

In the front matter, add a hero line with the path to the image:

title: "Lorem Ipsum"
date: 2025-02-27
hero: /images/lorem_ipsum.jpg

@wsitch
Copy link

wsitch commented Mar 20, 2025

I'd also like to attach a hero image to each blog post. I'm not sure this is possible without forking due to the way I'd like it to be shown in the post preview.

Current:
Image

I'd like to add an image under the title, to the left of the text, like this:

Desired:
Image

It's possible by editing the image into the blog post, of course:

# Maneuvering road object tracking with the IMM algorithm and an imaging radar sensor

![](assets/images/object_tracking_IMM_1666x1074.png){: align=left width=300 }

This paper summarizes how an interacting multiple model (IMM) algorithm uses measurements from an imaging radar sensor to estimate the dynamic state of a maneuvering road object with unknown control inputs. 

But this causes a problem! The post hero image is now in a strange spot in the actual blog post. I don't want the hero image there in the actual blog post, it'll be somewhere else in the post and probably larger with a caption.

I can't override the partial post.html because it's not granular enough:

    <!-- Post content -->
    <div class="md-post__content md-typeset">
      {% if post.meta.hero_image %}
        <img src="assets/{{ post.meta.hero_image }}" width="300" align="left">
      {% endif %}
      {{ post.content }}
  
      <!-- Continue reading link -->
      {% if post.more %}
        <nav class="md-post__action">
          <a href="{{ post.url | url }}">
            {{ lang.t("blog.continue") }}
          </a>
        </nav>
      {% endif %}
    </div>

I can't add a meta.hero_image floating left of the text under the title, I can only add it above, which forces the title to the right of the image:

Image

I can't modify post.content without modifying the Excerpt class in src/plugins/blog/__init__.py, which sounds like fork territory.

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
change request Issue requests a new feature or improvement
Projects
None yet
Development

No branches or pull requests

8 participants
@squidfunk @Guts @fertek @alexvoss @pvdemael @wsitch @mathisgauthey and others