Actions

Work Header

Rating:
Archive Warning:
Fandom:
Additional Tags:
Language:
English
Series:
Part 1 of AO3 Work Skin Tutorials
Stats:
Published:
2024-10-30
Updated:
2024-10-30
Words:
5,900
Chapters:
2/3
Comments:
14
Kudos:
28
Bookmarks:
16
Hits:
1,303

LINE Messenger / Chat AO3 Work Skin Guide

Summary:

A tutorial to mimic LINE chats in your stories, with some niceties like stickers.

Notes:

A lot of thanks to the two guides linked as 'inspiration' as without their knowledge, I wouldn't have been able to do this.

Please don't hesitate to ask if you have questions!

Chapter Text

This fiction uses, and is about, custom styling. There's fallback in some places, but if you have work skins disabled you likely won't get much out of this.


Contents

  1. Introduction
  2. Full Example
  3. Headers
  4. Footers
  5. Messages
  6. Names
  7. Avatars
  8. Names and Avatars
  9. Message Dates
  10. Embedded Links (Youtube)
  11. Shared Files
  12. Stickers
  13. Accessibility
  14. Fallback
  15. Changelog
  16. Attribution


Introduction[]

This chapter consists of a full example chat, followed by a step-by-step breakdown. Each step has a snippet with the CSS code (to go in the work skin) and HTML code (to go into your fic) needed to create it. You can take the snippet code and amend it to your own needs.

If you prefer to dive in and figure things out from scratch, Chapter 2 has all the code to replicate the full example chat and nothing else.

If you need an introduction to work skins or HTML in general, please check the AO3 documentation and/or one of the fics that inspired this one, who can do a much better job of it than me. Sorry! I'm happy to answer specific questions in the comments though.

The code has been tested in both Chrome and Firefox, on both desktop and mobile, across a few resolutions. While I can't promise it'll always look correct, it should usually be fine. Please let me know if it ever isn't.

Full Example[]

LINE Group Chat: Inner Monologue (54)

1 week ago

Me: Hey, I finally figured it out!!
Status:
Read by 30
Sent: 06:12 AM

LINE avatar for the hopeless bystander: a featureless yellow circle. Hapless Bystander: What did you figure out?
Sent:
06:12 AM

Me: How to make the workskin look nice?
Status:
Read by 30
Sent: 06:12 AM

LINE avatar for the sarcastic impulse: a featureless red circle. Sarcastic Impulse: Oh really?
Sent:
06:13 AM

Sarcastic Impulse: I'm guessing you're the first person to ever do this?
Sent:
06:13 AM

LINE avatar for the hopeless bystander: a featureless yellow circle. Hapless Bystander: Dunno sounds kinda cool
Sent:
06:13 AM

Me: It's super cool!
Status:
Read by 30
Sent: 06:13 AM

Me: Look, let me send you the code!
Status:
Read by 30
Sent: 06:13 AM

Uploaded File by Me: line_messages.css
Valid until: ~12/01 06:13
Size: 0.03 kB

Status:
Read by 30
Sent: 06:13 AM

Me: also look
Status:
Read by 30
Sent: 06:14 AM

LINE avatar for the sarcastic impulse: a featureless red circle. Sarcastic Impulse: Oh wow, however would we have lived without that?
Sent:
06:14 AM

Me: https://­www.youtube.com/­watch?­v=5yUr5ZiRcTw
Status:
Read by 30
Sent: 06:14 AM

Embedded youtube video thumbnail for the アラフォーマジック music video by Charisma.com. Features a very trippy and low-amount-of-colours image of a woman, Japanese text, and abstract geometric shapes as the background. Sorry. It's very hard to describe. Charisma.com - アラフォーマジック (Official Music Video)
Status:
Read by 30
Sent: 06:14 AM

LINE avatar for self-esteem: a featureless blue circle. Self-Esteem: Nah that's fire bro
Sent:
06:14 AM

LINE avatar for the hopeless bystander: a featureless yellow circle. Hapless Bystander: Not sure I quite follow but..
Sent:
06:14 AM

3 days ago

Me: Whatever, I'm just a genius
Status:
Read by 30
Sent: 06:15 AM

