Container queries did not retire the viewport. They just stopped it from running the whole show.
Container queries ate a lot of my old breakpoint soup. I still keep one rem-based media query around, and it is the one that decides whether the page is a single column or a real layout. Here is why that split still belongs to the viewport.
Profiling animation jank on a mid-range Android phone
A laptop will lie to you about motion. I started testing every enter animation on a mid-range Android phone, and a lot of my favorite CSS suddenly looked like a slideshow. Here is the checklist I now run before I ship a transition.
First paint should match the theme the reader already chose.
A theme toggle is easy. A first paint that does not blink white is the actual product. This is the small script I run before the CSS, the cookie I keep, and the one mistake that still causes a flash if you put the class on the wrong node.
A press state should feel like a finger, not like a hover that got louder.
Hover is a desktop rumor. Press is the real event. I have been replacing hover-only button motion with a short squash on :active, and the UI immediately feels more physical. Here is the CSS, and the part you should not animate.
Flexbox kept wrapping the wrong thing. Grid made the page honest.
I spent a week forcing a homepage into flexbox because I already knew flexbox. The sidebar jumped, the popular list sat too high, and the sticky header had nothing to stick against. Switching the page shell to grid was not fancy. It was the layout admitting what it always was.
Client checks should say the same thing the server would say.
A newsletter field that accepts “asdf” and then dies on the server is not validation. It is a shrug. I started writing the browser check as a copy of the server rule, including the error sentence, so the page never invents a second opinion.
You do not need to love path syntax to use a filter well.
I used to treat SVG as a file the designer exported. Then I needed a gooey menu and a noise overlay that did not ship a PNG. A couple of filter primitives got me there without becoming an Illustrator person. This is the short list I actually reuse.
The first public UI should look a little unfinished on purpose.
I used to hold a page until the mascot, the sounds, and the footer hills were perfect. Nobody saw it, so nobody told me the search was broken. Now I ship a plain version that already does the job, then I dress it. Taste comes after use.
The tiny theme details people feel without naming.
Readers highlight a sentence. The selection turns default blue, and your whole palette looks like it belongs to someone else. I started theming selection, scrollbars, and focus rings as part of the same token set as headings. It is a small file and a surprisingly large change in tone.
I had a boolean for hover, a boolean for open, and a boolean for stuck. Two of those are CSS. Moving them out of React made the header less jittery and deleted a pile of effects I only wrote because I was holding a hammer.
This site does not need Elastic. It needs a box, a list, and a filter that runs while you type. I built search as a small client script over a JSON index of titles and excerpts. The trick is not the algorithm. It is the empty state, the keyboard, and not blocking the first paint.
A sky that fades into hills looks simple and is easy to make expensive. I learned to keep the waves as a few paths, freeze them on scroll, and let CSS variables repaint the fill on theme change. No canvas. No per-frame JavaScript. The decoration stays decoration.