Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
CSS Grid 1: Tracks, fr, repeat(auto-fill, minmax()) and Named Grid Areas
repeat(auto-fill, minmax(14rem, 1fr)) builds a responsive grid without media queries by creating as many columns as fit the container; auto-fit collapses the empty columns to zero and stretches the items. We build Bookstore's catalog grid and page skeleton with Grid, and measure in Chromium and WebKit the difference between fr and minmax(0, 1fr), the implicit grid, named lines, grid-template-areas and how dense breaks the DOM order.
Flexbox: One-Dimensional Layout, flex-grow/shrink/basis and Real-World Scenarios
Flexbox hands out free space by flex-grow and takes away missing space weighted by flex-shrink × flex-basis, so the larger item shrinks more. We lay out Bookstore's header, catalog cards and coupon field with Flexbox, and measure in Chromium and WebKit what the flex shorthands expand to, the min-width: auto trap that pushes a long book title out of its line, and the fact that order does not change the Tab sequence.
Normal Flow, display and Positioning: sticky, z-index, Stacking Contexts and the Top Layer
z-index is only compared between siblings in the same stacking context; sticky sticks relative to the nearest scroll container, which is why overflow: hidden on an ancestor breaks it. On Bookstore's catalog page we keep a float inside its box with flow-root, measure the two-value syntax of display, fix the sticky toolbar with overflow-x: clip, move a badge under the header with isolation: isolate, and show in Chromium and WebKit that a modal dialog in the top layer beats every z-index.
The Box Model, Sizing and Logical Properties: box-sizing, Margin Collapse, Intrinsic Sizes and Units
With box-sizing: border-box, width measures the whole box; in normal flow stacked vertical margins do not add up, the larger one wins, while in flex and grid they add up. On Bookstore's book card and detail page we measure the box model, when margin collapse happens and when it doesn't, min-content/max-content/fit-content, the cover ratio with aspect-ratio, rem/em/ch and svh/lvh/dvh units, and RTL-ready logical properties in Chromium and WebKit.
Modern Selectors: :is(), :where(), :has(), :not() and State Pseudo-classes
:is() takes its specificity from its most specific argument, while :where() is always zero; :not() and :has() are calculated like :is(). On Bookstore's catalog and checkout pages we measure specificity through the DevTools protocol, style a book card without a cover with :has() and an invalid form row with :user-invalid without JavaScript, and show the real behavior of :focus-visible, :open, :nth-child(of S) and :empty in Chromium and WebKit.
How CSS Decides: The Cascade, Specificity, Inheritance and Cascade Layers (@layer)
The cascade decides which of the values written for an element wins, in this order: origin and importance, context, the style attribute, layers, specificity, order of appearance; layers come before specificity. We debug Bookstore's "why isn't this button red?" bug step by step through the protocol DevTools uses, move third-party CSS below our own styles with @layer, and measure inherit/initial/unset/revert/revert-layer in two browser engines.
What Arrived in HTML 2023–2026: search, popover, Invoker Commands, Customizable Select and What's Next
HTML has no versions, only Baseline dates: between 2023 and 2026, search, inert, exclusive details, popover, requestClose, Invoker Commands, :open and autocorrect became Baseline; but because Angular 22 targets widely available, only search and inert work in every browser it supports. In this post we lay out the timeline, the features not yet Baseline, Interop 2026, and a decision table for Bookstore built from web-features data.
Accessible Markup Basics and HTML in Frameworks: Native First, the Accessibility Tree, Angular Host Elements and Razor
Accessible markup starts with native elements first, choosing hidden or inert to hide things, avoiding positive tabindex, setting lang and dir correctly, and reading the HTML your framework produces from the browser's output. In this post we measure a focusable button inside aria-hidden, the capital İ that changes with lang="tr", Angular host elements inside ul without list items and Razor Tag Helpers that produce no aria-invalid, and put angular-eslint and the Nu Html Checker into CI.
Tables and Tabular Data: caption, thead, th scope, colgroup and Responsive Tables
A data table gets its name from caption and its row and column relationships from th scope; on a narrow screen it goes into a scrollable wrapper with tabindex, role="region" and a name. In this post we read Bookstore's order history in the accessibility tree and measure that text-align on col does nothing, a headers/id bug, WebKit not focusing a plain wrapper, and how an Angular row using a host element instead of tr empties the table.
The head and Meta Tags: charset, viewport, title, description, Open Graph, theme-color and link rels
A good head starts with meta charset, carries a single viewport that does not disable zoom, a page-specific title and one description, and puts Open Graph tags in the HTML from the server. In this post we measure that a page without a charset breaks Turkish characters, that a phone lays out a page without viewport at 980 pixels, that bots miss Open Graph added with JavaScript, color-scheme, and repeated meta tags in a Razor layout, with the Nu Html Checker and axe.
Images and Media: img, picture, srcset/sizes, video, audio, track and iframe
Give every img a width and height, choose alt by the image's job on the page, pair srcset with sizes when the image size changes with the screen, and never put loading="lazy" on an image on the first screen. In this post we measure these rules in Chromium and WebKit: a 0.14 layout shift from an image without dimensions, sizes="auto", AVIF/WebP/JPEG XL order in picture, the half-second delay of a lazy LCP image, subtitles with track and the iframe title.
Native Interactive Elements 2: select, datalist, Customizable Select and output/progress/meter
Use select for a choice and datalist for suggestions: datalist submits values outside its list, and a required select treats only a first option with value="" as a placeholder. In this post we measure a catalog filter, a customizable select with cover images via appearance: base-select (Chrome 135 and Safari 27, not Firefox) and output/progress/meter in Chromium and WebKit, and show the disabled placeholder trap and the output that is never submitted.