en CSS Weekly https://css-weekly.com CSS Weekly - Articles, Videos, Issues, and Quick Tips about CSS and frontend development en-us Mon, 16 Mar 2026 12:58:57 GMT Issue #637 https://feedpress.me/link/24028/17293750/issue-637 https://css-weekly.com/issue-637 Learn how to use border-shape to define custom border shapes for elements, how to style lists, how to improve your typography using text-indent keywords, and more. Thu, 05 Mar 2026 00:00:00 GMT Zoran Jambor Newsletter Learn how to use border-shape to define custom border shapes for elements, how to style lists, how to improve your typography using text-indent keywords, and more.

Headlines

border-shape: The Future of the Non-rectangular Web

border-shape: The Future of the Non-rectangular Web

Una Kravets introduces border-shape, a powerful upcoming CSS primitive that defines a custom border shape for an element.

Read more →


An In-Depth Guide to Customising Lists With CSS

An In-Depth Guide to Customising Lists With CSS

Richard Rutter created an extensive guide to styling lists, covering list-style, list-item, ::marker, counters(), counter(), @counter-style, symbolic, symbols(), symbols, and more to push your HTML and CSS lists to the next level.

Read more →




From Our Sponsor

What if your IDE flagged accessibility issues the same way it flags a missing semicolon?

What if your IDE flagged accessibility issues the same way it flags a missing semicolon?

BrowserStack's Accessibility DevTools does exactly that, catching WCAG violations as you code and routing fix suggestions through Copilot, Claude, or Cursor right where you're already working.

No context switching, no separate audit cycles. IBM research puts the cost of fixing accessibility post-release at 25x more than catching it in development. It's free and takes under a minute to install.

Read more →




CSS Weekly on YouTube

CSS text-indent Keywords?

CSS text-indent Keywords?

A brief guide on how to use CSS text-indent keywords, each-line and hanging to improve your typography.

Read more →


Frontend News #20: CSS Grid Lanes, ::search-text Pseudo-Element

Frontend News #20: CSS Grid Lanes, ::search-text Pseudo-Element

Find out how to create native masonry layouts using CSS grid-lanes, how a single emoji character causes massive performance issues, how to style in-page search results, how the Geolocation HTML element works, and more.

Read more →




Articles & Tutorials

Virtual Scroll-Driven 3D Scenes

Gunnar Bachelor examines the limitations of traditional DOM-based scrolling options, demonstrates how virtual scrolling enables more controlled scroll-driven interactions, and shows how to implement it responsibly.

Read more →


Potentially Coming to a Browser :near() You

Daniel Schwarz Danny has several ideas for how we could use :near(), a proposed pseudo-class that detects when the pointer is near an element.

Read more →


Sticky Grid Scroll: Building a Scroll-Driven Animated Grid

Theo Plawinski shows how to build a structured scroll-driven image grid where movement unfolds progressively within a sticky layout.

Read more →


Getting Started With The Popover API

Godstime Aburu gives a nice introduction to the Popover API.

Read more →


Popover API or Dialog API: Which to Choose?

Zell Liew goes over the differences between Popover API and Dialog API in terms of accessibility.

Read more →




Sponsored Link

Understand what web browsers are capable of at Web Day Out

Understand what web browsers are capable of at Web Day Out

The last few years have seen leaps in HTML, CSS, and JavaScript. If you haven’t kept up, Web Day Out is for you.

Join us on 12 March for a conference about what you can do in web browsers today. Featuring talks from Rachel Andrew, Manuel Matuzović, Harry Roberts & more.

Use code CSSWEEKLY_10 for 10% off.

Read more →




Tools

Hotkeys

Hotkeys is a type-safe, cross-platform hotkey library with sequence detection, key state tracking, hotkey recording, and framework adapters for React and more.

Read more →


Masonry Grid

A fast, lightweight, and responsive masonry grid layout library in vanilla JavaScript.

Read more →




Inspiration

March Mad CSS

March Mad CSS

March Mad CSS is the Ultimate CSS Tournament featuring 16 of the most elite CSS developers from around the world who will battle it out for the chance to be dubbed the INAUGURAL MADCSS CHAMPIONS OF THE WORLD.

Read more →




Until Next Week

Thanks for reading! If you find the content valuable, please consider supporting the newsletter on Patreon.

Happy coding,

Zoran Jambor

]]>
Frontend News #21: Multi-Column Layouts, :heading Pseudo-Class, Scaling Elements https://feedpress.me/link/24028/17287362/frontend-news-21-multi-column-layouts-heading-pseudo-class-scaling-elements https://css-weekly.com/videos/frontend-news-21-multi-column-layouts-heading-pseudo-class-scaling-elements Learn how multi-column layouts are becoming usable, how the new :heading pseudo-class works, how to scale content with layout, and more. Fri, 27 Feb 2026 00:00:00 GMT Zoran Jambor Video Learn how multi-column layouts are becoming usable, how the new :heading pseudo-class works, how to scale content with layout, and more.

Find out how to create multi-column layouts using CSS, how the new :heading pseudo-class works, how to scale content with layout using zoom property, and more.

Get free access to the entire course library from Vue School

Chapters / Links

00:00 Intro
00:30 Support for wrapped columns in multi-column layout
02:05 Vue School Free Weekend
02:45 Style Headings using the CSS :heading pseudo-class
04:22 How to scale elements and their layout with CSS "zoom"
05:34 Picknplace.js
06:34 VoxJong - CSS Mahjong Solitaire

]]>
CSS text-indent Keywords? https://feedpress.me/link/24028/17287363/css-text-indent-keywords https://css-weekly.com/videos/css-text-indent-keywords A brief guide on how to use CSS text-indent keywords, each-line and hanging to improve your typography. Wed, 25 Feb 2026 00:00:00 GMT Zoran Jambor Video A brief guide on how to use CSS text-indent keywords, each-line and hanging to improve your typography.

A brief guide on how to use CSS text-indent keywords, each-line and hanging to improve your typography.

Chapters

00:00 Intro & demo setup
00:24 How text-indent each-line keyword works
00:57 How text-indent hanging keyword works
01:34 Browser support for each-line and hanging keywords

Demo

https://codepen.io/ZoranJambor/pen/yyayYoK?editors=0100&layout=left

]]>
Frontend News #20: CSS Grid Lanes, ::search-text Pseudo-Element, HTML Geolocation Element https://feedpress.me/link/24028/17280489/frontend-news-20-css-grid-lanes-search-text-pseudo-element-html-geolocation-element https://css-weekly.com/videos/frontend-news-20-css-grid-lanes-search-text-pseudo-element-html-geolocation-element Find out how to create native masonry layouts, how to style in-page search results, and more. Fri, 20 Feb 2026 00:00:00 GMT Zoran Jambor Video Find out how to create native masonry layouts, how to style in-page search results, and more.

Find out how to create native masonry layouts using CSS grid-lanes, how a single emoji character causes massive performance issues, how to style in-page search results, how the <geolocation> HTML element works, and more.

Try Backlog as your Jira alternative

Links / Chapters

00:00 Intro
00:23 Introducing CSS Grid Lanes
01:47 Backlog
02:25 How to Style the New ::search-text
03:44 A Broken Heart
05:05 Introduction to the new HTML element geolocation
06:18 Bubble Color Picker

]]>
Issue #636 https://feedpress.me/link/24028/17279510/issue-636 https://css-weekly.com/issue-636 Learn what Interop 2026 entails, how to avoid common CSS mistakes, how to use Touch ID for SUDO, how to build flexible typographic scales, and more. Thu, 19 Feb 2026 00:00:00 GMT Zoran Jambor Newsletter Learn what Interop 2026 entails, how to avoid common CSS mistakes, how to use Touch ID for SUDO, how to build flexible typographic scales, and more.

Headlines

Announcing Interop 2026

Announcing Interop 2026

Yulun Wu and Jen Simmons announce Interop 2026, continuing the mission of improving cross-browser interoperability.

Read more →


<small>►</small> 5 CSS Fouls That I See Way Too Often

5 CSS Fouls That I See Way Too Often

Kevin Powell outlines some common CSS mistakes.

Read more →




From Our Sponsor

Web Performance: A Deep Dive

😮 Does your CDN handle HTTP priorities correctly? – Even when the browser correctly prioritizes resources on a page, many web servers simply don’t listen.

🚀 How to improve website performance – Learn to identify and fix the most common page speed issues based on request waterfalls.

🕵️‍♀️ Test your website speed – Measure website performance, get targeted insights, and check real user metrics collected from Chrome users.

🏡 Why do Lighthouse scores vary so much across tools? – Learn how simulated throttling and different test environments result in score discrepancies even when testing the same website.

🍞 Identify slow scripts with the Long Animation Frames API – Use browser APIs to debug slow user interactions for real users.

🎥 DevTools network throttling: a look under the hood – This video explains how Chrome implements network throttling and what the results can and can’t tell you.




CSS Weekly Blog

How To Use Touch ID for SUDO on macOS

How To Use Touch ID for SUDO on macOS

A hands-on guide to setting up macOS to use Touch ID for sudo—so you don't have to type your password every time manually.

Read more →




Articles & Tutorials

Building Typographic Scales in CSS with :heading(), sibling-index(), and pow()

Stuart Robson shows how to build flexible, mathematical typographic scales using :heading(), sibling-index(), and pow() for cleaner CSS design systems.

Read more →


The Corner Cases of Implementing CSS corner-shape in Blink

Noam Rosenthal shares the story about the complexity of implementing the corner-shape feature.

Read more →


CSS Animation Triggers: Playing animations on scroll without scrubbing. It's a match!

Brecht De Ruyte shows how CSS scroll-triggered animations let you use scroll position to determine when animations play.

Read more →


Spiral Scrollytelling in CSS With sibling-index()

Lee Meyer demonstrates how to arrange text in a spiral that animates as a vortex on scroll.

Read more →


Anchored Menus and a Lesson in Scoping

Chris Coyier explains how anchor-scope can be useful for button/menu setups that will appear multiple times on the same page.

Read more →




Sponsored Link

Understand what web browsers are capable of at Web Day Out

Understand what web browsers are capable of at Web Day Out

