Restyling apps at scale

tl;dr: If you want to change how an app looks, you need a designer in the loop.

Over the past few months we’ve had a lively debate about “theming” in GNOME, and how it affects our ecosystem. In this discussion I’ve found that there is a divide between people who design and/or develop apps, and people who don’t. I have yet to see an app developer who thinks the current approach to “theming” can work, while many people who aren’t app developers are arguing that it can.

After a few long discussions I started to realize that part of the reason why there’s so little agreement and so much drama around this issue is that we don’t agree what the problem is. Those who don’t work on apps often can’t see the issues with theming and think we want to remove things for no reason, while those who do are very frustrated that the other side doesn’t want to acknowledge how broken everything is.

The basic issue we’re arguing about is whether it’s possible to restyle applications automatically, at scale, without breaking them. In this post I’ll try to explain why I think that it isn’t possible, and why trying to do it is hurting our ecosystem.

There are no themes, just CSS

A fundamental misconception a lot of people have is that GTK 3 supports theming. This is not true, as there is no clearly defined theming API. There are CSS stylesheets, but they were only ever meant to be used by the platform and app developers. The platform stylesheet is called Adwaita (“the only one” in Sanskrit) for a reason.

However, some people (inlcluding major distributions) have been using custom stylesheets as a hacky approximation of “themes” for so long now that nobody even remembers that they are not a real theming API.

An older version of GRadio with Ubuntu’s Ambiance theme

Since CSS is a huge API surface, which is used by both app developers and “theme” developers, it’s very easy for the two to conflict. This leads to apps looking broken unless you manually do QA for every app/theme combination.

“You’re exaggerating, it’s not that bad.”

One of the most frustrating things about the current situation is that to users, it looks like it almost works. For the most part, third-party themes look and work okayish, there are just a few small bugs here and there. A button with too little contrast, an underline clashing with a border, a really large loading spinner. Not that big a deal, you’d think.

However, this view of the situation misses a few really important realities:

  1. App developers are doing a lot of bug fixing to account for “theming”, because people complain to them when their app is broken on certain distros. The current situation essentially forces developers to fix bugs for setups they never intended to support in the first place. They’re not happy about it, but they’re doing it because they don’t want their users to have broken apps.
  2. App developers are trying hard not do anything innovative or visual in their apps, because they know it will break with other stylesheets.
  3. “Theme” developers are fixing a lot of bugs for edge cases in individual apps in their stylesheets. Of course, this is a never-ending task because as soon as a new version of an app is released, something will very likely be broken again.

All of this only kinda sorta works because we have very few apps. If we ever hope to grow our ecosystem past a few dozen apps things have to change, because maintaining a “theme” gets less sustainable with every new app.

There is also the question of what your definition of “broken” is. Some people think that things like these are acceptable:

Date picker in Calendar on Pop OS: There are double arrows left of the month and year labels.
“New Folder” dialog in Nautilus with Ambiance: There’s an invisible “Create” button in the top right.
Gedit on Pop OS: There’s a brown rectangle sticking out of the window at the top, and the widgets at the top of the sidebar look awkward and don’t make sense in this configuration.

I believe this is nowhere near ok. App developers put a lot of effort into making sure their apps look and feel right, fixing bugs, and doing QA. Having distributors change their apps (often in ways that break things) with no QA before users get to experience them is developer-hostile, and would be unacceptable in any other context.

Can you imagine Samsung restyling every third-party app on their phones, without testing them, and when Instagram complains that the text on their buttons is illegible Samsung just shrug and say “Sorry, but branding is very important to us. Why don’t you change your app?”.

“But it’s fine as long as you follow best practices!”

This is a common sentiment among some people. “If only app developers followed best practices, used CSS variables, and derived their colors from theme colors, everything would be fine”, the argument goes. While it’s true that these things are important and make apps more flexible in terms of appearance, this doesn’t come close to solving the entire problem.

If every app only used default GTK controls, in very simple layouts, with no custom widgets or in-app CSS, then best practices would perhaps be enough to prevent apps from breaking. But the reality is that a) this is not the case, and b) we really don’t want it to be the case.

Human Interface Guidelines are just that: guidelines. They have to be implemented manually, they change and evolve over time, and the best apps on any platform push their boundaries in some places and experiment with new patterns (which then sometimes make their way back into the HIG).

This kind of experimentation means that it’s impossible to “theme” apps automatically. Visual design and interaction design are very closely linked, so if you want to change the style, you need a designer to actually think about what a widget should look like.