LINE Sticker, containing art of Ikuyo Kita from the manga and anime Bocchi the Rock! A stylised version of Kita is wearing a white labcoat over her traditional Japanese school uniform and a black professor's hat, pointing to the left balanced on one leg as if towards a scientific discovery. Read by 30
Sent: 06:15 AM


Headers[]

Inner Monologue (54)

 

Self-Esteem

CSS

#workskin .header {
    max-width: 350px;
    margin: auto;
    height: 3em;
    line-height: 3em;
    padding: 0 1em;
    font-weight: bold;
    border-top-left-radius: 1em;
    border-top-right-radius: 1em;
}

#workskin .dm {
    background-color: #7292c2;
    text-align: left;
}

#workskin .gm {
    background-color: #263147;
    text-align: center;
    color: #ffffff;
}

#workskin .arrow {
  display: inline-block;
  padding: 5px;
  transform: rotate(135deg);
  margin: 0 15px 0 5px;
}

#workskin .dm > .arrow {
    border: solid #000000;
    border-width: 0 1px 1px 0;
}

#workskin .gm > .arrow {
    border: solid #ffffff;
    border-width: 0 1px 1px 0;
}

HTML

<p class="header gm"><i class="arrow"></i>Inner Monologue (54)</p>
<p class="header dm"><i class="arrow"></i>Self-Esteem</p>

To add a header, create a paragraph with the class 'header'. You can then choose whether it's a group chat or direct message by adding 'gm' or 'dm' as an additional class.


Footers[]

 

CSS

#workskin .footer {
    display: flex;
    background-color: #f0f0f9;
    max-width: 350px;
    margin: auto;
    padding: 0.5em 1em;
    border-bottom-left-radius: 1em;
    border-bottom-right-radius: 1em;
}

#workskin .footer > .icon {
    width: 1.75em;
}

#workskin .footer > .message {
    flex-grow: 2;
    margin: 0 0.5em;
    padding: 0.5em 1.25em;
    background: #f5f5f5;
    border: solid 1px #cdcfd7;
    border-radius: 2em;
}

#workskin .footer > .inactive {
    color: #cdcfd7;
}

#workskin .footer > .active {
    color: #000000;
}

#workskin .footer > .row-gap-spacer {
    width: 0.5em;
}

HTML

<p class="footer">
    <img class="icon" src="https://imperiousmarshmallow.neocities.org/plus-svgrepo-com.svg">
    <span class="row-gap-spacer"></span>
    <img class="icon" src="https://imperiousmarshmallow.neocities.org/camera-svgrepo-com.svg">
    <span class="row-gap-spacer"></span>
    <img class="icon" src="https://imperiousmarshmallow.neocities.org/photo-svgrepo-com.svg">
    <span class="row-gap-spacer"></span>
    <span class="message inactive">Aa</span>
    <span class="row-gap-spacer"></span>
    <img class="icon" src="https://imperiousmarshmallow.neocities.org/microphone-alt-1-svgrepo-com.svg">
</p>
<p class="footer">
    <img class="icon" src="https://imperiousmarshmallow.neocities.org/right-arrow-svgrepo-com.svg">
    <span class="row-gap-spacer"></span>
    <span class="message active">A message is being typed here, by someone</br/>/They wonder what to write?</span>
    <span class="row-gap-spacer"></span>
    <img class="icon" src="https://imperiousmarshmallow.neocities.org/send-alt-1-svgrepo-com.svg">
</p>

To add a footer, create a paragraph with the class 'footer'. You can then add any number of icons - two configurations are shown above by adding an image with the class 'icon'. Please use your own icons for this though, rather than the ones I've uploaded, especially since these ones are licensed with CC Attribution and so can't be freely used without a notice like the one at the end of this tutorial.

If you want to add a message box, add a span with the class 'message', and you can then choose 'inactive' or 'active' classes which will change the font to be grey and black respectively.

The 'row-gap-spacer' spans are currently there because AO3 does not support the 'gap' or 'row-gap' CSS property. They just align the icons and message boxes internally more nicely, so put them in between whatever you do.

Messages[]

Message I'm sending!! Read by 30
05:00 AM

Message I just got!! 06:00 AM

CSS

