jockles.com

All the Fannish things I do.

Megaskin by Jockles

← Previous Chapter · Chapter Index · Next Chapter →

Chapter 9: Twitter/X CSS

Thanks to worlds_end_valentine, whose Twitter Work Skin Template this module is built on. Copied and adapted from it: the timestamp line, liked and reposted counts, labels, the sensitive content warning, polls, pictures and videos, scrollable threads, and DM reactions, group DMs, voice messages and the DM window.

9.1 Chapter Contents

This chapter goes through the CSS for the tweets, threads and DMs in the last chapter. The module has three parts: tweets and replies (tw and tw-reply), the scrolling thread they can sit in (tw-thread), and DMs (twdm). DMs are built just like iMessage, so if you've read that chapter, they'll be quick.

9.2 Getting the CSS

The Twitter/X CSS is here: jockles.com/fic/megaskin/css/twitter-x.css. It needs the core CSS too (jockles.com/fic/megaskin/css/core.css), so paste the core into your work skin first and this underneath it.

9.3 How the Module is Laid Out

The usual order - the main rules, Links, Dark theme and Auto theme - with a Scrolling section before the themes, because tweets and threads scroll differently from the phone-style chats. You'll notice that most rules name both .tw and .tw-reply. A reply is its own box rather than something inside a tweet, so every part that can turn up in both has to be given to both.

9.4 The Tweet

#workskin .tw {
  background: #ffffff;
  color: #0f1419;
  border: 1px solid #cfd9de;
  border-radius: 14px;
  padding: 0.8em 1em;
}

#workskin .tw-reply {
  background: #ffffff;
  color: #0f1419;
  border: 1px solid #cfd9de;
  border-top: none;
  padding: 0.7em 1em;
}

A tweet is a rounded white card. A reply is a square one with no top edge, so a stack of replies under a tweet joins up into one long card, with a single line between each one.

The text colours are Twitter/X's own: #0f1419 is its near-black, #536471 the grey for handles and small print, and #1d9bf0 its blue, which is used for links, hashtags, the verified tick and poll outlines.

9.5 Name Line and Profile Picture

#workskin .tw .tw-top,
#workskin .tw-reply .tw-top { display: block; overflow: hidden; }

#workskin .tw .tw-pfp,
#workskin .tw-reply .tw-pfp {
  display: block;
  float: left;
  width: 40px;
  height: 40px;
  line-height: 40px;
  margin: 0 0.65em 0 0;
  border-radius: 50%;
  overflow: hidden;
  text-align: center;
  background-color: #8b98a5;
  color: #ffffff;
  font-size: 0.85em;
  font-weight: bold;
}

#workskin .tw .tw-pfp ~ .tw-handle,
#workskin .tw-reply .tw-pfp ~ .tw-handle { display: block; }
  • The picture floats to the left, and the name and handle sit beside it.
  • overflow: hidden on the name line makes it grow tall enough to hold the floating picture. Without it, the tweet text would start beside the picture instead of under it.
  • ~ means "anywhere after, in the same line". So the last rule says: if there's a picture in the name line, put the handle on its own line under the name, the way Twitter/X does. With no picture, the handle stays beside the name.
  • Initials circles take colour1 to colour10, the same ten colours as every other app, which are in the core.

9.6 Text, Stats, Quotes and Notes

#workskin .tw .tw-text { display: block; font-size: 1.02em; margin: 0.2em 0 0.4em 0; }

#workskin .tw .tw-stats {
  display: block;
  color: #536471;
  font-size: 0.82em;
  padding-top: 0.45em;
  border-top: 1px solid #eff3f4;
  margin-top: 0.4em;
}

#workskin .tw .tw-stats b { color: #0f1419; }

#workskin .tw .tw-quote {
  display: block;
  border: 1px solid #cfd9de;
  border-radius: 12px;
  padding: 0.5em 0.8em;
  margin: 0.4em 0;
  font-size: 0.92em;
}

Most of the parts of a tweet are simple: a line with its own size, colour and spacing. The stats line has a pale line above it, and its numbers (in <b>) are dark while the words are grey. A quote tweet is a smaller rounded box inside the tweet. The Community Note (tw-note) and the sensitive content cover (tw-warn) are boxes the same way, with a pale grey background.

#workskin .tw .tw-stats .tw-liked,
#workskin .tw-reply .tw-stats .tw-liked {
  color: #f91880;
}

#workskin .tw .tw-stats .tw-rt,
#workskin .tw-reply .tw-stats .tw-rt {
  color: #00ba7c;
}