For example: How should the Pop theme know what a “flat” variant of the new Nautilus path bar should look like? It’s impossible to do this automatically, because it’s a new pattern.

The new path bar in Nautilus
The new path bar in Nautilus with the Pop OS theme (completely broken)

This is not a rare situation, even among core GNOME apps. Many of the apps I’ve personally worked on have their own equivalent of the Nautilus path bar. And that’s the way it should be. Apps have different needs that sometimes require custom solutions, and this experimentation is good for the ecosystem. However, it also means that automatic restyling is impossible.

“But what about Adwaita Dark and High Contrast?”

The point that the dark and high contrast variants of Adwaita can be seen as GTK 3 kinda sorta supporting themes is technically accurate, but misguided. Adwaita variants may technically just be different stylesheets, but this is just an implementation detail. There are very clear differences between them and third-party “themes”.

  1. They are very very close to Adwaita code-wise, and therefore much less likely to break.
  2. There’s a finite number of them, and they are part of the platform. This makes them a tangible target for developers to test for and support, which is completely different from third-party “themes” which just apply random CSS to every app without any QA.
  3. They are part of the same design language, so they require very little extra work to adapt to from a design point of view. If you follow the best practices mentioned above, often no work at all.
GNOME Builder with Adwaita Dark

“But what about consistency? I want all my apps to look the same!”

“Consistency” is a word you hear a lot in debates about theming, but it seems to mean different things to different people.

To some, consistency effectively means “everything should use the same colors”. This is relatively easy to achieve for some apps, even across toolkits, if you simply provide a “theme” for each toolkit.
However, this “consistency” is very shallow. Just because a Qt app uses the Adwaita colors it doesn’t automatically fit in with the GNOME platform. UI patterns are much more important, and they can’t be changed with theming. There is no magic that can redesign menu bar apps with header bars.

No matter how hard you theme these, they will never look native on GNOME

Real consistency can only happen by design, and requires the app developer to build it into the app at every step. If you want all your apps to look the same, only use apps built for your platform’s HIG. “Fixing” apps after the fact with theming isn’t really making your system more consistent, but it’s hurting app developers a great deal.

Of course, even the very shallow “everything uses the same colors” consistency is impossible to enforce across all apps and toolkits. Apps like Blender, Telegram, or Steam don’t respond to system theming at all, and even Firefox and Chromium only do so in a very limited fashion.

“But users *want* themes!”

“Users” want a lot of things, but just because you want something impossible that doesn’t make it possible. In this case, it’s important to be aware of the costs of giving complete visual freedom to “themes”, both in individual app developer effort, and chilling effects on the ecosystem. If given a choice between customization and more, better apps, I’m confident the majority of people would prefer the latter.

Would it be nice if there were a way to be able to restyle every app to make them look like Material Design, or macOS, or Windows 95, and have them all look as if they were built for that style? Absolutely! I would love that! However, as I’ve tried to explain in this blog post, this is simply not realistic.

So, what can we do?

As the recent discussions have shown, talking about solutions before we agree what the problem is isn’t very productive, so for now I’m mostly interested in making sure we’re all aware of the problem and its various facets. There are several different stakeholders with different perspectives on this issue, and making progress will mean making some hard choices. At this year’s GUADEC we had a Theming & Ecosystem BoF where we talked about a number of potential directions, and I hope we can move forward on that path.

No matter what we come up with though, I think it’s crucial that we start taking the needs of app developers seriously. Developers are the lifeblood of any platform, and we’ve been treating them very poorly. If we want to grow our ecosystem and actually compete with other major platforms, we need to fix that.

Note: The examples in this post have been chosen because the themes in question ship with major distributions, so app developers tend to get complaints about them. It’s not my intention to single them out, this problem applies to all third-party themes equally.

Banquets and Barbecues

tl;dr: We’re splitting up Fractal into two separate apps: One to replace IRC, the other to replace Telegram.

This is an in-depth post on the thinking behind the split of the Fractal app, which was decided at the hackfest in Strasbourg last week. For more information about the hackfest, have a look at my other blog post.

1-1 woes

One of the biggest problems with Fractal at the moment is that 1-1 messaging is pretty terrible. Since the rooms in the sidebar are sorted by most recent activity, high-traffic public rooms (such as GNOME IRC channels) tend to drown out rooms with less traffic, such as 1-1s and small groups. This is problematic because the signal-to-noise ratio in 1-1 chats and small groups tends to be much higher than in high-traffic public rooms. This leaves the user constantly searching for the rooms they care about, while the rooms they don’t care about are always at the top.