#workskin .chat {
  max-width: 350px;
  margin: auto;
  background-color: #7292c2;
  padding: 0 1em;
  overflow: auto;
  display: flex;
  flex-flow: column nowrap;
}

#workskin .msgbox {
  display: flex;
  width: 90%;
  margin: 0.5em 0;
  position: relative;
}

#workskin .msgbox .message {
  border-radius: 1.2em;
  padding: 7px 15px;
  position: relative;
  align-self: self-end;
}

#workskin .msgbox .time {
  font-size: .75em;
  color: #ffffff;
  align-content: flex-end;
  flex-shrink: 0;
  padding: 0 7px 2px 7px;
}

#workskin .sent {
  align-self: flex-end;
}

#workskin .sent .message {
    background-color: #85e249;
}

#workskin .sent .message::after {
  content: "";
  position: absolute;
  right: -0.7em;
  top: -0.4em;
  width: 13px;
  height: 17px;
  border-right: 9px solid #85e249;
  border-top-right-radius: 70%;
  transform: rotate(95deg);
}

#workskin .sent .time {
    text-align: right;
    flex-grow: 2;
    order: -1;
}

#workskin .received .message {
    background-color: #ffffff;
}

#workskin .received .message::after {
  content: "";
  position: absolute;
  left: -0.6em;
  top: -0.4em;
  width: 13px;
  height: 17px;
  border-left: 9px solid #ffffff;
  border-top-left-radius: 70%;
  transform: rotate(-95deg);
}

HTML

<div class="chat">
    <p class="msgbox sent">
        <span class="message">Message I'm sending!!</span>
        <span class="time">Read by 30<br />05:00 AM</span>
    </p>

    <p class="msgbox received">
        <span class="message">Message I just got!!</span>
        <span class="time">06:00 AM</span>
    </p>
</div>

Chats have the following hierarchy: a div with the 'chat' class to hold everything, under which there are 'msgbox' (message box) paragraphs that hold individual messages sent. At it's most basic, within each message box you then have a message and time.

You only need one 'chat' holding everything, and then as many 'msgbox's for as name messages as you have. To have messages show as either sent to received, add the 'sent' or 'received' class alongside the 'msgbox'.

To add a message, create a span with a 'message' class within a 'msgbox'. To add a time, create a span with a 'time' class within a 'msgbox'.

If you don't want times on your messages, you will still need to include the 'time' span, but you can leave its contents blank. Otherwise, alignment issues might happen.

Names[]

Wait who are you? 06:01 AM

Indignant Individualism What do you mean you don't know who I am? 06:01 AM

How dare you?? 06:01 AM

Self-Esteem Don't sweat it too much! 06:02 AM

CSS

Take all the 'Messages' CSS plus:

#workskin .msgbox .colbox {
  display: flex;
  flex-flow: column nowrap;
  align-self: self-end;
}

#workskin .msgbox .name {
  font-size: .75em;
  color: #ffffff;
  text-indent: 7px;
  padding-bottom: 2px;
}

HTML

<div class="chat">
    <p class="msgbox sent">
        <span class="message">Wait who are you?</span>
        <span class="time">06:01 AM</span>
    </p>

    <p class="msgbox received">
        <span class="colbox">
            <span class="name">Indignant Individualism</span>
            <span class="message">What do you mean you don't know who I am?</span>
        </span>
        <span class="time">06:01 AM</span>
    </p>

    <p class="msgbox received">
        <span class="message">How dare you??</span>
        <span class="time">06:01 AM</span>
    </p>

    <p class="msgbox received">
        <span class="colbox">
            <span class="name">Self-Esteem</span>
            <span class="message">Don't sweat it too much!</span>
        </span>
        <span class="time">06:02 AM</span>
    </p>
</div>

If you're in a group chat, you might want to include the name of the sender above their messages.

To add a name, create a 'colbox' (column box) span inside the 'msgbox', and then put a 'name' span together with the 'message' span inside that. The 'time' span remains outside the 'colbox'. The code will automatically align things for you.

To my knowledge LINE won't typically show the name again for consecutive messages, in which case you can again skip the column box.

Avatars[]

Wow, so we can really send messages? Read by 30
07:00 AM

Sure can! 07:00 AM

You did good! 07:00 AM

CSS

