Thom Bruce

CSS On the Other Hand...

Mentions

  • tailwindcss

CSS On the Other Hand...

Speaking of keeping things simple, you know what isn't?

Cascading Style Sheets. CSS. It's a nightmare!

And my site here, just one colour of text on another colour for the background--black-on-white or white-on-black if you're using my dark mode--it is simple. It is minimal. It is... still kind of a nightmare to style.

Specifically this grumble comes down to how forms are handled by different browser rendering engines. I have a form over on my contact page that looked beautiful in my preferred browser--simply perfect, simply exactly how I intended it to look. And then I downloaded and installed a Chromium-based browser and a WebKit-based browser (Helium and GNOME Web, respectively--I'll talk about browsers some more soon) and over there... well, over there we've suddenly got two separate problems.

Chromium looked mostly fine, mostly how it appeared in Firefox. There was just the options dropdown on a select box that failed to adopt dark background colours in dark mode. Meanwhile in WebKit... oh god, in WebKit everything's different.

And these are both really important targets! Chromium is the most used browser technology on the planet (using the Blink rendering engine), and WebKit is the only rendering engine that Apple even allows developers to use on iOS (outside of the EU anyway). That means regardless of if you're using Safari or Chrome or Firefox or anything else on iOS, the browser is probably using WebKit.

My preferred browser this past year has been Firefox (which uses a separate rendering engine called Gecko), and while Firefox is certainly... popular-ish... it's numbers are dwarfed by Chromium and WebKit.

And okay, I can say at least that I was pleased to see that Chromium looked a lot like Gecko's handling of the same markup. My form looked mostly fine in Chromium, apart from the options dropdown but I genuinely think Chromium does this a little better. See in Firefox and WebKit-based browsers, the rendering engine appears to be using its own UI for the dropdown menu. You don't have a lot of control over the shape or colours of it. Whereas in Chromium you do, hence the need for me to apply my own dark styles to it (because for some reason, it's one of only a few elements that won't inherit the colour-scheme from its ancestors).

Then, as I said, WebKit is doing something else entirely! The whole form wants to render differently, using WebKit's own default form styles that are already a little broken by some of my other CSS settings.

The solution looks simple enough in the end. We install and make use of the @tailwindcss/forms plugin (which resets form styles across all browser engines) and then we apply some of our own configurations on top. It looks like this:

@import "tailwindcss";

@plugin "@tailwindcss/forms";

@layer components {
  input, select, textarea, button {
    @apply
      bg-inherit
      border-inherit
      outline-none /* outline behaves inconsistently across different browser engines */
      ring-inherit /* use ring instead, applied in the @variant focus definition below */
      ring-offset-0 /* checkbox and radio are given a #fff ring-offset by default; we remove that here */
      text-inherit
      caret-inherit;
  
    /* Blink (Chromium) allows for option to be styled but does not support inherit */
    > option {
      @apply bg-light dark:bg-dark;
    }
  
    @variant focus {
      @apply ring-2;
    }
  }
}

But that doesn't really show the headache I had trying to figure out, in particular, why checkbox and radio buttons were again behaving... kind of weirdly. You can see above I've had to apply ring-offset-0, which effectively removes a default ring-offset value with a white background that Tailwind or Tailwind Forms was applying only to checkbox and radio buttons... for some reason (probably to make the focus state more apparent). Without that ring-offset-0 override, my own ring-2 focus style was creating an inconsistently large border on those elements. What it does on all of the other elements is provide a 2px border when the element is focused, but on radio buttons and checkboxes this was something like 4px and it just looked bizarre.

By the way, a good trick for really trying to dig into a problem like that is to set vibrant, contrasting colors on all of the potential culprits. At one point I had something like:

@apply
  bg-inherit
  border-blue-500
  outline-none
  outline-green-500
  ring-red-500
  text-inherit
  caret-inherit;

And this revealed that absolutely none of these were the cause of my frustration... which was in turn still frustrating. A 2px white border still existed in the focus state of those elements, and it was not a border, an outline or a ring shadow.

A second good trick is to activate your browser's devtools menu and start deactivating styles one by one. This is ultimately how I uncovered the ring-offset value and, after consulting the Tailwind docs for the specific class, I was able to remove that space with ring-offset-0.

The result of all of this is a consistent look for my website across all three major rendering engines (individual browsers may still vary a little, but it shouldn't be by much) and the final CSS is still lean and simple but... oh, the journey to get there so was not.

It feels to me like the options dropdown not inheriting background colour values in Chromium is an oversight in that engine (because pretty much everything else does, and the text colour was being inherited). And it feels like an unnecessary decision in Tailwind to have that ring-offset value applied by default. And those aren't actually the only headaches here.

There is also the decision I've obviously made to use ring, rather than adjusting the border or using outline. This choice once again comes down to how each browser handles this--outline looks a little different on all three engines, with WebKit once again being an extreme outlier that isn't even close to the other two, but ah well.

And ring ultimately makes more sense than adjusting the border width, as it is always going to be separate from the box-sizing of the element, whereas border... isn't necessarily. It is slightly easier, I think, to simply remember that we need to potentially adjust both border and ring colours for specific highlight states in future than it is to go messing around with border widths.

So okay... addendum to the previous post: Simplicity isn't easy. All software is in some way opinionated, even those programs which sell themselves as unopinionated (this, in and of itself, is fundamentally an opinion about how software should be). And this is abundantly clear in web design.

WebKit seems to be aggressively opinionated about how to handle forms, and it's really a toss-up whether you say Firefox or Chromium is more opinionated than the other. Firefox's handling of the select box handled my application of a dark mode by default but it still renders the options as like a desktop user-interaction element, whereas Chromium (and again I used Helium to check this) allows the designer a little more freedom to style the options dropdown but is fairly strict about how to apply those styles. They're both opinions, just different ones.

Okay, we wrapping up here? Have I rambled enough about yesterday's headache trying to get to the bottom of this? Sure.

In a future post, I will explain a little about why I chose to leave Chromium-based browsers and started using Firefox and also... why I might be switching back next year (I repeat, I've been using Helium--go check it out). At the end of the day though, it is my job to use as many as possible and to make sure that even if everything doesn't look quite the same across all browsers... that it does at least work. And actually whether or not it worked was never the issue here--I did just want to achieve that consistent look across all three.

Ah well... peace out or goodbye or something.