1-1 chats are quickly drowned out by high-traffic public rooms in the sidebar

One way to solve this problem is having a favorites group for “important” rooms. This is a feature Fractal has had for a while, and it does solve some of the problems with a room list sorted purely by recent activity. However, it only works well for rooms that are important over long periods of time, and needs to be managed manually. 1-1 chats are often brief, and there can be many of them in parallel. Putting them in favorites doesn’t make sense in many cases, as it would balloon the size of the favorites group, and require lots of manual work when starting or ending a conversation.

The “obvious” solution would be doing what Riot does: Having a separate group of 1-1 rooms in the sidebar, and thereby keeping the 1-1 conversations in one consistent place. However, this creates more problems than it solves. In practice, it results in multiple groups of arbitrary length competing for real estate in the sidebar. If you have a lot of 1-1s, this means that you’ll be able to see very few rooms (even when most of the 1-1s are old and not relevant at the moment). In Riot, this group is capped at 10 visible rooms by default, but that’s still not great if you only need 2 of them at the moment. The category can be collapsed, but then you can’t see which 1-1s have new messages, and it also means lots of busywork collapsing/expanding the group. Clearly this isn’t an ideal solution, which is why we were very hesitant to go down this path.

Riot’s separate 1-1 category doesn’t really solve the problem, because old 1-1s take up a ton of vertical real estate when it’s expanded

A way out?

As we were discussing this issue over the past few months, I started looking more closely at the way people use different messaging tools. One thing I found puzzling is that despite the fact that Matrix theoretically supports the use cases covered by popular apps like Whatsapp and Telegram, few people are actually using it to replace those apps. Instead, they use it to replace IRC and Slack.

Why? My theory is that most chat rooms fall in one of three categories:
Private Chats, which include 1-1s and small groups; Team Chats, which are larger, but still private and invite-only; and Public Rooms, which are basically like IRC.