The last few years have seen leaps in HTML, CSS, and JavaScript. If you haven’t kept up, Web Day Out is for you.

Join us on 12 March for a conference about what you can do in web browsers today. Featuring talks from Rachel Andrew, Manuel Matuzović, Harry Roberts & more.

Use code CSSWEEKLY_10 for 10% off.

Read more →




Tools

SVG Converter

An online SVG converter with color palette customization that can convert both JPG and PNG files to SVG.

Read more →


Buttony UI

A nice collection of customizable, animated buttons for your web projects.

Read more →




Inspiration

Picket Fence Animation Using Scroll Animations

Picket Fence Animation Using Scroll Animations

Chris Bolson created a stunning demo that showcases the power of scroll-driven animations.

Read more →




Until Next Week

Thanks for reading! If you find the content valuable, please consider supporting the newsletter on Patreon.

Happy coding,

Zoran Jambor

]]>
How To Use Touch ID for SUDO on macOS https://feedpress.me/link/24028/17275725/how-to-use-touch-id-for-sudo-on-macos https://css-weekly.com/videos/how-to-use-touch-id-for-sudo-on-macos A hands-on guide to setting up macOS to use Touch ID for sudo—so you don't have to type your password every time manually. Fri, 13 Feb 2026 00:00:00 GMT Zoran Jambor Video A hands-on guide to setting up macOS to use Touch ID for sudo—so you don't have to type your password every time manually.

On macOS 14 (Sonoma) and newer, you can use Touch ID for sudo. There is already a template file on your system that you can use to enable this.

Copy the template file /etc/pam.d/sudo_local.template to /etc/pam.d/sudo_local, then edit it and uncomment the specified line to enable Touch ID for sudo.


sudo cp /etc/pam.d/sudo_local.template /etc/pam.d/sudo_local
sudo nano /etc/pam.d/sudo_local

Uncomment the line stated in the file. Once you do, the file should look like this:

# sudo_local: local config file which survives system update and is included fo$
# uncomment following line to enable Touch ID for sudo
auth       sufficient     pam_tid.so

Save the file, and as soon as you open another terminal window, you can use Touch ID for sudo.

Note that this works only on your local machine, so you can't use it if you SSH into a remote server.