Take all the 'Messages' CSS plus:

#workskin .msgbox .avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: #aaaaaa;
  margin: 0 10px 0 0;
  flex-shrink: 0;
}

#workskin .msgbox .spacer {
  width: 50px;
  flex-shrink: 0;
}

HTML

<div class="chat">
    <p class="msgbox sent">
        <span class="message">Wow, so we can really send messages?</span>
        <span class="time">Read by 30<br />07:00 AM</span>
    </p>

    <p class="msgbox received">
        <img class="avatar" src="https://imperiousmarshmallow.neocities.org/haplessbystander.png" />
        <span class="message">Sure can!</span>
        <span class="time">07:00 AM</span>
    </p>

    <p class="msgbox received">
        <span class="spacer"></span>
        <span class="message">You did good!</span>
        <span class="time">07:00 AM</span>
    </p>
</div>

To include an avatar, add an image the 'avatar' class at the start of the 'msgbox'. If you don't want to show an avatar with every message, you can put in a 'spacer' span instead.

The skin assumes avatars are 40 by 40 pixels, and will automatically display pictures at this size regardless of their original one. I would recommend, however, making your avatar 40x40px to start with.

Names and Avatars[]

Wait who are you? 06:01 AM

Indignant Individualism What do you mean you don't know who I am? 06:01 AM

How dare you?? 06:01 AM

Self-Esteem Don't sweat it too much! 06:02 AM

CSS

Take all 'Messages', 'Names', and 'Avatars' CSS together.

HTML

<div class="chat">
    <p class="msgbox sent">
        <span class="message">Wait who are you?</span>
        <span class="time">06:01 AM</span>
    </p>

    <p class="msgbox received">
        <img class="avatar" src="https://imperiousmarshmallow.neocities.org/sarcasticimpulse.png" />
        <span class="colbox">
            <span class="name">Indignant Individualism</span>
            <span class="message">What do you mean you don't know who I am?</span>
        </span>
        <span class="time">06:01 AM</span>
    </p>

    <p class="msgbox received">
        <span class="spacer"></span>
        <span class="message">How dare you??</span>
        <span class="time">06:01 AM</span>
    </p>

    <p class="msgbox received">
        <img class="avatar" src="https://imperiousmarshmallow.neocities.org/haplessbystander.png" />
        <span class="colbox">
            <span class="name">Self-Esteem</span>
            <span class="message">Don't sweat it too much!</span>
        </span>
        <span class="time">06:02 AM</span>
    </p>
</div>

Message Dates[]

2 weeks ago

hey, you free? 06:03 AM

gotta talk to you about something 06:03 AM

Today

Laziness Sure, what's up?' 05:44 PM

CSS

Take all 'Messages' CSS (and optionally 'Avatars' CSS) plus:

#workskin .datebox {
  width: fit-content;
  margin: 0.5em auto 1em auto;
  background-color: #bcd6ff;
  text-align: center;
  padding: 0.6em 1em;
  border-radius: 1em;
  font-size: 0.8em;
  line-height: 1;
}

HTML

<div class="chat">
    <p class="datebox">2 weeks ago</p>

    <p class="msgbox sent">
        <span class="message">hey, you free?</span>
        <span class="time">06:03 AM</span>
    </p>

    <p class="msgbox sent">
        <span class="message">gotta talk to you about something</span>
        <span class="time">06:03 AM</span>
    </p>

    <p class="datebox">Today</p>

    <p class="msgbox received">
        <img class="avatar" src="https://imperiousmarshmallow.neocities.org/haplessbystander.png" />
        <span class="colbox">
            <span class="name">Laziness</span>
            <span class="message">Sure, what's up?'</span>
        </span>
        <span class="time">05:44 PM</span>
    </p>
</div>

To insert a message date box, add a 'datebox' paragraph in between the messages you want it to appear. It'll automatically center itself based on the text you put into it.

Embedded Links (Youtube)[]

https://­www.youtube.com/­watch?­v=5yUr5ZiRcTw 08:78 AM

Charisma.com - アラフォーマジック (Official Music Video) 08:78 AM

https://­www.youtube.com/­watch?­v=fQSJ5oe8Qf4 08:78 AM