Team Chats and Public Rooms share many characteristics: Both have relatively high amounts of traffic, and there’s a lot of noise. The main difference is that Team Chats are private and the members rarely change (e.g. a company’s internal Slack), while Public Rooms can be joined by anyone at any time, and there is no expectation of privacy (e.g. #gnome-hackers on IRC).

However, Private Chats have relatively little in common with the other two categories: They are low-traffic, and have little or no noise. This may sound like a small difference, but I think it’s the reason why 1-1s suck in Fractal/Riot/IRC, and why people aren’t using Matrix to replace Telegram.

The Banquet and the Barbecue

I’ve come to the conclusion that one app can’t cover all the use cases that the Matrix protocol supports, and still provide competitive UX. If you design an app to deal with lots of high-traffic rooms (e.g. Riot as it is today), it will suck for 1-1s, so people will use something else for those. Similarly, Telegram is primarily designed for 1-1s and small groups, which is why it’s a terrible experience if you have many high-traffic groups.

If we want Matrix to succeed as more than an IRC/Slack replacement we need multiple apps, each focusing on a distinct use case. For messaging, I think the most important distinction to make is between what I call the Banquet and the Barbecue.

Slack is one of the most widely used apps covering the Banquet use case

The Banquet is a big, loud place. There are tons of people, and you don’t know many of them. Lots of things are happening all the time, and it’s hard to keep track of everything. This is what Matrix is currently mostly used for. Slack, IRC, and Discord are also all in this category.

iMessage is a good example of an app focused on the Barbecue use case

The Barbecue is at the other end of the spectrum: It’s a calm, private environment where friends, family, co-workers, and other acquaintances hang out. Conversations are mostly between 2 or 3 people, slow, and often very personal. Telegram, Whatsapp, iMessage, Facebook Messenger, and a myriad of other chat apps are optimized for this use case.

Fracturing Fractal

Now, what does this mean for Fractal? After a long discussion on Thursday, we decided to split up Fractal into two separate apps with different interfaces, each containing a subset of the user’s Matrix rooms.

Exactly how rooms will be split between the two apps is not 100% clear yet. 1-1s are clearly Barbecue, public rooms are clearly Banquet, but private groups could go either way. For these cases we may need a way to explicitly move rooms between apps. The distinction should probably be part of the Matrix spec, so the intent for a room to be a Barbecue or Banquet room could be set when creating a room, and persist across devices.

The two apps will share practically all the internals, and even large parts of the interface. However, the split will allow us to do some things differently in each app to optimize the interfaces for the different use cases. Some of the changes we’re considering are a bubble-style message view in the Barbecue app, and more room categories (such as low-priority) in the Banquet app’s sidebar.

For more details on the split have a look at the blog posts by Daniel, Eisha, Julian, and Adrien.

Messages and Discussions

How exactly the apps will be branded (and what will happen to the Fractal name we all love) is still being decided, but there is some consensus to move to GNOME-style generic names. The Barbecue app will almost certainly be called “Messages”. For the Banquet app there’s less agreement, but my current favorite is “Discussions”.

Early-stage mockups showing what the two different apps could look like

The Fractal brand will not go away though: We’re thinking of keeping it around as the name of the community project that develops both GNOME Matrix apps, and/or using it for the backend powering both apps.

There are lots of details to be figured out in this transition, both from a design and an implementation perspective, but I’m very excited about this new direction. If you’d like to join the effort, come talk to us on Matrix.

Note: I have no illusions that this change will magically get everyone to leave Whatsapp/Telegram/iMessage and move to Matrix. In the short term, the goal is simply to make Matrix 1-1s a good experience. That said, if we ever want Matrix to make inroads with the general public, I think a move in this direction is an important precondition.

UX Hackfest London

Last week I took part in the GNOME Shell UX Hackfest in London, along with other designers and developers from GNOME and adjacent communities such as Endless, Pop!, and elementary. We talked about big, fundamental things, like app launching and the lock/login screen, as well as some smaller items, like the first-run experience and legacy window decorations.

I won’t recap everything in detail, because Cassidy from System76 has already done a great job at that. Instead, I want to highlight some of the things I found most interesting.

Spatial model

One of my main interests for this hackfest was to push for better animations and making better use of the spatial dimension in GNOME Shell. If you’ve seen my GUADEC Talk, you know about my grand plan to introduce semantic animations across all of GNOME, and the Shell is obviously no exception. I’m happy to report that we made good progress towards a clear, unified spatial model for GNOME Shell last week.

Everything we came up with are very early stage concepts at this point, but I’m especially excited about the possibility of having the login/unlock screen be part of the same space as the rest of the system, and making the transition between these fluid and semantic.

Tiling

Another utopian dream of mine is a tiling-first desktop. I’ve long felt that overlapping windows are not the best way to do multitasking on screens, and tiling is something I’m very interested in exploring as an alternative. Tiling window managers have long done this, but their UX is usually subpar. However, some text editors like Atom have pretty nice graphical implementations of tiling window managers nowadays, and I feel like this approach might be scalable enough to cover most OS-level use cases as well (perhaps with something like a picture-in-picture mode for certain use cases).

Tiling in the Atom text editor
Tiling in the Atom text editor

We touched on this topic at various points during this hackfest, especially in relation to the resizable half-tiling introduced in 3.26, and the coming quarter-tiling. However, our current tech stack and the design of most apps are not well suited to a tiling-first approach, so this is unlikely ot happen anytime soon. That said, I want to keep exploring alternatives to free-floating, overlapping windows, and will report on my progress here.

Header bars everywhere

A topic we only briefly touched on, but which I care about a lot, was legacy window decorations (aka title bars). Even though header bars have been around for a while, there are still a lot of apps we all rely on with ugly, space-eating bars at the top (Inkscape, I’m looking at you).

Screenshot of a full-screen Blender window with a title bar
On a 1366x768px display, a 35px title bar takes up close to 5% of the entire screen.

We discussed possible solutions such as conditionally hiding title bars in certain situations, but finally decided that the best course of action is to work with apps upstream to add support for header bars. Firefox and Chromium are currently in the process of implementing this, and we want to encourage other third-party apps to do the same.

Screenshot of Firefox with client-side decorations
Firefox with client-side decorations (in development)

This will be a long and difficult process, but it will result in better apps for everyone, instead of hacky partial solutions. The work on this has just begun, and I’ll blog more about it as this initiative develops.

In summary, I think the hackfest set a clear direction for the future of GNOME Shell, and one that I’m excited to work towards. I’d like to thank the GNOME Foundation for sponsoring my attendance, Allan and Mario for organizing the hackfest, and everyone who attended for being there, and being awesome! Until next time!

GNOME foundation sponsorship badge