Skip to content

Instantly share code, notes, and snippets.

@mitiko
Created August 9, 2022 14:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mitiko/674443e532031587b043d1b432c54a95 to your computer and use it in GitHub Desktop.
Save mitiko/674443e532031587b043d1b432c54a95 to your computer and use it in GitHub Desktop.
Styling first (and last) word in html with Tera

Styling first word (with Tera)

CSS has a ::first-letter and ::first-line pseudo elements. Unfortunately, it does not have a ::first-word (or ::last-word for that matter).

The main workaround posted is to use javascript but most of the reason to build my blog SSG style is to avoid javascript, plus no one likes delayed styling.

I'm using Zola, which relies on the Tera engine and the proper (static) way to do this is with shortcodes. However, turns out Zola doesn't render shortcodes in templates, only markdown pages. Thankfully, I'm not the first to stumble at this and @bluejekyll suggests using Tera Macros.

TL;DR I made a Tera macro to pop the first word of a page's title in a span and allow for styling it seperately.

Link to first-word macro. Link to last-word macro.

The setup

Create a templates/macros.html. Inject the macros file in a template (i.e. blogs.html):

{% import "macros.html" as macros %}

Zola complained when I did this right before my use place because it was inside a block, making the injection top-of-the-file works. Personally, I would like to use macros globally and I did the injection in base.html.

The macro

Tera has built-in filters for all the important operations: split, first, slice, and join.

{% macro style_first_word(string) %}
    {% set words = string | split(pat=" ") %}
    {% set first_word = words | first %}
    {% set remaining_words = words | slice(start=1) | join(sep=" ") %}

    <span class="first-word">
        {{ first_word }}
    </span>
    {{ remaining_words }}
{% endmacro style_first_word %}

Then some css magic:

span.first-word {
    font-size: 1.1em;
    color: rgb(0, 144, 137);
}

I actually didn't like how this looked, so I made a last-word macros as well. Just substitude first for last and slice(start=1) for slice(end=-1):

1c1
< {% macro style_first_word(string) %}
---
> {% macro style_last_word(string) %}
3,8c3,5
<     {% set first_word = words | first %}
<     {% set remaining_words = words | slice(start=1) | join(sep=" ") %}
<     
<     <span class="first-word">
<         {{ first_word }}
<     </span>
---
>     {% set last_word = words | last %}
>     {% set remaining_words = words | slice(end=-1) | join(sep=" ") %}
> 
10c7,10
< {% endmacro style_first_word %}
---
>     <span class="last-word">
>         {{ last_word }}
>     </span>
> {% endmacro style_last_word %}

The resulting macro looks like this:

{% macro style_last_word(string) %}
    {% set words = string | split(pat=" ") %}
    {% set last_word = words | last %}
    {% set remaining_words = words | slice(end=-1) | join(sep=" ") %}

    {{ remaining_words }}
    <span class="last-word">
        {{ last_word }}
    </span>
{% endmacro style_last_word %}

My main usage was in blog.html when listing articles:

<ul>
{% for page in section.pages %}
  <li>
    <a href="{{ page.path | safe }}">
      {{ macros::style_last_word(string=page.title) }}
    </a>
  </li>
{% endfor %}
</ul>

Hope I could be of help to some struggling soul!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment