<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Martin Michálek · Web &amp; Performance</title><description>Personal tech blog and web performance consulting.</description><link>https://michalek.blog/</link><language>en-us</language><item><title>WebExpo 2026 in Prague: Switch Angel, Daniel Cuthbert, Mike Kus &amp; FrontKec</title><link>https://michalek.blog/blog/webexpo-2026/</link><guid isPermaLink="true">https://michalek.blog/blog/webexpo-2026/</guid><description>Four WebExpo Prague talks worth seeing, a live FrontKec podcast recording, and a ticket discount code.</description><pubDate>Mon, 18 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;An invitation to WebExpo 2026: Switch Angel, Daniel Cuthbert, Mike Kus &amp;amp; FrontKec&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://webexpo.net/&quot;&gt;WebExpo&lt;/a&gt;, the big web conference here in Prague, lands at the end of May this year (May 27–29), and I&apos;ve of course already blocked out the city&apos;s Lucerna venue in my calendar.&lt;/p&gt;
&lt;p&gt;I went through the &lt;a href=&quot;https://webexpo.net/prague2026/program/&quot;&gt;program&lt;/a&gt; and picked four talks I&apos;d go to in a parallel universe — the one where I don&apos;t bump into one of you right before the talk and get lost in conversation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/content/dest/machal-webexpo-2026.webp&quot; alt=&quot;WebExpo 2026 promo: recommended talks and the MICHALEK26 discount code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I also helped curate the frontend talks for FrontKon. &lt;a href=&quot;https://www.frontkon.tech/cs/blog/co-si-nenech-ujit-na-web-expo-2026&quot;&gt;Our picks there&lt;/a&gt; cover a broader range. Here&apos;s my shorter, personal selection.&lt;/p&gt;
&lt;h2&gt;Four talks I&apos;d hate to miss {#talks}&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://webexpo.net/prague2026/sessions/patterns-for-restarting-the-world/&quot;&gt;&lt;strong&gt;Switch Angel: Patterns for restarting the world&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
The opening keynote. A well-known streamer, live coding music in Strudel, electronic pop in real time. Really looking forward to this one.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://webexpo.net/prague2026/sessions/daniel-cuthbert-coming-in-2026/&quot;&gt;&lt;strong&gt;Daniel Cuthbert: From HAL to Replicants&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Agents, payments, security — a world where AI doesn&apos;t just write your commit messages but also makes decisions for you. I don&apos;t think this will be sci-fi storytelling; it&apos;ll be hard reality.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://webexpo.net/prague2026/sessions/dont-trust-the-bot-a-human-framework-for-wvaluating-ai-copy/&quot;&gt;&lt;strong&gt;Michal Kessel Shitrit: Don&apos;t trust the bot&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
How not to send your users straight to hell with AI-generated microcopy. UX writing with common sense — exactly what I&apos;m &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:share:7452267804730286080/&quot;&gt;dealing with at work&lt;/a&gt; right now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://webexpo.net/prague2026/sessions/mike-kus-coming-in-2026/&quot;&gt;&lt;strong&gt;Mike Kus: Design like no-one is watching&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;
Design without fear of AI templates. A big name from the UX scene calling for creative instinct. Where do I sign?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Recording FrontKec on Wednesday: a chat about the first day&apos;s topics {#frontkec}&lt;/h2&gt;
&lt;p&gt;After day one, just before 6 p.m., I&apos;ll slip into the small cinema inside Lucerna with &lt;a href=&quot;https://www.frontendisti.cz/&quot;&gt;Robin Pokorný&lt;/a&gt; and we&apos;ll record a &lt;a href=&quot;https://webexpo.net/prague2026/sessions/2026-live-recording-of-the-podcast-frontkec-in-czech/&quot;&gt;live episode of FrontKec&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&apos;ll recap the day and talk through the talks. As usual, with you in the audience. Informal, just like the &lt;a href=&quot;https://www.vzhurudolu.cz/blog/262-frontkec-deset-dilu&quot;&gt;other episodes&lt;/a&gt; — only this time with fresh conference material in our heads.&lt;/p&gt;
&lt;p&gt;Come say hello.&lt;/p&gt;
&lt;h2&gt;A little discount from the garden…? {#discount}&lt;/h2&gt;
&lt;p&gt;The code &lt;strong&gt;&lt;code&gt;MICHALEK26&lt;/code&gt;&lt;/strong&gt; saves you &lt;strong&gt;1,000 CZK&lt;/strong&gt; on a &lt;a href=&quot;https://webexpo.net/tickets/&quot;&gt;ticket&lt;/a&gt; (both the conference ticket and the bundle).&lt;/p&gt;
&lt;p&gt;Premium workshops aren&apos;t included in the discount, just so you know.&lt;/p&gt;
&lt;p&gt;See you in Lucerna?&lt;/p&gt;
</content:encoded></item><item><title>Will AI Kill SaaS? Let&apos;s Think Again</title><link>https://michalek.blog/guide/ai-saas/</link><guid isPermaLink="true">https://michalek.blog/guide/ai-saas/</guid><description>Every AI wave brings apocalypse headlines for software subscriptions. But SaaS is far more than code you can vibe-generate in an afternoon.</description><pubDate>Fri, 06 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;AI is supposedly going to kill SaaS. Let&apos;s think about that one more time&lt;/h1&gt;
&lt;p&gt;We live in a world where one dark AI prediction is immediately replaced by the next. It&apos;s worth remembering that we humans are absolutely excellent at exactly one thing: overestimating how much we know about domains we don&apos;t actually understand.&lt;/p&gt;
&lt;p&gt;This particular brand of irrationality hits hardest among those of us who love the attention that doom-laden predictions reliably generate.&lt;/p&gt;
&lt;p&gt;So let&apos;s get concrete and talk about the &lt;strong&gt;SaaSpocalypse&lt;/strong&gt; — the coming apocalypse of SaaS companies. Software stocks are sliding because SaaS apps (Software as a Service) supposedly won&apos;t be needed anymore. Everyone can just write their own with AI.&lt;/p&gt;
&lt;h2&gt;We irrational humans and our AI catastrophes {#irrational-humans}&lt;/h2&gt;
&lt;p&gt;Yes, AI is changing the rules of the game. But not every rule change means the game is over.&lt;/p&gt;
&lt;p&gt;Look at the pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&quot;Juniors won&apos;t be needed. Who&apos;ll look after them?!&quot;&lt;/strong&gt;&lt;br /&gt;
Everyone says it, and demand for junior developers really is falling. Except it isn&apos;t falling because of AI alone — it&apos;s the broader economy too. And partly because it&apos;s &lt;a href=&quot;https://www.youtube.com/watch?v=_M_vM52bcxI&quot;&gt;deferred demand&lt;/a&gt;. The productivity boost AI gives to existing employees won&apos;t grow forever.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&quot;Jobs are vanishing. We&apos;re all out of work!&quot;&lt;/strong&gt;&lt;br /&gt;
Like when Jack Dorsey, former owner of Twitter, cut thousands of people at Block. Catastrophe — we&apos;re all losing our jobs! Except the whole thing was a bit different: the company simply &lt;a href=&quot;https://en.wikipedia.org/wiki/AI_washing&quot;&gt;needed to slim down&lt;/a&gt;. That&apos;s textbook &lt;a href=&quot;https://en.wikipedia.org/wiki/AI_washing&quot;&gt;AI washing&lt;/a&gt; — blaming (or crediting) AI for a decision that had other reasons entirely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&quot;SaaS faces its biggest test in twenty years. And it probably won&apos;t survive!&quot;&lt;/strong&gt;&lt;br /&gt;
…write others. It must be true. Some editor slapped a headline on it like &quot;The age of digital cannibalism has arrived: AI has started eating software from the inside.&quot; Personally, I&apos;d prefer AI to eat the editors who come up with headlines like that. But to the point — the SaaSpocalypse is exactly what I want to address here.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How many of these &quot;this whole industry dies in five years&quot; catastrophes have we lived through in the last decade alone? An electric car in every driveway within five years. Blockchain changes everything. Factory workers paid in crypto. Energy breakthroughs.&lt;/p&gt;
&lt;p&gt;Let&apos;s meet in the Metaverse, where we&apos;ll watch the end of an entire continent brought on by whatever this year&apos;s policy panic happens to be.&lt;/p&gt;
&lt;p&gt;The world is changing and will keep changing — but perhaps a little differently than the evangelists proclaim.&lt;/p&gt;
&lt;p&gt;Back to SaaS.&lt;/p&gt;
&lt;h2&gt;SaaSpocalypse {#saaspocalypse}&lt;/h2&gt;
&lt;p&gt;We run a SaaS product, so this topic genuinely interests me. AI has an enormous influence on everything in this field. We use AI; we strategically track everything that&apos;s happening. It&apos;s a big deal.&lt;/p&gt;
&lt;p&gt;But at the same time, I see that people aren&apos;t behaving rationally. Investors least of all. Let&apos;s illustrate it with a chart that&apos;s trending hard right now — the one showing software stocks falling off a cliff.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;/prirucka/images/saaspokalypse.jpg&quot; alt=&quot;SaaSpocalypse. The fall of software company stock prices&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Here we see the result of a vote among experts on SaaS, AI, and the future.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The reasoning goes like this: software development is undergoing a tectonic shift. &lt;a href=&quot;../guide/vibe-coding.md&quot;&gt;Vibe coding&lt;/a&gt; has opened up software development to the masses.&lt;/p&gt;
&lt;p&gt;Every other CEO is now a programmer.&lt;/p&gt;
&lt;p&gt;Designers are turning into &quot;builders.&quot;&lt;/p&gt;
&lt;p&gt;Our cat would be building its own SaaS by now. If we had a cat…&lt;/p&gt;
&lt;p&gt;Plenty of AI consultants are shouting that Cursor — interface-wise, a fairly thin layer on top of the developer editor &lt;a href=&quot;https://code.visualstudio.com&quot;&gt;VS Code&lt;/a&gt; — is &quot;the best software ever created.&quot;&lt;/p&gt;
&lt;p&gt;I understand the enthusiasm. But the enthusiasm, the dark predictions, and ultimately the stock price moves all point to the same thing: a lack of understanding of how software development actually works.&lt;/p&gt;
&lt;p&gt;Let&apos;s illustrate it with a made-up example.&lt;/p&gt;
&lt;p&gt;Somewhere around the twelfth LinkedIn post on the subject, I got annoyed. And invented Joe.&lt;/p&gt;
&lt;h2&gt;Joe and his invoicing software {#joe}&lt;/h2&gt;
&lt;p&gt;Once upon a time there was a guy named Joe. Joe is a marketer and a bit of an AI consultant. Joe is a fictional character, just to be clear.&lt;/p&gt;
&lt;p&gt;Joe had been paying for an invoicing SaaS for years. But yesterday he &quot;vibe-coded&quot; a mortgage calculator, got swept up in the excitement, and today decided to stop paying for the SaaS and build his own little invoicing gadget instead. Because the internet told him &lt;a href=&quot;https://www.vzhurudolu.cz/blog/258-ai-programovani-psani&quot;&gt;developers won&apos;t be needed anymore&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Day one — euphoria {#day-one}&lt;/h3&gt;
&lt;p&gt;Joe opens Cursor, throws together some kind of spec, and after a few iterations he has a solution. He types in the data, gets an invoice — in PDF, no less, and prettier than the one his old service produced. He immediately runs off to post on X: &quot;In two hours of work I built the same app I was paying $120 a year for. SaaS is dead!!!&quot;&lt;/p&gt;
&lt;p&gt;Welcome to the beautiful new world, Joe, where everyone can program anything!&lt;/p&gt;
&lt;h3&gt;Day two — what is git? {#day-two}&lt;/h3&gt;
&lt;p&gt;Different client. Different invoice. New fields are needed. So he just writes a prompt asking Cursor to tweak it. But something breaks in the process. Now even the original invoicing doesn&apos;t work anymore. Joe doesn&apos;t understand the messages in the terminal.&lt;/p&gt;
&lt;p&gt;He&apos;d love to roll back to the previous version. He&apos;s heard there&apos;s this thing called git. But there&apos;s no time to study it. In the end he hacks his way through somehow, but he&apos;s lost two hours he&apos;d meant to spend writing about how vibe coding is changing the world.&lt;/p&gt;
&lt;p&gt;Welcome to the world of version control, Joe.&lt;/p&gt;
&lt;h3&gt;Day three — weird messages in the terminal {#day-three}&lt;/h3&gt;
&lt;p&gt;Joe spends the whole morning learning git. People on X said even marketers need to know it now. So he can version his work, and when something breaks he steps back. Which means he can finally tackle those weird messages in the terminal.&lt;/p&gt;
&lt;p&gt;After two hours he gets it working, though he doesn&apos;t really know how. He&apos;s lost all track of time and never did that analysis for his client — but he is now, in addition to a marketer, basically a programmer. After all, programmers are the people who deal with weird messages on a screen.&lt;/p&gt;
&lt;p&gt;Welcome to the world of developer fundamentals, Joe.&lt;/p&gt;
&lt;h3&gt;Day four — wait, the invoice is in euros? {#day-four}&lt;/h3&gt;
&lt;p&gt;The next day he needs to send an invoice to a client in another country. Joe&apos;s stomach drops, because that means adding the option to invoice in a foreign currency. In Cursor that turns out to be trivial, but… hold on, how does the exchange rate and currency conversion actually work…? Joe goes off to study; an hour later he has it, results and all.&lt;/p&gt;
&lt;p&gt;In the end the client returns the invoice anyway — apparently because of incorrect handling of cross-border VAT and the reverse-charge mechanism. Joe is caught off guard and starts digging through the documentation of the SaaS app he stopped paying for a few days ago, hunting for the details. Three hours later he pulls it off and is finally ready to invoice across borders.&lt;/p&gt;
&lt;p&gt;Welcome to the world of managing know-how and product features that SaaS app authors handle for you, Joe.&lt;/p&gt;
&lt;h3&gt;Day five — &quot;How dare you?&quot; {#day-five}&lt;/h3&gt;
&lt;p&gt;Joe is getting a little frustrated now, because he hasn&apos;t gotten much done over the last several days. But he&apos;s already drafting an X post in the genre of &quot;what I learned building my own invoicing solution.&quot;&lt;/p&gt;
&lt;p&gt;Then an email from a client lands in his inbox — the one he sent his very first invoice to four days ago. The subject line reads &quot;How dare you?&quot; Joe&apos;s stomach drops, and it&apos;s about to get worse. The client attached a screenshot from his invoicing app. In place of the polished, AI-generated logo of Joe&apos;s consulting firm, there&apos;s just… uh… a porn image.&lt;/p&gt;
&lt;p&gt;After Joe showed off his invoices on X, someone had a little fun with them.&lt;/p&gt;
&lt;p&gt;Welcome to the world of online security, Joe!&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;/prirucka/images/vibe-coder-depression.jpg&quot; alt=&quot;A vibe coder in euphoria and in deep depression&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Joe&apos;s journey.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;And what happens on day six, dear readers?&lt;/p&gt;
&lt;p&gt;Joe goes off to renew his SaaS subscription.&lt;/p&gt;
&lt;p&gt;Whatever you think about how realistic the story is, it hopefully leaves you with at least a basic mental model of what most SaaS services actually provide.&lt;/p&gt;
&lt;h3&gt;SaaS is paid transfer of responsibility {#responsibility-transfer}&lt;/h3&gt;
&lt;p&gt;Because SaaS isn&apos;t just software.&lt;/p&gt;
&lt;p&gt;SaaS is often a deeply complex technical infrastructure (one day I&apos;ll try to sketch out everything that goes into testing web performance in &lt;a href=&quot;https://pagespeed.one/&quot;&gt;PageSpeed.ONE&lt;/a&gt;). SaaS is domain knowledge of the problem. SaaS is the know-how you accumulate as the author of an app. SaaS is product vision, communication with your audience, and discovering problems a vibe coder can&apos;t even imagine. SaaS is solving for stability, security, and speed.&lt;/p&gt;
&lt;p&gt;SaaS is taking responsibility for your problem. &lt;a href=&quot;https://www.fakturoid.cz&quot;&gt;Fakturoid&lt;/a&gt; takes on some responsibility for your invoicing and part of your financial management. We at &lt;a href=&quot;https://pagespeed.one/&quot;&gt;PageSpeed.ONE&lt;/a&gt; take on, through our SaaS, part of the responsibility for the performance of your websites.&lt;/p&gt;
&lt;p&gt;No matter how good it gets, AI won&apos;t take responsibility for anything.&lt;/p&gt;
&lt;p&gt;Programming isn&apos;t just writing code. That&apos;s why AI won&apos;t replace all programmers.&lt;/p&gt;
&lt;p&gt;SaaS isn&apos;t just a programmed app. That&apos;s why AI won&apos;t replace all SaaS.&lt;/p&gt;
</content:encoded></item><item><title>Vibe Coding: 25 Years of Building Websites, the Last Two Completely Different</title><link>https://michalek.blog/guide/vibe-coding/</link><guid isPermaLink="true">https://michalek.blog/guide/vibe-coding/</guid><description>AI-assisted coding democratises building software — and traps anyone who skips engineering thinking. Notes from the hype cycle.</description><pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Vibe Coding: I&apos;ve Built Websites for 25 Years — the Last Two Months Were Nothing Like It&lt;/h1&gt;
&lt;p&gt;Vibe coding is a hell of a revolution. It&apos;s deflating the cost of writing code for developers. And it&apos;s opening up the building of websites and other digital products to a much wider crowd than ever before.&lt;/p&gt;
&lt;p&gt;Vibe coding is also a bit of a trap. A trap for people who think they can get by without developers — or without developer thinking. And for developers themselves? For some, a huge opportunity. For others, pain.&lt;/p&gt;
&lt;p&gt;I thought my site Vzhůru dolů was basically dead. Vibe coding brought it back to life — not just technically, but editorially too. If I write only one article this year, it has to be this one.&lt;/p&gt;
&lt;p&gt;I&apos;ve tried to build this piece as a collage: motivation, small essays, and practical tips. As for the topic itself, I&apos;m currently in the head-exploding phase. So take me with a grain of salt — but we have to start here.&lt;/p&gt;
&lt;h2&gt;Swept Off My Feet {#riding-the-wave}&lt;/h2&gt;
&lt;p&gt;I spent more than 20 years actively building web applications, and I&apos;ve been circling web technologies for 27 years now. But I&apos;ve never experienced anything like this in the field. And I&apos;m not alone:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I just sat down with Windsurf and in three days I have a new version that within a week will do more than my nine months of work. It&apos;s genuinely insane.&quot;&lt;/p&gt;
&lt;p&gt;– &lt;em&gt;&amp;lt;cite&amp;gt;&lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7421846795984683008&quot;&gt;Petr Pixy Staníček&lt;/a&gt;&amp;lt;/cite&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Vibe coding democratises technology and development work. It makes it accessible to everyone:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I sat down with Wix Vibe and in two hours I had a finished election campaign site, CMS included. That used to be several weeks of evening work in WordPress.&quot;&lt;/p&gt;
&lt;p&gt;– &lt;em&gt;&amp;lt;cite&amp;gt;&lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7421846795984683008&quot;&gt;Michal Berg&lt;/a&gt;&amp;lt;/cite&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But developers and technically skilled people are not out of work. They have an advantage and a head start — as long as they don&apos;t sleep through it. The window of opportunity is open. Wide open.&lt;/p&gt;
&lt;p&gt;Okay. Beyond the enthusiasm, let&apos;s also try to stay sober:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;When you know exactly what you want, and you also know the best way to do it, AI saves you a lot of work. When you don&apos;t, the result can be very bad.&quot;&lt;/p&gt;
&lt;p&gt;– &lt;em&gt;&amp;lt;cite&amp;gt;&lt;a href=&quot;https://www.linkedin.com/posts/marekprokop_m%C3%A1m-hodn%C4%9B-p%C5%99%C3%A1tel-kte%C5%99%C3%AD-te%C4%8F-uj%C3%AD%C5%BEd%C4%9Bj%C3%AD-na-vibe-activity-7366146403502329858-4m91&quot;&gt;Marek Prokop&lt;/a&gt;&amp;lt;/cite&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;&quot;Vibe… What?&quot; {#vibe-what}&lt;/h2&gt;
&lt;p&gt;Let&apos;s start with a definition.&lt;/p&gt;
&lt;p&gt;Vibe coding is a way of programming where you describe your &lt;em&gt;intent&lt;/em&gt; in natural language and AI generates the code for you. Instead of writing individual lines, you talk to a model about what you want to do.&lt;/p&gt;
&lt;p&gt;The name comes from &lt;a href=&quot;https://x.com/karpathy/status/1886192184808149383?lang=en&quot;&gt;Andrej Karpathy&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;…you fully give in to the vibes, embrace exponentials, and forget that the code even exists.&quot;&lt;/p&gt;
&lt;p&gt;– &lt;em&gt;&amp;lt;cite&amp;gt;&lt;a href=&quot;https://x.com/karpathy/status/1886192184808149383?lang=en&quot;&gt;Andrej Karpathy&lt;/a&gt;&amp;lt;/cite&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My main tool is &lt;a href=&quot;https://cursor.com/&quot;&gt;Cursor&lt;/a&gt; — an editor built on top of VS Code with AI baked in. There are others: &lt;a href=&quot;https://windsurf.com/&quot;&gt;Windsurf&lt;/a&gt;, &lt;a href=&quot;https://github.com/features/copilot&quot;&gt;GitHub Copilot&lt;/a&gt;, Google&apos;s &lt;a href=&quot;https://antigravity.codes/&quot;&gt;Antigravity&lt;/a&gt; is having a moment, and plenty more. What they share is that the AI understands the context of your project and can actually work inside it.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/vibe-coding-cursor.jpg&quot; alt=&quot;Cursor in Agent mode&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Cursor&apos;s Agent mode is glorious — especially when you keep thinking like an engineer. And the interface is familiar from &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VS Code&lt;/a&gt;.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Cursor has an Agent mode where the AI works autonomously. It runs the terminal itself, reads files, installs libraries, writes to multiple files at once. You approve the work or steer it in a different direction.&lt;/p&gt;
&lt;p&gt;The difference from traditional development? You&apos;re not wrestling with syntax, not googling documentation, not writing boilerplate. You say what you want and the AI writes it. Then you review, fix, and direct.&lt;/p&gt;
&lt;p&gt;It&apos;s like having a junior who writes fast and writes a lot — but needs your guidance.&lt;/p&gt;
&lt;h2&gt;Vibe Coding vs. Vibe Engineering {#vibe-coding-vs-vibe-engineering}&lt;/h2&gt;
&lt;p&gt;Not all developer work with AI is the same. Let&apos;s draw at least two working distinctions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vibe coding&lt;/strong&gt; — I don&apos;t deal with the code at all. I sit down at Cursor or &lt;a href=&quot;https://www.macaly.com/&quot;&gt;Macaly&lt;/a&gt;, describe what I want, and let it run. This is perfect for prototypes and demos (where you&apos;ll throw the code away anyway), simple sites and landing pages, or one-off tools. I also use &quot;vibe coding&quot; as a broader label for this whole space.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vibe engineering&lt;/strong&gt; — an engineering approach beyond vibe coding. Here it&apos;s no longer about &quot;let it run,&quot; but about deliberate collaboration. You design the architecture, break the problem into sub-problems, and the AI implements according to your specs. But you craft those specs together. The developer and architect thinking stays with you. AI is a tool, not a replacement for your brain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We could argue about definitions, but I&apos;d rather not. They&apos;re just words. I mention them so that those of you who feel lost can at least tell apart the different flavours of &quot;vibing&quot; code.&lt;/p&gt;
&lt;p&gt;A side note: I&apos;ve always tried to translate terms into Czech, but here I give up. This field moves so fast that all of this might just be a waypoint on the road to even greater AI autonomy.&lt;/p&gt;
&lt;p&gt;What does matter, I&apos;ll mark again with a quote from Marek Prokop:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Watch out for this, and learn to program. It&apos;s needed even in the era of AI.&quot;&lt;/p&gt;
&lt;p&gt;– &lt;em&gt;&amp;lt;cite&amp;gt;&lt;a href=&quot;https://www.linkedin.com/posts/marekprokop_m%C3%A1m-hodn%C4%9B-p%C5%99%C3%A1tel-kte%C5%99%C3%AD-te%C4%8F-uj%C3%AD%C5%BEd%C4%9Bj%C3%AD-na-vibe-activity-7366146403502329858-4m91&quot;&gt;Marek Prokop&lt;/a&gt;&amp;lt;/cite&amp;gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the key difference between vibe coding and vibe engineering. You can manage vibe coding without deep knowledge — for a prototype or a simple landing page, that&apos;s enough. But the moment things get more complex, you need to be an engineer. To understand what the AI is doing. To be able to fix it when it gets things wrong.&lt;/p&gt;
&lt;h2&gt;Where Do I Start as a Beginner? {#where-to-start}&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.facebook.com/faborsky/posts/pfbid0tRgVkByRZY8qgVVyGy8asoD2ZA1h7uPcwqjv9czxYFwdYbw13RAQbL6ddsgXUvNwl&quot;&gt;Jindra Fáborský&lt;/a&gt; sorted this nicely into levels based on project complexity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Level 0&lt;/strong&gt; — one-off tools and little hacks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 1&lt;/strong&gt; — landing pages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 2&lt;/strong&gt; — whole websites&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 3&lt;/strong&gt; — app prototypes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 4&lt;/strong&gt; — internal tools&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Level 5&lt;/strong&gt; — production applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The higher the level, the more you need an engineering approach. Levels 0–2 are fine with vibe coding. From level 4 up, you have to be a vibe engineer.&lt;/p&gt;
&lt;p&gt;Great news for developers. For non-coders? Don&apos;t jump straight into rewriting the app that pays your bills. Please, don&apos;t do it.&lt;/p&gt;
&lt;h2&gt;Me and Vibing: Four Examples {#four-things-i-built}&lt;/h2&gt;
&lt;p&gt;Theory is nice, but let&apos;s get to what I actually did over the last two months.&lt;/p&gt;
&lt;h3&gt;Example one: a prototype of the FrontKon site {#example-frontkon}&lt;/h3&gt;
&lt;p&gt;On the team behind the &lt;a href=&quot;https://www.frontkon.cz/&quot;&gt;FrontKon&lt;/a&gt; conference, we&apos;re discussing a new website. I have a fairly clear opinion and vision for it. To make it easier to show the team what I mean, I go and build a &lt;a href=&quot;https://machal.github.io/frontkon-2026-prototype/cs/&quot;&gt;prototype&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One day of work, including nearly final content. I don&apos;t deal with the code — it&apos;ll be thrown away, it&apos;s a prototype. I used to build prototypes like this over weeks. By hand. And then they&apos;d often get discarded, which for prototypes is a good thing.&lt;/p&gt;
&lt;p&gt;First explosion of Michálek&apos;s head. But also the first realisation that vibe coding isn&apos;t enough. That I have to engage the developer part of my brain. That I need to read what Cursor says and poke at it a little.&lt;/p&gt;
&lt;h3&gt;Example two: a website for my son {#example-son}&lt;/h3&gt;
&lt;p&gt;My seventeen-year-old son wants to start his first business with a friend — &lt;a href=&quot;https://clipcut.cz/&quot;&gt;cutting reels out of videos&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We sit down together at Cursor. I expect it to be more complicated. Arguments about the look and so on, you know how it is… a teenager. A two-sentence prompt. He doesn&apos;t like the result, fair enough.&lt;/p&gt;
&lt;p&gt;I ask Cursor what style might appeal to Gen Z. It gives us four options. My son picks one, Cursor redoes it, and he&apos;s thrilled.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/vibe-coding-clipcut.jpg&quot; alt=&quot;The Clipcut website&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;The Clipcut site, done in 15 minutes. Style picked from Cursor&apos;s Gen Z recommendations.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;It&apos;s done in 15 minutes. I&apos;m laughing hysterically the whole time. My son asks if I&apos;m okay. I say yes — but I used to spend days or weeks on this. And clients had no chance to change it so easily.&lt;/p&gt;
&lt;p&gt;The tinkerers who hand-built small websites are dead. Macaly, or something like it, can be handled by anyone who can describe what they want.&lt;/p&gt;
&lt;h3&gt;Example three: editing copy in PageSpeed.ONE {#example-pagespeed}&lt;/h3&gt;
&lt;p&gt;I love &lt;a href=&quot;../guide/writing.md&quot;&gt;writing&lt;/a&gt;. I go to edit some copy in our help docs over at &lt;a href=&quot;https://pagespeed.one/&quot;&gt;PageSpeed.ONE&lt;/a&gt;. Cursor understands the context exactly and can imitate a specific writing style. I just tell it roughly what I want to write and roughly where. It edits the Markdown, adds links, runs a check.&lt;/p&gt;
&lt;p&gt;As my colleague Michal Matuška puts it: &quot;We all have to be full-stack.&quot; Including content authors. Including the company CEO.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/vibe-coding-vd-writing.jpg&quot; alt=&quot;Editing copy and writing with AI&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Vibe writing for Vzhůru dolů — Cursor understands context, can imitate a writing style, add back-links, and iterate beautifully, much like during software development.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;Example four: migrating Vzhůru dolů from PHP to Astro {#example-migration}&lt;/h3&gt;
&lt;p&gt;For two years I&apos;ve wanted to ditch the old dev stack on Vzhůru dolů. It runs on outdated PHP and the &lt;a href=&quot;https://grabaperch.com/&quot;&gt;Perch&lt;/a&gt; CMS, which nobody maintains anymore. There&apos;s an old database in there, and the whole thing is so fragile that I was even scared to look at it.&lt;/p&gt;
&lt;p&gt;I want a modern dev stack, I want it all dumped into Markdown, kept in a single repository and put on GitHub.&lt;/p&gt;
&lt;p&gt;In the &quot;old world,&quot; though, this would have meant sacrificing several weekends, or investing at least 50 — more likely 100 — thousand CZK into someone to handle it. I want none of that.&lt;/p&gt;
&lt;p&gt;This is already a relatively complex project. The first attempt with Cursor didn&apos;t work out. I took the old PHP repo and asked it for a rewrite into the new one. It drowned in the context of two different technologies.&lt;/p&gt;
&lt;p&gt;It turns out I have to learn the new dev stack, I have to give Cursor good instructions, and I have to watch what it&apos;s actually doing. To be the architect, not just a spectator.&lt;/p&gt;
&lt;p&gt;I could have been a spectator and had it faster. But it wouldn&apos;t be sustainable long-term — and that&apos;s not what I want.&lt;/p&gt;
&lt;p&gt;In the end, it&apos;s done. Two to three days of work in total — still amazing, honestly. It&apos;s built on &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;, available on GitHub, and has been live since the end of January.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/vibe-coding-vd.jpg&quot; alt=&quot;Migrating VzhuruDolu.cz to Astro&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Migrating Vzhůru dolů to Astro. Done in 2–3 days of work.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Developers Out of Work? {#developers-out-of-work}&lt;/h2&gt;
&lt;p&gt;Developers should fear for their jobs because of AI, they said. Nonsense. Developers have a big future, precisely because of AI — that&apos;s what I say.&lt;/p&gt;
&lt;p&gt;Yes, some do need to worry. Coders, hackers in the bad sense, sloppy copy-pasters… they may all lose their current jobs.&lt;/p&gt;
&lt;p&gt;But then there are the real developers. Developers with engineering thinking, knowledge of the technology, experience. Architects. Vibe engineers.&lt;/p&gt;
&lt;p&gt;They have an enormous advantage — an algorithmic way of thinking. The ability to break a problem into sub-problems. To design an architectural solution. To push back on the AI technically, to improve its work.&lt;/p&gt;
&lt;p&gt;To not get &lt;em&gt;bullshitted&lt;/em&gt; by Cursor.&lt;/p&gt;
&lt;p&gt;Just sit next to someone who lacks this for a moment. Watch how they write a prompt. And suffer — quietly, preferably.&lt;/p&gt;
&lt;h3&gt;Two types of developers {#two-types-of-developers}&lt;/h3&gt;
&lt;p&gt;If I simplify a lot, developers split by motivation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some love building products — websites, apps, a service for people.&lt;/li&gt;
&lt;li&gt;Others love writing code and fussing over it. They&apos;re in love with a specific technology.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The current AI wave strongly favours the first group and can put pressure on the second.&lt;/p&gt;
&lt;p&gt;It will get harder and harder to be fulfilled solely by writing beautiful code, and we&apos;ll focus more on the outcome that the technology delivers.&lt;/p&gt;
&lt;p&gt;With LLMs you can build a great product, be highly technical, and even have quality code — all without writing a single line of code yourself. And I think this will be hard for a lot of people in that second group to accept.&lt;/p&gt;
&lt;h3&gt;You have to be a developer, or gradually become one {#you-have-to-be-a-developer}&lt;/h3&gt;
&lt;p&gt;When I was building the prototype of the new FrontKon site, Cursor wanted to do server-side rendering with a custom generator running headless Chrome on top of an SPA. Technically it worked. In practice it was nonsense — far better solutions exist.&lt;/p&gt;
&lt;p&gt;If someone without experience had received this proposal, they probably would have accepted it. And they&apos;d have a problem.&lt;/p&gt;
&lt;p&gt;If you want to &quot;vibe&quot; products, sooner or later you have to become someone who understands the craft of development.&lt;/p&gt;
&lt;h3&gt;&quot;Software is eating the world&quot; {#software-eating-world}&lt;/h3&gt;
&lt;p&gt;Yes, a large share of tiny applications will be built by CEOs, marketers, and clients themselves — the kind of apps engineers wouldn&apos;t want to build anyway.&lt;/p&gt;
&lt;p&gt;But software is greedy; it&apos;s far from done eating the world. A huge wave of software is coming that previously couldn&apos;t exist because it was too expensive. This won&apos;t threaten developers.&lt;/p&gt;
&lt;p&gt;Yes, a breakthrough we don&apos;t see could always arrive. But right now it isn&apos;t happening. Developers aren&apos;t losing their jobs — at least not en masse and all at once.&lt;/p&gt;
&lt;h2&gt;A Few Concrete Cursor Tips {#cursor-tips}&lt;/h2&gt;
&lt;p&gt;Let&apos;s get to how to squeeze the most out of vibe coding.&lt;/p&gt;
&lt;h3&gt;Modes in Cursor {#cursor-modes}&lt;/h3&gt;
&lt;p&gt;Cursor has four main modes:&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Code changes&lt;/th&gt;
&lt;th&gt;Autonomy&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (multi-file)&lt;/td&gt;
&lt;td&gt;Maximum&lt;/td&gt;
&lt;td&gt;New feature from scratch, refactoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Plan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Design first&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Complex integration, you want control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Debug&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (targeted)&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Bug fixes, logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ask&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (text only)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Consultation, understanding code&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;Agent is the most powerful but also the most expensive on credits.&lt;/p&gt;
&lt;p&gt;For everyday work, Plan or Ask is often enough. Personally, I always start a new feature with Plan. We iterate over the brief, and only then do I let the Agent loose.&lt;/p&gt;
&lt;h3&gt;Context shortcuts {#context-shortcuts}&lt;/h3&gt;
&lt;p&gt;Cursor has handy shortcuts for working with context that sharpen what you&apos;re talking to the model about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@Codebase&lt;/code&gt; — searches the whole project, best for complex changes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Files&lt;/code&gt; / &lt;code&gt;@Folders&lt;/code&gt; — targeted context, saves tokens&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Docs&lt;/code&gt; — pull in documentation by URL&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Web&lt;/code&gt; — search the internet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The absolute killer is the ability to open a browser inside Cursor and point at the specific elements you want to change.&lt;/p&gt;
&lt;h3&gt;Vibe rules {#vibe-rules}&lt;/h3&gt;
&lt;p&gt;Three rules for working effectively — the ones that, out of all rules, help the most:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Decomposition.&lt;/strong&gt;
Don&apos;t ask for everything at once. Move in small features and iterations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursor rules.&lt;/strong&gt;
Set up &lt;a href=&quot;https://docs.cursor.com/context/rules&quot;&gt;&lt;code&gt;.cursor/rules&lt;/code&gt;&lt;/a&gt; in the project root. A persistent &quot;vibe&quot; setting — e.g. &quot;Write in TypeScript, speak English, use this code style.&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sniper vs. shotgun.&lt;/strong&gt;
For small edits, use &lt;code&gt;Ctrl+K&lt;/code&gt; (inline edit) instead of rewriting an entire file through the agent.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Models {#models}&lt;/h3&gt;
&lt;p&gt;I don&apos;t feel much need to experiment with models, because the default Composer suits me beautifully, but I do switch occasionally, roughly like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://cursor.com/blog/composer-1-5&quot;&gt;Default (Composer)&lt;/a&gt;:&lt;/strong&gt; Fast, for everyday work. Enough for me in 80% of cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.anthropic.com/claude/sonnet&quot;&gt;Claude Sonnet&lt;/a&gt;:&lt;/strong&gt; Smarter, switch it on when the default gets &quot;stuck in a loop.&quot; A killer for text.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://gemini.google/about/&quot;&gt;Gemini&lt;/a&gt;:&lt;/strong&gt; For working with huge context (the whole repository at once). I switch to it only occasionally.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Flow Not Found… or Is It There After All? {#flow}&lt;/h2&gt;
&lt;p&gt;This surprised me the most. I was afraid I&apos;d lose the joy of creating while vibing, but the deep work is still there — it just looks different now.&lt;/p&gt;
&lt;p&gt;It&apos;s not about polishing code. It&apos;s not about tuning semicolons and brackets. It&apos;s about direction, architecture, context. About building the final product.&lt;/p&gt;
&lt;p&gt;I hand off a task and wait. Then I review, fix, and steer further. Less typing, more thinking.&lt;/p&gt;
&lt;p&gt;And you know what? Surprisingly, the deep work and the flow are not missing. I still reach the state where I forget about the world and I&apos;m immersed in the problem. The problem is just different — it&apos;s not &quot;how do I write this function,&quot; but &quot;how do I design this whole thing so it makes sense.&quot;&lt;/p&gt;
&lt;p&gt;But this won&apos;t suit people who don&apos;t experience the final product that comes out of them so much, and instead enjoy fussing over the code.&lt;/p&gt;
&lt;h2&gt;This Is Big, but We Still Need People {#people-still-matter}&lt;/h2&gt;
&lt;p&gt;AI is not a replacement for developers. It&apos;s a multiplier.&lt;/p&gt;
&lt;p&gt;We still need people. People control the machines and will keep controlling them. I hope.&lt;/p&gt;
&lt;p&gt;We need people for meetings, for kitchen conversations, for the whole offline context that&apos;s still enormous. For &lt;a href=&quot;../guide/ai-saas.md&quot;&gt;accountability and security&lt;/a&gt;. For decisions that require understanding the broader context of the company and the team.&lt;/p&gt;
&lt;p&gt;Vibe coding democratises technology. Developers and technically skilled people have an advantage. But they have to use it.&lt;/p&gt;
</content:encoded></item><item><title>My 2025 in review: from freelancer to business owner</title><link>https://michalek.blog/blog/2025-year-in-review/</link><guid isPermaLink="true">https://michalek.blog/blog/2025-year-in-review/</guid><description>A year of pivots — scaling PageSpeed.ONE, reshaping a frontend community, an overload crisis, and learning growth has a cost.</description><pubDate>Tue, 06 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;My 2025: entrepreneurial, strategic, successful — but also anxious and searching for form&lt;/h1&gt;
&lt;p&gt;2025 was a pivot year for me, and pivots are always significant. If it had been only positive, there would be nothing to write about, nothing to learn from, and the whole year would have been terribly boring.&lt;/p&gt;
&lt;h2&gt;A little anxiety about the world out there {#anxiety}&lt;/h2&gt;
&lt;p&gt;Let me start with the &quot;anxious&quot; part of the title. Some of you surely feel this tension too, especially the older ones. On a personal level your life is beautiful — arguably more beautiful every year — yet you&apos;re increasingly seized by gloom, or even anxiety, about what&apos;s happening in the world, in geopolitics, in society at large.&lt;/p&gt;
&lt;p&gt;It started with the invasion of Ukraine, it continues with a second Trump term, and the ground is shifting hard here in Central Europe too. The light at the end of the tunnel keeps getting fainter. My father has an old saying for moments like these — roughly, &quot;the world is going to hell.&quot; I used to laugh at it. Now it fits. I won&apos;t dwell on this much further, but I try to be honest here, and this framing can&apos;t be missing.&lt;/p&gt;
&lt;p&gt;Let&apos;s instead focus on what I actually lived through last year, personally and above all professionally.&lt;/p&gt;
&lt;h2&gt;From freelancer to business owner {#business-owner}&lt;/h2&gt;
&lt;p&gt;First and foremost, I&apos;ve probably already transformed from a freelancer into a business owner.&lt;/p&gt;
&lt;p&gt;Don&apos;t get me wrong — it&apos;s just one of my roles. I&apos;m still a content author, a performance and web enthusiast, a boss and co-owner of a company, a product person, a community guy, and above all a dad.&lt;/p&gt;
&lt;p&gt;In 2025 my self-perception around making money shifted. I spent &lt;a href=&quot;https://www.vzhurudolu.cz/blog/192-volna-noha-20&quot;&gt;well over twenty years&lt;/a&gt; freelancing, and the inertia of that mindset is enormous.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;https://res.cloudinary.com/vzhurudolu-cz/image/upload/v1767688556/vzhurudolu-blog/evoluce_keryv9.jpg&quot; alt=&quot;Evolution from freelancer to founder&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;&lt;em&gt;Evolution.&lt;/em&gt;&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Being a solo freelancer and being an entrepreneur with your own company and people in it are completely different leagues. The mental and skill-based transformation from the first to the second took me roughly five years.&lt;/p&gt;
&lt;p&gt;Throughout that time I kept asking myself one question: &lt;em&gt;What will you do if your business fails, or if it simply stops being fun?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My answer was always that I&apos;d just go back to freelancing. That held until the second half of 2025, when I started answering instead that in such a case I&apos;d go and build a new business. Not bad — I wouldn&apos;t have expected that of myself.&lt;/p&gt;
&lt;h2&gt;PageSpeed.ONE: consulting is flying, but we want to push harder on the product {#pagespeed}&lt;/h2&gt;
&lt;p&gt;The business, of course, is &lt;a href=&quot;https://pagespeed.one/&quot;&gt;PageSpeed.ONE&lt;/a&gt; — a great team of people who help companies speed up their websites and, in turn, improve conversions or traffic.&lt;/p&gt;
&lt;p&gt;Last year was excellent. Thanks in part to a new colleague, Tomáš, we moved into consulting on backend and infrastructure (Cloudflare gave us a bit of a run for our money) and specifically on &lt;a href=&quot;https://pagespeed.one/wordpress&quot;&gt;WordPress&lt;/a&gt;. We also focused heavily on other platforms, mainly &lt;a href=&quot;https://pagespeed.one/shoptet&quot;&gt;Shoptet&lt;/a&gt; and Shopify.&lt;/p&gt;
&lt;p&gt;I personally leaned hard into sales, and the numbers show it. What surprised me was how much I ended up enjoying it.&lt;/p&gt;
&lt;p&gt;We worked with an estimated 30–40 new clients, including names like Česká spořitelna (one of the largest Czech banks), and we also did more work for retailers like Heureka and Datart. Brilliant.&lt;/p&gt;
&lt;p&gt;At the same time we were building our &lt;a href=&quot;../guide/ai-saas.md&quot;&gt;SaaS&lt;/a&gt; &lt;a href=&quot;https://pagespeed.one/monitoring-plus&quot;&gt;speed-monitoring service&lt;/a&gt;. We made nice progress on it, but we didn&apos;t have as much time for it as we&apos;d have liked. We&apos;re not the first to discover, painfully, that time and attention are finite, and that the shift from agency mode to product mode is always very hard. This will be the main goal for 2026.&lt;/p&gt;
&lt;h2&gt;FrontKon and Frontendisti.cz: from community to company thinking {#frontendisti}&lt;/h2&gt;
&lt;p&gt;Another big mental shift happened with &lt;a href=&quot;https://www.frontendisti.cz/&quot;&gt;Frontendisti.cz&lt;/a&gt;, the Czech frontend community. We spent a lot of time figuring out how to secure the future of both the community and the &lt;a href=&quot;https://www.frontkon.cz/&quot;&gt;FrontKon&lt;/a&gt; conference, which until now rested on the large volunteer investment of me, Tomáš, Břetík, and many others. I&apos;ll be honest: in the first quarter I had one foot out the door, at least from organising FrontKon. But what was needed here was a change of mindset.&lt;/p&gt;
&lt;p&gt;I think we got a new drive — at least I did — especially for the coming editions of FrontKon, which in 2025 essentially became bigger than the entire Frontendisti community. It&apos;s an event that&apos;s already outgrowing its community. We have ideas in our heads that should make that increasingly clear in the years ahead. At least I hope so!&lt;/p&gt;
&lt;p&gt;Under Frontendisti, Robin and I also moved our &lt;a href=&quot;https://www.vzhurudolu.cz/podcast&quot;&gt;podcast&lt;/a&gt; over, under a new name, &lt;a href=&quot;https://www.frontendisti.cz/frontkec&quot;&gt;FrontKec&lt;/a&gt;. Thematically and strategically it belongs to the community, while I&apos;m gradually winding down the Vzhůru dolů project — as you&apos;ve surely already noticed.&lt;/p&gt;
&lt;p&gt;That&apos;s a lot of transformation, a lot of growth, a lot of change and demanding management problems. It would be strange if no little crisis showed up, right? Oh, it showed up, you bet it did.&lt;/p&gt;
&lt;h2&gt;The little crisis {#crisis}&lt;/h2&gt;
&lt;p&gt;In hindsight I can see the crisis lasted almost half the year. A crisis of overload: too many big topics at once (not just work, but personal too), too little deep work, and the resulting bouts of insomnia — alarms that, when they start buzzing, mean you need to change something quickly.&lt;/p&gt;
&lt;p&gt;I&apos;ve been through it several times in my career, usually during my various freelancing transitions. It happened, for instance, when I started selling training, while I was writing one of my books, or when COVID arrived and gutted a big part of my livelihood.&lt;/p&gt;
&lt;p&gt;I know there&apos;s always a way out — taking a meta view of your time, self-analysis with a book in hand, changing how you organise things, decisively ending some activities — but this time I reacted fairly slowly, so I suffered for needlessly long. I&apos;m not sure why, but I&apos;d say the overload this time was so big it blocked the alarms. Oh, and I&apos;m also getting nicely old.&lt;/p&gt;
&lt;h2&gt;(Out of) shape {#shape}&lt;/h2&gt;
&lt;p&gt;When I look at what I wanted to change, move forward, or achieve in 2025, I can be very satisfied. Except for one thing: my physical fitness.&lt;/p&gt;
&lt;p&gt;Stress does its thing, age does too, the metabolism isn&apos;t what it used to be, and my classic maintenance activities (a bit of running, walking to and from work) clearly stopped being enough.&lt;/p&gt;
&lt;p&gt;I&apos;ll have to solve this too this year, so for the first time in my life I&apos;ve joined the heap of clichés who want to lose weight and get in shape come January.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;By the way, if you&apos;re interested in cultural tips for reading, listening, or watching, take a look at my &lt;a href=&quot;https://www.facebook.com/machal/posts/pfbid02Gs2HieoNRL1DPyQTa3EmohDidVzsokxcr8P9GdYhJQ2rQzuvtdTJWZVXwSb8JgJPl&quot;&gt;personal&lt;/a&gt; or &lt;a href=&quot;https://www.linkedin.com/posts/martinmichalek_p%C4%9Bt-kulturn%C3%ADch-zdroj%C5%AF-kter%C3%A9-v-roce-2025-activity-7412773472722116608-aPhu&quot;&gt;work&lt;/a&gt; recommendations from 2025.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;&quot;2025 was great!&quot; {#great}&lt;/h2&gt;
&lt;p&gt;One of the year&apos;s projects was getting my older son into secondary school. If you don&apos;t have kids finishing primary school — or you&apos;re not in Prague — you can&apos;t imagine what it &lt;a href=&quot;https://www.facebook.com/machal/posts/pfbid07VGapCiGY9KYyd87jmwim3BYDAq7DiTLwu8bn7yKzMhjWLcPayjabDSrpVVw8w2Jl&quot;&gt;involves&lt;/a&gt;. There are many candidates for the academic high schools and very few spots.&lt;/p&gt;
&lt;p&gt;In the end it turned out great. He got into his second-choice school, he&apos;s very happy there, and he went through a transformation of his own — he settled in really well and is generally independent when it comes to preparing for school.&lt;/p&gt;
&lt;p&gt;On New Year&apos;s morning, Honza woke up and called out, &quot;2025 was great!&quot; My wife and I exchanged a glance. That&apos;s really wonderful, we imagined — how he can appreciate it all. How he can appreciate that, with his effort and ours, he got into a good school, and that he&apos;s doing quite well there.&lt;/p&gt;
&lt;p&gt;&quot;2025 was great,&quot; he calls again, and adds: &quot;…because I finally started drinking and smoking weed!&quot;&lt;/p&gt;
&lt;p&gt;So to you too, dear readers, I wish for 2026 that you always chase &lt;strong&gt;your&lt;/strong&gt; own dreams, and not other people&apos;s.&lt;/p&gt;
</content:encoded></item><item><title>The art of saying no</title><link>https://michalek.blog/blog/saying-no/</link><guid isPermaLink="true">https://michalek.blog/blog/saying-no/</guid><description>Capable people keep getting more work until something breaks. Learning to say no — constructively — is a survival skill, not arrogance.</description><pubDate>Mon, 10 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;The art of saying no&lt;/h1&gt;
&lt;p&gt;Feeling buried? I used to be, all the time. I still fight it. But one thing I have learned for sure:&lt;/p&gt;
&lt;p&gt;The talent of many talented people gets wrecked by never mastering the art of saying &lt;em&gt;no&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;You are good? You get more work.&lt;/p&gt;
&lt;p&gt;Still keeping up? You get even more.&lt;/p&gt;
&lt;p&gt;And on it goes — until you collapse under the weight of your own commitments.&lt;/p&gt;
&lt;p&gt;Or until you start refusing, in earnest.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/vzhurudolu-cz/image/upload/v1741590750/vzhurudolu-blog/ano-ne_l4q8ty.webp&quot; alt=&quot;Yes and no signs in a forest&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Why capable people drown {#why-capable-people-drown}&lt;/h2&gt;
&lt;p&gt;Some people cannot turn down their boss. Some cannot turn down colleagues. Some cannot refuse friends, a partner, their kids. And some braid the whip themselves. They tell themselves things like &quot;Nothing is impossible&quot; or &quot;Never give up&quot; — and in the end the only thing they give up is quality, traded for quantity. They burn out, or simply stop enjoying the work they once loved. They forgot they cannot do everything. They forgot how liberating &lt;em&gt;no&lt;/em&gt; can be.&lt;/p&gt;
&lt;p&gt;You need to say &lt;em&gt;no&lt;/em&gt; to yourself too. To your own ideas, your own projects, your own pet thoughts. That is the hard part, because ideas are like children. We love them. But killing ideas has a polite name: prioritisation.&lt;/p&gt;
&lt;h2&gt;No is not arrogance {#no-is-not-arrogance}&lt;/h2&gt;
&lt;p&gt;Refusing is not easy, I know. It can sound harsh; you can come across as arrogant. That is why so many people fear that a &lt;em&gt;no&lt;/em&gt; will make others like them less. But being liked only because you never say &lt;em&gt;no&lt;/em&gt; means other people are living at your expense. Whose life is it — theirs or yours?&lt;/p&gt;
&lt;p&gt;To some, &lt;em&gt;no&lt;/em&gt; may sound too blunt. It does not have to be. You just have to learn the &lt;em&gt;constructive no:&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I won&apos;t be doing this, but I can point you to someone — or send you materials that should help.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In time you will learn the plain no as well; it only takes a little empathy: &quot;Sorry, but I already have a lot on my plate right now.&quot;&lt;/p&gt;
&lt;p&gt;Because saying &lt;em&gt;no&lt;/em&gt; often means saying &lt;em&gt;yes&lt;/em&gt; to yourself.&lt;/p&gt;
</content:encoded></item><item><title>From maker to manager: my pivotal 2024</title><link>https://michalek.blog/blog/2024-year-in-review/</link><guid isPermaLink="true">https://michalek.blog/blog/2024-year-in-review/</guid><description>The year I finally stopped being ashamed of being a manager — and found I actually enjoyed it.</description><pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;From maker to manager: my pivotal 2024&lt;/h1&gt;
&lt;p&gt;I remember my early days on the web. Around the turn of the millennium I happily coded websites — until some &quot;manager&quot; at the agency tapped me on the shoulder. &quot;I just need one tiny thing,&quot; he&apos;d say, and wreck my whole day. Evil, evil managers. The golden age of coding!&lt;/p&gt;
&lt;p&gt;Twenty years later, I&apos;m taking on the very role that used to annoy me — and I&apos;m finally letting go of the shame of being a manager.&lt;/p&gt;
&lt;h2&gt;From coder and content maker to manager {#maker}&lt;/h2&gt;
&lt;p&gt;In 2024 I made the definitive decision that the next chapter of my career would be managerial and entrepreneurial.&lt;/p&gt;
&lt;p&gt;It hurt. Somewhere deep down, the question still lingers: &quot;Aren&apos;t you betraying yourself and the whole craft of web building?&quot;&lt;/p&gt;
&lt;p&gt;But there are moments in life when clinging to the craft means stagnation. And if there&apos;s one thing I truly can&apos;t stand at work, it&apos;s boredom.&lt;/p&gt;
&lt;p&gt;Last year we founded a company around &lt;a href=&quot;https://pagespeed.one/&quot;&gt;PageSpeed.ONE&lt;/a&gt;, and one of my side activities became the main thing I do for a living.&lt;/p&gt;
&lt;p&gt;For years I&apos;d sensed the need for both strategic and day-to-day leadership across all my projects — PageSpeed.ONE, the Frontendisti community, the podcast. I was doing it, but somewhat reluctantly.&lt;/p&gt;
&lt;h2&gt;Who else, if not you? {#who}&lt;/h2&gt;
&lt;p&gt;Makers and craftspeople know the feeling. &quot;I won&apos;t deal with that — I&apos;m doing my own work well, it&apos;ll somehow work out.&quot;&lt;/p&gt;
&lt;p&gt;But then the very right question is supposed to arrive: &quot;Who else, if not you?&quot; And as Spider-Man says, &quot;With great power comes great responsibility.&quot; If you can see a problem and you have the skills to fix it, you simply must. When you&apos;ve got a hammer in your hand and you spot a nail that hasn&apos;t been driven in… well, you know the rest.&lt;/p&gt;
&lt;p&gt;My circumstances and my own skills forced me into becoming a manager. Evil, evil life, plotting such a trick against me!&lt;/p&gt;
&lt;p&gt;But in 2024 the turning point came. I found I actually enjoyed it.&lt;/p&gt;
&lt;p&gt;Consistent wins started rolling in. I gradually delegated much of my original work at PageSpeed, did great teamwork with my partner Michal and the rest of the team. Fast iteration on problems, improving processes… and, given the size of the team, a solid drive toward the goal while keeping the vision and strategic direction intact.&lt;/p&gt;
&lt;p&gt;In the Frontendisti community, thanks to a great team and our new colleague Kačka Macháčková, we pushed our &lt;a href=&quot;https://www.frontkon.cz/&quot;&gt;FrontKon&lt;/a&gt; conference to a level we previously hadn&apos;t even dared to dream of.&lt;/p&gt;
&lt;h2&gt;A new environment {#environment}&lt;/h2&gt;
&lt;p&gt;While retuning my head, I also realised I had to surround myself with a new environment.&lt;/p&gt;
&lt;p&gt;I started listening to business podcasts, reading books, and filtering my social feeds. The mind needs not only information, but also a good environment. These people and their brands shaped mine the most:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The excellent &lt;a href=&quot;https://scaleupboard.com/scale-up-podcast/&quot;&gt;Scale Up&lt;/a&gt; podcast by Roman Stupka.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://open.spotify.com/show/1pN2i5xR6Enif894StTWzt&quot;&gt;Cinkátko&lt;/a&gt; by Michala Gregorová.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.lennysnewsletter.com/&quot;&gt;Lenny&apos;s Newsletter&lt;/a&gt; by Lenny Rachitsky.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;A new inner baby {#baby}&lt;/h2&gt;
&lt;p&gt;My entrepreneurial-managerial part of the brain is like my new little baby. I cradle it, feed it knowledge. I watch it grow — its first steps are behind it, it can already handle quite a lot. It&apos;s lovely to watch.&lt;/p&gt;
&lt;p&gt;I wish you many such new inner babies in 2025 — no matter how old you are!&lt;/p&gt;
&lt;p&gt;This text came about as the first output from my retrospective of 2024. I know for certain I won&apos;t write the rest, but you know what? Let me at least stash them here briefly.&lt;/p&gt;
&lt;h2&gt;What else did 2024 bring me? {#more}&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I still write, don&apos;t you think otherwise. Last year I wrote dozens of texts, mostly for the PageSpeed.ONE help docs, a big &lt;a href=&quot;../guide/writing.md&quot;&gt;piece on writing&lt;/a&gt; for Vzhůru dolů, an &lt;a href=&quot;https://www.lupa.cz/clanky/nova-metrika-rychlosti-webu-inp-jak-zlepsit-uzivatelskou-zkusenost-a-treba-i-zvysit-konverze/&quot;&gt;article about INP on Lupa.cz&lt;/a&gt;, and after a long break an English &lt;a href=&quot;https://calendar.perfplanet.com/2024/dont-let-your-redesign-ruin-performance-a-case-study/&quot;&gt;piece for the WebPerf Calendar&lt;/a&gt;. I also &lt;a href=&quot;https://www.linkedin.com/in/martinmichalek/&quot;&gt;write a lot on LinkedIn&lt;/a&gt;, which I&apos;m simultaneously trying to tame so it serves me less bullshit and more substance. I enjoy writing for social networks. Maybe one day it&apos;ll even be worth reading.&lt;/li&gt;
&lt;li&gt;I gave 8 &lt;a href=&quot;https://www.youtube.com/playlist?list=PLOs14ZGnaZuvmYRYnRd9qXXLQXTKPfOyj&quot;&gt;talks&lt;/a&gt; and was a guest in 3 interviews. I&apos;d highlight especially my talk for &lt;a href=&quot;https://www.slideshare.net/slideshow/seo-restart-2024-martin-michalek-nova-metrika-rychlosti-inp-a-prakticke-tipy-jak-ji-zlepsit/266887596&quot;&gt;SEO Restart on INP&lt;/a&gt;, the talk at our &lt;a href=&quot;https://www.youtube.com/watch?v=xem_YPyB-zQ&amp;amp;list=PLOs14ZGnaZuvmYRYnRd9qXXLQXTKPfOyj&amp;amp;index=4&amp;amp;t=3s&quot;&gt;FrontKon 2024&lt;/a&gt;, and the conversation for the &lt;a href=&quot;https://www.youtube.com/watch?v=yXzQThSLfHE&amp;amp;list=PLOs14ZGnaZuvmYRYnRd9qXXLQXTKPfOyj&amp;amp;index=1&amp;amp;t=240s&quot;&gt;Socials podcast&lt;/a&gt;. I accepted almost every invitation, and there were many. This year I&apos;d like to retreat into my shell a bit more — write more, build more. And manage and run the business, of course.&lt;/li&gt;
&lt;li&gt;At PageSpeed.ONE we landed around 30 new consulting clients last year, including brands like SIKO and Heureka.cz. We officially started selling the &lt;a href=&quot;https://pagespeed.one/monitoring-plus&quot;&gt;paid monitoring PLUS version&lt;/a&gt; and shipped &lt;a href=&quot;https://pagespeed.one/blog&quot;&gt;5 new releases&lt;/a&gt;. We have ambitious plans, and the team is firing on all cylinders.&lt;/li&gt;
&lt;li&gt;My family and I spent 14 days exploring &lt;a href=&quot;https://www.linkedin.com/posts/martinmichalek_2fa-activity-7221046698767192064-xKUv?utm_source=share&amp;amp;utm_medium=member_desktop&quot;&gt;Tanzania&lt;/a&gt; on our own, and came back with dozens of stories — some genuinely adventurous. I got a massive culture shock there, even though I&apos;d spent the whole year &quot;training&quot; by driving to Brno.&lt;/li&gt;
&lt;li&gt;I bought a gravel bike, which was the best investment in myself all year.&lt;/li&gt;
&lt;li&gt;I read nearly all six volumes of &lt;a href=&quot;https://www.databazeknih.cz/serie/duna-86&quot;&gt;Dune&lt;/a&gt; by Frank Herbert, and I&apos;m thrilled. I also saw at least two deeply harrowing films (The Zone of Interest and The Citizen). My excessive optimism about life genuinely needs that kind of counterweight.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not everything worked out, of course. The planned step-change for the podcast is being postponed to this year. Exercising at the level I do is no longer quite enough for a guy pushing fifty, so it seems that in this phase of life I&apos;ll have to step up my self-care a bit. And I still don&apos;t really know what to do with Vzhůru dolů now that I write here so much less.&lt;/p&gt;
&lt;p&gt;All in all, though, I consider 2024 a very successful and pivotal year for me. I&apos;m curious what this year will bring.&lt;/p&gt;
</content:encoded></item><item><title>WebP images: the leaner alternative to JPEG, PNG, and GIF</title><link>https://michalek.blog/guide/webp/</link><guid isPermaLink="true">https://michalek.blog/guide/webp/</guid><description>WebP cuts image weight versus JPEG and PNG, adds transparency and animation, and ships everywhere. When it pays off and how to serve it safely.</description><pubDate>Sun, 07 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;WebP: smaller images without dropping anyone&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://developers.google.com/speed/webp/&quot;&gt;WebP&lt;/a&gt; is a raster image format Google introduced back in 2010. More than a decade later it is the boring, dependable choice: supported by practically every browser worth targeting, with Internet Explorer being the only notable holdout — and almost nobody is shipping for IE anymore.&lt;/p&gt;
&lt;p&gt;Here is why it earned its place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;meaningfully smaller files than both JPEG and PNG&lt;/li&gt;
&lt;li&gt;alpha transparency, which used to be PNG&apos;s party trick&lt;/li&gt;
&lt;li&gt;animation, the one thing GIF was good for&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WebP does give up a couple of things JPEG offers. It does not do &lt;a href=&quot;https://en.wikipedia.org/wiki/Chroma_subsampling&quot;&gt;chroma subsampling&lt;/a&gt; the same way, and progressive rendering is not part of the picture either.&lt;/p&gt;
&lt;p&gt;It is also sometimes described as slower to decode and harder on the CPU. &lt;a href=&quot;https://images.guide/#how-does-webp-perform&quot;&gt;images.guide&lt;/a&gt; keeps that worry honest:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back in 2013, the compression speed of WebP was ~10× slower than JPEG but is now negligible (some images may be 2× slower). For static images that are processed as part of your build, this shouldn&apos;t be a large issue. Dynamically generated images will likely cause a perceivable CPU overhead and will be something you will need to evaluate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words: only worth a second thought if you are generating images on the fly. For build-time assets, ship it and move on.&lt;/p&gt;
&lt;h2&gt;Browser support: the Chromium crowd, plus Firefox and Safari {#browser-support}&lt;/h2&gt;
&lt;p&gt;Since WebP comes from Google, every Chromium-based browser ships it out of the box — Chrome, Edge, Opera, Brave, and the rest. Firefox has supported it for years, and Safari joined the club too. For most global audiences that puts you comfortably above 90% coverage today.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supported: Chrome and Chromium derivatives, Firefox, &lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-14-beta-release-notes#Media&quot;&gt;Safari 14 and up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Not supported, and never will be: every version of Internet Explorer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the current numbers, check &lt;a href=&quot;https://caniuse.com/#feat=webp&quot;&gt;caniuse.com/webp&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So what about the small slice of users on browsers without support? No drama — you do not have to serve them a page with no images.&lt;/p&gt;
&lt;h2&gt;A JPEG fallback with &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; {#fallback}&lt;/h2&gt;
&lt;p&gt;The clean answer is to generate two sets of images — WebP and JPEG — and let the browser pick the right one using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;&lt;/a&gt; element:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source srcset=&quot;image.webp&quot; type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;img src=&quot;image.jpg&quot; alt=&quot;…&quot;&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Chromium and friends download only the WebP; everyone else quietly gets the JPEG.&lt;/p&gt;
&lt;p&gt;If you cannot use &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;, there are alternatives — server-side content negotiation or &lt;a href=&quot;https://github.com/vincentorback/WebP-images-with-htaccess&quot;&gt;&lt;code&gt;.htaccess&lt;/code&gt; rules&lt;/a&gt;. But the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; approach is the most predictable and the most performance-friendly.&lt;/p&gt;
&lt;p&gt;For images referenced from CSS, you can detect WebP support — and its individual features — with a library like &lt;a href=&quot;https://modernizr.com/download&quot;&gt;Modernizr&lt;/a&gt;. The CSS then looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box {
  background-image: url(&quot;image.jpg&quot;);
}

.webp .box {
  background-image: url(&quot;image.webp&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Google also publishes a tiny &lt;a href=&quot;https://developers.google.com/speed/webp/faq#in_your_own_javascript&quot;&gt;detection snippet&lt;/a&gt; on its WebP pages.&lt;/p&gt;
&lt;p&gt;Is it worth maintaining two copies of every image? It depends — but on larger sites, in my experience, it pays off handsomely.&lt;/p&gt;
&lt;h2&gt;How much data does WebP actually save? {#savings}&lt;/h2&gt;
&lt;p&gt;On one client e-commerce project I &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/rychlost-designeri&quot;&gt;wrote about&lt;/a&gt;, the team&apos;s results were concrete:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;After switching to WebP they cut 30% off the homepage weight (1250 kB → 950 kB) and shaved a fifth off page load time (19.8 s → 16.8 s).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I see similar numbers across other tests and client work. Halving image payload is not unusual.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developers.google.com/speed/webp/&quot;&gt;Google&apos;s own studies&lt;/a&gt; put the general savings at roughly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;26% smaller than lossless PNG&lt;/li&gt;
&lt;li&gt;25–34% smaller than lossy JPEG&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How to produce WebP {#how-to-produce}&lt;/h2&gt;
&lt;p&gt;There is no shortage of ways to generate WebP these days:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Design apps:&lt;/strong&gt; Sketch, Pixelmator, and GIMP export directly. Photoshop and other Adobe tools do not, but there is a &lt;a href=&quot;https://github.com/fnordware/AdobeWebM&quot;&gt;plugin&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI and libraries:&lt;/strong&gt; &lt;a href=&quot;https://developers.google.com/speed/webp/docs/cwebp&quot;&gt;cwebp&lt;/a&gt; for the &lt;a href=&quot;https://developers.google.com/speed/webp/docs/using&quot;&gt;libwebp&lt;/a&gt; codec.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build pipelines:&lt;/strong&gt; plugins like &lt;a href=&quot;https://github.com/imagemin/imagemin-webp&quot;&gt;imagemin-webp&lt;/a&gt; for Gulp, Grunt, or whatever bundler you run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server-side:&lt;/strong&gt; &lt;a href=&quot;https://imagemagick.org/script/webp.php&quot;&gt;ImageMagick&lt;/a&gt; and similar libraries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Online services:&lt;/strong&gt; &lt;a href=&quot;https://kraken.io/&quot;&gt;Kraken.io&lt;/a&gt; and others — excellent compression, usually paid, sometimes not cheap.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more options, see &lt;a href=&quot;https://web.dev/serve-images-webp/&quot;&gt;web.dev&lt;/a&gt; or &lt;a href=&quot;https://images.guide/#how-do-i-convert-to-webp&quot;&gt;images.guide&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Save on developers, spend on consultants</title><link>https://michalek.blog/blog/save-on-devs-spend-on-consultants/</link><guid isPermaLink="true">https://michalek.blog/blog/save-on-devs-spend-on-consultants/</guid><description>The more you save on a cheap platform and cheap developers, the more you tend to pay consultants to fix UX, SEO, accessibility, and speed later.</description><pubDate>Tue, 16 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Save on developers, spend on consultants&lt;/h1&gt;
&lt;p&gt;Dear site owners: the more you save on your platform and your developers, the more you will pay consultants to fix it all afterward.&lt;/p&gt;
&lt;p&gt;That can be perfectly fine — it may still pay off. But you should put this variable into your math.&lt;/p&gt;
&lt;p&gt;&quot;We&apos;ll save X on the platform and Y on developers, but we&apos;re budgeting Z for consulting on UX, SEO, accessibility, or speed. And we&apos;d rather hire those consultants at the start of the project, so they can keep an eye on it.&quot; Something like that.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/vzhurudolu-cz/image/upload/v1714374394/vzhurudolu-blog/mili-provozovatele_ogqic1.jpg&quot; alt=&quot;What the consultant sees versus what the owner sees&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;The off-the-shelf platform trap {#off-the-shelf-trap}&lt;/h2&gt;
&lt;p&gt;Take a hosted e-commerce platform like &lt;a href=&quot;https://www.shopify.com/&quot;&gt;Shopify&lt;/a&gt;. I think these can be genuinely great platforms — speed included, as long as you don&apos;t mess with them too much. But they&apos;re also very often badly used.&lt;/p&gt;
&lt;p&gt;&quot;We&apos;ll build it on the cheap platform. Look how much we save every month…&quot; Okay, but then don&apos;t count on customizing it heavily to your needs. We often see original templates forced into a custom design that, as a result, hurts UX and… breaks performance.&lt;/p&gt;
&lt;h2&gt;WordPress, the classic {#wordpress-classic}&lt;/h2&gt;
&lt;p&gt;Or &lt;a href=&quot;https://wordpress.org/&quot;&gt;WordPress&lt;/a&gt;. A classic. I probably don&apos;t even need to write this anymore… But I do, dear readers, I do.&lt;/p&gt;
&lt;p&gt;Yes, everything can be done well on WordPress too. But it&apos;s often done, well, you know how… You hire a developer who is cheap and doesn&apos;t get it. Even relatively large sites are often just an unmaintained pile of plugins glued together. A cheap developer is cheap. So they do it badly, don&apos;t communicate, don&apos;t follow up, and happen to be off in the Canary Islands…&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;https://pagespeed.one/&quot;&gt;PageSpeed.ONE&lt;/a&gt; we see this constantly when consulting on speed. Audits and analysis can be significantly more demanding on cheap solutions than on bespoke ones.&lt;/p&gt;
&lt;h2&gt;Just put it in the calculation {#put-it-in-the-calculation}&lt;/h2&gt;
&lt;p&gt;It may still work out well — economically, for the project, or otherwise. Of course it can. But definitely put it into your calculation. Don&apos;t let it catch you off guard. I told you so.&lt;/p&gt;
</content:encoded></item><item><title>Web Vitals: Google&apos;s core metrics for real-world speed</title><link>https://michalek.blog/guide/web-vitals/</link><guid isPermaLink="true">https://michalek.blog/guide/web-vitals/</guid><description>An introduction to Core Web Vitals — LCP, INP, CLS — how Google uses them, and where to measure them on your site.</description><pubDate>Tue, 02 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Web Vitals: Google&apos;s core metrics for real-world speed&lt;/h1&gt;
&lt;p&gt;Web Vitals is Google&apos;s label for metrics that describe real user experience on the web.&lt;/p&gt;
&lt;p&gt;Measuring performance (and UX) used to be a specialist discipline. For everyone else the landscape was noisy. Google narrowed the focus to a small set of metrics — with tooling and a promise they would not change every month.&lt;/p&gt;
&lt;p&gt;Today we mainly track &lt;strong&gt;LCP&lt;/strong&gt;, &lt;strong&gt;INP&lt;/strong&gt; (replacing FID), and &lt;strong&gt;CLS&lt;/strong&gt;. Google folds them into &lt;a href=&quot;https://developers.google.com/search/docs/appearance/core-web-vitals&quot;&gt;page experience signals&lt;/a&gt;. If you need the business case first, &lt;a href=&quot;https://pagespeed.one/znalosti/proc-resit-rychlost&quot;&gt;PageSpeed.ONE explains why speed matters&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This guide is a quick tour of the metrics and how to read them.&lt;/p&gt;
&lt;h2&gt;The metrics {#metriky}&lt;/h2&gt;
&lt;p&gt;Web Vitals includes more than three numbers, but Google highlights &lt;strong&gt;Core Web Vitals (CWV)&lt;/strong&gt; as the baseline every site owner should know.&lt;/p&gt;
&lt;h3&gt;Core Web Vitals {#core}&lt;/h3&gt;
&lt;p&gt;The headline trio — &lt;a href=&quot;https://pagespeed.one/metriky/cwv&quot;&gt;Core Web Vitals&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Largest Contentful Paint (LCP)&lt;/strong&gt; — how fast main content appears; a loading metric between &lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint&lt;/a&gt; and &lt;a href=&quot;https://web.dev/speed-index/&quot;&gt;Speed Index&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interaction to Next Paint (INP)&lt;/strong&gt; — responsiveness after user input; &lt;a href=&quot;https://web.dev/inp-cwv/&quot;&gt;INP replaced FID&lt;/a&gt; as a Core Web Vital in March 2024.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cumulative Layout Shift (CLS)&lt;/strong&gt; — visual stability while the page renders.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Google buckets each metric into three states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Good&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Needs improvement&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Poor&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thresholds from &lt;a href=&quot;https://web.dev/defining-core-web-vitals-thresholds/&quot;&gt;Google&apos;s documentation&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Good&lt;/th&gt;
&lt;th&gt;Needs improvement&lt;/th&gt;
&lt;th&gt;Poor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;≤ 2.5 s&lt;/td&gt;
&lt;td&gt;2.5 – 4 s&lt;/td&gt;
&lt;td&gt;&amp;gt; 4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP&lt;/td&gt;
&lt;td&gt;≤ 200 ms&lt;/td&gt;
&lt;td&gt;200 – 500 ms&lt;/td&gt;
&lt;td&gt;&amp;gt; 500 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS&lt;/td&gt;
&lt;td&gt;≤ 0.1&lt;/td&gt;
&lt;td&gt;0.1 – 0.25&lt;/td&gt;
&lt;td&gt;&amp;gt; 0.25&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;For a single score per URL, Google recommends the &lt;strong&gt;75th percentile&lt;/strong&gt; across mobile and desktop field data. The worst metric wins — that is how &lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;PageSpeed Insights&lt;/a&gt; reports pass/fail today.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;/prirucka/images/web-vitals.jpg&quot; alt=&quot;Diagram of Core Web Vitals metrics LCP, INP, and CLS&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Core Web Vitals at a glance. Source: &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;web.dev&lt;/a&gt;.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Optimization guides on web.dev:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-lcp/&quot;&gt;Optimize LCP&lt;/a&gt; — also &lt;a href=&quot;https://pagespeed.one/metriky/lcp&quot;&gt;LCP on PageSpeed.ONE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-inp/&quot;&gt;Optimize INP&lt;/a&gt; — also &lt;a href=&quot;https://pagespeed.one/metriky/inp&quot;&gt;INP on PageSpeed.ONE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-cls/&quot;&gt;Optimize CLS&lt;/a&gt; — also &lt;a href=&quot;https://pagespeed.one/metriky/cls&quot;&gt;CLS on PageSpeed.ONE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What about the other metrics? {#dalsi-metriky}&lt;/h3&gt;
&lt;p&gt;Specialists still care about &lt;a href=&quot;https://web.dev/ttfb/&quot;&gt;TTFB&lt;/a&gt;, FCP, TBT, and the rest. LCP alone will not reveal a slow backend or a late hero image without measuring upstream.&lt;/p&gt;
&lt;h2&gt;How to measure Web Vitals {#mereni}&lt;/h2&gt;
&lt;p&gt;Google updated its tooling quickly when Vitals landed.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;/prirucka/images/web-vitals-psi.jpg&quot; width=&quot;1920&quot; height=&quot;540&quot; alt=&quot;Core Web Vitals section in PageSpeed Insights&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Web Vitals in PageSpeed Insights. Lab data may still list FCP even though it is not part of CWV.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Practical entry points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot;&gt;&lt;strong&gt;PageSpeed Insights&lt;/strong&gt;&lt;/a&gt; — field data in the CrUX section; try it on your URL now.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://search.google.com/search-console&quot;&gt;&lt;strong&gt;Search Console&lt;/strong&gt;&lt;/a&gt; — Core Web Vitals report by URL group.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/crux&quot;&gt;&lt;strong&gt;Chrome UX Report&lt;/strong&gt;&lt;/a&gt; — raw field data; &lt;a href=&quot;http://g.co/chromeuxdash&quot;&gt;CrUX Dashboard&lt;/a&gt; in Looker Studio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebPageTest&lt;/strong&gt; — highlights Vitals in results (&lt;a href=&quot;https://www.webpagetest.org/&quot;&gt;example run&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma&quot;&gt;&lt;strong&gt;Web Vitals extension&lt;/strong&gt;&lt;/a&gt; — live values in Chrome.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChrome/web-vitals&quot;&gt;&lt;strong&gt;web-vitals JS library&lt;/strong&gt;&lt;/a&gt; — send metrics to analytics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;INP and FID require &lt;strong&gt;real-user (RUM)&lt;/strong&gt; data. Synthetic tools such as Lighthouse or WebPageTest approximate interactivity with &lt;strong&gt;Total Blocking Time (TBT)&lt;/strong&gt; instead.&lt;/p&gt;
&lt;p&gt;Google says Core Web Vitals should change at most once a year — but they also admit the set is not final. This article will keep evolving.&lt;/p&gt;
&lt;hr /&gt;
</content:encoded></item><item><title>CSS Units (em, rem, %, px, vh, vw): Which One to Use Where?</title><link>https://michalek.blog/guide/css-units/</link><guid isPermaLink="true">https://michalek.blog/guide/css-units/</guid><description>A practical guide to CSS units for web design — em, rem, %, px, vh, and vw — and which one fits each situation.</description><pubDate>Mon, 03 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;CSS Units (em, rem, %, px, vh, vw): Which One to Use Where?&lt;/h1&gt;
&lt;p&gt;Let&apos;s round up all the CSS units you can reasonably use in modern web design — and show, with examples, what each one is good for.&lt;/p&gt;
&lt;p&gt;My go-to units are the ones relative to font size: &lt;code&gt;rem&lt;/code&gt; and &lt;code&gt;em&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But I don&apos;t treat them as Supermen among CSS units either. They simply aren&apos;t right for everything. For different jobs we&apos;ll still need Spider-Man, Batman, and the rest of their colleagues.&lt;/p&gt;
&lt;h2&gt;A quick overview of useful units {#overview}&lt;/h2&gt;
&lt;p&gt;These are the six worth committing to memory.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Unit&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;How it computes the size?&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;relative to the font size on the &lt;code&gt;html&lt;/code&gt; element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;em&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;relative to the font size on the element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;px&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the reference pixel, the CSS pixel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;percentage relative to the parent element&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a percentage of the browser window&apos;s width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a percentage of the browser window&apos;s height&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;There are of course others — &lt;code&gt;pt&lt;/code&gt;, &lt;code&gt;ex&lt;/code&gt;, or &lt;code&gt;vmax&lt;/code&gt;, to name a few. But their usefulness is either small or close to none, so to keep things simple I&apos;ll leave them out of this text entirely.&lt;/p&gt;
&lt;h2&gt;Which units to use in which situations? {#scenarios}&lt;/h2&gt;
&lt;p&gt;Throughout this text I care a lot about not breaking the natural inheritance of font size in browsers. Besides us, the page authors, the user may want to change it — and sometimes browsers change it too. So for different uses I recommend different units:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Base font size of the document: &lt;a href=&quot;#document-font-size&quot;&gt;%&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dimensions derived from the document&apos;s font size: &lt;a href=&quot;#rem&quot;&gt;rem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dimensions derived from the parent&apos;s font size: &lt;a href=&quot;#em&quot;&gt;em&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Media Queries: &lt;a href=&quot;#media-queries&quot;&gt;em&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Line height: &lt;a href=&quot;#line-height&quot;&gt;a unitless number&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Borders, decoration: &lt;a href=&quot;#decoration&quot;&gt;px&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Typography based on window size: &lt;a href=&quot;#viewport-typography&quot;&gt;vw&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&apos;s quite possible you&apos;ll get by with &lt;code&gt;px&lt;/code&gt; almost everywhere. I&apos;ll get to that &lt;a href=&quot;#px&quot;&gt;at the end of the text&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Base font size of the document: % {#document-font-size}&lt;/h2&gt;
&lt;p&gt;The default font size in the vast majority of browsers is &lt;code&gt;16px&lt;/code&gt;. But there are less prominent browsers that set the font size differently — simply so that reading is more comfortable on a particular device.&lt;/p&gt;
&lt;p&gt;For example, the browser on the Kindle 3 had a default font size of &lt;code&gt;26px&lt;/code&gt;, and Opera Mini 7 used &lt;code&gt;17px&lt;/code&gt;. We could bet that most of the most widespread browsers don&apos;t change the default font size, but my experience says it&apos;s better not to.&lt;/p&gt;
&lt;p&gt;Nicolas Hoizey wrote a nice article on default font sizes in browsers, &quot;People don&apos;t change the default 16px font size in their browser (You wish!)&quot;: &lt;a href=&quot;https://nicolas-hoizey.com/2016/03/people-don-t-change-the-default-16px-font-size-in-their-browser.html&quot;&gt;nicolas-hoizey.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If the default font size doesn&apos;t suit you, change it with relative units — ideally percentages:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
  font-size: 125%;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sets the text a quarter larger than the default. In nearly all browsers that means &lt;code&gt;20px&lt;/code&gt;. On the Kindle 3 it would be &lt;code&gt;33px&lt;/code&gt;. It&apos;s important to realize that this is fine. If a browser sets a different font size, it does so for sensible reasons.&lt;/p&gt;
&lt;h3&gt;Why not px? Because people enlarge text in their browsers {#why-not-px}&lt;/h3&gt;
&lt;p&gt;If we used &lt;code&gt;px&lt;/code&gt; here, we&apos;d be forbidding our dear users from changing the default font size in their browsers.&lt;/p&gt;
&lt;p&gt;To be clear, we&apos;re not talking about &quot;zooming,&quot; which is available via a keyboard shortcut or easily set in the browser interface, but about increasing the font size for all websites. That feature still exists in browsers and operating systems. And yes, people use it. We probably will too one day. It&apos;s used by people with weaker eyesight, or simply with lower-quality displays.&lt;/p&gt;
&lt;p&gt;Evan Minto, a developer at Archive.org, measured this and found that 3% of users had changed the font size in their browser. As he aptly noted, that&apos;s more than the share of visitors using Internet Explorer, Edge, or Opera Mini at the time.&lt;/p&gt;
&lt;p&gt;Because we want to build solutions with the widest possible reach, we shouldn&apos;t ignore this. He writes about it in &quot;Pixels vs. Ems: Users DO Change Font Size&quot;: &lt;a href=&quot;https://medium.com/@vamptvo/pixels-vs-ems-users-do-change-font-size-5cfb20831773&quot;&gt;medium.com&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Dimensions derived from the document&apos;s font size: rem {#rem}&lt;/h2&gt;
&lt;p&gt;I set the font size of individual parts of the document, the outer and inner spacing, and other properties across the document and components, in &lt;code&gt;rem&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1rem&lt;/code&gt; (1 root &lt;code&gt;em&lt;/code&gt;) holds the default font size set by the author for the document — possibly further adjusted by the user or the browser, as we&apos;ve already seen.&lt;/p&gt;
&lt;p&gt;If we don&apos;t change it on the document, &lt;code&gt;1rem&lt;/code&gt; = &lt;code&gt;16px&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;p { margin-bottom: 1rem; }
h1 { font-size: 2rem; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this code I set the paragraphs&apos; bottom margin to the height of the text. First-level headings will be twice as large as the standard font size.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;rem&lt;/code&gt; is also handy from a developer&apos;s point of view:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1rem&lt;/code&gt; holds the base font size, so you don&apos;t have to remember whether it&apos;s 12, 14, 16, or however many pixels.&lt;/li&gt;
&lt;li&gt;A layout width set in &lt;code&gt;rem&lt;/code&gt; will keep an optimal line length even when the user enlarges the text.&lt;/li&gt;
&lt;li&gt;Thanks to &lt;code&gt;rem&lt;/code&gt; you can also scale the whole document up within specific ranges between design breakpoints.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What if I get assets in px? {#assets-in-px}&lt;/h3&gt;
&lt;p&gt;You may be used to working in &lt;code&gt;px&lt;/code&gt; when turning a design into code, because designers deliver assets in those units. But as I&apos;ve written, setting anything derived from the main font size in &lt;code&gt;px&lt;/code&gt; complicates life for many users.&lt;/p&gt;
&lt;p&gt;How to get out of the design-versus-accessibility conflict? Automatic CSS processing can help.&lt;/p&gt;
&lt;p&gt;You may know the PostCSS library, which enables automated processing of styles. The PostCSS plugin &quot;postcss-pxtorem&quot; handles converting &lt;code&gt;px&lt;/code&gt; to &lt;code&gt;rem&lt;/code&gt; for selected properties. It simply turns &lt;code&gt;font-size:16px&lt;/code&gt; into &lt;code&gt;font-size:1rem&lt;/code&gt;: &lt;a href=&quot;https://github.com/cuth/postcss-pxtorem&quot;&gt;github.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So I consider &lt;code&gt;rem&lt;/code&gt; the main unit for building interfaces. But &lt;code&gt;em&lt;/code&gt; is very useful too.&lt;/p&gt;
&lt;h2&gt;Dimensions derived from the parent&apos;s font size: em {#em}&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;em&lt;/code&gt; unit holds the font size of the element, not the document.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
  font-size: 100%; /* = 16px */
}

p {
  padding: 1em; /* = 16px */
}

.button {
  font-size: 75%;
  padding: 1em; /* = 12px */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that &lt;code&gt;1em&lt;/code&gt; means different things in different places in the document. Sometimes that&apos;s a good thing: for example, when you&apos;re coding a component whose size should be determined precisely by the font size on the parent element.&lt;/p&gt;
&lt;p&gt;Of course, developers find &quot;ems&quot; a bit harder to work with than &quot;rems.&quot; Not everyone wants to become a walking calculator for converting between &lt;code&gt;em&lt;/code&gt; and pixels.&lt;/p&gt;
&lt;h3&gt;Just note that em is not the typographic em quad {#em-is-not-em-quad}&lt;/h3&gt;
&lt;p&gt;The &quot;em quad&quot; is a typographic unit measured from the width of the capital &quot;M.&quot; &lt;code&gt;em&lt;/code&gt; is sometimes inaccurately called the em quad. But then it would be a different size for different typefaces.&lt;/p&gt;
&lt;p&gt;And it isn&apos;t. The W3C defined &lt;code&gt;em&lt;/code&gt; differently. Its size at the root of the document is the same in all browsers and with any typeface — &lt;code&gt;16px&lt;/code&gt;. Unless, that is, it&apos;s changed by the treacherous trio of user, browser, or page author.&lt;/p&gt;
&lt;h2&gt;Media Queries: em {#media-queries}&lt;/h2&gt;
&lt;p&gt;Why not use &lt;code&gt;px&lt;/code&gt;? I&apos;d recommend avoiding pixels because of the inability of Media Queries to respond to font-size enlargement.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media screen and (min-width: 30em) { }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &quot;PX, EM, or REM? Examining Media Query Units in 2021,&quot; Iris Winter writes that because of an imperfect implementation in Safari it&apos;s still better not to use pixels, and to prefer &lt;code&gt;em&lt;/code&gt; or possibly &lt;code&gt;rem&lt;/code&gt;. Both units refer, in Media Queries, to the document&apos;s font size, so they&apos;re freely interchangeable: &lt;a href=&quot;https://betterprogramming.pub/px-em-or-rem-examining-media-query-units-in-2021-e00cf37b91a9&quot;&gt;betterprogramming.pub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In coding practice, though, you can use automatic conversion from &lt;code&gt;px&lt;/code&gt;, because CSS pixels are easier to work with here. A handy PostCSS plugin called &quot;postcss-em-media-query&quot; will help: &lt;a href=&quot;https://github.com/niksy/postcss-em-media-query&quot;&gt;github.com&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Line height: a unitless number {#line-height}&lt;/h2&gt;
&lt;p&gt;A unitless value is specific to line height, but it makes perfect sense:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;h1 {
  line-height: 1.5;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the CodePen example (see below) the line height is simply one and a half times the font size of the first-level heading. And then it doesn&apos;t matter at all how anyone sets their font size.&lt;/p&gt;
&lt;p&gt;Why is this better than setting it &quot;hard&quot; in &lt;code&gt;rem&lt;/code&gt;, &lt;code&gt;em&lt;/code&gt;, or &lt;code&gt;px&lt;/code&gt;? If the font size changes in some context — by the author or the user — you then don&apos;t have to change the line-height setting too.&lt;/p&gt;
&lt;h2&gt;Layout: percentages, but other units too {#layout}&lt;/h2&gt;
&lt;p&gt;Percentages work well for layout. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.layout-col {
  width: 50%;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A reminder: they&apos;re always calculated from the width of the nearest parent element.&lt;/p&gt;
&lt;p&gt;But there are more usable units for layout:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Percentages or &lt;code&gt;vw&lt;/code&gt; stretch with the window&apos;s width, &lt;code&gt;vh&lt;/code&gt; with its height.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rem&lt;/code&gt; and &lt;code&gt;em&lt;/code&gt; go by the font size.&lt;/li&gt;
&lt;li&gt;In flexbox you can also use absolute units (&lt;code&gt;flex:1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;In CSS grid there are the so-called fractional &lt;code&gt;fr&lt;/code&gt; units (&lt;code&gt;grid-template-columns:3fr 1fr&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Sometimes fixed dimensions in &lt;code&gt;px&lt;/code&gt; come in handy too.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Borders, decoration: px {#decoration}&lt;/h2&gt;
&lt;p&gt;I recommend using &lt;code&gt;px&lt;/code&gt; only where you need a precise expression in pixels. For example, for borders between navigation items:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.nav-item {
  border-left: 1px solid white;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just to be safe, a reminder that this is no longer a hardware pixel, but the reference — or so-called &quot;CSS pixel.&quot; I write about it on Vzhůru dolů: &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-pixel&quot;&gt;vzhurudolu.cz/prirucka/css-pixel&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Typography based on window size: vw {#viewport-typography}&lt;/h2&gt;
&lt;p&gt;You may also need to grow and shrink the font size according to the window&apos;s width or height. In that case, remember the &lt;code&gt;vw&lt;/code&gt; (viewport width) or &lt;code&gt;vh&lt;/code&gt; (viewport height) units.&lt;/p&gt;
&lt;p&gt;For example, this heading from the example will have a font size of &lt;code&gt;2rem&lt;/code&gt; plus, always, two percent of the window&apos;s width:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.heading {
  font-size: calc(2rem + 2vw);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I&apos;m adding a link to a CodePen that uses what I consider an optimal unit setup on a simple example.&lt;/p&gt;
&lt;p&gt;CodePen: &lt;a href=&quot;https://codepen.io/machal/pen/dvdxWG&quot;&gt;codepen.io/machal&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;What if I still want to use mainly px? {#px}&lt;/h2&gt;
&lt;p&gt;In web design there&apos;s always a whole range of possible solutions. Some are optimal for users but demanding to implement; others are a compromise. Units are no different. I don&apos;t think a lot of kittens will die if you favor &quot;CSS pixels.&quot; Using &lt;code&gt;px&lt;/code&gt; is significantly more convenient to implement for a large share of design types.&lt;/p&gt;
&lt;p&gt;Still, make sure the text in the design is large enough for most users to read. As a baseline, at least those &lt;code&gt;16px&lt;/code&gt; are generally recommended. You should also ask yourself whether you&apos;re bothered by anything on the following list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Users who changed their font size in the system or browser (about 3% on Archive.org) won&apos;t see their setting reflected on your site. They&apos;re left with the option of zooming the whole page.&lt;/li&gt;
&lt;li&gt;A change in font size won&apos;t be correctly reflected in Media Queries.&lt;/li&gt;
&lt;li&gt;The design doesn&apos;t account for fluid typography that grows with the viewport.&lt;/li&gt;
&lt;li&gt;The designer likewise didn&apos;t account for a flexible change in a component&apos;s size based on the parent&apos;s font size, nor for a global change in font size at certain design breakpoints.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>BEM: A naming convention for CSS classes</title><link>https://michalek.blog/guide/bem/</link><guid isPermaLink="true">https://michalek.blog/guide/bem/</guid><description>Block, Element, Modifier — a simple, widely adopted way to name CSS classes so component styles stay readable and easy to maintain.</description><pubDate>Mon, 05 Jun 2017 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;BEM: A naming convention for CSS classes&lt;/h1&gt;
&lt;p&gt;BEM is a way to name CSS classes so that their different types never get confused with one another.&lt;/p&gt;
&lt;p&gt;There are two ways to look at BEM:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A full-blown methodology for organizing CSS. See the complete documentation at &lt;a href=&quot;https://en.bem.info/methodology/&quot;&gt;bem.info&lt;/a&gt;. It was invented and is used at Russian search company Yandex.&lt;/li&gt;
&lt;li&gt;A naming convention for classes. See &lt;a href=&quot;http://getbem.com/&quot;&gt;getbem.com&lt;/a&gt;. This is the trimmed-down version that other authors extracted from the original methodology, and it is the one I will cover here.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I do not use BEM as a full methodology — I usually reach for my own ways of organizing CSS instead. That is a fairly common scenario, I think. You might also want to combine BEM with another system: SMACSS, ITCSS, or others.&lt;/p&gt;
&lt;p&gt;For me the biggest value of BEM lies in the naming convention. At first glance this might look like a very short topic, but there is still plenty to say. You will see in a moment.&lt;/p&gt;
&lt;h2&gt;BEM as Block, Element, Modifier {#block-element-modifier}&lt;/h2&gt;
&lt;p&gt;First the quick overview, with links to more detailed explanations below.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class type&lt;/th&gt;
&lt;th&gt;Naming pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#block&quot;&gt;Block&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.block&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#element&quot;&gt;Element&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.block__element&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#modifier&quot;&gt;Modifier&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.block--modifier&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#element-modifier&quot;&gt;Element modifier&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.block__element--modifier&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h2&gt;Why use BEM and where does it fit? {#why-bem}&lt;/h2&gt;
&lt;p&gt;I consider BEM an extension of &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/oocss&quot;&gt;object-oriented CSS (OOCSS)&lt;/a&gt; for medium-sized and large projects. To adopt BEM you therefore need to be able to write styles componentwise, keep the specificity of your &lt;a href=&quot;../guide/css-selectors.md&quot;&gt;CSS selectors&lt;/a&gt; low, and so on.&lt;/p&gt;
&lt;h3&gt;Unambiguous meaning of classes in CSS and HTML {#unambiguous-meaning}&lt;/h3&gt;
&lt;p&gt;If your project has, say, more than twenty components and you write CSS in an object-oriented way, there is a high chance the meaning of your classes will start to blur:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;nav class=&quot;nav nav-secondary nav-visible&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading this code, you might wonder whether &lt;code&gt;nav-secondary&lt;/code&gt; and &lt;code&gt;nav-visible&lt;/code&gt; modify the original component or are standalone objects. Is &lt;code&gt;nav-secondary&lt;/code&gt; independent? What about &lt;code&gt;nav-visible&lt;/code&gt;? Should you look in &lt;code&gt;nav.css&lt;/code&gt; or in &lt;code&gt;nav-secondary.css&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;With BEM everything is clear:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;nav class=&quot;nav nav--secondary nav--visible&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;nav&lt;/code&gt; is a block — in other words, a standalone component. &lt;code&gt;nav--secondary&lt;/code&gt; and &lt;code&gt;nav--visible&lt;/code&gt; are its modifiers. We will most likely find them all in &lt;code&gt;nav.css&lt;/code&gt;, or in a file with an extension matching whichever &lt;a href=&quot;https://www.vzhurudolu.cz/blog/12-css-preprocesory-1&quot;&gt;preprocessor&lt;/a&gt; you use.&lt;/p&gt;
&lt;p&gt;A component marked up with BEM therefore carries more information than one marked up with plain OOCSS — both in CSS and in HTML. The code is easier to understand, you need less documentation and fewer comments, and it is easier to move around within a project or across projects.&lt;/p&gt;
&lt;h3&gt;It is simple and widely adopted {#simple-and-widespread}&lt;/h3&gt;
&lt;p&gt;The BEM principle is not complicated, and it is easy to explain to colleagues who do not work with CSS much. They certainly do look at HTML, though, and thanks to BEM they get more information about a component&apos;s structure there — even without documentation.&lt;/p&gt;
&lt;p&gt;On top of that, BEM is nothing new and is well established among front-end developers. So if you stick to what is described here, new colleagues will have no trouble finding their way around the project.&lt;/p&gt;
&lt;h3&gt;Is it &quot;ugly&quot;? {#is-it-ugly}&lt;/h3&gt;
&lt;p&gt;That is a common objection, especially from programmers. Aesthetics are subjective, so it is hard to base the decision to use a methodology on them.&lt;/p&gt;
&lt;p&gt;Yes, it can look ugly. But either BEM solves a problem for you or it does not. If it does, use it. I &lt;em&gt;definitely&lt;/em&gt; recommend it. The exception is tiny projects, or &lt;a href=&quot;https://www.vzhurudolu.cz/podcast/css-v-js&quot;&gt;generating CSS with JavaScript&lt;/a&gt; in apps that fully depend on JS.&lt;/p&gt;
&lt;p&gt;And now let&apos;s dive deeper into BEM.&lt;/p&gt;
&lt;h2&gt;BEM in detail {#bem-in-detail}&lt;/h2&gt;
&lt;h3&gt;Block {#block}&lt;/h3&gt;
&lt;p&gt;A block is essentially a UI component — an independent, reusable element of the user interface. Blocks can be nested inside one another freely.&lt;/p&gt;
&lt;p&gt;It is denoted by a class whose words are separated by a hyphen: &lt;code&gt;.block-name&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Element {#element}&lt;/h3&gt;
&lt;p&gt;A part inside a block that we need to style. An element cannot be used on its own in the interface; its existence only makes sense within a block.&lt;/p&gt;
&lt;p&gt;You recognize it by a class prefixed with the block name and completed with the element name, separated by two underscores: &lt;code&gt;.block-name__element-name&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Modifier {#modifier}&lt;/h3&gt;
&lt;p&gt;A variant of a component. It describes visual properties (&lt;code&gt;.block--small&lt;/code&gt;), state (&lt;code&gt;.block--disabled&lt;/code&gt;), or behavior (&lt;code&gt;.block--animated-to-left&lt;/code&gt;). It should not carry a name tied to appearance (&lt;code&gt;.block--green&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In code it is a class prefixed with the block name and completed with the modifier name, separated by two hyphens: &lt;code&gt;.block-name--modifier-name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You may have come across modifiers written with a single underscore (&lt;code&gt;.block_modifier&lt;/code&gt;). That is the &quot;classic&quot; BEM syntax. It &lt;a href=&quot;http://stackoverflow.com/a/25213997/889682&quot;&gt;appears&lt;/a&gt; to have been Harry Roberts who reshaped it into the double-hyphen form — or at least popularized that variant.&lt;/p&gt;
&lt;p&gt;The &quot;classic&quot; notation lets you split modifiers into two types — &quot;boolean&quot; and &quot;key-value&quot;. Honestly, I cannot remember when I ever needed that. So for its simplicity and clarity I, too, prefer the &quot;Roberts&quot; variant.&lt;/p&gt;
&lt;h3&gt;Element modifier {#element-modifier}&lt;/h3&gt;
&lt;p&gt;A variant of an element is also possible. You may need it especially in more complex components. As an example, take the active item in a tabbed navigation: &lt;code&gt;.tabs-nav__tab-item--active&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The same naming rules apply as for modifiers. In code it is a class prefixed with the block name and completed with the element name, separated by two hyphens: &lt;code&gt;.block-name__element-name--modifier-name&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Names are separated by a hyphen {#hyphen-separated-names}&lt;/h3&gt;
&lt;p&gt;As you can see from the examples above, the words in block, element, and modifier names are separated by a single hyphen. For example &lt;code&gt;.block-name--modifier-name&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;BEM and CSS organization systems {#bem-and-css-systems}&lt;/h2&gt;
&lt;p&gt;As I wrote, BEM builds on &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/oocss&quot;&gt;OOCSS&lt;/a&gt;. It is also nice that it complements broader CSS organization systems such as SMACSS or ITCSS.&lt;/p&gt;
&lt;p&gt;Let&apos;s sort out those methodologies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;OOCSS&lt;/em&gt; is a methodology for writing the component part of your styles. It is a necessary foundation for a sensible way of writing the component part of the code on every project.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;BEM&lt;/em&gt; is a methodology for naming the component part of your styles. It is only unnecessary on tiny projects.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;ITCSS&lt;/em&gt; or &lt;em&gt;SMACSS&lt;/em&gt; are methodologies for organizing the whole of your CSS, including the non-component parts: the typographic baseline, helpers, and so on. How suitable these high-level organization methodologies are differs from project to project, and sometimes you have to come up with your own.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BEM does not conflict with any of these methodologies. It usually just adds a way of naming classes on top of them.&lt;/p&gt;
&lt;h2&gt;A navigation example {#navigation-example}&lt;/h2&gt;
&lt;p&gt;Take this HTML:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul class=&quot;nav nav--secondary&quot; role=&quot;navigation&quot;&amp;gt;
  &amp;lt;li class=&quot;nav__item&quot;&amp;gt;
    &amp;lt;a href=&quot;/&quot;&amp;gt;Home&amp;lt;/a&amp;gt;
  &amp;lt;/li&amp;gt;
  &amp;lt;li class=&quot;nav__item nav__item--active&quot;&amp;gt;
    &amp;lt;a href=&quot;/&quot;&amp;gt;Products&amp;lt;/a&amp;gt;
  &amp;lt;/li&amp;gt;  
  &amp;lt;!-- … --&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.nav&lt;/code&gt; is a block (the component name)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.nav--secondary&lt;/code&gt; is a modifier (a variant of the component)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.nav__item&lt;/code&gt; is an element (a DOM element inside the component)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.nav__item--active&lt;/code&gt; is an element modifier (a variant of the element)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I include the &lt;code&gt;role&lt;/code&gt; attribute here for good measure, so we don&apos;t forget about &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/html5-struktura&quot;&gt;accessibility&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Selector specificity in BEM {#specificity}&lt;/h2&gt;
&lt;p&gt;Because BEM stems from OOCSS, the goal is to keep selector specificity (weight) as low as possible. We then write the CSS like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.nav { 
  /* Rules common to all navigations */ 
}

.nav--secondary { 
  /* Changing rules for this modification */ 
}

.nav__item {
  /* Rules for this element */ 
}

.nav__item--active {
  /* Changing rules for this element modification */ 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has two benefits: selectors keep a low specificity, and we don&apos;t repeat CSS code.&lt;/p&gt;
&lt;h3&gt;Keeping selector weight low {#low-weight}&lt;/h3&gt;
&lt;p&gt;Selectors like &lt;code&gt;.nav.nav--secondary&lt;/code&gt; then become pointless, thanks to prefixing the modifier.&lt;/p&gt;
&lt;h3&gt;Not repeating code needlessly {#no-repetition}&lt;/h3&gt;
&lt;p&gt;A common problem with non-object-oriented CSS is repeating declarations from &lt;code&gt;.nav&lt;/code&gt; in modifiers like &lt;code&gt;.nav--secondary&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;True, we could then allow ourselves simpler HTML such as &lt;code&gt;&amp;lt;nav class=&quot;nav--secondary&quot;&amp;gt;&lt;/code&gt;, but the CSS would be complex and horribly hard to maintain. Simpler HTML is no advantage either, because we can no longer see from it what is a component and what is its modifier.&lt;/p&gt;
&lt;p&gt;You can find more about specificity in &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/oocss&quot;&gt;the OOCSS article&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;An element within a modifier {#element-in-modifier}&lt;/h2&gt;
&lt;p&gt;The only exception where a two-class selector is acceptable is an element inside a modified block:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.nav--secondary .nav__item {
  /* Changing rules for the navigation item
     in the secondary navigation */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An element is always dependent on its parent block, and it would make no sense to make it standalone. At the same time, it would be quite annoying to create modifiers for all the elements inside a modified block (&lt;code&gt;.nav__item--secondary&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;For practical reasons it is therefore the only thing in the BEM naming system allowed to have double the selector specificity.&lt;/p&gt;
&lt;h2&gt;What not to do {#what-not-to-do}&lt;/h2&gt;
&lt;p&gt;Let me point out a few more pitfalls.&lt;/p&gt;
&lt;h3&gt;BEM and the trap of nesting in preprocessors {#preprocessor-nesting}&lt;/h3&gt;
&lt;p&gt;Some people make writing BEM syntax easier &lt;a href=&quot;https://www.vzhurudolu.cz/blog/12-css-preprocesory-1&quot;&gt;in CSS preprocessors&lt;/a&gt; by nesting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Better not do this: */
.nav {
  &amp;amp;__item { }
  &amp;amp;--secondary { }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just please don&apos;t overdo it. Nesting in preprocessors is a good servant but a bad master. It is not problematic in itself, but in the code of less experienced CSS authors it leads &lt;a href=&quot;https://www.vzhurudolu.cz/blog/65-css-kod-problemy&quot;&gt;to monolithic blocks and bracket hell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another problem can arise when searching in editors. You might find yourself searching for &lt;code&gt;.nav__item&lt;/code&gt; — and in code with the &quot;ampersand&quot; syntax that simply won&apos;t work.&lt;/p&gt;
&lt;h3&gt;Multiple block nesting {#multiple-nesting}&lt;/h3&gt;
&lt;p&gt;In the DOM structure you can nest freely. The hierarchy of CSS selectors, however, should always stay single-level. So &lt;code&gt;.block__element__heading&lt;/code&gt; is wrong. It should be &lt;code&gt;.block__element-heading&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is so that the CSS selector does not depend on the DOM structure and you don&apos;t have to change it with every HTML tweak. &lt;a href=&quot;https://www.vzhurudolu.cz/blog/63-bem-chyby&quot;&gt;Don&apos;t mirror the DOM structure in your CSS&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Crossing components {#crossing-components}&lt;/h3&gt;
&lt;p&gt;I often see constructs like this in CSS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.button {
  /* Code for the Button component */
}

.card .button {
  /* Changes to the Button component when it appears inside Card */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes there is no way around it, but in principle crossing components is wrong. It then becomes hard to say whether the code belongs to the &lt;code&gt;card&lt;/code&gt; component or to &lt;code&gt;button&lt;/code&gt;. It is better to create a modifier like &lt;code&gt;button--small&lt;/code&gt;. &lt;a href=&quot;https://www.vzhurudolu.cz/blog/63-bem-chyby&quot;&gt;Leave crossbreeding to the gardeners&lt;/a&gt; — don&apos;t try it with components.&lt;/p&gt;
&lt;p&gt;We are almost at the end. The last part of the text is devoted to using BEM in inhospitable conditions.&lt;/p&gt;
&lt;h2&gt;Using BEM in a non-BEM environment {#bem-in-non-bem}&lt;/h2&gt;
&lt;p&gt;What if your project uses something like Bootstrap, which is written in an object-oriented way but without BEM naming?&lt;/p&gt;
&lt;p&gt;If Bootstrap or another library dominates the codebase, I would drop BEM for the sake of consistency. Bootstrap also has &lt;a href=&quot;http://codeguide.co/&quot;&gt;its own coding standards&lt;/a&gt;, so I recommend staying within their guard rails. Code Guide is not very strict, but it is a perfectly adequate guideline for most situations.&lt;/p&gt;
&lt;p&gt;If, however, you were using Bootstrap or another library only as an add-on to your own robust code base, I would consider either prefixing the library selectors or your own parts of the code. In the early days of one of my projects, for example, we used the &lt;code&gt;vc-&lt;/code&gt; prefix to distinguish our components from the Bootstrap ones.&lt;/p&gt;
&lt;p&gt;You have reached the end. There would be more to say about BEM, but I will save that for another time.&lt;/p&gt;
</content:encoded></item><item><title>The CSS display property: outer and inner display explained</title><link>https://michalek.blog/guide/css-display/</link><guid isPermaLink="true">https://michalek.blog/guide/css-display/</guid><description>A practical tour of the CSS display property, including the modern two-keyword syntax and values like flow-root, contents, and list-item.</description><pubDate>Sun, 14 Jun 2026 10:53:50 GMT</pubDate><content:encoded>&lt;h1&gt;The CSS display property, from the basics to the modern syntax&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;display&lt;/code&gt; property tells the browser how to render an element in CSS.&lt;/p&gt;
&lt;p&gt;There is nothing to it. And yet this article will try to show you that it can be a surprisingly complicated thing.&lt;/p&gt;
&lt;p&gt;Those of you who know its basic values such as &lt;code&gt;block&lt;/code&gt; or &lt;code&gt;inline&lt;/code&gt; may be surprised that since 2020 we have had a new version of the specification that adds a whole range of further options — the &quot;CSS Display Module Level 3&quot;. &lt;a href=&quot;https://www.w3.org/TR/css-display-3/&quot;&gt;w3.org/TR/css-display-3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s start with a simple overview of the most useful values of the &lt;code&gt;display&lt;/code&gt; property. You probably already know most of them.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable table-1-quarter f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Value&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;How it renders&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An inline-level element that creates no line breaks before or after itself (the default).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A block-level element. It breaks the line before and after itself.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline-block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Internally a block-level element, externally inline, creating no line breaks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flex&lt;/code&gt;, &lt;code&gt;inline-flex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates a &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-flexbox&quot;&gt;flexbox layout&lt;/a&gt;. The inline variant does not break lines before and after.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grid&lt;/code&gt;, &lt;code&gt;inline-grid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates a &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-grid&quot;&gt;grid layout&lt;/a&gt;. The inline variant does not break lines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;table&lt;/code&gt;, &lt;code&gt;inline-table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A table layout. The inline variant again forms a table within a line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Does not render the element, nor its descendants.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;The table is far from covering all the options and their specific behaviors, pitfalls, and tricks. So read on.&lt;/p&gt;
&lt;p&gt;Did you know, for example, that…?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;a href=&quot;#vnejsi&quot;&gt;the &lt;code&gt;flow-root&lt;/code&gt; value&lt;/a&gt; you no longer need a &quot;clearfix&quot; to contain floats, that is, to reset a floated layout?&lt;/li&gt;
&lt;li&gt;Browsers now support &lt;a href=&quot;#viceslovna&quot;&gt;multi-keyword values&lt;/a&gt; such as &lt;code&gt;inline flex&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Besides &lt;code&gt;none&lt;/code&gt;, there is also &lt;a href=&quot;#none-contents&quot;&gt;the &lt;code&gt;contents&lt;/code&gt; value&lt;/a&gt; for hiding an element. And do you know what it can do?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Outer and inner display {#typy}&lt;/h2&gt;
&lt;p&gt;The first thing we need to realize is the plain fact that, according to the specification, there are now two types of display:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Inner display&lt;/em&gt;&lt;br /&gt;
The value of the &lt;code&gt;display&lt;/code&gt; property determines how the browser lays out the element&apos;s descendants, in other words its inner elements. This is where values such as &lt;code&gt;flex&lt;/code&gt;, &lt;code&gt;grid&lt;/code&gt;, or &lt;code&gt;table&lt;/code&gt; belong.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Outer display&lt;/em&gt;&lt;br /&gt;
The value defines how the element itself is displayed relative to its surroundings. The view from the outside. This is determined by values such as &lt;code&gt;inline&lt;/code&gt;, &lt;code&gt;block&lt;/code&gt;, or &lt;code&gt;none&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Got it? Excellent. This will come in handy once we start talking about multi-keyword values.&lt;/p&gt;
&lt;h2&gt;Outer display {#vnejsi}&lt;/h2&gt;
&lt;p&gt;Outer display essentially determines the role of the styled box in the page&apos;s flow.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/vdlayout/css-display-inline-block.jpg&quot; width=&quot;1600&quot; height=&quot;450&quot; alt=&quot;CSS display - inline and block&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
The display property. The outer display values are our old acquaintances.
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;This type of display includes the following values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inline&lt;/code&gt;&lt;br /&gt;
Creates a box that is &quot;inline-level&quot;. It breaks nothing before or after itself, it simply renders within the line.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;block&lt;/code&gt;&lt;br /&gt;
Generates a box that is &quot;block-level&quot;. Put simply, this means it renders across the full width of its parent and breaks the line before and after itself.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inline-block&lt;/code&gt;&lt;br /&gt;
Generates a box that behaves like an inline box on the outside and always generates a new block context on the inside. By the way, the specification treats this value going forward merely as another notation for the keyword pair &lt;code&gt;inline flow-root&lt;/code&gt;. More on that later.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run-in&lt;/code&gt;&lt;br /&gt;
Generates an &quot;inline-level&quot; box with special behavior — it tries to insert itself into the following block element. If a block element follows the &quot;run-in&quot; element, the &quot;run-in&quot; becomes its first inline box. If an inline field follows, the &quot;run-in&quot; element becomes a block element.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can try all the options out in CodePen.&lt;/p&gt;
&lt;p&gt;CodePen: &lt;a href=&quot;https://codepen.io/machal/pen/wvzYXeg?editors=0000&quot;&gt;codepen.io/machal/pen/wvzYXeg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The variant with the &lt;code&gt;run-in&lt;/code&gt; display type is missing from my demo, because it is not supported anywhere other than &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/msie&quot;&gt;Internet Explorer&lt;/a&gt; (!).&lt;/p&gt;
&lt;p&gt;CodePen does not work in this granddaddy of browsers, so you would get nothing out of the demo. See support on CanIUse.&lt;br /&gt;
&lt;a href=&quot;https://caniuse.com/run-in&quot;&gt;caniuse.com/run-in&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The granddaddy is sadly dead by now, though, so you do not need to care about &lt;code&gt;run-in&lt;/code&gt; either.&lt;/p&gt;
&lt;h2&gt;Inner display {#vnitrni}&lt;/h2&gt;
&lt;p&gt;Inner display values switch on a new formatting context inside the affected element (the term &quot;formatting context&quot; is used for this in CSS).&lt;/p&gt;
&lt;p&gt;The formatting context affects the way inner elements are rendered, and possibly the behavior of properties applied to the element.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flow&lt;/code&gt;&lt;br /&gt;
The &lt;code&gt;flow&lt;/code&gt; value switches on flow formatting (&quot;flow layout&quot;). This is the normal way of displaying, which is automatically turned on by the values &lt;code&gt;block&lt;/code&gt;, &lt;code&gt;inline&lt;/code&gt;, and &lt;code&gt;inline-block&lt;/code&gt;. It is the default layout mode in CSS.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flow-root&lt;/code&gt;&lt;br /&gt;
Creates a block context container (like &lt;code&gt;display:block&lt;/code&gt;) and lays out its content using flow (&quot;flow layout&quot;). The &lt;code&gt;flow-root&lt;/code&gt; value, however, always generates a new block formatting context for its content, so you do not need to clear floats with a &quot;clearfix&quot;, for example. What is interesting about this value is that it is supported by all modern browsers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex&lt;/code&gt;&lt;br /&gt;
Switches on the &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-flexbox&quot;&gt;flexbox&lt;/a&gt; formatting context. It turns the styled element into a flexbox container and its direct descendants into flexbox items.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grid&lt;/code&gt;&lt;br /&gt;
Starts the &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-grid&quot;&gt;grid&lt;/a&gt; formatting context. It turns the styled element into a grid container and its direct descendants into its items.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;table&lt;/code&gt;&lt;br /&gt;
Turns the element into a table. In this case, however, there are two &quot;containers&quot;. &lt;code&gt;display:table&lt;/code&gt; generates a table container, which creates a block formatting context and contains an additionally generated table grid box, which creates the table&apos;s formatting context.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ruby&lt;/code&gt;&lt;br /&gt;
This is exotic and unnecessary in a Central European context. &quot;Ruby annotations&quot; are short runs of characters placed above or below the base text, used in East Asian typography as a pronunciation guide. Feel free to forget about it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have prepared two explanatory CodePens where you can test what you see in the image.&lt;/p&gt;
&lt;p&gt;In the first one, we simply have three elements placed in a single parent, with no layout.&lt;/p&gt;
&lt;p&gt;CodePen: &lt;a href=&quot;https://codepen.io/machal/pen/KKgGeQQ?editors=0000&quot;&gt;codepen.io/machal/pen/KKgGeQQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The second CodePen is more interesting. All three inner elements are &quot;flowing&quot;, floated:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container p {
  float: left;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CodePen: &lt;a href=&quot;https://codepen.io/machal/pen/WNGayad?editors=0000&quot;&gt;codepen.io/machal/pen/WNGayad&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can see the result in the image.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/vdlayout/css-display-outer.jpg&quot; width=&quot;1600&quot; height=&quot;450&quot; alt=&quot;CSS display - inner display with floated children&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;The inner display value options with inner floated elements.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Normal flow display (&lt;code&gt;display:flow&lt;/code&gt;) cannot contain floats, we would need the aforementioned &quot;clearfix&quot;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display:flow-root&lt;/code&gt; contains floats, it always creates a new block formatting context.&lt;/li&gt;
&lt;li&gt;Floats have no effect on &lt;code&gt;display:flex&lt;/code&gt; and &lt;code&gt;display:grid&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Floats do affect the inner elements in &lt;code&gt;display:table&lt;/code&gt;, because the parent here is in a normal block formatting context flow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s go through a few more specific values.&lt;/p&gt;
&lt;h2&gt;Generating boxes with markers: list-item {#list-item}&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;display:list-item&lt;/code&gt; notation causes the element to generate a &lt;code&gt;::marker&lt;/code&gt; pseudo-element.&lt;/p&gt;
&lt;p&gt;If no inner display type value is given, the default is flow — like &lt;code&gt;display:flow&lt;/code&gt;. If no outer display type value is given, the default type is block — &lt;code&gt;display:block&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to this, we can style our container as if it were a &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt; element:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container {
  list-style-type: square;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CodePen: &lt;a href=&quot;https://codepen.io/machal/pen/gOwqJmq?editors=0000&quot;&gt;codepen.io/machal/pen/gOwqJmq&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first example in the following image shows the &lt;code&gt;list-item&lt;/code&gt; display type.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/vdlayout/css-display-etc.jpg&quot; width=&quot;1600&quot; height=&quot;450&quot; alt=&quot;CSS display - list-item, none, contents&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Other types of (non-)display in CSS.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;We will discuss the second and third values from the image in the next section.&lt;/p&gt;
&lt;h2&gt;Hiding elements: the none and contents values {#none-contents}&lt;/h2&gt;
&lt;p&gt;To all the possible methods of controlling how boxes are rendered to the screen, we must also add methods of &lt;em&gt;not rendering&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The following two values of the &lt;code&gt;display&lt;/code&gt; property serve this purpose.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt; – neither the element nor its descendants are rendered to the screen at all.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contents&lt;/code&gt; – the element itself is not rendered to the screen, but its descendants are.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;contents&lt;/code&gt; display type works as if the element were replaced in the DOM tree by its content (including pseudo-elements such as &lt;code&gt;::before&lt;/code&gt; and &lt;code&gt;::after&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;CodePen: &lt;a href=&quot;https://codepen.io/machal/pen/zYKmaMb?editors=0000&quot;&gt;codepen.io/machal/pen/zYKmaMb&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Display types for internal layout: the table- and ruby- values {#table-ruby}&lt;/h2&gt;
&lt;p&gt;Display models that force an internal layout, such as &lt;code&gt;display:table&lt;/code&gt; and &lt;code&gt;display:ruby&lt;/code&gt;, have a complex structure with several different roles that their descendants can fill.&lt;/p&gt;
&lt;p&gt;As mentioned above, the &lt;code&gt;display:table&lt;/code&gt; notation does create a table container, but that container creates a block formatting context.&lt;/p&gt;
&lt;p&gt;So we do not achieve a tabular display this way. To do that we would need additional elements representing the rows and cells of the table with the correct &lt;code&gt;display&lt;/code&gt; property values (&lt;code&gt;table-row&lt;/code&gt;, &lt;code&gt;table-cell&lt;/code&gt;…).&lt;/p&gt;
&lt;p&gt;It is similar with &lt;code&gt;display:ruby&lt;/code&gt;, only the inner elements are different.&lt;/p&gt;
&lt;h2&gt;Multi-keyword values {#viceslovna}&lt;/h2&gt;
&lt;p&gt;This is a new thing, added to the specification in the second half of 2020 by the last browser to do so, which was Chrome, implemented in 2023.&lt;/p&gt;
&lt;p&gt;Do you remember when I wrote about the different types of display — inner and outer? If not, quickly skim the start of this text or its headings. Then you will understand why multi-keyword values for the &lt;code&gt;display&lt;/code&gt; property make sense to me.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;single-keyword&lt;/em&gt; values above can in fact be taken as shorthands for &lt;em&gt;multi-keyword&lt;/em&gt; notations of inner, outer, or specific display.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Shorthand&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Full notation&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What is generated&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contents&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;element omitted, descendants generated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;block flow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;block box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flow-root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;block flow-root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;block box that always creates a new block formatting context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inline flow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inline box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline-block&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inline flow-root&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inline box that always creates a new block context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;run-in&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;run-in flow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;run-in box (an inline box with specific rules)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list-item&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;block flow list-item&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;block box with an additional list item marker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline list-item&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inline flow list-item&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inline box with an additional list item marker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;block flex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;block flex container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline-flex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inline flex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inline flex container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;block grid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;block grid container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline-grid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inline grid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inline grid container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;block table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;block table wrapper box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inline-table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inline table&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;inline table wrapper box&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;It is probably clear from the table, but just to be safe here are three examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;display:block&lt;/code&gt; denotes a block element (&lt;code&gt;block&lt;/code&gt;) placed in the normal document flow (&lt;code&gt;flow&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display:inline-flex&lt;/code&gt; defines a flexbox container (&lt;code&gt;flex&lt;/code&gt;) placed within a line (&lt;code&gt;inline&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display:list-item&lt;/code&gt; renders a list element (&lt;code&gt;list-item&lt;/code&gt;) placed in the normal flow (&lt;code&gt;flow&lt;/code&gt;) and at the same time block-level (&lt;code&gt;block&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that is everything about the &lt;code&gt;display&lt;/code&gt; property, thank you for your attention.&lt;/p&gt;
</content:encoded></item><item><title>CSS selectors: a complete guide to selectors and combinators</title><link>https://michalek.blog/guide/css-selectors/</link><guid isPermaLink="true">https://michalek.blog/guide/css-selectors/</guid><description>A practical reference to CSS selectors and combinators — elements, classes, IDs, attribute selectors, and how to combine them.</description><pubDate>Sun, 14 Jun 2026 10:53:50 GMT</pubDate><content:encoded>&lt;h1&gt;CSS selectors&lt;/h1&gt;
&lt;p&gt;This guide fills a gap in my coverage of &lt;a href=&quot;https://www.vzhurudolu.cz/css&quot;&gt;CSS&lt;/a&gt; fundamentals.&lt;/p&gt;
&lt;p&gt;While researching it, I noticed that surprisingly few resources cover selectors this comprehensively in one place. So here is one.&lt;/p&gt;
&lt;p&gt;I&apos;m aiming primarily at beginners, but I think refreshing this topic won&apos;t hurt more advanced readers either. Let&apos;s start with a table summarizing the most important things you&apos;ll find in this article.&lt;/p&gt;
&lt;h2&gt;The most important selectors {#key-selectors}&lt;/h2&gt;
&lt;p&gt;Selectors pick a particular group of elements in the DOM and let you style them.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Selector&lt;/th&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#class&quot;&gt;Class&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.class&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#type&quot;&gt;Element&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tag&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#id&quot;&gt;Identifier&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#id&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#attributes&quot;&gt;Attribute&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[attr]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#universal&quot;&gt;Everything&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h2&gt;The most important combinators {#key-combinators}&lt;/h2&gt;
&lt;p&gt;Combinators join simple selectors into more complex groups and let styling apply only under certain conditions.&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Combinator&lt;/th&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#descendant&quot;&gt;Descendant&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A B&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#child&quot;&gt;Child&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;code&amp;gt;A &amp;gt; B&amp;lt;/code&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#next-sibling&quot;&gt;Next sibling&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A + B&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;#subsequent-sibling&quot;&gt;Subsequent sibling&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A ~ B&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;I&apos;m deliberately leaving out &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-pseudotridy&quot;&gt;pseudo-classes&lt;/a&gt;, which undoubtedly belong among CSS selectors. But I want to keep this within the scope of an article, not a book.&lt;/p&gt;
&lt;h2&gt;Element selectors {#elements}&lt;/h2&gt;
&lt;p&gt;These selectors pick elements from the DOM by HTML tag name.&lt;/p&gt;
&lt;h3&gt;Type selector – &lt;code&gt;tag&lt;/code&gt; {#type}&lt;/h3&gt;
&lt;p&gt;This contains the name of an HTML element and represents an instance of that element type in the document tree.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;h1&lt;/code&gt; — represents all &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; elements in the document.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;li span&lt;/code&gt; — selects all &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements nested inside an &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Universal selector – &lt;code&gt;*&lt;/code&gt; {#universal}&lt;/h3&gt;
&lt;p&gt;A special variant of the type selector that represents an element of any type.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; — represents all elements in the document.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;body * .box&lt;/code&gt; — represents an element with the &lt;code&gt;.box&lt;/code&gt; class that is nested at the second level inside a &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Attribute selectors {#attributes}&lt;/h2&gt;
&lt;p&gt;Selectors that pick elements by attributes — their presence, a match against their entire value, or a match against part of the value.&lt;/p&gt;
&lt;h3&gt;Class selector – &lt;code&gt;.className&lt;/code&gt; {#class}&lt;/h3&gt;
&lt;p&gt;One of the best-known and probably the single most useful selector, which picks elements by class.&lt;/p&gt;
&lt;p&gt;It represents elements belonging to the class identified by the &lt;code&gt;class&lt;/code&gt; attribute in HTML.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;
  &amp;lt;p class=&quot;a&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;b&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;c&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.a&lt;/code&gt; selector picks both &lt;code&gt;&amp;lt;p class=&quot;a&quot;&amp;gt;&lt;/code&gt; and all the &lt;code&gt;&amp;lt;span class=&quot;a&quot;&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;
&lt;p&gt;More examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.heading&lt;/code&gt; — all elements that have the &lt;code&gt;class&lt;/code&gt; attribute set to &lt;code&gt;heading&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1.heading&lt;/code&gt; — all &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; elements that have the &lt;code&gt;heading&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1.heading.heading-large&lt;/code&gt; — all &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; elements that have both the &lt;code&gt;heading&lt;/code&gt; class and &lt;code&gt;heading-large&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may have noticed that the syntax &lt;code&gt;.heading&lt;/code&gt; is equivalent to the tilde attribute selector (i.e. &lt;code&gt;[class~=heading]&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Class selectors are the foundation of almost all web styling today — think of methodologies like OOCSS, &lt;a href=&quot;../guide/bem.md&quot;&gt;BEM&lt;/a&gt;, but also newer &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-utility&quot;&gt;utility CSS&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;ID selector – &lt;code&gt;#id&lt;/code&gt; {#id}&lt;/h3&gt;
&lt;p&gt;The ID selector represents an instance of an element whose identifier matches the value of the &lt;code&gt;id&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;
  &amp;lt;p class=&quot;a&quot;&amp;gt;&amp;lt;span class=&quot;a&quot; id=&quot;first&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;b&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;c&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.a#first&lt;/code&gt; selector picks only &lt;code&gt;&amp;lt;span class=&quot;a&quot; id=&quot;first&quot;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In HTML documents it&apos;s possible for multiple elements to match a single ID selector. That&apos;s fine from the CSS selector&apos;s point of view — but of course not from the standpoint of HTML semantics or accessibility.&lt;/p&gt;
&lt;h3&gt;Attribute presence and value selectors – &lt;code&gt;[attr]&lt;/code&gt; {#attr-value}&lt;/h3&gt;
&lt;p&gt;Here we test whether an attribute exists on an HTML element, or detect its value.&lt;/p&gt;
&lt;p&gt;These are the selectors that look for the presence of an attribute or a specific value on an HTML element.&lt;/p&gt;
&lt;p&gt;Types of attribute selectors:&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Selector&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;h1[title]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element that has a &lt;code&gt;title&lt;/code&gt; attribute with &lt;em&gt;any&lt;/em&gt; value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;h1[title=Hello]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exact-match attribute selector. An &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element whose &lt;code&gt;title&lt;/code&gt; attribute is &lt;em&gt;exactly&lt;/em&gt; &lt;code&gt;Hello&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;h1[title~=Hello]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tilde attribute selector matching one value. An &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element whose &lt;code&gt;title&lt;/code&gt; attribute &lt;em&gt;contains&lt;/em&gt; the string &lt;code&gt;Hello&lt;/code&gt; in at least one value. Values are separated by spaces for the selector&apos;s purposes, so &lt;code&gt;&amp;lt;h1 title=&quot;Hello world&quot;&amp;gt;&lt;/code&gt; satisfies it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;code&amp;gt;h1[title|=Hello]&amp;lt;/code&amp;gt;&lt;/td&gt;
&lt;td&gt;Prefix-match selector. This one is peculiar. The matched value must be either exactly &lt;code&gt;Hello&lt;/code&gt;, or start with &lt;code&gt;Hello&lt;/code&gt; immediately followed by a &lt;code&gt;-&lt;/code&gt;. It really only makes sense for matching language codes. For example, &amp;lt;code&amp;gt;[hreflang|=&quot;en&quot;]&amp;lt;/code&amp;gt; matches both &lt;code&gt;en&lt;/code&gt; and &lt;code&gt;en-US&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h3&gt;Substring attribute selectors – &lt;code&gt;[attr^=]&lt;/code&gt; {#attr-substring}&lt;/h3&gt;
&lt;p&gt;Here we pick elements by matching part of an attribute&apos;s value. These are selectors for finding substrings within an attribute value.&lt;/p&gt;
&lt;p&gt;Types of substring attribute selectors:&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;rwd-scrollable f-6&quot; markdown=&quot;1&quot;&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Selector&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;h1[title^=Hello]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The caret attribute selector represents an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element with a &lt;code&gt;title&lt;/code&gt; attribute whose value &lt;em&gt;begins with&lt;/em&gt; &lt;code&gt;Hello&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;h1[title$=Hello]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The dollar attribute selector represents an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element with a &lt;code&gt;title&lt;/code&gt; attribute whose value &lt;em&gt;ends with&lt;/em&gt; &lt;code&gt;Hello&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;h1[title*=Hello]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The asterisk attribute selector represents an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element with a &lt;code&gt;title&lt;/code&gt; attribute whose value &lt;em&gt;contains&lt;/em&gt; &lt;code&gt;Hello&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;In all substring selectors, if the value were an empty string, the selector represents nothing. The element simply isn&apos;t selected.&lt;/p&gt;
&lt;h3&gt;Case-insensitivity flag &lt;code&gt;[ i]&lt;/code&gt; {#attr-case}&lt;/h3&gt;
&lt;p&gt;Thanks to this newer flag, we can turn off case sensitivity.&lt;/p&gt;
&lt;p&gt;By default, selectors for HTML do distinguish between uppercase and lowercase.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;i&lt;/code&gt; identifier stands for &quot;insensitive&quot; — that is, not distinguishing uppercase and lowercase in the selector.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;h1[title=Hello]&lt;/code&gt; — picks &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; elements with a &lt;code&gt;title&lt;/code&gt; attribute valued &lt;code&gt;Hello&lt;/code&gt;, but not &lt;code&gt;hello&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1[title=Hello i]&lt;/code&gt; — picks &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; elements with a &lt;code&gt;title&lt;/code&gt; attribute valued &lt;code&gt;Hello&lt;/code&gt; and also &lt;code&gt;hello&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By the way, even this relatively new flag is supported by all modern browsers. See &lt;a href=&quot;https://caniuse.com/css-case-insensitive&quot;&gt;CanIUse.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Take a look at a demo from reader Lukáš Chylík.&lt;/p&gt;
&lt;p&gt;CodePen: &lt;a href=&quot;https://codepen.io/luko248/pen/eYVWOEQ?editors=1100&quot;&gt;cdpn.io/e/eYVWOEQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;s&lt;/code&gt; identifier before the closing bracket (&lt;code&gt;]&lt;/code&gt;) stands for &quot;sensitive&quot; — case sensitivity. Currently only Firefox supports it, but &lt;code&gt;s]&lt;/code&gt; isn&apos;t really needed in HTML, because it just replicates the browsers&apos; default behavior.&lt;/p&gt;
&lt;h2&gt;Combinators {#combinators}&lt;/h2&gt;
&lt;p&gt;Combinators are special characters that let you combine simple selectors into more complex ones and extend a selector&apos;s reach only when certain conditions are met — such as an element being nested inside a particular parent in the DOM.&lt;/p&gt;
&lt;h3&gt;Descendant combinator – &lt;code&gt;A B&lt;/code&gt; {#descendant}&lt;/h3&gt;
&lt;p&gt;The whitespace combinator separates two selectors (&lt;code&gt;A B&lt;/code&gt;) and selects a descendant (&lt;code&gt;B&lt;/code&gt;) that is nested inside a particular element &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A selector in the form &lt;code&gt;A B&lt;/code&gt; represents an element &lt;code&gt;B&lt;/code&gt; that is any descendant of some ancestor element &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;
  &amp;lt;p class=&quot;a&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;b&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;c&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;      
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.box .a&lt;/code&gt; selector picks the &lt;code&gt;&amp;lt;p class=&quot;a&quot;&amp;gt;&lt;/code&gt; element and also all the &lt;code&gt;&amp;lt;span class=&quot;a&quot;&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;
&lt;p&gt;More examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.heading span&lt;/code&gt; — all &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements that are descendants of elements with the &lt;code&gt;heading&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1 em&lt;/code&gt; — all &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; elements that are descendants of an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1 * em&lt;/code&gt; — all &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; elements that are descendants at the second level or deeper inside an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Child combinator &lt;code&gt;A &amp;gt; B&lt;/code&gt; {#child}&lt;/h3&gt;
&lt;p&gt;The greater-than combinator (&lt;code&gt;A &amp;gt; B&lt;/code&gt;) selects element &lt;code&gt;B&lt;/code&gt; that is a direct descendant of element &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So while &lt;code&gt;A B&lt;/code&gt; selects &lt;code&gt;B&lt;/code&gt; at any level of nesting inside &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;A &amp;gt; B&lt;/code&gt; selects only the &lt;code&gt;B&lt;/code&gt; elements that are direct descendants of &lt;code&gt;A&lt;/code&gt; — its &quot;children.&quot;&lt;/p&gt;
&lt;p&gt;Take an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;
  &amp;lt;p class=&quot;a&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;b&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;c&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;      
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.box &amp;gt; .a&lt;/code&gt; selector picks only the &lt;code&gt;&amp;lt;p class=&quot;a&quot;&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;More examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.heading &amp;gt; span&lt;/code&gt; — all &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements that are direct descendants of elements with the &lt;code&gt;heading&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1 &amp;gt; em&lt;/code&gt; — all &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; elements that are direct descendants of an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.box ol &amp;gt; li p&lt;/code&gt; — all &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements that are descendants of &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;, where &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; must be a direct descendant of &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt; and a descendant at any level of an element with the &lt;code&gt;.box&lt;/code&gt; class.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whitespace around the child combinator is optional. &lt;code&gt;h1 &amp;gt; em&lt;/code&gt; and &lt;code&gt;h1&amp;gt;em&lt;/code&gt; are identical. The spaced form is preferred for readability.&lt;/p&gt;
&lt;h3&gt;Next-sibling combinator &lt;code&gt;A + B&lt;/code&gt; {#next-sibling}&lt;/h3&gt;
&lt;p&gt;The plus combinator (&lt;code&gt;A + B&lt;/code&gt;) selects element &lt;code&gt;B&lt;/code&gt; that is an adjacent sibling of &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The elements represented by both selectors share the same parent in the document tree, and the element represented by the first (&lt;code&gt;A&lt;/code&gt;) immediately precedes the element represented by the second (&lt;code&gt;B&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;
  &amp;lt;p class=&quot;a&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;b&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;c&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;      
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.a + p&lt;/code&gt; selector picks only the &lt;code&gt;&amp;lt;p class=&quot;b&quot;&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;More examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;h1 + p&lt;/code&gt; — the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element that immediately follows each &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1.heading + h2&lt;/code&gt; — the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; element that immediately follows each &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; with the &lt;code&gt;heading&lt;/code&gt; class.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Spaces are again optional. &lt;code&gt;h1 + p&lt;/code&gt; is the same as &lt;code&gt;h1+p&lt;/code&gt;, but prefer the former.&lt;/p&gt;
&lt;h3&gt;Subsequent-sibling combinator – &lt;code&gt;A ~ B&lt;/code&gt; {#subsequent-sibling}&lt;/h3&gt;
&lt;p&gt;The tilde combinator (&lt;code&gt;A ~ B&lt;/code&gt;) selects element &lt;code&gt;B&lt;/code&gt; that is a sibling of &lt;code&gt;A&lt;/code&gt; but does not immediately follow it.&lt;/p&gt;
&lt;p&gt;Both elements share the same parent. The difference from &lt;code&gt;A + B&lt;/code&gt; is that with the tilde combinator the elements need not be adjacent.&lt;/p&gt;
&lt;p&gt;Back to the example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;
  &amp;lt;p class=&quot;a&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;b&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p class=&quot;c&quot;&amp;gt;&amp;lt;span class=&quot;a&quot;&amp;gt;…&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;      
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.a ~ p&lt;/code&gt; selector picks the &lt;code&gt;&amp;lt;p class=&quot;b&quot;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;p class=&quot;c&quot;&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;
&lt;p&gt;More examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;h1 ~ p&lt;/code&gt; — all &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements that share the same parent as &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h1.heading ~ h2&lt;/code&gt; — all &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; elements that share the same parent as an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; with the &lt;code&gt;heading&lt;/code&gt; class.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Spaces in the selector are again optional.&lt;/p&gt;
&lt;h2&gt;Browser support {#support}&lt;/h2&gt;
&lt;p&gt;All the CSS selectors I mention here are fully supported in every browser, including MSIE. The only exception is the case-sensitivity flag (&lt;code&gt;[title=Hello s]&lt;/code&gt;), which you won&apos;t get working in that old browser.&lt;/p&gt;
&lt;p&gt;There is, however, one group of selectors — mentioned in the Selectors Level 4 specification — that has no support.&lt;/p&gt;
&lt;h3&gt;Column selectors – &lt;code&gt;A || B&lt;/code&gt; {#column}&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;A || B&lt;/code&gt; — the column combinator. It selects element &lt;code&gt;A&lt;/code&gt; belonging to column &lt;code&gt;B&lt;/code&gt;. See, for example, &lt;code&gt;col.selected || td&lt;/code&gt; in tables.&lt;/p&gt;
&lt;p&gt;It would be useful to have such a selector, but no browser supports it yet, just like the similarly focused &lt;code&gt;:nth-col()&lt;/code&gt; and &lt;code&gt;:nth-last-col()&lt;/code&gt; pseudo-classes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/mdn-css_selectors_column&quot;&gt;CanIUse.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/selectors-4/#table-pseudos&quot;&gt;Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the continuation of this text, I&apos;ll focus on &lt;a href=&quot;https://www.vzhurudolu.cz/prirucka/css-pseudotridy&quot;&gt;pseudo-classes in CSS&lt;/a&gt;, which are really just slightly peculiar selectors.&lt;/p&gt;
</content:encoded></item><item><title>Inbox Zero: How to Escape Email Chaos for Good</title><link>https://michalek.blog/guide/email-inbox-zero/</link><guid isPermaLink="true">https://michalek.blog/guide/email-inbox-zero/</guid><description>A practical, battle-tested system for clearing your inbox, cutting stress, and staying on top of email without living inside it.</description><pubDate>Sun, 14 Jun 2026 10:53:50 GMT</pubDate><content:encoded>&lt;h1&gt;Inbox Zero: how to escape email chaos&lt;/h1&gt;
&lt;p&gt;Email doesn&apos;t have to be a source of dread. Your inbox doesn&apos;t have to overflow with marketing newsletters, half-finished threads, and irrelevant noise. It doesn&apos;t have to be full at all. And you don&apos;t have to keep forgetting things and letting people slip through the cracks.&lt;/p&gt;
&lt;p&gt;You don&apos;t have to feel a small pang of guilt every single time you remember your inbox exists.&lt;/p&gt;
&lt;p&gt;I know two ways out. The first is to pretend email doesn&apos;t exist. The second is &lt;strong&gt;Inbox Zero&lt;/strong&gt;, a method for processing email systematically.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/inbox-zero-main.jpg&quot; width=&quot;1600&quot; height=&quot;900&quot; alt=&quot;An empty, calm inbox — what Inbox Zero feels like&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;This is what we all want. Sometimes it&apos;s enough to switch off the badge on the app icon. Sometimes you need more — a method.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Why email still deserves your respect {#e-mail-vyhody}&lt;/h2&gt;
&lt;p&gt;Among some professionals, email has earned such a bad reputation that they flee to real-time chat tools (Slack, Teams, instant messaging in general) or pick up the phone for every little thing. Sooner or later, that leads to forgotten decisions, people left out of the loop, and general communication chaos.&lt;/p&gt;
&lt;p&gt;Email has real strengths. The recipient shouldn&apos;t expect an instant reply, so you get time to think. Conversations leave a searchable, permanent record. Email isn&apos;t as built for interruption as IM, which makes it far friendlier to &lt;a href=&quot;https://www.vzhurudolu.cz/podcast/75-hluboka-prace&quot;&gt;deep work&lt;/a&gt;. And everyone has an email address — even people who barely use it — which makes it the one truly universal platform.&lt;/p&gt;
&lt;p&gt;Email simply complements every other channel beautifully. I&apos;d go so far as to call it the essential cornerstone of online communication. It has a bad name, but maybe only because people use it badly.&lt;/p&gt;
&lt;p&gt;For me, the manual for using email well is called Inbox Zero. What surprised me is how few people actually know and use the method.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/inbox-zero-stats.jpg&quot; width=&quot;1600&quot; height=&quot;900&quot; alt=&quot;A tongue-in-cheek statistic about Inbox Zero&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Rigorous scientific research has shown that the overwhelming majority of people appreciate an article about Inbox Zero.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;That&apos;s part of why this article exists. Let&apos;s get into it.&lt;/p&gt;
&lt;h2&gt;What is Inbox Zero? {#inbox-zero}&lt;/h2&gt;
&lt;p&gt;Inbox Zero is a method whose goal is to process and organize incoming email efficiently. The aim is to keep your inbox regularly empty — or close to it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.43folders.com/43-folders-series-inbox-zero&quot;&gt;Inbox Zero&lt;/a&gt; was invented and popularized in the 2000s by &lt;a href=&quot;http://www.merlinmann.com/&quot;&gt;Merlin Mann&lt;/a&gt;, a productivity expert.&lt;/p&gt;
&lt;p&gt;In practice, by the book, it looks roughly like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At least once a day, you give your inbox dedicated time.&lt;/li&gt;
&lt;li&gt;You go through your messages, and each action follows the four Ds (Do, Delegate, Defer, Delete).&lt;/li&gt;
&lt;li&gt;You then either archive or delete each message.&lt;/li&gt;
&lt;li&gt;Profit! The inbox is clean.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main point of Inbox Zero is to lower the stress that comes with email, raise your productivity, and keep a sense of control over your communication.&lt;/p&gt;
&lt;p&gt;The marketing pitch is that the goal is to keep both your mind and your inbox clear.&lt;/p&gt;
&lt;p&gt;That&apos;s accurate. Genuinely.&lt;/p&gt;
&lt;p&gt;In the rest of this article I&apos;ll expand on that and add my own experience.&lt;/p&gt;
&lt;p&gt;I&apos;ve personally used Inbox Zero for about ten years. I&apos;d guess I switched over when &lt;a href=&quot;https://en.wikipedia.org/wiki/Inbox_by_Gmail&quot;&gt;Google Inbox&lt;/a&gt; arrived — the now-defunct, innovative Gmail alternative that, among other things, catered to Inbox Zero enthusiasts.&lt;/p&gt;
&lt;p&gt;These days I&apos;m back on plain Gmail, but more or less any email client will do the job.&lt;/p&gt;
&lt;p&gt;What does Inbox Zero give me? Less stress from an overflowing inbox, less fear of falling behind, less forgetting, faster retrieval of information. Easier, more systematic organization of my work.&lt;/p&gt;
&lt;h2&gt;How I work and which tools I use {#komunikace}&lt;/h2&gt;
&lt;p&gt;Before we get into concrete, practical tips, I feel the need to put my version of Inbox Zero into a bit of context.&lt;/p&gt;
&lt;p&gt;How do I work? I&apos;m a freelancer; my specialty is &lt;a href=&quot;https://www.vzhurudolu.cz/martin&quot;&gt;web performance consulting&lt;/a&gt;, but the bulk of my work today is more or less management. With three colleagues I run consulting under the &lt;a href=&quot;https://pagespeed.one/&quot;&gt;PageSpeed.ONE&lt;/a&gt; brand, where we have around fifty clients. As part of another team I help develop a &lt;a href=&quot;https://pagespeed.one/app/&quot;&gt;speed tester&lt;/a&gt;. I also help run a developer community and occasionally write articles or &lt;a href=&quot;https://www.vzhurudolu.cz/ebooky&quot;&gt;ebooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I get around a hundred emails a day, plus messages on social media, in IM tools, and so on. It&apos;s quite a lot, and without a method I&apos;d be sunk.&lt;/p&gt;
&lt;p&gt;I use a ton of communication channels, like most people. Here&apos;s how I relate to each of them in the context of my take on Inbox Zero.&lt;/p&gt;
&lt;h3&gt;Email (Gmail) {#komunikace-email}&lt;/h3&gt;
&lt;p&gt;Email is my main communication hub. Every notification I could route there — mostly from Basecamp, our project management tool — lands in email. But I don&apos;t visit often, just a few times a day. Notifications are off. I use Gmail.&lt;/p&gt;
&lt;h3&gt;IM (Slack) {#komunikace-im}&lt;/h3&gt;
&lt;p&gt;We use Slack for real-time team communication. IM is essential for the occasional blocker or problem that genuinely can&apos;t wait.&lt;/p&gt;
&lt;p&gt;We also have lower-priority channels just for chatting. I keep Slack notifications on only in the afternoon, when I&apos;m not doing deep work, though I do peek in sometimes in the morning. The same goes for WhatsApp, Messenger, iMessage, and the rest of my personal communication.&lt;/p&gt;
&lt;p&gt;If it&apos;s not on fire, I don&apos;t reply immediately. With the exception of my wife and kids, of course.&lt;/p&gt;
&lt;h3&gt;Phone {#komunikace-tel}&lt;/h3&gt;
&lt;p&gt;I use the phone very little, but it occasionally comes in handy for explaining more complicated — or rather moderately complicated — topics.&lt;/p&gt;
&lt;p&gt;Some clients are very phone-oriented, and I try to respect that. Luckily I rarely have real emergencies and disasters at work, so I can usually pick up without fear of a major interruption and without stress.&lt;/p&gt;
&lt;p&gt;After a long stretch of communicating only by email, you can get a feeling I call &quot;emotional disconnection,&quot; so sometimes it&apos;s good to meet up or at least call. The phone is, after meeting in person, the most human form of communication for me. But I&apos;d rather meet people than call them.&lt;/p&gt;
&lt;h3&gt;Video calls {#komunikace-call}&lt;/h3&gt;
&lt;p&gt;Online meetings (or, more aptly, &quot;calls&quot;) have all but replaced in-person meetings in my field, and honestly that suits me. I&apos;m in regular contact with most clients. Every now and then I prefer to meet in person. But it&apos;s getting harder and harder to push for in-person work meetings, don&apos;t you think?&lt;/p&gt;
&lt;p&gt;So much for the wider context of how I communicate. Now, on to email and Inbox Zero. Before we begin, we need to meet a few prerequisites.&lt;/p&gt;
&lt;h2&gt;Prerequisite one: dedicated, limited time — say, after lunch {#predpoklad-1}&lt;/h2&gt;
&lt;p&gt;It&apos;s going to cost you time. There&apos;s no way around it. Make your peace with it. Emails in your inbox are waiting, and they don&apos;t have legs. They won&apos;t walk away and they won&apos;t resolve themselves unless you give them time. You have to set that time aside.&lt;/p&gt;
&lt;p&gt;Some methods recommend dealing with email as fast as possible, or maybe once an hour, but personally that would kill me. I give email attention only a few times a day. It works roughly like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the morning I don&apos;t look at the inbox at all. I&apos;m deep in focused work, sorry.&lt;/li&gt;
&lt;li&gt;After lunch I give email half an hour to forty-five minutes. That&apos;s my main Inbox Zero block.&lt;/li&gt;
&lt;li&gt;In the afternoon I&apos;m doing more managerial work; I peek into email occasionally and reply now and then so nothing gets stuck on me, but most of it I push to the next day anyway.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That half hour to forty-five minutes after lunch is in my daily schedule and I plan around it. There&apos;s no conjuring it out of thin air if my day is packed with other tasks.&lt;/p&gt;
&lt;p&gt;I normally log email processing in Toggl as work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Communication within PageSpeed.ONE projects I track as team management.&lt;/li&gt;
&lt;li&gt;More complex, advisory emails to clients I track as paid work for them.&lt;/li&gt;
&lt;li&gt;For all other email I have a &quot;Communication&quot; label, and I try to keep it under about 30 minutes a day. That covers unpaid client communication, various newsletters, anything around my own brand, the occasional personal email, and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice that I deal with email after lunch. Yes, that&apos;s usually when I&apos;m most tired in the whole day — and email also doesn&apos;t demand much of my brain capacity.&lt;/p&gt;
&lt;h2&gt;What about the other prerequisites? You&apos;ll want to tweak your email settings {#predpoklad-2}&lt;/h2&gt;
&lt;p&gt;Let&apos;s move on to the next step: reconfiguring everything so it&apos;s as un-annoying as possible and all in one place.&lt;/p&gt;
&lt;h3&gt;No notifications {#predpoklad-2-notifikace}&lt;/h3&gt;
&lt;p&gt;I&apos;m a genuinely big opponent of real-time notifications and the drudgery of dealing with them as they arrive. The only things that actually buzz at me are text-message alerts and the occasional important IM from family. Email gets no exception.&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/inbox-zero-badge.jpg&quot; width=&quot;1600&quot; height=&quot;900&quot; alt=&quot;A notification badge on a mobile email client&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;A clear mind with this on your phone? Where on earth do you switch the thing off?! (&lt;a href=&quot;https://unsplash.com/photos/X8ejw0g0C_g&quot;&gt;Unsplash&lt;/a&gt;)&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;I&apos;ve even turned off the little badges showing unread counts on every app icon. And yet, thanks to Inbox Zero, I still handle most emails within 24 hours.&lt;/p&gt;
&lt;h3&gt;Everything in one place {#predpoklad-2-jedno}&lt;/h3&gt;
&lt;p&gt;All my mailboxes, including the historical ones, forward into a single, most-current inbox that I actually use.&lt;/p&gt;
&lt;p&gt;In Gmail I&apos;ve disabled tabs like Promotions and Social. If it&apos;s meant to reach me, let it go straight to the inbox — including newsletters, of which I subscribe to somewhere between five and ten, and that still feels like a lot.&lt;/p&gt;
&lt;p&gt;I don&apos;t subscribe to promotional mail at all, nor to notifications from social networks. Whatever happens on social media can stay there. I do check in occasionally — actually, unhealthily often, ahem.&lt;/p&gt;
&lt;p&gt;I also barely use labels and categories in Gmail. The only exception is automated messages from various tools, like Google Search Console, because those can&apos;t be routed to Slack or another sensible place where our work notifications land.&lt;/p&gt;
&lt;h3&gt;Reasonable email length {#predpoklad-2-delka}&lt;/h3&gt;
&lt;p&gt;I used to write long messages. I notice this is common among (former) developers. These days I have an aversion to it, so if you send me a long email, you&apos;ll probably wait a while for a reply — or I&apos;ll just call you.&lt;/p&gt;
&lt;p&gt;I try to hold the line on my own side too. I like methods, or rather descriptions of the ideal email, like &lt;a href=&quot;http://five.sentenc.es/&quot;&gt;Five.sentenc.es&lt;/a&gt;. Try to cram everything into five sentences. It won&apos;t always work, but it&apos;s a great exercise in brevity. For less experienced writers, it&apos;s worth learning the &lt;a href=&quot;https://www.intercom.com/blog/how-to-send-the-perfect-message-with-the-five-ws/&quot;&gt;Five Ws method&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So how should you go through your inbox each day? Different people do it differently, and I don&apos;t want to force anything on anyone, so I can only offer my own process. For inspiration.&lt;/p&gt;
&lt;h2&gt;Step 1: prioritize {#krok-1}&lt;/h2&gt;
&lt;p&gt;I scan the emails with my eyes and start with the easiest ones. The point is to build momentum early. Let&apos;s be honest — processing email usually isn&apos;t the most thrilling part of the day.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generally I first go through the team&apos;s internal messages, which means clearing all the Basecamp email notifications. I log that as its own time block.&lt;/li&gt;
&lt;li&gt;Second come the other emails that can be handled quickly, in under a minute each. I log this as a separate &quot;Communication&quot; item. While I&apos;m at it, I often clear various social notifications too.&lt;/li&gt;
&lt;li&gt;Third are the specific, more complex emails I can track as dedicated time, usually for a particular client. These are mostly quick advice, a reminder of priorities, or pulling some data and sending an illustration.&lt;/li&gt;
&lt;li&gt;Fourth are the emails I already know I won&apos;t get to. They&apos;re usually low priority. I defer those to the next day. There&apos;s about a tenth of them each day.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step 2: act {#krok-2}&lt;/h2&gt;
&lt;p&gt;Something needs to happen with every email, and we can&apos;t just delete them all, can we…&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/inbox-zero-schema.jpg&quot; width=&quot;1600&quot; height=&quot;900&quot; alt=&quot;A diagram of how Inbox Zero works&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;A simplified — and still complicated — diagram. And really it&apos;s such a simple thing, isn&apos;t it?&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;The original Inbox Zero method works with these &quot;D&quot; actions; I&apos;ve tweaked them a bit with my own experience:&lt;/p&gt;
&lt;h3&gt;Delete {#krok-2-smazat}&lt;/h3&gt;
&lt;p&gt;If an email isn&apos;t relevant or doesn&apos;t require action, just delete it. It probably came just for your information, or not even that. For me this splits further into two different actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Delete&lt;/strong&gt; — emails I won&apos;t need to archive. They contain no important information, or they&apos;re just a duplicate of a Basecamp message (or another tool) where it&apos;ll be searchable anyway. Even so, it&apos;s good to respond somehow, so the people on the other end know you&apos;ve seen it. Emoji reactions in Basecamp are great for this. Email doesn&apos;t offer that yet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Archive&lt;/strong&gt; — messages or threads that contain important information. I archive most messages rather than delete them. As a result, I know what nonsense I wrote to whom eight or ten years ago. You want that.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Delegate {#krok-2-delegovat}&lt;/h3&gt;
&lt;p&gt;If an email requires action but you&apos;re not the right person to deal with it, delegate it to the right person or team.&lt;/p&gt;
&lt;p&gt;For me that means adding or updating an appropriate task for my colleagues. I don&apos;t actually delegate much, though, because our responsibilities are fairly well divided and we all know what we&apos;re supposed to do.&lt;/p&gt;
&lt;h3&gt;Do {#krok-2-vyridit}&lt;/h3&gt;
&lt;p&gt;If an email needs a quick, simple action you can finish within a few minutes, I do it right away. Reply, perform the requested action, whatever it is. This is where you&apos;ll feel like you actually got something done. Is it more than a minute or two of work? Then I track the time for the client.&lt;/p&gt;
&lt;h3&gt;Defer {#krok-2-odsunout}&lt;/h3&gt;
&lt;p&gt;For emails that need more time or effort but that you can&apos;t get to right now, set them aside for later. Use your task list or the snooze feature in your email client. They&apos;ll disappear from view, at least for now.&lt;/p&gt;
&lt;h3&gt;Deter {#krok-2-odmitnout}&lt;/h3&gt;
&lt;p&gt;Emails that are spam or irrelevant — just mark them as spam or unsubscribe. This one is especially satisfying.&lt;/p&gt;
&lt;h2&gt;Step 3: profit! {#krok-3-profit}&lt;/h2&gt;
&lt;p&gt;You&apos;re done. Every day you&apos;ll be rewarded with the sight of an empty inbox:&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;
&amp;lt;img src=&quot;../dist/images/original/inbox-zero-gmail.jpg&quot; width=&quot;1600&quot; height=&quot;900&quot; alt=&quot;Inbox Zero in Gmail&quot;&amp;gt;
&amp;lt;figcaption markdown=&quot;1&quot;&amp;gt;
&lt;em&gt;Peace and quiet right here.&lt;/em&gt;
&amp;lt;/figcaption&amp;gt;
&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;It&apos;s a good feeling. It doesn&apos;t have to be perfect right away. Mine isn&apos;t perfect either, even after all these years. But it helps. Give Inbox Zero a try.&lt;/p&gt;
</content:encoded></item><item><title>On Writing: How to Start and Never Stop</title><link>https://michalek.blog/guide/writing/</link><guid isPermaLink="true">https://michalek.blog/guide/writing/</guid><description>A practical, motivational guide to building a writing habit, beating blank-page fear, and getting into flow — from someone who&apos;s written for 30 years.</description><pubDate>Sun, 14 Jun 2026 10:53:50 GMT</pubDate><content:encoded>&lt;h1&gt;On writing: how to start and never stop&lt;/h1&gt;
&lt;p&gt;Start writing. Just start. Right now. Or once you&apos;ve finished this article.&lt;/p&gt;
&lt;p&gt;Writing will deepen your knowledge and help the people around you. Writing will build your reputation.&lt;/p&gt;
&lt;p&gt;But the best thing about writing is something else entirely. You can work your way into an incredible state of flow. You&apos;ll enjoy the act of writing itself. And you&apos;ll keep wanting to come back to it.&lt;/p&gt;
&lt;p&gt;It&apos;s possible that writing isn&apos;t for you — I can&apos;t rule that out. But it&apos;s also possible that you&apos;re just approaching the process the wrong way. That&apos;s why this article exists. To help you.&lt;/p&gt;
&lt;p&gt;You already have things to write about. Everyone does. The subject is you, your life, your friends, your family, your work. Something happens every day, and if you want it to, every day teaches you something. You can even get a &lt;a href=&quot;https://www.linkedin.com/posts/martinmichalek_dejte-si-na-sv%C3%A9-v%C4%9Bci-pozor-a-poctiv%C4%9B-z%C3%A1lohujte-activity-7161265988494090240-GqBm/&quot;&gt;story&lt;/a&gt; out of an ordinary trip across town.&lt;/p&gt;
&lt;p&gt;It&apos;ll surprise you how useful or interesting your knowledge, experience, comments, or anecdotes can be to others.&lt;/p&gt;
&lt;p&gt;Only a handful of people write about any given field, any given topic. Finding a niche where nobody else is standing is easy.&lt;/p&gt;
&lt;p&gt;Writing is thinking. It lets you formulate your ideas, communicate better, and get better at what you do.&lt;/p&gt;
&lt;p&gt;Write concisely, cut the filler. When you don&apos;t know how to start, start in the middle.&lt;/p&gt;
&lt;p&gt;The difference between someone average and an expert is often simply that the expert writes.&lt;/p&gt;
&lt;p&gt;I&apos;ve been writing for almost 30 years. Did I have a talent for it? I don&apos;t think so. My first texts were terrible. I just wrote about what I enjoyed. And kept thinking about how to do it better next time.&lt;/p&gt;
&lt;p&gt;Let me try to sum up what I think about writing and how you could get started too.&lt;/p&gt;
&lt;h2&gt;Why write at all? {#why-write}&lt;/h2&gt;
&lt;p&gt;There are plenty of reasons to write. But the best one is to find your way into a state where you simply enjoy it.&lt;/p&gt;
&lt;h3&gt;Sharpening your knowledge {#knowledge}&lt;/h3&gt;
&lt;p&gt;Writing sharpens your knowledge, because writing is thinking. Having to formulate your ideas forces you to actually think about the topic. Having to back up your claims with examples, data, or illustrations forces you to do research. That&apos;s how you get better at the subject.&lt;/p&gt;
&lt;p&gt;Yes, you do have to actually do the thing you&apos;re writing about. If you want to &lt;a href=&quot;https://www.vzhurudolu.cz/&quot;&gt;write about web development&lt;/a&gt;, you can&apos;t know nothing about it. But thanks to writing, within a few hours you&apos;ll become noticeably better at it than most other people.&lt;/p&gt;
&lt;h3&gt;Sharing knowledge and building a reputation {#reputation}&lt;/h3&gt;
&lt;p&gt;When you want to help one person, you explain it to them. When you want to help more people, you write it down. It&apos;s tempting once you realize you can help hundreds or thousands of people at once.&lt;/p&gt;
&lt;p&gt;It&apos;s addictive when people start writing to you with positive feedback.&lt;/p&gt;
&lt;p&gt;We mostly write for free, but you can still get something out of it. A reputation, for instance. That always comes in handy, whether you eventually turn it into money or not. But that&apos;s a topic for another time.&lt;/p&gt;
&lt;h3&gt;Flow like nothing else {#flow}&lt;/h3&gt;
&lt;p&gt;This is actually the most important part, because you don&apos;t have to write for the people out there — you can write mainly for yourself.&lt;/p&gt;
&lt;p&gt;For me, flow is the main reason I write almost every day. With most pieces I drop into a state where the world disappears and the writing just pulls me in. It&apos;s a drug.&lt;/p&gt;
&lt;p&gt;Tomorrow I&apos;ll want it again.&lt;/p&gt;
&lt;h2&gt;Can you write too? {#can-you-write}&lt;/h2&gt;
&lt;p&gt;By now you know I enjoy writing. I talk about writing with people, and I see that almost everyone would like to write something now and then — but they&apos;ve got a pile of obstacles in the way. Let&apos;s look at them. Maybe we can jump over them together.&lt;/p&gt;
&lt;h3&gt;&quot;I have no talent&quot; {#talent}&lt;/h3&gt;
&lt;p&gt;Maybe so. We&apos;re either born with talent or we&apos;re not. Some people have writing in their blood; others have something else.&lt;/p&gt;
&lt;p&gt;But people usually underestimate how far talent can be replaced by practice.&lt;/p&gt;
&lt;p&gt;Somewhere in our heads we all have a muscle that produces great writing. And we either train that muscle or we don&apos;t.&lt;/p&gt;
&lt;p&gt;Maybe some of you know me through my writing. Maybe you think I have a talent for it. But no, I don&apos;t think it was ever there. My high-school language teacher could explain that to you. My writing was pretty bad until I started training the writing muscle. Now it&apos;s a decent bicep.&lt;/p&gt;
&lt;p&gt;Does my younger son have talent? When he texts me, I suffer, and I usually can&apos;t understand him at all. But in fourth grade he wanted to try writing a sci-fi novella. He started, dropped into flow, and finished it.&lt;/p&gt;
&lt;p&gt;His work, &quot;AI Destroys the World,&quot; had an idea and a plot. But it was unreadable, because it was riddled with mistakes. One prompt in ChatGPT fixed that, cleaning up the errors and the text overall. Suddenly an eleven-year-old turned out to be a fairly talented young writer.&lt;/p&gt;
&lt;p&gt;The novella ended with what I consider the greatest closing line of any book ever:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the end, though, it all turned out fine. Relationships were mended, the machines were repaired, and the president&apos;s grave was also restored. It was a tough seven years.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Does he have talent? I still don&apos;t know. It doesn&apos;t actually matter. Talent is overrated. We also have tools now. And then there&apos;s training the muscle.&lt;/p&gt;
&lt;h3&gt;&quot;I was bad at it in school&quot; {#school}&lt;/h3&gt;
&lt;p&gt;Almost anyone can say this, myself included. School generally isn&apos;t great at teaching practical skills. None of the writing habits I&apos;ve built came from a classroom — and that&apos;s true for most writers I know. So it&apos;s no wonder teachers don&apos;t really know how to teach writing.&lt;/p&gt;
&lt;p&gt;Teachers are, at best, theorists of writing. They couldn&apos;t write, and they couldn&apos;t teach you to.&lt;/p&gt;
&lt;p&gt;Writing in practice turns out to be something completely different from what we remember from school.&lt;/p&gt;
&lt;p&gt;So you can forget the misery of writing in school, with one exception: the outline. Writing an outline before you write is genuinely useful. The teachers were right to push it on you. I&apos;ll come back to the outline later.&lt;/p&gt;
&lt;h3&gt;&quot;It won&apos;t be good, people will criticize me&quot; {#criticism}&lt;/h3&gt;
&lt;p&gt;Yes, your first attempts won&apos;t be good. But iterate, and think about how to do it better the second time.&lt;/p&gt;
&lt;p&gt;Or try rewriting the whole thing a week later. It&apos;ll be better, you&apos;ll see.&lt;/p&gt;
&lt;p&gt;That perfectionist inside us, forbidding us from publishing an &quot;imperfect&quot; piece… Or is it more like fear? Fear that someone will tell you your writing is bad? Fear of embarrassing yourself?&lt;/p&gt;
&lt;p&gt;Let me tell you something. I&apos;ve written a lot. Every week I write something for social media, and almost every week a longer piece. I&apos;ve written &lt;a href=&quot;https://www.vzhurudolu.cz/ebooky&quot;&gt;four books&lt;/a&gt;. I&apos;ve had a lot of reactions, and sometimes they genuinely thrill me.&lt;/p&gt;
&lt;p&gt;But one thing has never happened — nobody has ever come up to me and said one of my pieces was truly awful.&lt;/p&gt;
&lt;p&gt;The worst thing that&apos;s ever happened with my writing is that an article didn&apos;t get as many readers as I expected. It didn&apos;t spark interest. Or a post of mine got no likes. Really. Nothing worse is waiting for you, either.&lt;/p&gt;
&lt;p&gt;I think people are generally good at separating the text from the author. They&apos;ll read your piece, maybe they won&apos;t like it, but that&apos;s no reason to connect it to you.&lt;/p&gt;
&lt;p&gt;People only remember the good pieces. Can you actually recall some truly terrible thing you read recently? Probably not. You didn&apos;t finish it. And you forgot the author long ago.&lt;/p&gt;
&lt;h3&gt;&quot;I don&apos;t know what to write about&quot; {#topic}&lt;/h3&gt;
&lt;p&gt;You don&apos;t — but you can. That&apos;s a skill you can learn, like any other.&lt;/p&gt;
&lt;p&gt;Take the skill of driving home. Did you always know how to get home by car from somewhere new? No, you had to learn it. Or you had to learn to use a tool, like Google Maps.&lt;/p&gt;
&lt;p&gt;In the same way, you can learn how to figure out what to write about.&lt;/p&gt;
&lt;p&gt;Let&apos;s try it in practice. What did you learn at work today? That&apos;s generally a good topic. People usually overestimate how much everyone else knows. Unless you&apos;re a complete beginner in your field, if you learned something at work, it&apos;s probably interesting to the rest of us too. Write about it.&lt;/p&gt;
&lt;p&gt;But you can write an interesting article even when you&apos;re just starting out in a field — as long as you can explain something in a way nobody else has yet.&lt;/p&gt;
&lt;p&gt;The vast majority of people never write anything, precisely because they assume the result will be pointless. Maybe it&apos;s pointless to you, because you already know it. You just learned it. But it&apos;ll surprise you how many people out there will be grateful for what you know.&lt;/p&gt;
&lt;p&gt;I sometimes don&apos;t know what to write about either, but I have tools. I keep a notes database (I use Evernote) where I log topics I&apos;d like to write about someday. I keep adding to those notes as I read new articles or pick up new information from client work.&lt;/p&gt;
&lt;p&gt;When I&apos;m stuck for a topic, I check my notes. And I always discover I actually have an enormous backlog of things I want to write.&lt;/p&gt;
&lt;p&gt;But you don&apos;t have to write only about your work. Something happens to you every day, your opinions surface every day, something funny pops into your head every day. Something interesting happens every day, even when you&apos;re not traveling anywhere.&lt;/p&gt;
&lt;p&gt;You just have to look at the world the right way.&lt;/p&gt;
&lt;p&gt;Every time something interesting happens, a piece I could write about it is already popping into my head. That, too, is a skill you can learn.&lt;/p&gt;
&lt;h3&gt;&quot;Writing is torture for me&quot; {#torture}&lt;/h3&gt;
&lt;p&gt;I once &lt;a href=&quot;https://x.com/machal/status/1805695060639728124&quot;&gt;wrote&lt;/a&gt; on X:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To remind myself how painful writing an article is for some people, I decided to fix my bike myself. &quot;I&apos;ll have it done in half an hour.&quot;
Most of Sunday gone. The bike is more broken than before. Now I&apos;m looking for a repair shop.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, I can imagine that for someone, fixing a bike is just fun work they do every day. Not for me. But I believe it isn&apos;t fun for me only because I&apos;ve spent very little of my life fixing bikes.&lt;/p&gt;
&lt;p&gt;I believe I could get the same pleasure from fixing a bike as I get from writing this article. I&apos;d just have to train the muscle.&lt;/p&gt;
&lt;p&gt;Writing is torture for a lot of people. It&apos;s possible they&apos;ll simply never get the hang of it. But it&apos;s also possible they just don&apos;t practice much and are going about it the wrong way.&lt;/p&gt;
&lt;h3&gt;&quot;Isn&apos;t writing obsolete by now?&quot; {#obsolete}&lt;/h3&gt;
&lt;p&gt;This is something I often debate with younger people. &quot;Why write books when nobody reads them anymore?&quot; &quot;Why agonize over an article when you could film it and turn it into a reel?&quot; they tell me.&lt;/p&gt;
&lt;p&gt;Yes, to some extent that&apos;s true, and to some extent people read less online these days. It&apos;s partly a generational thing.&lt;/p&gt;
&lt;p&gt;On the other hand — text is not a dead format. Really, it isn&apos;t.&lt;/p&gt;
&lt;p&gt;The book market may have its best years behind it, but online, people still read a lot.&lt;/p&gt;
&lt;p&gt;What&apos;s changed are the expectations. Generic rambling on a topic that&apos;s been written about a million times, in the format of a dissertation like twenty years ago, no longer flies.&lt;/p&gt;
&lt;p&gt;Shorter pieces work today. Pieces enriched with photos, examples, interactive demos, quotes, tables… work.&lt;/p&gt;
&lt;p&gt;The best pieces are the ones with little text and a lot of everything else.&lt;/p&gt;
&lt;p&gt;But if people care about the topic and you give it good form, they&apos;ll read even a really long piece — and one without images, like this one. If you&apos;re still reading, you&apos;re proof.&lt;/p&gt;
&lt;p&gt;Text has a huge advantage. You can consume it at your own pace. Some people scan the headings, some the images, some slow down on a particular point and focus on it. Video and audio don&apos;t offer that — there you&apos;re almost entirely at the mercy of the author&apos;s pace and style.&lt;/p&gt;
&lt;p&gt;Text is still the most searchable and scannable format there is.&lt;/p&gt;
&lt;p&gt;And besides… even if you want to film a reel, you&apos;ll probably need to organize your thoughts first. You&apos;ll do the research, draft a structure, maybe even a script. Then you film it. You&apos;ve actually done a big chunk of the writing process.&lt;/p&gt;
&lt;p&gt;Writing is thinking. And the result of writing doesn&apos;t have to be text.&lt;/p&gt;
&lt;h3&gt;&quot;…but ChatGPT…&quot; {#chatgpt}&lt;/h3&gt;
&lt;p&gt;With the arrival of AI (or rather, language models), a lot of people started to panic. Supposedly AI will replace writers.&lt;/p&gt;
&lt;p&gt;AI won&apos;t replace writers, but it will make some parts of the creative process easier.&lt;/p&gt;
&lt;p&gt;I use ChatGPT for research. I simply ask it what the piece should be about and ask about things I don&apos;t know. Of course, I then verify everything with a search engine.&lt;/p&gt;
&lt;p&gt;I use ChatGPT to check my drafts. What&apos;s missing? What&apos;s redundant? What might be hard to understand for a specific audience?&lt;/p&gt;
&lt;p&gt;I love ChatGPT, but I can&apos;t imagine it writing an article for me. AI doesn&apos;t have your context. It doesn&apos;t have your knowledge, your style, your imagination, your personality.&lt;/p&gt;
&lt;p&gt;Yes, an enormous volume of model-generated text is being produced, and will keep being produced. In some fields that&apos;ll be enough — generic news, for instance. But in specialized fields, or in creative writing? There&apos;ll be a lot of generated text, it&apos;ll be extremely similar, and therefore uninteresting to readers.&lt;/p&gt;
&lt;p&gt;So what can your added value be? Your knowledge and experience, your style, your personality. Just like now.&lt;/p&gt;
&lt;p&gt;I write more about working with AI on both code and text in &lt;a href=&quot;../guide/vibe-coding.md&quot;&gt;Vibe Coding: I&apos;ve built websites for 25 years, but the last two months were completely different&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So much for motivation and breaking through blocks. Now let&apos;s try actually writing something.&lt;/p&gt;
&lt;h2&gt;How to write {#how}&lt;/h2&gt;
&lt;p&gt;Pick a topic, build a structure. Trim that structure so the first draft takes you no more than an hour. Try to find the core message and write that first. Concisely, please.&lt;/p&gt;
&lt;h3&gt;Time to write {#time}&lt;/h3&gt;
&lt;p&gt;Put writing in your calendar, turn it into a habit, and don&apos;t write for too long in one sitting.&lt;/p&gt;
&lt;p&gt;Writing has to be repeated until it becomes a habit, otherwise you&apos;ll never write anything. I write every Monday through Wednesday, always in the first hour of the morning. Sometimes, when I&apos;m enjoying it, Thursday and Friday too. I have quiet, a clear head, and a topic prepared in advance. In those three hours I often write a whole article.&lt;/p&gt;
&lt;p&gt;I think writing for three hours or more in one stretch is nonsense. Fatigue catches up with you and it stops flowing. You burn out, or, losing perspective, you overcomplicate the article. Some people struggle to stay at the level the text actually needs. The longer they write, the deeper into the topic they go. You don&apos;t want that.&lt;/p&gt;
&lt;p&gt;That&apos;s why for years I&apos;ve split my work time into one-hour blocks followed by a break. Roughly like at school.&lt;/p&gt;
&lt;p&gt;I think it&apos;s very important to let the topic gradually form and settle in your head.&lt;/p&gt;
&lt;p&gt;I finish shorter articles in those three hours. On day one I do the research, prepare the structure, prepare the examples, and try the topic out in practice if I can. On day two, in the second hour, I write the whole thing. On day three, in the third hour, I just do proofreading, images, and publish the finished piece.&lt;/p&gt;
&lt;p&gt;Some articles, like this one, need more of those one-hour blocks — ten, maybe. But when an article is good, when I&apos;m enjoying it and drop into flow, I have no trouble finding another hour anytime. Then it isn&apos;t work, it&apos;s a joy.&lt;/p&gt;
&lt;p&gt;But it all starts with the time to write. One hour every morning. Or just some days of the week. Put it on your to-do list or in your calendar. If you don&apos;t create the time, your writing will be pushed aside by other obligations and will never happen.&lt;/p&gt;
&lt;h3&gt;The curse of the blank page {#blank-page}&lt;/h3&gt;
&lt;p&gt;Everyone knows it, even experienced writers. You have a topic, you&apos;ve done the research, and now there&apos;s a blank page in front of you. How on earth do you begin?!&lt;/p&gt;
&lt;p&gt;My recipe for this is simple. First, I always copy the outline I prepared earlier into the document. So when I start, the page isn&apos;t blank anymore.&lt;/p&gt;
&lt;p&gt;And now the main trick of experienced writers — you don&apos;t have to write from the beginning. The beginning is hard. Write something about the main load-bearing idea first. Try to develop it, answer the likely questions, add examples, and so on.&lt;/p&gt;
&lt;p&gt;Only then write the conclusion. And then you might realize the conclusion is actually a good beginning for the article, because it contains the summary.&lt;/p&gt;
&lt;h3&gt;Structure: put the important stuff up top, ask &quot;why?&quot; {#structure}&lt;/h3&gt;
&lt;p&gt;People do read online, but you have to win the battle for their attention. They&apos;re more patient with topics that interest them, or with authors they like. To boost your chances, make it easy for people to decide whether the text is for them or not.&lt;/p&gt;
&lt;p&gt;First, write down the main idea — or at least what the article is about, or some surprising thing you discovered. That has to be in the headline or the first paragraph. It&apos;s called the &lt;a href=&quot;https://en.wikipedia.org/wiki/Inverted_pyramid_(journalism)&quot;&gt;inverted pyramid&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When I write about technology, I always try to answer three basic questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;What?&quot; — what I&apos;m writing about right now.&lt;/li&gt;
&lt;li&gt;&quot;Why?&quot; — why it&apos;s interesting, important, useful, funny, or surprising to the reader.&lt;/li&gt;
&lt;li&gt;&quot;How?&quot; — how to try the topic out in practice.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &quot;how&quot; is important, don&apos;t forget it. People want to try out new knowledge as fast as possible, so I often add demos and practical applications to every article.&lt;/p&gt;
&lt;p&gt;There&apos;s nothing complicated about it. These three questions have been my main checklist the whole time I&apos;ve been writing.&lt;/p&gt;
&lt;p&gt;I used these three questions to write this very piece.&lt;/p&gt;
&lt;h3&gt;Short, punchy, with verbs, the way you speak {#form}&lt;/h3&gt;
&lt;p&gt;Everyone can write, because everyone can talk.&lt;/p&gt;
&lt;p&gt;In school they taught you to write so your language teacher would like it. But you can write differently — you can write the way you speak. The advantage is that nobody has to teach you this anymore.&lt;/p&gt;
&lt;p&gt;The second advantage is that it&apos;ll be far easier for readers to read.&lt;/p&gt;
&lt;p&gt;And then there&apos;s dictation. Dictation on a phone has come a long way, so a certain portion of my texts came about by dictating them into my phone. I then spent a long time editing, trimming, cleaning them up, sure. But dictation might be exactly the technology that helps you become a writer.&lt;/p&gt;
&lt;p&gt;Write so it reads well. People online don&apos;t like long sentences. People don&apos;t like long paragraphs. Every sentence can be shortened. I&apos;m doing it right now, and I assume that as a reader you don&apos;t mind at all.&lt;/p&gt;
&lt;p&gt;When you do write longer sentences, you can suddenly change the pace or highlight information by using one thing. A short sentence.&lt;/p&gt;
&lt;p&gt;When you want to emphasize a sentence, put it in its own paragraph.&lt;/p&gt;
&lt;p&gt;If information is important, it should be in a heading inside the article. I&apos;m not a fan of bolding text — to me it&apos;s a waste of attention. We have so many ways to highlight what matters: headings, sentences in their own paragraphs, bullet points, quotes, images, tables.&lt;/p&gt;
&lt;p&gt;Better than bolding text is putting the information in a heading or another form of media.&lt;/p&gt;
&lt;p&gt;When I do emphasize something inline, the way I&apos;d emphasize it in speech, I use &lt;em&gt;italics&lt;/em&gt;. Italics have the advantage of not pulling at the eyes, letting people read the text they chose smoothly.&lt;/p&gt;
&lt;p&gt;Use verbs. A sentence without a verb is harder to read and harder to grasp. You can use such a sentence differently. As an exclamation, an accent. Otherwise, don&apos;t write much like this, without verbs.&lt;/p&gt;
&lt;p&gt;Cut the filler. Nobody likes filler. When you reread your article, ask of every sentence whether it can be said more concisely and whether it even needs to be there at all.&lt;/p&gt;
&lt;h3&gt;You won&apos;t get far without feedback {#feedback}&lt;/h3&gt;
&lt;p&gt;Don&apos;t write for the drawer. A text comes alive only in another person&apos;s head, through their feedback.&lt;/p&gt;
&lt;p&gt;If you&apos;re afraid of the failure of public publishing, shrink your audience.&lt;/p&gt;
&lt;p&gt;Show your text to someone close to you. Ask them for their opinion or feedback.&lt;/p&gt;
&lt;p&gt;My friend &lt;a href=&quot;https://www.ilincev.com/&quot;&gt;Ondřej Ilinčev&lt;/a&gt;, who has written for a long time and writes brilliantly, got started by emailing his articles to just a few clients at a time.&lt;/p&gt;
&lt;p&gt;Another partner of mine, &lt;a href=&quot;https://robinpokorny.com/&quot;&gt;Robin Pokorný&lt;/a&gt;, writes among other places on his employer&apos;s internal blog.&lt;/p&gt;
&lt;p&gt;Blogs used to have comments everywhere. Those were the golden days, because most people focused on the actual problems in the text. Today blog comments mostly don&apos;t work anymore. They&apos;ve been replaced by comments on social media — but there are usually too few of them, which doesn&apos;t work for quality feedback. Or there are too many, and you don&apos;t want that either, because then they turn partly toxic and focus on the author themselves, or on something completely unrelated. Like the commenters&apos; worldview.&lt;/p&gt;
&lt;p&gt;Build yourself a safe environment of first readers. People who are kind to you, but who can also be honest.&lt;/p&gt;
&lt;p&gt;If you dare to venture a bit further out, try social media. On &lt;a href=&quot;https://www.facebook.com/machal&quot;&gt;Facebook&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/martinmichalek/&quot;&gt;LinkedIn&lt;/a&gt;, for instance, you can write longer pieces. Pieces of just a few paragraphs work great.&lt;/p&gt;
&lt;p&gt;Mastery in honing the core of an idea is offered by &lt;a href=&quot;https://x.com/machal&quot;&gt;X&lt;/a&gt; and its post-length limit.&lt;/p&gt;
&lt;p&gt;Check whether someone already writes about your topic. Send them your text — maybe they&apos;ll publish it. Don&apos;t worry, the media really aren&apos;t flooded with outside submissions. Very few people actually write.&lt;/p&gt;
&lt;p&gt;I told you to definitely show your text to someone. Another person. But that &quot;other person&quot; can also be you. Just look at your text again a few days later. After a week it&apos;ll be even better. I&apos;ve been my own editor this way for a long time. Texts and ideas ripen in the head.&lt;/p&gt;
&lt;p&gt;I often surprise myself a week later at how badly I wrote something. But I can fix it.&lt;/p&gt;
&lt;p&gt;Read your text out loud, or at least in a whisper. Does the read-aloud text make sense? Does it have good pace? Does it sound the way you speak? Reading your own text aloud really helps. You suddenly hear what you didn&apos;t see before.&lt;/p&gt;
&lt;h3&gt;Tools and skills: above all, learn to touch-type {#tools-skills}&lt;/h3&gt;
&lt;p&gt;Tools are overrated. But if you want, I&apos;ll mention the ones I use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;a href=&quot;https://evernote.com/&quot;&gt;Evernote&lt;/a&gt; (a notes database) I log ideas for pieces. I gradually flesh them out and add to them. When I learn something interesting about a topic, I add a link to that topic&apos;s page in Evernote. Then when I finally write it up, it&apos;s prepared and I don&apos;t have to do as detailed a research pass. I also often write the first drafts of my texts in Evernote.&lt;/li&gt;
&lt;li&gt;I move texts from Evernote into &lt;a href=&quot;https://workspace.google.com/products/docs/&quot;&gt;Google Docs&lt;/a&gt; when I need feedback from other people. The collaboration features in Google Docs are indispensable.&lt;/li&gt;
&lt;li&gt;I use &lt;a href=&quot;https://openai.com/chatgpt/&quot;&gt;ChatGPT&lt;/a&gt; as a writing assistant. It helps me do research and build structures. It gives me content feedback on my texts. It already does a lot of things brilliantly, though it doesn&apos;t yet catch all my language mistakes.&lt;/li&gt;
&lt;li&gt;I store texts in &lt;a href=&quot;https://www.markdownguide.org/&quot;&gt;Markdown&lt;/a&gt;. It&apos;s a format that&apos;s excellent for searching back through and editing. All my articles are in Markdown, all the chapters of all my books too. I can search back through Markdown when I want to add a link to a topic or edit something retroactively. Like deleting Internet Explorer from every text. That&apos;s a joy.&lt;/li&gt;
&lt;li&gt;To make sure I&apos;m writing well, I use grammar checkers and occasionally just a search engine. It&apos;s a shame to kill a piece with visible mistakes in it. A certain portion of readers is sensitive to that. I also watch out for &lt;a href=&quot;https://practicaltypography.com/&quot;&gt;correct typographic characters&lt;/a&gt;. Readers will forgive the odd mistake, but there can&apos;t be too many of them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But choose your tools to suit yourself. Or don&apos;t. Tools won&apos;t make you a better writer.&lt;/p&gt;
&lt;p&gt;There is, however, one skill I consider essential. It&apos;s something I hated in high school, only to discover a few years later that it&apos;s one of the most important skills school ever taught me.&lt;/p&gt;
&lt;p&gt;Having all your fingers in play when typing is a superpower.&lt;/p&gt;
&lt;p&gt;People sometimes tell me they don&apos;t understand my writing productivity. This is one of the answers. Between someone who touch-types and someone who types &lt;em&gt;some other way&lt;/em&gt;, there&apos;s a huge difference in speed. That much I know for sure.&lt;/p&gt;
&lt;h2&gt;Writing is glorious {#glorious}&lt;/h2&gt;
&lt;p&gt;Writing can be one of the best things you ever do. It can help the world learn about you, just as you can help other people.&lt;/p&gt;
&lt;p&gt;Writing can be so enjoyable that you choose it over the shows on Netflix.&lt;/p&gt;
&lt;p&gt;You can write too. Carve out time for it, write from the core, write concisely, and improve through feedback from others or from yourself.&lt;/p&gt;
&lt;p&gt;Start writing. Just start. Right now.&lt;/p&gt;
&lt;p&gt;Here are some other resources on writing that I know well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ondřej Ilinčev wrote a nice piece on &lt;a href=&quot;https://www.ilincev.com/clanek-za-3h&quot;&gt;how to write an article in 3 hours&lt;/a&gt;. Ondřej is a master of writing efficiency.&lt;/li&gt;
&lt;li&gt;I once enjoyed an article from a &lt;a href=&quot;https://www.obsahova-agentura.cz/blog/jak-napsat-web-aby-ho-lide-precetli&quot;&gt;content agency&lt;/a&gt; that takes a more business-minded approach to writing. That&apos;ll come in handy if you want to squeeze some money out of writing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What did I forget? What helps you with writing? Write to me &lt;a href=&quot;mailto:martin@vzhurudolu.cz&quot;&gt;by email&lt;/a&gt; or on social media.&lt;/p&gt;
</content:encoded></item></channel></rss>