A count the account has used turns pink for a like or green for a repost, like the real buttons.

9.7 Polls

#workskin .tw .tw-opt,
#workskin .tw-reply .tw-opt {
  display: block;
  border: 1px solid #1d9bf0;
  border-radius: 6px;
  padding: 0.4em 0.7em;
  margin: 0.35em 0;
  color: #0f1419;
}

#workskin .tw .tw-opt.res,
#workskin .tw-reply .tw-opt.res {
  border-color: transparent;
  background-color: #eff3f4;
  background-image: linear-gradient(#cfd9de, #cfd9de);
  background-repeat: no-repeat;
  background-size: 0% 100%;
}

#workskin .tw .tw-opt.p50,
#workskin .tw-reply .tw-opt.p50 {
  background-size: 50% 100%;
}

An open poll is just a blue outline. A finished one (res) is cleverer: the bar is a background picture. linear-gradient(#cfd9de, #cfd9de) is a "gradient" from one colour to the same colour, which is a trick for making a solid block of colour that can be sized. background-size then sets how wide the block is, from 0% to 100% of the option, and no-repeat stops it filling the rest. Each p class just sets a different width. win swaps the grey block for a blue one and makes the text bold.

Adding a poll percentage that isn't there

The skin has p0 to p100 in tens, plus p25, p33, p67 and p75. To add another, copy one of the rules and change both numbers:

#workskin .tw .tw-opt.p45,
#workskin .tw-reply .tw-opt.p45 {
  background-size: 45% 100%;
}

The percentage the reader sees is just the text in tw-pct, so it doesn't have to match the bar exactly - the nearest bar is usually close enough.

9.8 Pictures and Videos

#workskin .tw .tw-media,
#workskin .tw-reply .tw-media {
  display: block;
  overflow: hidden;
  border: 1px solid #cfd9de;
  border-radius: 14px;
  margin: 0.5em 0;
  background: #eff3f4;
  color: #536471;
  font-style: italic;
  text-align: center;
  line-height: 1.3;
}

One picture fills the rounded box at its own shape, and overflow: hidden rounds off its corners with the box. An embedded video (video) is 200px tall, and a description gets padding to make it about the size of a picture.

Two, three and four pictures work exactly like WhatsApp's photo galleries - squares made with padding-top, floated into a grid, with land for wide pictures - so see Photo Galleries in the WhatsApp CSS chapter for how. The only differences are the sizes (49.2% squares with a 1.2% gap, adding up to 99.6%), and this at the end:

#workskin .tw .tw-media.two::after,
#workskin .tw .tw-media.three::after,
#workskin .tw .tw-media.four::after {
  content: "";
  display: block;
  clear: both;
}

Floating things don't take up any height, so a box of floated pictures would shrink to nothing, and the stats line would slide up behind the pictures. This adds an invisible empty line after them with clear: both, which means "go below anything floating", so the box stretches down to hold them.

9.9 The Scrolling Thread

#workskin .tw-thread {
  width: 380px;
  max-width: 100%;
  margin: 1.2em auto;
  box-sizing: border-box;
  border: 1px solid #cfd9de;
  border-radius: 14px;
  overflow: hidden;
  background: #ffffff;
  color: #0f1419;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 0.92em;
  line-height: 1.35;
}

#workskin .tw-thread .mob {
  width: auto;
  max-width: none;
  margin: 0;
  border-width: 0 0 1px 0;
  border-radius: 0;
  max-height: none;
  overflow: visible;
  background: transparent;
  color: inherit;
}

A thread is its own phone-sized box, built like the core's mob. The second rule takes the tweets inside it apart: no width of their own, no gap around them, no rounded corners, no scrolling, and only a bottom edge, so they stack into one feed with a line between each one. background: transparent and color: inherit make every tweet take the thread's colours, which is how a whole thread follows one theme.

#workskin .tw-thread .tw-foot {
  display: block;
  padding: 0.7em 1em;
  border-top: 1px solid #eff3f4;
  color: #536471;
}

#workskin .tw-thread .tw-foot > p { margin: 0; padding: 0; }

#workskin .tw-thread .tw-foot span {
  float: right;
  padding: 0.25em 0.9em;
  border-radius: 1em;
  background: #1d9bf0;
  color: #ffffff;
  font-weight: bold;
  font-size: 0.9em;
}

The "Tweet your reply" bar sits under the scrolling part, so it stays in place. AO3 wraps its text in a paragraph, which the middle rule flattens, and the Reply button floats to the right.