tricot「右脳左脳」Music Video 08:78 AM

CSS

Take all 'Messages' CSS (and optionally 'Avatars' CSS) plus:

#workskin .msgbox .ytembed {
  border-radius: 1.2em;
  align-self: self-end;
  overflow: hidden;
}

#workskin .msgbox .ytembed .videotitle {
  font-size: .9em;
  font-weight: bold;
  padding: 0 15px 7px 15px;
  display: block;
}

#workskin .sent .ytembed {
    background-color: #85e249;
}

#workskin .received .ytembed {
    background-color: #ffffff;
}

HTML

<div class="chat">
    <p class="msgbox sent">
        <span class="message"><a href="https://www.youtube.com/watch?v=5yUr5ZiRcTw">https://&shy;www.youtube.com/&shy;watch?&shy;v=5yUr5ZiRcTw</a></span>
        <span class="time">08:78 AM</span>
    </p>

    <p class="msgbox sent">
        <span class="ytembed">
            <img src="http://i3.ytimg.com/vi/5yUr5ZiRcTw/hqdefault.jpg" />
            <span class="videotitle">Charisma.com - アラフォーマジック (Official Music Video)</span>
        </span>
        <span class="time">08:78 AM</span>
    </p>

    <p class="msgbox received">
        <img class="avatar" src="https://imperiousmarshmallow.neocities.org/haplessbystander.png" />
        <span class="message"><a href="https://www.youtube.com/watch?v=fQSJ5oe8Qf4">https://&shy;www.youtube.com/&shy;watch?&shy;v=fQSJ5oe8Qf4</a></span>
        <span class="time">08:78 AM</span>
    </p>

    <p class="msgbox received">
        <span class="spacer"></span>
        <span class="ytembed">
            <img src="http://i3.ytimg.com/vi/fQSJ5oe8Qf4/hqdefault.jpg" />
            <span class="videotitle">tricot「右脳左脳」Music Video</span>
        </span>
        <span class="time">08:78 AM</span>
    </p>
</div>

Although I used it for Youtube, if you want to include an embedded link / preview to anything, you can do so by adding a 'ytembed' span instead of a 'message' span in the 'msgbox'. You can then include an image for the thumbnail, and a 'videotitle' span if you want for the thumbnail preview text.

The &shy; appears in the link text in the example because web browsers split links across lines differently, leading to different layouts. &shy; gives the browser an indication of where it's okay to split the words / link.

Shared Files[]

song1.mp3
Valid until: ~12/01 06:13
Size: 4.33 mB
28:33 AM

song2.mp3
Valid until: ~12/01 06:13
Size: 3.99 mB
00:23 AM

CSS

Take all 'Messages' CSS (and optionally 'Avatars' CSS) plus:

#workskin .msgbox .message .filename {
  font-weight: bold;
}

#workskin .msgbox .message .filedetails {
  color: #777777;
  font-size: 0.75em;
  display: block;
}

#workskin .msgbox .message .download {
    display: inline-block;
    padding: 5px;
    transform: rotate(-45deg);
    margin-left: 15px;
    border: solid #777;
    border-width: 0 1px 1px 0;
}

HTML

<div class="chat">
    <p class="msgbox sent">
        <span class="message">
            <span class="filename">song1.mp3<br/></span>
            <span class="filedetails">Valid until: ~12/01 06:13<i class="download"></i><br />Size: 4.33 mB</span>
        </span>
        <span class="time">28:33 AM</span>
    </p>

    <p class="msgbox received">
        <img class="avatar" src="https://imperiousmarshmallow.neocities.org/haplessbystander.png" />
        <span class="message">
            <span class="filename">song2.mp3<br/></span>
            <span class="filedetails">Valid until: ~12/01 06:13<i class="download"></i><br />Size: 3.99 mB</span>
        </span>
        <span class="time">Read by 30<br />00:23 AM</span>
    </p>
</div>

To add a shared file, create 'filename' and 'filedetails' spans within the 'message' span (itself within the 'msgbox' paragraph). Unfortuanately this nesting was necessary to nicely handle the different font sizes and colours for downloads.

If you want a download button, you can also add an i element with the 'download' class.

Stickers[]

06:15 AM

I can do that too!! 06:15 AM

