Automatically add a span with a class around all emojis

As soon as I use one or more emojis in HTML or Markdown (I usually write posts in HTML rather than MD), I’d like to add a <span class="emoji"> around the the emoji (or emojis, if used in succession).

I’d like to do this because I want to be able to style all emojis without manually having to add a class to the emojis. I’d prefer if Hugo did this while rendering the site so I don’t have to use JS.

There should be unicode ranges for emojis that could be targeted.

Anyone attempted anything like this?

Doing this via output in Hugo will result in 27bytes per emoji extra. Not saying that is much, but it adds up for people that are very, ehm, expressive with emojis.

Some notes:

  • CSS: I don’t think there is a way to target specific character codes per CSS, that would have been my first approach. You could do a search for [however_characters_are_found=1234] and then use :before and :after to style them. I had a very quick check, but it does not appear this is possible currently.
  • JavaScript: It is possible to target character codes via for instance charAt in (I know you don’t want that) Javascript. You could parse your output and dynamically add the spans.
  • Hugo: You could use findRe to create a regular expression to find and replace all characters of a certain unicode character class or each emoji manually before outputting the content/description. That might be the Hugo way to do it. It will be resource intense though.
  • Hugo 2: Shortcode. {{< emoji name=":alert:" >}} and in layouts/shortcodes/emoji.html the logic to parse the name into an emoji inside of a span. Caveat (someone else will jump in and have the knowledge): I don’t know if you need to use {{< or {{% for the shortcode call in the markdown so that the HTML is not double-parsed or removed.

I’m surgical with emojis. And to be clear, I’m not proposing this conversion should be the new standard. :smile:

You can target the ranges, but you still have to wrap an element around them (which is what I was asking for).

/* Basic emoji ranges and what they contain */
.emoji-style {
  /* Emoticons (😀 😃 😄 etc) */
  unicode-range: U+1F600-1F64F;
}

.specific-styles {
  /* Target specific categories */
  
  /* Just face emojis */
  unicode-range: U+1F600-1F637;
  /* Example: make all face emojis bigger */
  font-size: 1.5em;
  
  /* Animals (🐶 🐱 🐭 etc) */
  unicode-range: U+1F400-1F4D3;
  /* Example: give animals a subtle bounce */
  animation: bounce 1s infinite;
  
  /* Hearts (❤️ 💕 💞 etc) */
  unicode-range: U+2764, U+1F493-1F49F;
  /* Example: make hearts red */
  color: red;
  
  /* Food items (🍎 🍕 🌮 etc) */
  unicode-range: U+1F345-1F37F;
  /* Example: add a hover effect */
  transition: transform 0.2s;
}

/* You can combine multiple ranges */
.multiple-ranges {
  unicode-range: U+1F600-1F64F, /* emoticons */
                 U+1F300-1F5FF, /* symbols & pictographs */
                 U+1F680-1F6FF, /* transport & map symbols */
                 U+2600-26FF;   /* misc symbols */
}

/* You can also target specific emojis by their code */
.single-emoji {
  /* Only targets 🌟 */
  unicode-range: U+1F31F;
}

That sounds like the way! I don’t even know where to start though. If someone succeeds with this, please report back in this thread. :slight_smile:

If this is for your personal site, and you don’t intend to include mathematical markup in your pages, you can use the passthrough render hook for this.

Regarding the regex approach… Unlike Rust, Go does not recognize/support the Unicode “Emoji_Presentation” character class.

That’s not targeting. I was talking about a construct like a[href=^https] that would target all links that start with https.

Using unicode-range you could try a construct like this:

@font-face {
  font-family: "Hearts";
  unicode-range: U+2764, U+1F493-1F49F;
  size-adjust: 200%;
}
@font-face {
  font-family: "Food";
  unicode-range: U+1F345-1F37F;
  size-adjust: 200%;
}
.content p {
  font-family: Hearts, Food, other fonts;
}

I am unsure if you need to name the src of the emoji ranges. If in doubt add src: local("Apple Color Emoji"), local("Segoe UI Emoji"), local("Segoe UI Symbol"), local("Noto Color Emoji"); which should match with most these days.

and if in CSS

using transform.Emojify you may brute force wrap :something: with an HTML tag on the already rendered content.

with enableEmoji = false and this markdown: I :heart: Emojis the following

{{ define "main" }}
   {{ .Content | replaceRE `(:\w+:)` "<span class=\"emoji\">$1</span>" | transform.Emojify | safeHTML }}
   {{ .Content | replaceRE `(:(\w+):)` "<span class=\"emoji emo-$2\">$1</span>" | transform.Emojify | safeHTML }}
safeHTML }}

will result in

   <p>I <span class="emoji">❤️</span> Emojis</p>  <!-- &#x2764;&#xfe0f; -->

   <p>I <span class="emoji emo-heart">❤️</span> Emojis</p>

not sure about the security implication, but I guess this should be safe to do.

  • Content already rendered completely
  • regex captures a word only, dunno if one could inject there.
  • HTML tag in your template
  • transform.Emojify can be considered safe?

p.s. you may also target the markdown but then I guess you will have to set all content to unsafe

That does select the emojis from a certain font. It does not style them, since unicode-range is not a selector.

Cool! Would rather write :heart: with my OS emoji picker, because I have some trouble memorizing all the :emojicodes:. It would also make it more portable to another SSG or CMS later. But :emojicode: is better than nothing. :slight_smile:

This is now offtopic :wink: but I would assume that given that these emojis now are selected via a name they can be styled separately from others. Naming with the mentioned method, then applying styles in a class, then using on the container element of the text containing the emojis (for instance, the <main> element).

This

@font-face {
  font-family: "Hearts";
  unicode-range: U+2764, U+1F493-1F49F;
  size-adjust: 200%;
}

does not „name“ an emoji, it names a font subset. There’s no way (yet?) to select (and then style) characters or character ranges in CSS without wrapping them in a HTML element. That’s what I tried to say, and yes, it was OT.