Reading List
The most recent articles from a list of feeds I subscribe to.
Moving away from Tailwind, and learning to structure my CSS
Hello! 8 years ago, I wrote excitedly about discovering Tailwind.
At that time I really had no idea how to structure my CSS code and given the choice between a pile of complete chaos and Tailwind, I was really happy to choose Tailwind. It helped me make a lot of tiny sites!
I spent the last week or so migrating a couple of sites away from Tailwind and towards more semantic HTML + vanilla CSS, and it was SO fun and SO interesting, so here are some things I learned!
As usual I’m not a full-time frontend developer and so all of my CSS learning has happened in fits and starts over many years.
it turns out Tailwind taught me a lot
When I started thinking about structuring CSS, I was intimidated at first: I’m not very good at structuring my CSS! But then I started reading blog posts talking about how to structure CSS (like A whole cascade of layers or How I write CSS in 2024) and I realized a couple of things:
- Every CSS code base has a bunch of different things going on (layouts! fonts! colours! common components!)
- It’s extremely useful to have systems or guidelines to manage each of those things, otherwise things descend into chaos
- Tailwind has systems for some of these, and I already know those systems! Maybe I can imitate the systems I like!
For example, Tailwind has:
- a reset stylesheet
- a colour palette
- a font scale
the systems I’m going to talk about
I’m going to talk about a few aspects of my CSS codebase and my thoughts so far what kind of rules I want to impose on the codebase for each one. Some of them are copied from Tailwind and some aren’t.
- reset
- components
- colours
- font sizes
- utility classes
- the base
- spacing
- responsive design
- the build system
1. reset
I just copied Tailwind’s “preflight styles”
by going into tailwind.css and copying the first 200 lines or so.
I noticed that I’ve developed a relationship with Tailwind’s CSS reset over time,
for example Tailwind sets box-sizing: border-box on every element (which means
that an element’s width includes its padding):
* { box-sizing: border-box; }
I think it would be a real adjustment for me to switch to writing CSS without
these, and I’m sure there are lots of other things in the Tailwind reset (like
html {line-height: 1.5;}) that I’m subconsciously used to and don’t even realize are
there.
2. components
This next part is the bulk of the CSS!
The idea here is to organize CSS by “components”, in a way that’s spiritually related to Vue or React components. (though there might not actually be any Javascript at all in the site)
Basically the idea is that:
- Each “component” has a unique class
- The CSS for one component never overrides the CSS for any other component
- Each component has its own CSS file
So editing the CSS for one component won’t mysteriously break something in another component. And probably like 80% of the CSS that I would actually want to change is in various component files, so if I’m editing a 100-line component, I just have to think about those 100 lines. It’s way easier for me to think about.
For example, this HTML might be the .zine “component”.
<figure class="zine horizontal">
<img src="whatever.jpg">
</figure>
And the CSS looks something like this, using nested selectors:
.zine {
...
&.horizontal {
...
}
&.vertical {
...
}
&:hover {
...
}
}
I haven’t done anything programmatic (like web components or @scope) that ensures that components won’t interfere with each other, but just having a convention and trying my best already feels like a big improvement.
Next: conventions to maintain some consistency across the site and keep these components in line with each other!
3. colours
colours.css has a bunch of variables like this which I can use as necessary.
Colour is really hard and I didn’t want to revisit my use of colour in this
refactor, so I left this alone.
The only guideline I’m trying to enforce here is that all colours used in the site are listed in this file.
:root {
--pink: #fea0c2;
--pink-light: #F9B9B9;
--red: #f91a55;
--orange: rgb(222, 117, 31);
...
}
4. font sizes
One thing I appreciated about Tailwind was that if I wanted to set a font
size, I could just think “hm, I want the text to be big”, write text-lg, and
be done with it! And maybe if it’s not big enough I’d use xl or 2xl instead.
No trying to remember whether I’m using em or px or rem.
So I defined a bunch of variables, taken from Tailwind, like this:
--size-xs: 0.75rem;
--line-height-xs: 1rem;
--size-sm: 0.875rem;
--line-height-sm: 1.25rem;
Then if I want to set a font size, I can do it like this. It’s a little more verbose than Tailwind but I’m happy with it for now.
h3 {
font-size: var(--size-lg);
line-height: var(--line-height-lg);
}
5. utilities
There are some things like buttons that appear in many different components. I’m calling these “utilities”.
I copied some utility classes from Tailwind (like .sr-only for things that
should only appear for screenreader users).
This section is pretty small and I try to be careful about making changes here.
6. the base
“base” styles are styles that apply across the whole site that I chose myself. I
have to keep this section really small because I’m not confident enough to
enforce a lot of styles across the whole site. These are the only two I feel
okay about right now, and I might change the <section> one:
/* put a 950px column in the middle of each <section> */
section {
--inner-width: 950px;
padding: 3rem max(1rem, (100% - var(--inner-width))/2);
}
a {
color: var(--orange);
}
I think for the base styles it’s going to be easiest for me to work kind of bottom up – first start with almost nothing in the base styles, and then move some styles from the components into base styles as I identify common things I want.
7. spacing
I haven’t completely worked out an approach to managing padding and margins yet. I’m definitely trying to be more principled than how I was doing it in Tailwind though, where I would just haphazardly put padding and margins everywhere until it looked the way I wanted.
Right now I’m working towards making the outer layout components in charge of
spacing as much as possible. For example if I have a <section> with a bunch of
children that I want to have space between them, I might use this to space the
children evenly:
section > *+* {
margin-top: 1rem;
}
Some inspiration blog posts:
8. responsive design: use more grid!
The way I was doing responsive design in Tailwind was to use a lot of media
queries. Tailwind has this md:text-xl syntax that means “apply the text-xl
style at sizes md or larger”.
I’m trying something pretty different now, which is to make more flexible CSS grid layouts that don’t need as many breakpoints. This is hard but it’s really interesting to learn about what’s possible with grid, and it’s a good example of something that I don’t think is possible with Tailwind.
For example, I’ve been learning about how to use auto-fit to automatically use
2 columns on a big screen and 1 column on a small screen like this:
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), max-content));
justify-content: center;
I also used grid-template-areas a lot which is an amazing feature that I don’t think you can use with Tailwind.
Some inspiration:
- A responsive grid layout with no media queries from CSS Tricks
9. the build system: esbuild
In development, I don’t need a build system: CSS now has both built in import statements, like this:
@import "reset.css";
@import "typography.css";
@import "colors.css";
and built in nested selectors, like this:
.page {
h2 { ...}
}
If I want, I can use esbuild to bundle the CSS file for production. That looks something like this.
esbuild style.css --bundle --loader:.svg=dataurl --loader:.woff2=file --outfile=/tmp/out.css
Even though I usually avoid using CSS and JS build systems, I don’t mind using esbuild (which I wrote about in 2021 here) because it’s based on web standards and because it’s a static Go binary.
why migrate away from Tailwind?
A few people asked why I was migrating away from Tailwind. A few factors that contributed are:
- Tailwind has become much more reliant on a build system since 2018, I think it’s impossible (?) to use newer versions of Tailwind without using a build system. So I’ve been using Tailwind v2 for years. (there’s also litewind apparently)
- It’s always been true that you’re supposed to use Tailwind with a build
system, but I’ve never really done that, so I have 2.8MB
tailwind.min.cssfiles (270K gzipped) in a lot of my projects and it feels a little silly. - I’m a lot better at CSS than I was when I started using Tailwind
- Ultimately Tailwind is limiting: if you want to do Weird Stuff in your CSS, it’s not always possible with Tailwind. Those limits can be extremely useful (a lot of this post is about me reimplementing some of Tailwind’s limits!) but at this point I’d like to be able to pick and choose.
- I ended up with sites that mixed both vanilla CSS and Tailwind in the same project and that was not fun to maintain
- I got curious about what writing more semantic HTML would feel like.
CSS features I’m curious about
While doing this I learned about a lot of CSS features that I didn’t use but am curious about learning about one day:
@layer(from A Whole Cascade of Layers)- @scope) (especially this example of how to use @scope in a “component” CSS design from the specification!)
- container queries
- subgrid
one last reason I moved away from Tailwind
I’ve been talking a lot in this post about what I learned from using Tailwind, and that’s all true.
But I read this post 3 years ago called Tailwind and the Femininity of CSS that really stuck with me. I honestly probably started out with an attitude towards CSS a little like that post describes:
They’ve heard it’s simple, so they assume it’s easy. But then when they try to use it, it doesn’t work. It must be the fault of the language, because they know that they are smart, and this is supposed to be easy.
But in the last 10 years I’ve learned to really love and respect CSS as a technology.
So I decided years ago that I wanted to react to “CSS is hard” by getting better at CSS and taking it seriously as a technology, instead of devaluing it. Doing that changed everything for me: I learned that so many of my frustrations (“centering is impossible”) had been addressed in CSS a long time ago, and that also what “centering” means is not always straightforward and it makes sense that there are many ways to do it. CSS is hard because it’s solving a hard problem!
I’ve been so impressed by the new CSS features that have been built in the last 10-15 years (some of which I’ve talked about in this post!) and how they make it easier to use CSS, and spending the time to improve my CSS skills has been a really cool experience.
And that post made me feel like Tailwind contributes to the devaluing of CSS expertise, and like that’s not something I want to be a part of, even if Tailwind has been a useful tool for me personally. Especially in this time of LLMs where it feels more important than ever to value humans’ expertise.
Another blog post criticizing Tailwind that influenced me:
that’s all for now!
Thanks to Melody Starling who originally designed and wrote the CSS for wizardzines.com, everything cool and fun about the site is thanks to Melody.
Also I read so many incredible blog posts about CSS while working on this (from CSS Tricks, Smashing Magazine, and more), I’ve tried to link some of them throughout this post and I really appreciate how much folks in the CSS community share their practices.
Refactoring English: Month 17
New here?
Hi, I’m Michael. I’m a software developer and founder of small, indie tech businesses. I’m currently working on a book called Refactoring English: Effective Writing for Software Developers.
Every month, I publish a retrospective like this one to share how things are going with my book and my professional life overall.
Highlights
- I’m torn between focusing on my book and pursuing security bug bounties.
- I’m considering a course to teach what I’ve learned about using AI to find security vulnerabilities.
Goal grades
At the start of each month, I declare what I’d like to accomplish. Here’s how I did against those goals:
It's 2026 and women are still asked to teach others to think a little bit and not be a prick
This article was originally drafted in 2024 but I struggled to finish it then. I was stuck wondering if I was just moaning over the past. Recently, Salma and Jo both shared thoughts that gave me the rage and energy to come back to this. Today is the day I finally have the courage to publish.
I can’t recall how many times I thought of writing something like this. I thought of riding certain waves inspired by other authors but most times the embarrassment got the best of me. During those waves this post could have been titled “When I leave tech”, “I’m still a woman in tech” etc. But today it is called “It's 2026 and women are still asked to teach others to think a little bit and not be a prick”. Temporary title.
Some weeks ago I went to a tech meet-up and one of the talks was about being a woman in tech and I am finally ready to put into words why I sat through it so uncomfortably.
It was a great speaker and everything they said was absolutely true and accurate. But I was annoyed that in 2024 we still have to teach people how to have basic human kindness, empathy, compassion and just not being a fucking prick. I was annoyed that, once again, a woman did that labour.
For every slide that brought an example of discrimination that happens, I recalled something I had either witnessed or experienced. It brought back many bad memories that I’ve tried my best to repress. It covered many examples that an HR training titled “how not to be a prick and avoid getting us sued” would cover but it mostly avoided one particular topic.
So the following isn’t a criticism to the speaker at all, or to anyone who has ever done a talk about the realities of being a woman in tech but, I have to address the elephant in the room:
A big part of the problems women in tech have is co-workers hitting on them. And the problems begin when those co-workers are rejected. And we can’t have a big slide saying “women who reject romantic advances from co-workers face retaliation nearly all the time”.
So I was just sitting there, nodding and agreeing that women are often dismissed, overlooked or ignored at work, especially if they are also caregivers in their personal life, while thinking about all the shitty things I also went through because I was once young and vaguely attractive.
But now that I am much older (I mean invisible), wiser and a lot more able to stand-up for myself (I mean I can afford to lawyer up) I can vaguely share how shitty it was to a woman in tech before it was shitty to be a woman in tech in a post-pandemic AI gobbling powered tech landscape. I could go on in very detail but it would be a really depressing post.
I started working in tech straight out of University and I would have been 21 years old. I was very junior and inexperienced with real-life complex websites. Physically, I carried a baby face for a little while so I actually looked young. I knew I was very junior and I really wanted to keep a job. I grew up poor in Portugal and all my life so far was hearing every day from my parents how we had zero money, hearing about the financial crash and how it left my dad unemployed for a very long time, Troika, and how no one my age could get a job at the time. I really wanted to do well at my first job. This was also seemingly the only place hiring around. I wanted to do well and be liked. I imagine now how some 30+ male co-workers could smell my naivety like a shark in bloody waters.
Once in a while there would be chocolates on my desk, inappropriate unprompted messages sharing how sad they were to go home to their partners, drunk messages, all sorts of accusations, gossip and giggles if I was nice back to anyone. But “it’s best not to rock the boat when you know there’s no other jobs out there” I thought. I had my own hiccups at the time. Like I said, I was quite junior but I was also met with a lot of cruelty and a lot of people thought I didn’t deserve to be there so they treated me as such. The money to employ me wasn’t coming out of their own pockets but they acted like it was. I also had the typical mistreatment for being a woman: if someone asked a question and I answered, they deemed that answer wrong by default, for example. Any compliments or encouragement from men, were met with “he only said that because you’re a woman” comments from other men. I was never going to win so for a long time I kept smiling, being easygoing and surviving.
It’s hard to switch from this mentally when you grew up afraid, unsupported and full of shame. This people-pleasing trait I had stayed with me for many years, even when switching jobs. This was okay enough to keep me afloat but not when it came to rejecting romantic advances. That’s when, of course, eventually, someone takes things badly.
In male dominated fields, especially when there’s lots of them, statistically, the bad apples are there and they make your life a living hell. From suddenly getting poor performance reviews, to punishing everyone who is friendly with you so that you are isolated, to even making odd comments about what you did in your free time which implies a level of stalking and eventually, not allowing you to own features at work so that the poor performance accusations can have legs.
You see, most people think sexual harassment is a creepy guy just putting their hands on your shoulders and try to massage you. That’s what the HR training slides show with the stock pictures right? But for me, it was mostly retaliation.
And when I changed jobs, a new batch of unknown enemies would spawn. There’s nothing like starting a new job and going through onboarding with a male colleague and everything is going great until he asks “so, do you have a boyfriend?” and you know exactly what’s going to happen next. Half of the time, they would immediately stop being nice to me. No more bare minimum human kindness. No more answering my questions without implying I am an idiot. For them, I am not a colleague who will contribute to work. I am an object and if I am not single, I am of no use. And where do you turn after this? After all, they are the x10 developer that knows the whole codebase and they are super valuable and the HR person is also the office admin who claims we are all a happy family.
It’s undeniable (and normal) that people meet their partners at work. That’s how I met my husband. So this isn’t about that. And, as we all know, there is no patriarchy without women. The other type of bullying that surprised me was when co-workers perceived me as a romantic threat. That’s a pickle in any social situation but at work it has devastating consequences too. And when that wasn’t the reason for their bullying, other male centered reasons thrived. I’ve had women talk me down and micromanage every single thing I did disguised as care but it was all down to their bias, hatred, shame and fear. Turns out my strategy of trying to be generally likable was a threat to some. Retaliation soon begins too.
Sometime in 2013, I had the courage to interject in a conversation I was, technically a part of, where I was the only woman in. This was happening while everyone was working on their computers in our little team island. They were, as you do in bro-locker-room-culture, talking about honking their car if they see, what they perceived to be, a fit woman walking on the street. I, twenty-two years old then, said “well, don’t do that. That’s really scary”.
“Why? If I like what I see, I honk”, said the (probably close to his 30s) co-worker.
“Why do you have to do that?” I asked.
“Because. So that they know” he said, shrugging his shoulders.
“Okay, we don’t know if you’re going to stop your car and do something to us” I tried explaining while having my heart broken realising who I was dealing with.
“Okay, well I am not going to do that”
“Okay, and I don't know that!”
“But I am not!”
“For a very similar reason, I try to avoid getting in the lift alone with strange men”
“Really? That’s fucking weird” He laughed.
Almost everyone involved (and deliberately quiet too) in this conversation has had daughters since. I wonder if their views have changed.
And as I wrote this shitty real dialogue, I realised that we still fucking need women in tech talks being forcibly fed in javascript meet-ups because the fucking bare minimum probably doesn’t exist in their heads at all. Maybe we need to talk about the shitty things that they do rather than the things we have to do to stay and survive in the tech industry.
I’ve never had any harassment / basic human kindness HR training at a job. So far, I’ve only seen descriptions of that being retold on the internet as a meme or in a Code of Conduct at tech events that most people scroll past. But tech companies (and their parents) clearly are not teaching “heyyyyy bestie can you please not be a monster / creep / prick?” so of course that labour is going to fall on a woman in her free time at a tech meet-up.
We have to spoon feed bare minimum and many times, they just don’t want to get it. I saw the faces around me during this talk. I saw many of them zoning out and on their phones.
But of course, our advice to women in tech is to lean-in!! Get a mentor!! Put yourself out there!! Work for free!! Be quiet!! Be the glue!!! Smile!! Be agreeable!!
No! Here’s an idea: let’s teach how to fucking gather the evidence of harassment and bullying and use the law to full extent to push HR to do something about the rockstars. Maybe, many years ago, many people would have learned a few lessons if I had the money and support to do so then. Because now I only live with hatred and disgust every time some of those people still, for a fucking wild reason or just lack of self awareness, try to engage with me on social media.
I can’t believe I am finally at a job where nothing bad of the sort has ever happened. So, at least there’s some hope. But, my god, how much I worry now wondering if there’s young women out there stuck in the same financial situation I was in the early 2010s because of AI layoffs and the manosphere and still putting up with this crap.
Introducing Piper: a pipe operator-first PHP utility library
When I experimented with Elixir a few years ago, I fell in love with the pipe operator |>. Since then, I’ve always dreamt of a similar tool in PHP.
Last year, we finally got it! Unfortunately, the standard array & string manipulation functions in PHP aren’t exactly known for their API consistency, which makes the pipe operator awkward to use.
I ported Laravel’s excellent collection & string helpers to a pipe operator-optimized API. Piper is an attempt to wrap the standard library to make it compatible with the pipe operator.
use function Spatie\Piper\Arr\{filter, join, map};
use function Spatie\Piper\Str\{prefix, suffix};
[1, 2, 3, 4, 5, 6]
|> filter(fn (int $i) => $i % 2 === 0)
|> map(fn (int $i) => pow($i, 2))
|> join(', ', ', and ')
|> prefix('The winning numbers are ')
|> suffix('.');
// "The winning numbers are 4, 16, and 36."
I wrote a technical introduction to the package on the Spatie blog. Documentation can be referenced here, and the repository is hosted on GitHub.
The sad part (maybe?)
I’ve never seen a coding agent return code using a pipe operator unless I’ve explicitly asked it to. That makes sense: the models we use are trained on years of historical data, and the pipe operator is a fairly new feature.
I might never use this library. I might never use the pipe operator at all. Agentic coding is pushing syntax to a standstill. New programming APIs that bring benefits to execution will be pushed forward. But the whole fight for making code look good seems to have been extinguished as AI is slowly moving us to focus on outcomes more than line-by-line code cleanliness. That’s not necessarily a bad thing, but part of our craft might get lost along the way.
Ironically, I convinced myself to actually write this because I have AI at my disposal. Manually porting 234 functions and a full test suite is not something I was looking forward to. Instead, the time spent building and refining this package is measurable in hours.
Either way, this is a fun experiment to conduct. And I look forward to tinkering further and giving it a shot in some real projects.