9.10 Scrolling

#workskin .tw-thread .tw-scroll {
  display: block;
  max-height: 580px;
  overflow-y: auto;
  overflow-x: hidden;
}

#workskin .tw {
  max-height: 700px;
  overflow-y: auto;
  overflow-x: hidden;
}

In a thread, only the tw-scroll part scrolls, at the same height as every other chat. A tweet on its own scrolls as a whole, and it's allowed to be taller (700px), because a tweet with a picture is usually taller than a chat window and you'd rather not scroll it if you can help it. Adding no-scroll to a tweet switches its scrolling off, as usual.

9.11 DMs

#workskin .twdm .msg {
  display: table;
  max-width: 72%;
  margin: 0.2em 0;
  padding: 0.55em 0.9em;
  border-radius: 20px;
}

#workskin .twdm .out {
  margin-left: auto;
  background: #1d9bf0;
  color: #ffffff;
  border-bottom-right-radius: 4px;
}

#workskin .twdm .in {
  margin-right: auto;
  background: #eff3f4;
  color: #0f1419;
  border-bottom-left-radius: 4px;
}

These are iMessage's bubbles in Twitter/X colours, with slightly rounder corners. The header, timestamps (twdm-time, with time-out on the right), sender names and pictures all work the way they do in iMessage. Reactions are a pill pulled up under the bubble with a negative margin, like WhatsApp's.

Voice messages
#workskin .twdm .voice .twdm-wave {
  width: 90px;
  overflow: hidden;
  white-space: nowrap;
  opacity: 0.7;
}

#workskin .twdm .voice .twdm-wave::before {
  content: "\2583\2585\2587\2586\2584\2582\2583\2586\2587\2585\2583\2582\2584\2586\2585\2583\2582\2584\2583\2582";
  font-size: 0.8em;
  letter-spacing: 1px;
}

The sound wave is made of text. Each \258x is a block character - ▃▅▇▆▄▂ - of a different height, and twenty of them in a row look like a wave. (The usual way to draw stripes in CSS is a repeating gradient, but AO3 won't accept one.) To change the shape, change the order of the codes: \2581 is the shortest block and \2588 the tallest.

9.12 Links

#workskin .tw .fake-link, #workskin .tw a:not(.tl),
#workskin .tw-reply .fake-link, #workskin .tw-reply a:not(.tl) { color: #1d9bf0; }

#workskin .twdm .in .fake-link, #workskin .twdm .in a:not(.tl) { color: #1d9bf0; }

#workskin .twdm .out .fake-link, #workskin .twdm .out a:not(.tl) { color: #ffffff; }

Blue everywhere, except in your own blue DM bubbles, where links are white so they show up. tw-link, for hashtags and @mentions, is the same blue.

9.13 Dark and Auto Themes

#workskin .tw.theme-dark { background: #000000; color: #e7e9ea; border-color: #2f3336; }

#workskin .tw-thread.theme-dark { background: #000000; color: #e7e9ea; border-color: #2f3336; }

#workskin .tw-thread.theme-dark .tw-replying,
#workskin .tw-thread.theme-dark .tw-date,
#workskin .tw-thread.theme-dark .tw-label,
#workskin .tw-thread.theme-dark .tw-pollinfo {
  color: #71767b;
}

Twitter/X's dark mode is black, with #e7e9ea for text and #71767b for grey. Tweets, replies and DMs each have their own dark rules, as you'd expect. Threads have a second set: every part of a tweet again, but starting .tw-thread.theme-dark. That's what lets you put theme-dark on the thread once instead of on every tweet inside it - the tweets don't have a theme of their own, so they need to be told by the thread.

The auto theme is the whole lot again inside @media (prefers-color-scheme: dark), so change a dark colour in both places.

9.14 Taking Parts Out

Search for the class names and delete every rule with them in, including in the dark and auto blocks:

  • DMs: everything starting .twdm, and anything with twdm- in it.
  • Threads: everything starting .tw-thread, and tw-scroll and tw-foot.
  • Polls: tw-opt, tw-pct and tw-pollinfo, which is also the biggest saving, since there are 15 bar sizes.
  • Picture galleries: tw-photo and tw-desc, and the two, three and four rules. Keep tw-media for single pictures.
  • Extras: tw-note, tw-warn, tw-label, tw-liked and tw-rt each come out on their own.

Keep the tweet, name line, text and stats, and tw-reply if you use replies anywhere.

← Previous Chapter · Chapter Index · Next Chapter →