There is an additional limitation on macOS where this doesn't work when you're recording the screen — you'll still be asked for your password. However, there is a way to bypass this limitation if you enter this into the terminal nd run it:


  defaults write com.apple.security.authorization ignoreArd -bool TRUE`

Links

]]>
Issue #635 https://feedpress.me/link/24028/17275488/issue-635 https://css-weekly.com/issue-635 Learn how CSS is used in the real world, how powerful the customizable select can be, how to easily target recently selected elements from the Elements Panel in the Console of Chrome DevTools, and more. Thu, 12 Feb 2026 00:00:00 GMT Zoran Jambor Newsletter Learn how CSS is used in the real world, how powerful the customizable select can be, how to easily target recently selected elements from the Elements Panel in the Console of Chrome DevTools, and more.

Headlines

The CSS Selection

The CSS Selection

Bart Veneman analyzes real-world CSS usage across 100,000 websites.

Read more →


Nice Select

Nice Select

Adam Argyle showcases how powerful customizable <select> can be.

Read more →




From Our Sponsor

48 hours of free learning with Vue School Free Weekend

48 hours of free learning with Vue School Free Weekend

Get free access to the entire course library from the #1 source of Vue.js learning and build real production-ready skills in a weekend. Learn Vue 3, Nuxt, Pinia, TypeScript, authentication, UI patterns, and modern tooling.

Read more →




CSS Weekly on YouTube

<small>►</small> Chrome DevTools Tips: Target Recent Elements in Console

Chrome DevTools Tips: Target Recent Elements in Console

A Chrome Developer Tools quick tip outlining how to easily target recently selected elements from the Elements Panel in the Console.

Read more →




Articles & Tutorials

CSS @scope: An Alternative To Naming Conventions And Heavy Abstractions

Blake Lundquist explores how the new @scope rule can help you keep CSS maintainable in a world of increasingly complex interfaces.

Read more →


How to Create a CSS-Only Elastic Text Effect

Temani Afif explores tricks to achieve a fancy text effect with just CSS.

Read more →


Re-Creating a Pantone Color Deck in CSS

Mads Stoumann shows how to build a fully interactive color fan deck where the spread adapts to the container width, cards know their position among their siblings, and clicking a card to "focus" it is handled entirely by the browser’s native <details> element.

Read more →


Trying to Make the Perfect Pie Chart in CSS

Juan Diego Rodríguez explores how to create a semantic pie chart with flexible markup that avoids using a JavaScript library.

Read more →


Interop 2025: A Year of Convergence

Nicole Sullivan gives a nice overview of Interop 2025.

Read more →




Sponsored Link

Optimize page speed and Core Web Vitals

Optimize page speed and Core Web Vitals

Wondering why your website is slow? DebugBear provides comprehensive performance monitoring and in-depth technical reports to help you speed up your website.

Read more →




Tools

All SVG Icons

AllSVGIcons is a free online library of high-quality SVG icons that you can download and use in your projects right away.

Read more →


Circle Crop Image

An online app that transforms any image into a perfect circle instantly — ideal for profile pictures, social media, and design projects.

Read more →




Inspiration

Video Text - Wrapping, Selectable, Stylable From CSS

Video Text - Wrapping, Selectable, Stylable From CSS

Ana Tudor created a stunning demo that turns boring headlines into a dynamic video where the text wraps naturally, is selectable, can be copied, supports any backdrop, and is easily stylable with CSS.

Read more →




Until Next Week

Thanks for reading! If you find the content valuable, please consider supporting the newsletter on Patreon.

Happy coding,

Zoran Jambor

]]>
Chrome DevTools Tips: Target Recent Elements in Console https://feedpress.me/link/24028/17272933/chrome-devtools-tips-target-recent-elements-in-console https://css-weekly.com/videos/chrome-devtools-tips-target-recent-elements-in-console A Chrome Developer Tools quick tip outlining how to easily target recently selected elements from the Elements Panel in the Console. Mon, 09 Feb 2026 00:00:00 GMT Zoran Jambor Video A Chrome Developer Tools quick tip outlining how to easily target recently selected elements from the Elements Panel in the Console.

To target the currently selected element in the Elements Panel, you can use the $0 selector in the Console.

To target the previously selected element, you can use the $1 selector — and you can target the history of selected elements with $2, $3, and $4.

]]>
Issue #634 https://feedpress.me/link/24028/17270228/issue-634 https://css-weekly.com/issue-634 Learn how to easily solve annoying problems using CSS, how to visually connect related elements using Anchor Positioning, what Too Early Breakpoints are, and more. Wed, 04 Feb 2026 00:00:00 GMT Zoran Jambor Newsletter Learn how to easily solve annoying problems using CSS, how to visually connect related elements using Anchor Positioning, what Too Early Breakpoints are, and more.

Headlines

<small>►</small> CSS Properties That Solve Annoying Problems

CSS Properties That Solve Annoying Problems

Kevin Powell shares a few fantastic CSS tips that you’ll surely find useful.

Read more →


Drawing Connections with CSS Anchor Positioning

Drawing Connections with CSS Anchor Positioning

Roland Franke provides a practical exploration of CSS Anchor Positioning and the anchor() function for visually connecting related elements without extra markup.

Read more →




From Our Sponsor

Identify and fix web performance issues with DebugBear

Identify and fix web performance issues with DebugBear

Is your website slower than it should be? DebugBear provides in-depth web performance analytics based on synthetic tests and real user monitoring.

Detect pages with critical issues, get in-depth technical reports to identify solutions, and measure how performance impacts conversion rates.

Read more →




Articles & Tutorials

The Too Early Breakpoint

Ahmad Shadeed shares opinion on why you shouldn't switch to the smallest design too early.

Read more →


Typographic scales and technical pens

Rob Weychert shows how to create a flexible system for consistent stroke widths across type sizes.

Read more →


Performance-Optimized Video Embeds with Zero JavaScript

Stefan Bauer explores an approach of using a closed details element to prevent the embed from loading until that details element is opened.

Read more →


What is JPEG XL and do we really need another image format?

Aaron T. Grogg explains what JPEG XL is, how it compares to other image formats like AVIF and WebP, and whether you should use it on your websites.

Read more →


Live Region Support

Adrian Roselli outlines the best way to use live regions, covering how they are exposed to the audience who experiences them — screen reader users.

Read more →




Sponsored Link

Creating PDFs can be tedious … but what if you could create them using HTML and CSS?

Creating PDFs can be tedious … but what if you could create them using HTML and CSS?

Did you know CSS has powerful features specifically for paged media? Running headers, page numbers, custom page sizes – it’s all at your fingertips! With EuroPDF, powered by the industry-leading PrinceXML rendering engine, you can easily take advantage of these features to create stunning PDFs.

Read more →




Tools

ilamy Calendar

A powerful, full-featured React calendar component library built with TypeScript, Tailwind CSS, and modern React patterns. Features multiple calendar views, drag-and-drop support, recurring events, and comprehensive internationalization.

Read more →


X-Ray React

Xray-react is a development tool that reveals the component structure of your React UI.

Read more →




Inspiration

CSS Optical Illusions

CSS Optical Illusions

Alvaro Montoro created a stunning collection of optical illusions with pure CSS. No JavaScript, no animations—just clever use of colors, patterns, and gradients to trick your brain.

Read more →




Until Next Week

Thanks for reading! If you find the content valuable, please consider supporting the newsletter on Patreon.

Happy coding,

Zoran Jambor

]]>
Issue #633 https://feedpress.me/link/24028/17265551/issue-633 https://css-weekly.com/issue-633 Understand the fundamentals of CSS Layout, learn how stacking contexts work, why you should use the HTML autocomplete attribute on fields for 2FA, and more. Wed, 28 Jan 2026 00:00:00 GMT Zoran Jambor Newsletter Understand the fundamentals of CSS Layout, learn how stacking contexts work, why you should use the HTML autocomplete attribute on fields for 2FA, and more.

Headlines

Understanding the fundamentals of CSS Layout

Understanding the fundamentals of CSS Layout

Kilian Valkhof gives a fantastic deep dive into the fundamentals of CSS layout.

Read more →


Unstacking CSS Stacking Contexts

Unstacking CSS Stacking Contexts

Gabriel Shoyombo explains how stacking contexts works, what controls the stacking order, and practical approaches to “unstack” elements when needed.

Read more →




From Our Sponsor

12 Top Web Design Tools and Resources for 2026 – AI and Creative Picks

🤖 Power Up Builds with CSAI + Pro + Cornerstone — Bring AI directly into WordPress and the Cornerstone Builder to generate copy, code, images, and more without leaving the builder. The ultimate all-in-one solution for building impressive, custom websites.

Design Faster with Blocksy — A lightweight, modular WordPress theme that gives designers speed, flexibility, and full WooCommerce support out of the box.

🧠 Build Instantly with Mobirise AI — Generate complete websites from a single prompt using an AI-powered, no-code builder made for rapid launches and prototyping.

🎨 Create High-End Sites with Uncode — A creative WordPress theme packed with advanced layouts, animations, and design tools for premium client projects.

🔤 Identify Fonts with WhatFontIs — Upload any image and instantly get accurate font matches, usable alternatives, and licensing details in seconds.

Animate with Slider Revolution — Design stunning sliders, hero sections, and interactive animations using a powerful visual editor and modern templates.




Quick Tips

How to debug @starting-style at-rule in Chrome DevTools

How to debug @starting-style at-rule in Chrome DevTools

A quick tip showing how to debug the Starting Style at-rule in Chrome DevTools.

Read more →


Use HTML “autocomplete” attribute for one-time codes and web authentication

Use HTML “autocomplete” attribute for one-time codes and web authentication

A short reminder that you should use the HTML autocomplete attribute on fields for 2FA, one-time codes, and web authentication.

Read more →




Articles & Tutorials

Try text scaling support in Chrome Canary

Josh Tumath explains what the "text-scaling” meta tag is, and how you can use it to improve accessibility.

Read more →


Anchor Interpolated Morph (AIM)

Adam Argyle gives an introduction to a new CSS transition technique: Anchor Interpolated Morphing (AIM).

Read more →


How Web Performance Impacts User Experience

Matt Zeunert explains how website speed impacts user experience and how you can measure performance and business outcomes.

Read more →


Lowering the specificity of multiple rules at once

Manuel Matuzović shares a tip on how to easily lower the specificity of multiple rules using cascade layers.

Read more →


Responsive Hexagon Grid Using Modern CSS

Temani Afif demonstrates how to create a repeating grid of hexagons using modern CSS features.

Read more →




From Our Friends

CSS Weekly covers CSS. Web Weekly covers the rest.

CSS Weekly covers CSS. Web Weekly covers the rest.

HTML, JavaScript APIs, browser updates, and web standards — stay up-to-date with the web platform! No npm install required.

Read more →




Tools

ReliCSS

ReliCSS is a client-side CSS analyzer that detects outdated CSS hacks, IE6-9 patterns, and deprecated vendor prefixes.

Read more →


Avatune

Avatune is a production-ready avatar system with AI-powered generation and framework-native components. Works seamlessly with React, Vue, Svelte, and Vanilla JavaScript.

Read more →




Inspiration

CSS Animated Light & Shadow

CSS Animated Light & Shadow

Vicio Bonura created a stunning, animated shadow effect using CSS.

Read more →




Until Next Week

Thanks for reading! If you find the content valuable, please consider supporting the newsletter on Patreon.

Happy coding,

Zoran Jambor

]]>
<![CDATA[How to debug <code>@starting-style</code> at-rule in Chrome DevTools]]> https://feedpress.me/link/24028/17263204/how-to-debug-starting-style-at-rule-in-chrome-devtools https://css-weekly.com/how-to-debug-starting-style-at-rule-in-chrome-devtools Learn how to debug the Starting Style at-rule in Chrome DevTools. Sun, 25 Jan 2026 00:00:00 GMT Zoran Jambor Article Learn how to debug the Starting Style at-rule in Chrome DevTools.

Chrome DevTools Elements Panel with starting-style labels

In Chrome 143+, you can find a label “starting-style” in the Elements Panel, on elements where the starting style at-rule is applied.

When you click it, the transition will be triggered, allowing you to see what it looks like, and the @starting-style rule will appear in the Styles pane, allowing you to easily tweak, edit, or debug its CSS.

Toggling the label in the Elements Panel again will trigger the transition with the changes from DevTools applied.

Demo

https://codepen.io/ZoranJambor/pen/eYaEwez

Links

]]>
Issue #632 https://feedpress.me/link/24028/17259621/issue-632 https://css-weekly.com/issue-632 Find out what the current state of the web is, how we should redefine the Pixel Perfect concept, how to be more productive in Chrome DevTools Elements Panel, and more. Wed, 21 Jan 2026 00:00:00 GMT Zoran Jambor Newsletter Find out what the current state of the web is, how we should redefine the Pixel Perfect concept, how to be more productive in Chrome DevTools Elements Panel, and more.

Headlines

The 2025 Web Almanac

The 2025 Web Almanac

HTTP Archive’s annual state of the web report is out — it’s a comprehensive, data-backed view of the web, built with trusted experts, across 15 chapters on content, user experience, publishing, and distribution.

Read more →


Rethinking “Pixel Perfect” Web Design

Rethinking “Pixel Perfect” Web Design

Amit Sheen takes a hard look at the “Pixel Perfect” legacy concept, explaining why it’s failing us and redefining what “perfection” actually looks like in a multi-device, fluid world.

Read more →




From Our Sponsor

Top WordPress Plugins to Supercharge Your Site in 2026

🎨 Build Stunning Pages with Brizy – Drag-and-drop editor for responsive pages without coding. Comes with pre-made blocks, icons, and a White Label option for agencies.

🕒 Simplify Bookings with Amelia – Automate appointments and events with an intuitive interface, packages, and client-friendly design.

📊 Create Dynamic Tables & Charts with wpDataTables – Handle millions of rows with filtering, sorting, WooCommerce integration, and responsive layouts.

🌟 Level Up Visuals with Slider Revolution – Design stunning sliders, hero sections, and animations using 250+ templates and a visual editor.

Build Modern Websites with LayerSlider - Create sliders, popups, rich animations and websites with effortless editing, and access to millions of visual assets.

🗺️ Interactive Maps with MapSVG – Build color-coded, data-driven maps with custom objects, filtering, and image attachments.




CSS Weekly on YouTube

<small>►</small> Chrome DevTools Elements Panel Tips & Tricks

Chrome DevTools Elements Panel Tips & Tricks

In this guide, you’ll learn how to hide inspect element popups that sometimes obscure your view, how to work with CSS classes effectively, and how to keep interactive elements, such as dropdowns, from disappearing while DevTools are focused.

Read more →


<small>►</small> Automate Your Testing Workflows Using BrowserStack’s AI Agents

Automate Your Testing Workflows Using BrowserStack’s AI Agents

Find out how to use BrowserStack’s AI agents to automate your testing workflows. In this hands-on guide, you’ll see how to easily use the Test Case Generator Agent to turn user stories into detailed, structured test cases in seconds, and then convert those cases into automated tests with the Low-Code Authoring Agent.

Read more →




Articles & Tutorials

Animating Responsive Grid Layout Transitions with GSAP Flip

Iqbal Muthahhary explores how to use GSAP’s Flip plugin to animate dynamic grid layout changes, showing how grid items can resize and rearrange fluidly.

Read more →


CSS in 2026: The New Features Reshaping Frontend Development

Jemima Abu shows how she replaced 150+ lines of JavaScript with just a few new CSS features.

Read more →


View Transitions & Playing Video

Chris Coyier explores how to keep audio & video playing during a View Transition.

Read more →


How to Favicon in 2026: Three files that fit most needs

Andrey Sitnik gives an exhaustive guide to favicons in 2025, including steps for static HTML and Webpack. TLDR: prefer SVG over PNG, trust browsers to downscale, drop obscure formats.

Read more →


I Learned The First Rule of ARIA the Hard Way

Hashim Quraishi explains how semantic HTML does a lot more accessibility work than we usually give it credit for — and that ARIA is easy to abuse when we use it both as a shortcut and as a supplement.

Read more →




Sponsored Link

Check page speed and Google Core Web Vitals for your website

Check page speed and Google Core Web Vitals for your website

DebugBear’s free website speed test delivers a comprehensive performance report for your website, based on custom-built analysis, Lighthouse scores, and Google CrUX metrics based on real visitor experience.

Diagnose page speed issues with tailored recommendations and a detailed network request waterfall that shows how different resources impact rendering progress.

Read more →




Tools

Browser Score

An interactive tool by Lea Verou that shows how your browser stacks up in terms of support for web platform features.

Read more →


CanIUse Embed

An interactive, configurable, and responsive embed that shows Baseline status or browser support for web platform features.

Read more →




Inspiration

Text Frame Border Animation Rotation

Text Frame Border Animation Rotation

Fernando Cohen created a stunning, organic animated frame using CSS & SVG.

Read more →




Until Next Week

Thanks for reading! If you find the content valuable, please consider supporting the newsletter on Patreon.

Happy coding,

Zoran Jambor

]]>
Issue #631 https://feedpress.me/link/24028/17255561/issue-631 https://css-weekly.com/issue-631 See the overview of best CSS features that landed in Chrome in 2025, learn what the future of CSS Masonry looks like, what the practical use cases for overflow: clip are, and more. Thu, 15 Jan 2026 00:00:00 GMT Zoran Jambor Newsletter See the overview of best CSS features that landed in Chrome in 2025, learn what the future of CSS Masonry looks like, what the practical use cases for overflow: clip are, and more.

Headlines

CSS Wrapped 2025

CSS Wrapped 2025

The Chrome CSS/UI DevRel team created another edition of CSS Wrapped, showcasing 22 powerful new CSS features that landed in Chrome in 2025.

Read more →


Introducing CSS Grid Lanes

Introducing CSS Grid Lanes

Jen Simmons, Elika Etemad, and Brandon Stewart introduce the future of masonry layouts on the web.

Read more →




From Our Sponsor

Looking for a Jira alternative your team will actually enjoy?

Looking for a Jira alternative your team will actually enjoy?

Backlog is a project management tool built for teams who want structure—without the overwhelm.

If Jira feels heavy or complex, Backlog offers a cleaner, more intuitive experience with all the essentials: kanban boards, Gantt charts, issues, sprints, docs, version control, and more.

Read more →




CSS Weekly on YouTube

<small>►</small> Practical Use-Cases for “overflow: clip;”

Practical Use-Cases for “overflow: clip;”

A brief guide outlining the difference between overflow: hidden and overflow: clip, along with practical use cases when you’ll find overflow: clip life-saving.

Read more →


<small>►</small> Frontend News #19: CSS overscroll-behavior, scrollbar-gutter, text-grow Properties

Frontend News #19: CSS overscroll-behavior, scrollbar-gutter, text-grow Properties

Find out how overscroll-behavior: contain is changing, how to use the scrollbar-gutter CSS property, what the new text-grow property does, how to analyze your CSS, and more.

Read more →




Articles & Tutorials

The Deep Card Conundrum

Amit Sheen demonstrates how to create a stunning 3D card with layers of depth.

Read more →


Using 100vw is now scrollbar-aware (in Chrome 145+, under the right conditions)

Bramus Van Damme explains that in Chrome 145+, 100vw will automatically subtract the size of the (vertical) scrollbar from it if you have forced the html element to always show a vertical scrollbar (using overflow[-y]: scroll) or if you reserve space for it (using scrollbar-gutter: stable).

Read more →


Directional CSS with scroll-state(scrolled)

Una Kravets gives an introduction to the new scroll-state query feature that lets you apply styles based on the last scroll direction of your user’s scroll.

Read more →


How to Load CSS (Fast)

Yoav Weiss shows a clever, creative way to ship only critical/necessary CSS for each page type (home, search, etc.) while avoiding duplicate code in the CSS bundles.

Read more →


Accessible Faux-Nested Interactive Controls

Eric Bailey shows how to create a user interface pattern with a large clickable element (such as a card) and clickable controls within that card.

Read more →




What Have I Been up To

AI Developer Newsletter

AI Developer Newsletter

I’ve launched a new, proper website for my latest project, AI Developer. There you’ll find articles, tips, videos, past newsletter issues, and more.

Check it out, and subscribe today—AI Developer Newsletter Issue #2 is landing in a few days. ;)

Read more →




Tools

Web Platform Features Explorer

Web Platform Features Explorer is an online tool that lets you discover new features and APIs and stay up to date with changes.

Read more →


React-Beautiful-Color

React-Beautiful-Color is a flexible and beautiful color picker for React built with compound components for maximum customization.

Read more →




Inspiration

Mesmerizing Corner Shapes using superellipse() — CSS Only

Mesmerizing Corner Shapes using superellipse() — CSS Only

I’ve created a pure CSS animation that showcases the power of the corner-shape CSS property and its superellipse() function.

Read more →




Until Next Week

Thanks for reading! If you find the content valuable, please consider supporting the newsletter on Patreon.

Happy coding,

Zoran Jambor

]]>
Automate Your Testing Workflows Using BrowserStack’s AI Agents https://feedpress.me/link/24028/17255562/automate-your-testing-workflows-using-browserstacks-ai-agents https://css-weekly.com/videos/automate-your-testing-workflows-using-browserstacks-ai-agents Find out how to use BrowserStack’s AI agents to automate your testing workflows. Fri, 12 Dec 2025 00:00:00 GMT Zoran Jambor Video Find out how to use BrowserStack’s AI agents to automate your testing workflows.

In this hands-on guide, you’ll see how to easily use the Test Case Generator Agent to turn user stories into detailed, structured test cases in seconds, and then convert those cases into automated tests with the Low-Code Authoring Agent.

Try BrowserStack for free

Baseline Status for Video

Chapters

00:00 Why you should automate your testing workflows
00:58 How to opt-in to BrowserStack AI
01:36 Overview of the demo project
03:09 Overview of BrowserStack AI Agents
03:31 How to use the Test Case Generator Agent to create structured test cases
06:03 How to use the Low-Code Authoring Agent to create automated tests
09:10 How to record a test flow using the Low-Code Automation
10:03 How to use AI to control recording flow in the Low-Code Automation
12:14 Why you should start using BrowserStack AI today

]]>
Chrome DevTools Elements Panel Tips & Tricks https://feedpress.me/link/24028/17255563/chrome-devtools-elements-panel-tips-tricks https://css-weekly.com/videos/chrome-devtools-elements-panel-tips-tricks Find out how to become more productive when working with the Elements panel in Chrome DevTools. Fri, 12 Dec 2025 00:00:00 GMT Zoran Jambor Video Find out how to become more productive when working with the Elements panel in Chrome DevTools.

Find out how to become more productive when working with the Elements panel in Chrome DevTools.

In this guide, you’ll learn how to hide inspect element popups that sometimes obscure your view, how to work with CSS classes effectively, and how to keep interactive elements, such as dropdowns, from disappearing while DevTools are focused.

Chapters

00:00 How to hide Inspect Element popups while hovering
01:06 How to hover over elements with pointer-events: none;
01:39 How to highlight all elements a CSS selector matches
02:07 How to work with CSS classes in the elements panel effectively
03:32 How to prevent dropdowns from disappearing while the DevTools are focused
05:26 How to use Command Palette in Chrome DevTools

]]>
Frontend News #19: CSS overscroll-behavior, scrollbar-gutter, text-grow Properties, & More https://feedpress.me/link/24028/17255564/frontend-news-19-css-overscroll-behavior-scrollbar-gutter-text-grow-properties-more https://css-weekly.com/videos/frontend-news-19-css-overscroll-behavior-scrollbar-gutter-text-grow-properties-more Find out how “overscroll-behavior: contain” is changing, how to use the scrollbar-gutter CSS property, what the new text-grow property does, how to analyze your CSS, and more. Tue, 09 Dec 2025 00:00:00 GMT Zoran Jambor Video Find out how “overscroll-behavior: contain” is changing, how to use the scrollbar-gutter CSS property, what the new text-grow property does, how to analyze your CSS, and more.

Find out how overscroll-behavior: contain is changing, how to use the scrollbar-gutter CSS property, what the new text-grow property does, how to analyze your CSS, and more.

Grab Piccalilli courses and level up your front-end skills

Chapters

00:00 About this episode
00:19 Use overscroll-behavior: contain to prevent a page from scrolling
03:02 Premium Piccalilli courses
04:12 A Tiny Bit-O-CSS for Stable Scrollbar Gutters
05:53 The Universal Focus Ring
06:43 Project Wallace, CSS Analytics
07:55 CSS text-grow

]]>
Practical Use-Cases for “overflow: clip;” https://feedpress.me/link/24028/17255565/practical-use-cases-for-overflow-clip https://css-weekly.com/videos/practical-use-cases-for-overflow-clip A brief guide outlining the difference between "overflow: hidden" and "overflow: clip". Fri, 05 Dec 2025 00:00:00 GMT Zoran Jambor Video A brief guide outlining the difference between "overflow: hidden" and "overflow: clip".

A brief guide outlining the difference between overflow: hidden and overflow: clip, along with practical use cases when you’ll find overflow: clip life-saving.

Chapters

00:00 The problem with “overflow-x: hidden”
01:12 How “overflow-x: clip” works
01:35 Practical use-cases for “overflow: clip”
02:23 Browser support for “overflow: clip”

Demo

https://codepen.io/ZoranJambor/pen/bNpQbJP

Links

]]>
Frontend News #18: Self-Destructing CSS, Throttle Specific Requests In Chrome DevTools https://feedpress.me/link/24028/17255566/frontend-news-18-self-destructing-css-throttle-specific-requests-in-chrome-devtools https://css-weekly.com/videos/frontend-news-18-self-destructing-css-throttle-specific-requests-in-chrome-devtools Find out why you should use self-destructing CSS pattern when working with web components, how to throttle specific requests in Chrome DevTools, and more. Wed, 03 Dec 2025 00:00:00 GMT Zoran Jambor Video Find out why you should use self-destructing CSS pattern when working with web components, how to throttle specific requests in Chrome DevTools, and more.

Find out why you should use self-destructing CSS pattern when working with web components, how to throttle specific requests in Chrome DevTools, and more.

Free Your Code Time: Get 50% Off Managed Hosting & 50 Free Migrations

Chapters

00:00 Intro
00:24 Enhancing Web Components Safely with Self-Destructing CSS
01:49 Cloudways — Get 50% Off Managed Hosting
02:32 How To Throttle Specific Requests In Chrome DevTools
03:58 It is OK to Say “CSS Variables” Instead of (or Alongside) “Custom Properties”
04:49 SVG Gobbler
05:39 Choose Your Monster - Customizable Select

]]>
Issue #630 https://feedpress.me/link/24028/17255567/issue-630 https://css-weekly.com/issue-630 Learn what upcoming CSS Masonry means for web developers, how to adjust perceived font weight in dark mode, how to create an adaptive SVG favicon, and more. Wed, 03 Dec 2025 00:00:00 GMT Zoran Jambor Newsletter Learn what upcoming CSS Masonry means for web developers, how to adjust perceived font weight in dark mode, how to create an adaptive SVG favicon, and more.

Masonry: Things You Won’t Need A Library For Anymore

Masonry: Things You Won’t Need A Library For Anymore

Patrick Brosset takes a deep dive into what CSS Masonry means for web developers and how you could make use of it in your own work.

Read more →


Using CSS To Fix the Irradiation Illusion

Using CSS To Fix the Irradiation Illusion

Adam Argyle explains how to adjust perceived font weight in dark mode without the layout shift, using variable fonts and the GRAD axis.

Read more →




From Our Sponsor

Last Chance: Get Certified with up to 50% OFF

Last Chance: Get Certified with up to 50% OFF

Your final opportunity this year to get certified in Vue, React, Angular, or JS with up to 50% off. Start the new year with validated skills and a credential that stands out. Offer ends soon.

Read more →




CSS Weekly on YouTube

<small>▶</small> How To Create an Adaptive SVG Favicon Using the prefers-color-scheme Media Query

How To Create an Adaptive SVG Favicon Using the prefers-color-scheme Media Query

Find out how to create an adaptive favicon that automatically switches to a light/dark color scheme using SVG icon format and prefers-color-scheme media query.

Read more →


<small>▶</small> Frontend News #18: Self-Destructing CSS, Throttle Specific Requests In Chrome DevTools

Frontend News #18: Self-Destructing CSS, Throttle Specific Requests In Chrome DevTools

Find out why you should use the self-destructing CSS pattern when working with web components, how to throttle specific requests in Chrome DevTools, and more.

Read more →




Articles & Tutorials

Grid: How grid-template-areas Offer a Visual Solution for Your Code

Saron Yitbarek gives a short introduction on how to use grid-template-areas to visually place elements on a grid.

Read more →


Dialog and Popover: Baseline Layered UI Patterns

David A. Herron shows how to build UI patterns for modal windows and prompts using the <dialog> and popover web features

Read more →


How To Use Web Components, and Why You’d Want To

Kevin Powell gives a nice introduction to Web Components.

Read more →


Scrollytelling on Steroids With Scroll-State Queries

Lee Meyer outlines some common use cases for scroll-based styling.

Read more →


Exploring Large HTML Documents On The Web

Matt Zeunert looks at examples of large HTML documents around the web and peeks into the code to see what’s making them so big.

Read more →




Sponsored Link

Save £60 on all Piccalilli courses and get a 50% discount coupon to use any time

Save £60 on all Piccalilli courses and get a 50% discount coupon to use any time

Every purchase of Complete CSS, Mindful Design and JavaScript for Everyone during this period gets you a 50% discount coupon that you can use at any time, on any course.

That means if you buy one course for £189 (down from £249), you get the next one for £124.50, saving over £180 against the full, £498 price of both courses!

Read more →




Tools

Indie UI

Indie UI is a collection of styled UI components, built with React.js, shadcn, and Framer Motion for animation.

Read more →


ShadcnThemer

Shadcn Themer is a web application that lets you create, customize, and share themes for shadcn/ui.

Read more →




Inspiration

Chrome: CSS Scroll Based Animations

Chrome: CSS Scroll Based Animations

Pim van Die created a stunning demo that showcases the power of scroll-based animations.

Read more →




Until Next Week

Thank you so much for reading!

If you want to support this newsletter and my work, check out:
CSS Stickers
CSS Weekly on Buy Me a Coffee
CSS Weekly on Patreon
CSS Weekly YouTube Channel
Mastering Linting
Happy coding,
Zoran Jambor

]]>
Issue #629 https://feedpress.me/link/24028/17255569/issue-629 https://css-weekly.com/issue-629 Learn the new range syntax for CSS style queries and the if() function, the exciting new things you can do with subgrid, and more. Tue, 25 Nov 2025 00:00:00 GMT Zoran Jambor Newsletter Learn the new range syntax for CSS style queries and the if() function, the exciting new things you can do with subgrid, and more.

Range Syntax for Style Queries

Range Syntax for Style Queries

Una Kravets explains how to use the new range syntax for CSS style queries and the if() function.

Read more →


Brand New Layouts with CSS Subgrid

Brand New Layouts with CSS Subgrid

Joshua Comeau demonstrates some of the exciting new things you can do with subgrid, and, along the way, explains the basic mechanics of subgrid.

Read more →




From Our Sponsor

Save £60 on all Piccalilli courses and get a 50% discount coupon to use any time

Save £60 on all Piccalilli courses and get a 50% discount coupon to use any time

Every purchase of Complete CSS, Mindful Design and JavaScript for Everyone during this period gets you a 50% discount coupon that you can use at any time, on any course. That means if you buy one course for £189 (down from £249), you get the next one for £124.50, saving over £180 against the full, £498 price of both courses!

Read more →




CSS Weekly on YouTube

<small>▶</small> How to Easily Create Modern, CSS-First Forms in WordPress

How to Easily Create Modern, CSS-First Forms in WordPress

Learn how to build stylable forms in WordPress using the IvyForms plugin easily. Along the way, you’ll learn how to use Chrome DevTools Changes drawer, how to tweak colors consistently using OKLCH color format, how to apply additional CSS in WordPress theme editor, and more.

Read more →


<small>▶</small> How To Add Additional CSS to a WordPress Theme When “Customize” Is Missing

How To Add Additional CSS to a WordPress Theme When “Customize” Is Missing

Learn two simple (but confusing) ways to add Additional CSS to WordPress, even if your theme is missing the “Appearance – Customize” option.

Read more →




Articles & Tutorials

Introduction to CSS if Statements and Conditional Logic

Matt Lawrence gives a nice, detailed guide to conditional logic in CSS.

Read more →


How to Create 3D Images in CSS with the Layered Pattern

Sunkanmi Fafowora shows how to stack multiple items into layers, adjusting the Z position and colors of each item based on its index value to create an illusion of 3D.

Read more →


light-dark() Isn’t Always the Same As prefers-color-scheme

Stefan Judis explains why the new light-dark() CSS function isn’t a drop-in replacement for prefers-color-scheme media queries.

Read more →


Responsive Letter Spacing

Tyler Sticka outlines an interesting approach to responsive letter spacing.

Read more →


Keyframes Tokens: Standardizing Animation Across Projects

Amit Sheen explains how to consolidate and standardize keyframes to turn animations into a clear, predictable system.

Read more →




CSS Weekly Black Friday Deal

Get Your CSS Stickers Pack for 40% Off — This Week Only

Get Your CSS Stickers Pack for 40% Off — This Week Only

If you still haven’t gotten your CSS Stickers pack, now is your chance to get it with a massive 40% discount. If you jump on this deal, you won’t only get an awesome stickers pack, but you’ll also support my work and CSS Weekly—thanks. Use the coupon code BLACKFRIDAY2025 at checkout.

Read more →




Tools

Monorail

A tool that allows you to turn any CSS keyframe animation into an interactive graph. You might find it useful for animation debugging or breaking down complex animations.

Read more →


Awesome Tailwind CSS

A collection of high-quality resources related to Tailwind CSS.

Read more →




Inspiration

Hypnotic Animation Using sibling-Index() + corner-shape

Hypnotic Animation Using sibling-Index() + corner-shape

Chris Bolson created a mesmerizing animation by combining sibling-index() and corner-shape.

Read more →




Until Next Week

Thank you so much for reading!

If you want to support this newsletter and my work, check out:
CSS Stickers
CSS Weekly on Buy Me a Coffee
CSS Weekly on Patreon
CSS Weekly YouTube Channel
Mastering Linting
Happy coding,
Zoran Jambor

]]>
Issue #628 https://feedpress.me/link/24028/17255572/issue-628 https://css-weekly.com/issue-628 Learn how to create timetable layouts using CSS, practical uses for the random() function, how to create performant SVG maps, and more. Wed, 19 Nov 2025 00:00:00 GMT Zoran Jambor Newsletter Learn how to create timetable layouts using CSS, practical uses for the random() function, how to create performant SVG maps, and more.

Building a multi stage timetable with modern CSS using grid, subgrid, round(), and mod()

Building a multi stage timetable with modern CSS using grid, subgrid, round(), and mod()

Nils Binder explains how to create timetable layouts using modern CSS features.

Read more →


More CSS random() Learning Through Experiments

More CSS random() Learning Through Experiments

Chris Coyier demonstrates the power of the CSS random() function.

Read more →




From Our Sponsor

Free Your Code Time: Get 50% Off Managed Hosting & 50 Free Migrations

Free Your Code Time: Get 50% Off Managed Hosting & 50 Free Migrations

Deploy more, spend less. This BFCM, cut your server costs in half for 3 months and offload the tedious work. Get 50% off on all plans and 50 free, hands-off migrations. Perfect for spinning up new client sites, staging environments, or moving legacy projects you’ve been working on. Free up your time for the code that matters, not server management.

Read more →




CSS Weekly on YouTube

<small>▶</small> Create Performant, Stylable Map UI Components Using MapSVG

Create Performant, Stylable Map UI Components Using MapSVG

Learn how to use the MapSVG WordPress plugin to create customizable, performant map UI components that you can easily style with CSS.

Read more →




Articles & Tutorials

Some practical examples of view transitions to elevate your UI

Declan Chidlow shares practical uses of view transitions, the things that will trip you up, and guidance to help you navigate them.

Read more →


The Range Syntax Has Come to Container Style Queries and if()

Daniel Schwarz explains why the range syntax, coming to container style queries and the if() function, represents CSS’s biggest leap in terms of conditional logic.

Read more →


CSS Gamepad API Visual Debugging With CSS Layers

Godstime Aburu created a deep dive on how CSS can help you debug controllers and build a reusable visual debugger for your own projects.

Read more →


Animating CSS width or height no longer forces a Main Thread animation  (in Chrome, under the right conditions)

Bramus Van Damme shares an exciting animation/performance change that recently landed in Chrome Canary.

Read more →


A complete guide to the HTML number input

Ollie Williams explains everything you need to know about the HTML number input.

Read more →




Sponsored Link

Final Hours: 60% Off Dev Certifications + $469 in Bonuses. Ends Tonight!

Final Hours: 60% Off Dev Certifications + $469 in Bonuses. Ends Tonight!

Vue & Nuxt official certs, React, Angular & JS expert-reviewed paths — up to 60% off! Includes 2 AI dev courses + a Junior cert free. Built by industry leaders & trusted by 680+ companies like IBM & PwC.

Read more →




Tools

Mirrow

Mirrow is a playground and production tooling for SVGs. It lets you design, style, and animate everything in a single file and get ready-to-use code for React, Svelte, and beyond.

Read more →


Typing SVG Generator

A Powerful Typing SVG Generator—it supports multi-line & blank-space formatting, multiple cursor styles, customizable delete speed, and more.

Read more →




Inspiration

Pure CSS (-_-) I See U

Pure CSS (-_-) I See U

A stunning CSS-only demo of an eye that follows the mouse cursor.

Read more →




Until Next Week

Thank you so much for reading!

If you want to support this newsletter and my work, check out:
CSS Stickers
CSS Weekly on Buy Me a Coffee
CSS Weekly on Patreon
CSS Weekly YouTube Channel
Mastering Linting
Happy coding,
Zoran Jambor

]]>
Top 5 CSS Navigation Menu Mistakes https://feedpress.me/link/24028/17256030/top-5-css-navigation-menu-mistakes https://css-weekly.com/top-5-css-navigation-menu-mistakes Find out how to improve the UI of your navigation menus with a few lines of CSS. Tue, 08 Apr 2025 00:00:00 GMT Zoran Jambor Article Find out how to improve the UI of your navigation menus with a few lines of CSS.

Along the way, you'll learn how to create a delayed closing effect for the dropdown menu, utilize the :has() pseudo-class to simplify your HTML structure, and more.

This article is a result of my subjective experience of noticing problems with the navigation menus of products and apps I've been using in the past few weeks. The same patterns and problems are repeated often, and I outline them here.

Note This guide is focused on the UI of the navigation menus for the sake of
brevity and clarity. One of the most important aspects of any interactive
component, including navigation menus, is accessibility, and I will cover this
in a follow-up guide.

Demo & Setup

The navigation Menu HTML structure is straightforward. The top-level navigation menu is designated with the class .menu and dropdown with .submenu. I’ve applied some basic styling—you’ll find the relevant demo code in the @layer demo { ... } at the top of CSS.

The final demo, with all tips from this article applied:

https://codepen.io/ZoranJambor/pen/VYwNJPp/9a005c9b6e41f35dc5db10a45667f73f?editors=0000

The HTML here is cleaned up for the sake of brevity. I would heavily rely on classes instead of cascade in a real-world project to reduce specificity.

The dropdown is styled horizontally to make the mistakes more apparent in this simple demo—I'm not suggesting that the horizontal pattern is better or preferable to a classic, vertical one.

Mistake #1: Small target areas

The target area of text-only menus is often too small, making the interactions with navigation items cumbersome, especially on touch devices.

A screenshot of a navigation menu showcasing too small target areas.

The way to fix this mistake is to add additional padding around the anchor links, thus expanding the interactive, clickable area.

/**
 * Expand the target area
 * for links by adding padding.
 */
.menu a {
  padding-inline: 1rem;
  padding-block: 0.5rem;
}

Once you apply additional padding, the perceived gap between items will increase, so make sure to adjust it, keeping in mind that there always should be a space between menu items.

A screenshot of a navigation menu showcasing expanded target area.

Mistake #2: Not using gap with Flexbox

Navigation menus are most often created using Flexbox, as it provides an easy way to adjust positioning and alignment, but the Flexbox is not utilized fully, and the spacing between items is added using margin.

Patterns I see in this case, which all work but are unnecessary:

/* Using an owl selector to add margin only on subsequent items. */
.menu > * + * {
  margin-left: 1rem;
}

/* Using :not() to avoid adding margin to the last (or first) item. */
.menu > li:not(:last-child) {
  margin-right: 1rem;
}

/* Resetting the margin on last/first item to zero. */
.menu > li {
  margin-right: 1rem;
}
.menu > li:last-child {
  margin-right: 0;
}

Instead, you can use the gap property with Flexbox to add spacing only between items without.

/**
 * You can use the `gap` property
 * with Flexbox.
 */
.menu {
  display: flex;
  gap: 1rem;
}

A screenshot of a navigation menu showcasing gaps between menu items.

Note that the gap property did not work with Flexbox initially when Flexbox was first released, so you had to resort to a different solution, but this is now in the Baseline and has worked in all modern browsers since April 2021.







Mistake #3: Unforgiving target areas for dropdowns

Similar to the first point, navigation menus with dropdowns should have forgiving target areas, and this specifically means that you need to adjust the target area to the path most likely taken by a user.

A screenshot of a navigation menu showcasing the potential path of a mouse cursor for a dropdown menu.

The easiest way to fix this mistake is to add a pseudo-element and position it to cover the empty area users will likely utilize.

/**
 * Expand the target area of dropdown menus
 */
.submenu::after {
  content: "";
  display: block;
  position: absolute;
  width: 100%;
  height: 3rem;
  bottom: 100%;
  left: 0;
  /* background: darkred; */
}

To test this and tweak the positioning, add a background to the pseudo-element, and once you’re happy with the result, remove it, making the element transparent. This will increase the target area without affecting the visual style.

A screenshot of a navigation menu showcasing an additional pseudo-element that expands the target area of the dropdown.

Note that the element is going underneath other top-level menu items, so it won’t interfere with user interactions with those elements.

Mistake #4: No delay before closing dropdowns

This point is tied directly with the previous one—you want to create forgiving target areas for clicks, touch, and hover events.

If a user accidentally moves the mouse away from the dropdown menu, you don’t want to close it immediately; you want to give the user a chance to reposition their pointer and continue where they left off without starting from zero by moving the mouse to the top-level item. As you suspect, this becomes more and more crucial as the number of your dropdown menu levels increases.

You can achieve this with a bit of JavaScript. When the user hovers over an item with a dropdown, you add a class to the item or tweak the style directly, and after the user hovers away from the dropdown tree, you delay the closing of the dropdown a bit.

/**
 * A simplified example of how you might
 * implement menu delay with one sublevel.
 */
const menus = document.querySelectorAll(".menu > li");
const submenus = document.querySelectorAll(".submenu");

// Track the timeout delay
let hideTimeout = null;

// Add event listeners to all top-level items
menus.forEach((menu) => {
  const submenu = menu.querySelector(".submenu");

  menu.addEventListener("mouseenter", (e) => {
    // Immediately hide all (other) dropdown menus
    submenus.forEach((otherSubmenu) => {
      otherSubmenu.style.display = "";
    });

    // And show the child submenu
    if (submenu) {
      clearTimeout(hideTimeout);
      submenu.style.display = "flex";
    }
  });

  // There's no need for mouseleave event if the item has no dropdown
  if (!submenu) return;

  // Close the menu after the timeout
  // This can be canceled in the mouseenter event
  menu.addEventListener("mouseleave", () => {
    hideTimeout = setTimeout(() => {
      submenu.style.display = "";
    }, 500);
  });
});

This is a simplified example of how you might handle a delayed closing—it doesn’t take into consideration that there might be additional sublevels of dropdown menus, nor the positioning of the dropdown when there isn’t enough space on the screen.

CSS-Only Dropdown Delay

Alternatively, you can achieve a delayed closing effect without JavaScript, using only modern CSS.

Note This is an experimental technique that aims to showcase the power of modern
CSS, but it still doesn't work in all browsers and currently has a major
downside in Chrome—don't use it in production.

The dropdown menu show/hide interaction is created using the display property:

/* Hide the dropdown by default. */
.submenu {
  display: none;
  /* Plus properties related to positioning & styling. */
}

/* Show the dropdown when its parent menu item is hovered. */
.menu li:hover a + .submenu {
  display: flex;
}

Using transition-behavior, you can transition the display property and have it delay closing, mimicking the complex JavaScript behavior in a few lines of CSS.

/**
 * Delay the closing of the dropdown
 * menu on mouseout using only CSS.
 */
.submenu {
  transition: display 1s;
  transition-behavior: allow-discrete;
}

You can transition non-animatable properties using transition-behavior: allow-discrete; as there is no in-between state from none to block (or flex), the value will be flipped on transition-in before the start of the animation and on transition-out after the end of the animation, as defined in transition-duration, meaning that the dropdown will stay entirely visible until the transition finishes (1s in the example).

Unfortunately, this isn’t a viable option at the moment, as it doesn’t work in Firefox (Firefox doesn’t support transitioning display property yet), and it is severely bugged in Chrome, where the items in the dropdown become inaccessible when the transition-delay is triggered. This means that Safari is currently the only browser where this works as expected.

Additionally, we need to create the code to close the dropdown immediately when a user hovers over another top-level item. An approach I’ve been exploring is using :has() pseudo-class to set the transition to none (thus canceling the transition and changing the value immediately) when a top-level item is hovered over.

/**
 * Stop the transition when another menu item is hovered
 * by resetting the transition to `none`
 * on all menu items that are not hovered over,
 * but only when one of the menu items is in the state of hover
 */
.menu ul:has(> .li:hover) .li:not(:hover) .submenu {
  transition-property: none;
}

Unfortunately, this isn't a reliable approach as it doesn't work in Safari—it seems that the transition can't be interrupted once it starts.

https://codepen.io/ZoranJambor/pen/emYeZXv?editors=0000

A demo showing how CSS-only dropdown menu delay works, along with issues in various browsers.

This CSS-only solution will hopefully be supported cross-browser in the near future, but until then, you still need a bit of JavaScript to create a close delay effect for your dropdown menus.

How to use :has() pseudo-class to add arrows on menu items with submenus

You can utilize :has() to easily create an arrow that indicates an existing dropdown without adding additional classes to HTML.

/**
 * Add an arrow to menu items that have a submenu,
 * defined as `a` elements that have the next sibling `.submenu`
 */
.menu a:has(+ .submenu)::after {
  content: "▼";
  margin-left: 1em;
  font-size: 0.5em;
  position: relative;
  top: -0.2em;
}

A screenshot of a navigation menu showcasing an arrow indicating a presence of a dropdown menu created using :has() pseudo-class.

Mistake #5: Not animating anchor links

The last of the common mistakes I usually see is using in-page anchor links without animating them.

By default, when you create an anchor link and tie it to a section on the page using an id attribute, the page will immediately jump to the target section once the user clicks it.

A much nicer and clearer experience is to scroll the page elegantly to the target section. You don’t even have to use JavaScript to handle this; there is a CSS property, scroll-behavior, that lets you define how the browser handles the scrolling when triggered by the navigation or CSSOM scrolling APIs.

You can set it to any element with a scrollable overflow; this would be the root element for the viewport (entire page).

/**
 * Enable smooth scroll for anchor links.
 */
html {
  scroll-behavior: smooth;
}

If you are using scroll-behavior: smooth;, you’ll want to make sure to provide an alternative experience to users who prefer an interface that removes, reduces, or replaces motion-based animations.

/**
 * Disable anchor link animations for
 * users who prefer less motion.
 */
@media (prefers-reduced-motion) {
  html {
    scroll-behavior: auto;
  }
}

Proving my point, Hashnode, the platform I’m using to publish this, should add scroll-behavior: smooth; to improve the experience for the Table of contents element linking to the sections of this article.

Conclusion

Most of the advice shared here is straightforward and obvious, but I still see many of these mistakes in the wild, so take this as a reminder that with just a few lines of CSS, you can make your navigation menus and UI much more user-friendly and usable.

As I’ve already mentioned, this is just a part of the story of creating good navigation menus. The other significant part that you shouldn’t ignore is accessibility, and I will cover this in a follow-up article where I’ll show you how to make dropdown menus accessible.

Further Learning

]]>
Start Using Minimap Section Headers in VS Code https://feedpress.me/link/24028/17256031/start-using-minimap-section-headers-in-vs-code https://css-weekly.com/start-using-minimap-section-headers-in-vs-code Learn how to get the most out of Visual Studio Code minimap and turn it into a valuable, indispensable tool in your coding workflow. Fri, 13 Dec 2024 00:00:00 GMT Zoran Jambor Article Learn how to get the most out of Visual Studio Code minimap and turn it into a valuable, indispensable tool in your coding workflow.

You’re likely more than familiar with the minimap in Visual Studio Code—it gives you a quick overview of the currently opened file, so you can easily jump to any part of the code you want to work on. But minimap is actually much more powerful than this. In this article, you’ll learn how to get the most out of it and make it actually useful beyond just being an oversized scrollbar.

The minimap has several customizable options, and you’ll find them in Settings under ”Text Editor → Minimap.”

VS Code screenshot showing the minimap options under Text Editor -> Minimap.

How Minimap Section Headers Work

Most minimap options are straightforward and clearly explained, so I’ll outline here the one option you might not be aware of: Section Headers.

Section headers allow you to display specially designated comments in the minimap, which makes it trivial to quickly find a specific section of your code. You can enable them by toggling the option “Show Mark Section Headers.”

VS Code screenshot showing the minimap option Show Mark Section Headers.

When enabled, any comment you add to your code designated with “MARK:” will be visible in the minimap. Note that the designation is case-sensitive, so it must be in uppercase to work.







Additionally, all characters after MARK: will be visible in the minimap, including the closing comment characters like */ or --!>, so use them with single-line comments or format your comments in a way that comment opening and closing strings are on the separate lines. Keep this in mind when working with languages that only support multi-line comments, like CSS or HTML.

VS Code screenshot showing what minimap section headers look like in a CSS file.

You can tweak the styling of the section headers by adjusting the "Section Header Font Size" and "Section Header Letter Spacing" options. Depending on how you set up your minimap size (Scale option in settings), you'll want to tweak this and potentially increase the font size to make it more apparent.

VS Code screenshot showing section headers with a bigger font size.

I like the font size set to 16 and the letter spacing to 0. If you're using smaller font sizes, consider increasing letter spacing to make the section headers more readable.

How Section Headers Work With Named Folding Regions

Section headers in minimap also work with named folding regions. You can enable this option in minimap settings under "Show Region Section Headers."

VS Code screenshot showing the minimap option Show Region Section Headers.

Named regions allow you to collapse/expand a specific, arbitrary part of code, and they are created with a special comment that looks along the lines of //#region to designate the start of the region and //#endregion to designate the end of the region.

Note You can find the list of folding range designations for different
languages in VS Code Docs

Any string after the opening region designation will appear as a section header in the minimap.

VS Code screenshot showing named folding regions in the minimap.

The downside of named folding regions is that they don't work in minimap as section headers for all languages. In CSS, you can create a named folding range, but its name will not appear in the minimap, at least not in the current version of Visual Studio Code, 1.96.0.

Conclusion

Using section headers can make your minimap more valuable, as they allow you to quickly jump to different parts of code. This can be especially useful in larger files or when you often jump between key parts of the code in one file.

Additionally, section headers can make your code more readable, as they'll force you to organize it into logical sections, improving your workflow and making you a bit more productive.

]]>
<![CDATA[Transition to <code>height: auto;</code> & <code>display: none;</code> Using Pure CSS]]> https://feedpress.me/link/24028/17256032/transition-to-height-auto-display-none-using-pure-css https://css-weekly.com/transition-to-height-auto-display-none-using-pure-css Find out how to easily transition to intrinsic sizes and trigger transitions when an element receives its first style update using new CSS features. Thu, 08 Aug 2024 00:00:00 GMT Zoran Jambor Article Find out how to easily transition to intrinsic sizes and trigger transitions when an element receives its first style update using new CSS features.

UPDATE, September 12, 2024: In the earlier version of this article, calc-size was used with a single
argument, like this: calc-size(auto). This is no longer supported;
calc-size() works only as a two-argument form, so the article and all demos
are updated to reflect this, and instead of calc-size(auto), you should now
use calc-size(auto, size).

CSS Transitions are the easiest way to add interactions on the web; all you need is an element in two different states with the transition property applied to its initial state, and the browser will smoothly animate the element between these two states.

The challenging part when working with CSS Transitions is dealing with intrinsic element sizes like auto and running transitions when an element receives its first style update—when it’s added to DOM, on page load, or when its display value changes from none. In this article and video, you’ll learn how to deal with both cases using upcoming CSS features: calc-size() function, interpolate-size property, @starting-style at-rule, and transition-behavior property.

Note: The features mentioned in this article are experimental, subject to change,
and not yet ready for production. However, you can test them and use them as
progressive enhancements today.

CSS Transition to intrinsic size (height: auto;)

Let’s say you want to create a disclosure widget that expands an element from its initial, closed state (height: 0;) to an open state, showing all its content (height: auto;).

A simplified setup for this could look something like this:

.disclosure-widget {
  height: 0;
  transition: all 0.7s ease-in-out;
}

.disclosure-widget[open] {
  height: auto;
}

Initially, the widget is in a closed state with height: 0;, and when the attribute open is present on the HTML element, the widget expands to its content-based height. As the transition property is defined on the widget, it would be reasonable to assume that this switch between states will be animated, but it doesn’t work.

https://codepen.io/ZoranJambor/pen/rNEwVjz/c4cf9c533985e001a47a4f31cc287199

This element’s height is expected to be smoothly animated as the transition property is set, but it doesn't work.

Note: The height property is used in the examples for clarity and simplicity, but you should be using its logical equivalent, block-size. If you want to learn more about logical properties, check out my video, Guide to Logical CSS Properties.

The animation doesn’t happen because browsers don’t support the transition to intrinsic sizing keywords such as auto or min-content. The new interpolate-size property and calc-size() function will allow you to circumvent this and perform math on intrinsic sizes in a safe, well-defined way.







CSS calc-size() function

The calc() CSS function lets you perform calculations when specifying CSS property values, with one of the best features being that you can mix various data types, like pixels and percentages. For example, width: calc(90% - 10px); will give you exactly the value you’re looking for, 90% of the screen width reduced by 10px.

The downside of calc() is that it doesn’t support calculations on intrinsic sizing keywords, including auto, and that’s precisely why the new calc-size() function was introduced—to allow calculations and thus transitions and animation to or from intrinsic sizes.

The CSS calc-size() function is a CSS function similar to calc(), but that also supports operations on exactly one of the values auto, min-content, max-content, fit-content, stretch, or contain, which are the intrinsic sizing keywords. This allows transitions and animations to and from these values (or mathematical functions of these values), as long as the calc-size() function is used on at least one of the endpoints of the transition or animation to opt in.

Explainer: calc-size() function for transitions and animations to/from intrinsic sizes

The calc-size function takes two arguments. The first argument is the basis, and the second argument is the calculation, where the passed basis argument, is available as the size keyword. This means we can rewrite our rule as height: calc-size(auto, size);, and our transition should immediately work:

.disclosure-widget[open] {
  height: calc-size(auto, size);
}

https://codepen.io/ZoranJambor/pen/gONRzbG/76f6397d24217197860fd5267751b61b

Passing the auto keyword in calc-size() enables the browser to animate the transition.

The calc-size() is not supported in all browsers, so as a fallback, you can leave the height declaration from the original example in the code—in which case, browsers that don’t support calc-size() will ignore its declaration and fallback to height: auto;:

.disclosure-widget[open] {
  height: auto;
  height: calc-size(auto, size);
}

The second, calculation argument lets you perform any calculations you can with calc(), including calculations on intrinsic sizes: calc-size(auto, size + 50px) .

CSS interpolate-size property

The calc-size() function does solve our transitioning problems with intrinsic sizes (including height: auto;), but it still feels like a hack unless you’re trying to do an actual calculation.

That's precisely why we got the interpolate-size property, which lets you choose the interpolation behavior and decide for yourself if you want the browser to interpolate intrinsic sizes.

The default value is numeric-only, which is the behavior you’re familiar with, where only transitions and animations to numeric values (like 250px) work. The new value you can use is allow-keywords, which will, as it clearly states, let you interpolate between keyword values.

To enable this new animation behavior, specify the interpolate-size on the :root element to opt-in to the new behavior for the entire page:

:root {
  interpolate-size: allow-keywords;
}

Of course, you can restrict it to elements that you want, but even W3C specification suggests you enable the new behavior for the entire page:

Specifying interpolate-size: allow-keywords on the root element chooses the new behavior for the entire page. We suggest doing this whenever compatibility isn’t an issue.

Once we set interpolate-size to allow-keywords in our demo, we can remove the calc-size() function and only use the value auto.

https://codepen.io/ZoranJambor/pen/eYwRjoX/1a2a5121d82f1833dc0591590dd05e7a

Specifying interpolate-size: allow-keywords; on the :root element enables the new animation behavior for the entire page.

It will work precisely as expected, exactly as it should have worked from the start when we got CSS Transitions. A similar stance is represented in W3C Editor’s Draft CSS Values and Units Module Level 5:

If we had a time machine, this property wouldn’t need to exist. It exists because many existing style sheets assume that intrinsic sizing keywords (such as auto, min-content, etc.) cannot animate. Therefore this property exists to allow style sheets to choose to get the expected behavior.

Browser support for CSS interpolate-size property and calc-size() function

The calc-size() function and interpolate-size property are supported by default in Chrome 129.

Neither calc-size() nor interpolate-size works in Safari or Firefox, but there are open issues on GitHub for both Firefox and Safari, so hopefully, we'll see these features in Baseline soon.

Features status by vendor:
Blink - Shipping on desktop 128
WebKit - Unknown
Mozilla - Unknown

You can check if the browser supports calc-size() and interpolate-size using the @supports at-rule:

/* Check calc-size() function support */
@supports (height: calc-size(auto, size)) {
  /* ... */
}

/* Check interpolate-size property support */
@supports (interpolate-size: allow-keywords) {
  /* ... */
}

Workaround with JavaScript

As neither calc-size() nor interpolate-size are part of Baseline, you will need to use a workaround to transition to intrinsic size if you want to see animations in production.

One reliable workaround is to calculate the element size in JavaScript and then set that exact number as the container height instead of the keyword auto—in this case, CSS Transitions will work, as you’ll circumvent intrinsic sizes with numbers.

In CSS, you only need to set the widget height and its transition:

.disclosure-widget {
  height: 0;
  transition: all 0.7s ease-in-out;
}

In JavaScript, first, get the widget’s closed state height (because it could be different from 0), then set the height to auto to force content-sized dimensions, get the element’s height and store it, and lastly, return the widget to its initial height:

// Get page elements
const toggle = document.querySelector(".toggle");
const widget = document.querySelector(".disclosure-widget");

// Widget State
let isOpen = false;

// Get the widget open/closed height
const closedHeight = widget.style.height;
widget.style.height = "auto";
const openHeight = widget.offsetHeight + "px";
widget.style.height = closedHeight;

// Handle widget state switch
toggle.addEventListener("click", (e) => {
  let height = isOpen ? closedHeight : openHeight;

  widget.toggleAttribute("open");
  widget.style.height = height;
  isOpen = !isOpen;
});

https://codepen.io/ZoranJambor/pen/LYKLepZ/930f4ada9257b219d2e17cf6c520e0d6

This JavaScript-based solution works in all modern browsers and doesn’t require extra markup in HTML.

The downsides of this approach are more complexity in JavaScript and potential performance penalties, as calculating the correct size of the element requires forcing extra layouts to happen.

Workaround with CSS Grid

There is also an alternative approach using CSS Grid and fraction units to get around this issue. As CSS Grid and its fr units are animatable, you can set the closed state of grid-template-rows to 0fr and then transition the open state to 1fr. As long as you have only one row in your grid, 1fr will take the entirety of available space, which translates exactly to the auto value.

This is how the setup could look:

.disclosure-widget {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: all 0.7s ease-in-out;
}

.disclosure-widget__container {
  min-height: 0;
}

.disclosure-widget[open] {
  grid-template-rows: 1fr;
}

https://codepen.io/ZoranJambor/pen/abgwVEr/ba5b0e1b4b96cdcd6d9aaa8bd48d7e40

This CSS Grid-based solution works in all modern browsers.

The downsides of this approach are that you need an extra element in HTML as a container, and you’re forced to opt-in to CSS Grid even if you don’t really need it.

CSS Transition from display: none;

Another challenge related to transitioning from height: 0; to height: auto; is that often, in real-world scenarios, you’ll want this transition to happen at the moment the element receives its first style update—on page load, when it’s added to DOM, or when its display property changes from none.

Let’s update our calc-size() example so that in the hidden state, the element is not only visually hidden but also hidden from screen readers using display: none;.

.disclosure-widget {
  display: none;
  height: 0;
  transition: all 1s ease-in-out;
}

.disclosure-widget[open] {
  display: block;
  height: auto;
  height: calc-size(auto, size);
}

https://codepen.io/ZoranJambor/pen/oNrwPQG/3e0e601693327646b5ba468f384d261a

After adding display: none; to the hidden state, the animation no longer works.

As you might have expected, the transition (animation) is no longer working because the display is not an animatable property, meaning it can’t gradually be flipped from none to block. When the transition occurs, the value changes immediately, and the element disappears without transition. Likewise, the element is not animated on animation-in because CSS Transitions are not triggered on an element's initial style update—when its display changes from none to another value.

Let’s work around both of these issues with new CSS additions, the @starting-style at-rule, and the transition-behavior property.

CSS @starting-style at-rule

You can use @starting-style at-rule to enable transitions when the display value changes or when an element is first added to the page.

Within the @starting-style block, you simply need to specify the rules from which you want the transition to start. This is necessary because the elements that are first-time added to the page don’t have a previous state, so there is nothing from which the browser can create a transition to the state you want.

For our example, the only value we want to transition is height, so our @starting-style will look like this:

.container[open] {
  height: calc-size(auto, size);
  display: block;

  @starting-style {
    height: 0;
  }
}

https://codepen.io/ZoranJambor/pen/poXwOGo/8766d670276e4dcabd012f1b3489c8e0

With initial styles specified in @starting-style at-rule, the browser can animate the transition on the first style update—when the display value changes from none.

The @starting-style at-rule can be used as a standalone rule or nested within a ruleset. In the previous example, we nested it directly within our selector. If you want to use it as a standalone rule, you need to specify the selector for which it should be applied:

@starting-style {
  .container[open] {
    height: 0;
  }
}

The @starting-style at-rule doesn’t increase the specificity—it has the same specificity as the original rule, so make sure you include it after your original rule to avoid the situation where your original rule overrides it.

CSS transition-behavior property

The @starting-style at-rule fixes our transition-in problem, but transition-out is still not working. As mentioned, display isn’t an animatable property, so its value is immediately flipped from block to none when the transition starts—hiding the animation.

That’s where the transition-behavior property comes in. It lets you specify if transitions should be started for properties that aren’t animatable; specifically for properties whose animation behavior is discrete, like display and content-visibility.

Possible values for transition-behavior are normal and allow-discrete. The normal value means that transitions won’t be started for discrete properties, and it’s the default behavior.

If we change the transition-behavior in our example to allow-discrete, our transition-out will work as expected:

.disclosure-widget {
  display: none;
  height: 0;
  transition: all 0.7s ease-in-out;
  transition-behavior: allow-discrete;
}

https://codepen.io/ZoranJambor/pen/gONRdEB/0e7e11faa4b43bd49e701c1f7f9b61fe

Specifiying transition-behavior: allow-discrete; tells the browser to start transitions for non-animatable properties.

The transition-behavior: allow-discrete; changes the behavior of the display property by flipping its value at the end of the transition so that the animation has time to happen before the element ‘disappears.’

The thing to note is that you need to specify the transition on the discrete property as well. In our example, we’ve used the all keyword, which includes all properties. However, if we switch this to only height, transition-behavior won’t have any effect because we’re not transitioning the display property. Only when we specifically add it as a transition-property will the transition-behavior apply to it.

If we rewrite our transition from the shorthand values, this is how it would look:

.disclosure-widget {
  display: none;
  height: 0;
  transition-property: height, display;
  transition-duration: 0.5s;
  transition-timing-function: ease-in-out;
  transition-behavior: allow-discrete;
}

You can use the @starting-style at-rule and transition-behavior property combo any time you want to apply a transition to elements that are injected into DOM or on page load and with all disclosure widgets (native or custom) like Dialog, Popover, and so on.

Browser support for CSS @starting-style at-rule and transition-behavior property

The @starting-style at-rule is supported in stable versions of Chrome, Edge, Safari, and Firefox.

The transition-behavior property is supported in stable versions of Chrome and Edge but not in Safari and Firefox. It should ship in Safari 18, but there is no indication when it will be available in Firefox.

There is a problem with the current version of Firefox, version 129. The @starting-style at-rule doesn’t support animating from display: none;, so in this case, the transition-in in our demo will not be animated in Firefox.

Still, you can use both new features immediately as progressive enhancement. In the browsers that support those properties, users will see nice, animated transitions, and in the browsers that don’t support them, disclosure widgets will be functional, just not animated.

You can check if the browser supports transition-behavior using the @supports at-rule:

/* Check transition-behavior property support */
@supports (transition-behavior: allow-discrete) {
  /* ... */
}

Detecting @starting-style() support is not that necessary as the feature is already in Baseline, and it’s a bit more complicated, as @supports still can’t detect at-rules. Once the browsers implement at-rule support detection, you’ll be able to test it like this:

/* Check @starting-style() at-rule support */
@supports at-rule(@starting-style) {
  /* ... */
}

Workaround with JavaScript

An alternative solution, if you don’t want to use transition-behavior as progressive enhancement, is to switch the display value after the transition finishes using JavaScript.

Even though the @starting-style at-rule is supported in all modern browsers, for simplicity and clarity, we’ll handle both cases manually:

// Get page elements
const toggle = document.querySelector(".toggle");
const widget = document.querySelector(".disclosure-widget");

// Widget state
let isOpen = false;

// Set display to "block" immediately after clicking
// the button before adding the "open" attribute
// to ensure the CSS transition happens
toggle.addEventListener("click", (e) => {
  if (isOpen === false) {
    widget.style.display = "block";
  }

  // Ensure the display is switched before
  // the "open" attribute is toggled
  requestAnimationFrame(() => {
    widget.toggleAttribute("open");
  });

  // Click always toggles the state
  isOpen = !isOpen;
});

// At the end of the transition,
// when the widget is closed,
// hide it by changing the display value
widget.addEventListener("transitionend", (event) => {
  // We only want to trigger this on the close transition
  if (isOpen === false) {
    widget.style.display = "none";
  }
});

https://codepen.io/ZoranJambor/pen/wvLeOYr/beaf789d3432264a492e84dcf774804f

On animation-in, we switch the display property to block and wait using requestAnimationFrame until the next tick of the event loop to flip the open attribute and trigger the CSS Transition.

On animation-out, we wait for the transition to end using the transitioned event and only then switch the display to none to give the browser time to finish the transition before we hide the element.

Conclusion

Hopefully, this gives you an idea of how new CSS features can simplify your code by entirely removing Javascript requirements, allowing you to create smooth interactive widgets with just a few lines of CSS.

With the interpolate-size property and calc-size() function, you can animate transitions to intrinsic sizes (most notably to height: auto;).

The transition-behavior property and @starting-style at-rule let you use transitions for elements that are added to the page or removed from the DOM and for elements that are hidden from screen readers using display: none; or content-visibility: hidden;.

Further Reading

]]>