06:15 AM

CSS

Take all 'Messages' CSS (and optionally 'Avatars' CSS)

HTML

<div class="chat">
    <p class="msgbox sent">
        <img src="https://imperiousmarshmallow.neocities.org/kita_professor_ao3.png">
        <span class="time">06:15 AM</span>
    </p>

    <p class="msgbox received">
        <img class="avatar" src="https://imperiousmarshmallow.neocities.org/haplessbystander.png" />
        <span class="message">I can do that too!!</span>
        <span class="time">06:15 AM</span>
    </p>

    <p class="msgbox received">
        <span class="spacer"></span>
        <img src="https://imperiousmarshmallow.neocities.org/kita_professor_ao3.png">
        <span class="time">06:15 AM</span>
    </p>
</div>

To add any image (not just a sticker), you can just put the image into the relevant place within the 'msgbox'. This is often replacing the 'message' span.

As the chat is set to be 350px wide, I found that about 130px is a good width to limit stickers. Anything too wide or big will likely break the layout.

Accessibility[]

LINE Sticker, containing art of Ikuyo Kita from the manga and anime Bocchi the Rock! A stylised version of Kita is wearing a white labcoat over her traditional Japanese school uniform and a black professor's hat, pointing to the left balanced on one leg as if towards a scientific discovery. 06:15 AM

CSS

Take all the 'Messages' CSS

HTML

<div class="chat">
    <p class="msgbox sent">
        <img src="https://imperiousmarshmallow.neocities.org/kita_professor_ao3.png" alt="LINE Sticker, containing art of Ikuyo Kita from the manga and anime Bocchi the Rock! A stylised version of Kita is wearing a white labcoat over her traditional Japanese school uniform and a black professor's hat, pointing to the left balanced on one leg as if towards a scientific discovery.">
        <span class="time">06:15 AM</span>
    </p>
</div>

It is generally good practice to include 'alt text' on images, which web browsers, screen readers, and other tools can read as a description of the image. This then helps those with various accessibility needs to know what the image is, even if they can't see it / have other difficulties.

This isn't specifically work skin related, and alt text has been avoided from previous code snippets for clarity, but the full code in Chapter 2 does include it. I try to always include alt text.

Fallback[]

CSS

#workskin .secret {
  display: none;
}

HTML

<p class="secret">This fiction uses, and is about, custom styling. There's fallback in some places, but if you have work skins disabled you likely won't get much out of this.<hr/></p>

It is possible for people to turn off creator skins and/or download the work, both of which break the custom formatting.

To work around this (not my idea, please see the inspirations for this fic!) it is possible to have a style that hides extra text, meaning it only shows up when the style is turned off. This extra text can then add additional context.

I've used this to include a bit of text at the top of all fics that use a style, informing the reader if they switch it off that things might break.

It's hard to explain or provide an example, but if you try turning the style off for this tutorial, you can see what the fallback looks like in the full example at the start. The full fallback code is included in Chapter 2. You may have to do some trial and error on what to hide away for it to look nice (or at least tolerable) for your own fic.

Changelog[]

2024/10/30 - Initial Version
2025/03/14 - Added 'message date box' CSS for message history, rounded top corners on headers, and corrected an obscure layout bug.
2025/12/24 - Fixed issue with spacer examples no longer being parsed correctly by AO3. Added 'footer' section for messages, with two possible styles.
2026/02/16 - Fixed issue with sent messages not aligning to the right properly.

Attribution[]

Plus Icon - By CyCraft, found at https://www.svgrepo.com/svg/393166/plus
Camera Icon - By Dazzle UI, found at https://www.svgrepo.com/svg/533059/camera
Photo Icon - By Vlad Cristea, found at https://www.svgrepo.com/svg/522624/photo
Microphone Icon - By Dazzle UI, found at https://www.svgrepo.com/svg/533111/microphone-alt-1
Send Icon - By Dazzle UI, found at https://www.svgrepo.com/svg/533310/send-alt-1
Right Arrow Icon - By Ankush Syal, found at https://www.svgrepo.com/svg/520912/right-arrow

All icons licensed under the CC Attribution licence, details of which can be found at https://www.svgrepo.com/page/licensing/#CC%20Attribution