惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
L
LINUX DO - 最新话题
Recorded Future
Recorded Future
月光博客
月光博客
博客园 - 【当耐特】
博客园 - 叶小钗
宝玉的分享
宝玉的分享
量子位
雷峰网
雷峰网
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
Vercel News
Vercel News
L
LangChain Blog
B
Blog
Y
Y Combinator Blog
爱范儿
爱范儿
GbyAI
GbyAI
S
Security @ Cisco Blogs
T
The Blog of Author Tim Ferriss
A
About on SuperTechFans
博客园 - Franky
P
Palo Alto Networks Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
云风的 BLOG
云风的 BLOG
C
Cisco Blogs
Scott Helme
Scott Helme
I
Intezer
T
The Exploit Database - CXSecurity.com
MyScale Blog
MyScale Blog
T
Tor Project blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Troy Hunt's Blog
N
News and Events Feed by Topic
大猫的无限游戏
大猫的无限游戏
F
Fortinet All Blogs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Security Affairs
Cyberwarzone
Cyberwarzone
PCI Perspectives
PCI Perspectives
小众软件
小众软件
D
DataBreaches.Net
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Know Your Adversary
Know Your Adversary
Forbes - Security
Forbes - Security
S
Securelist
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
The Last Watchdog
The Last Watchdog

Butler's Log

Agentic Version Control Benchmarks Grit: rewriting Git in Rust with agents Git Merge 2026 Agent-safe Git with GitButler We’ve raised $17M to build what comes after Git Announcing the GitButler CLI for Linux The Great CSS Expansion A couple of git nits Simplifying Git by Using GitButler Introducing the GitButler CLI GitButler 0.19 - "Commander Keen" But Head: Crafting a Custom Font MCP vs RAG: Two Very Different Ways to Gain Context Getting Started With GitButler Agents Using the GitButler MCP Server to Build Better AI-Driven Git Workflows Using GitButler With Multiple GitHub Accounts Advent of Code! Upcoming GitButler Events Use GitButler for your Gerrit workflow Integrating GitButler and GitHub Enterprise Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 3 Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 2 Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 1 Grid Happens: Because Flexbox Wasn’t Enough Using Cursor Hooks for automatic version control Deep Dive into the new Cursor Hooks GitButler 0.16 - "Sweet Sixteen" GitButler's Claude Code tab GitButler's Annual Open Source Pledge Report Git Mini Summit 2025 Videos Automate Your AI Workflows with Claude Code Hooks Managing Multiple Claude Code Sessions Without Worktrees GitButler 0.15 - "Quirky Quinceañera" 20 years of Git. Still weird, still wonderful. GitButler's new patch based Code Review (Beta) Going down the rabbit hole of Git's new bundle-uri How to do patch-based review with git range-diff How Core Git Developers Configure Git Why is Git Autocorrect too fast for Formula One drivers? Stacked Branches with GitButler Git Merge 2024 Talks are Up GitButler 0.13 - "Lucky Baseball" Fearless Rebasing Git Merge 2024 Why GitHub Actually Won GitButler is joining the Open Source Pledge The New Era of Town Hall Chat The Future of Open Source GitButler is now Fair Source Git Merge 2024 GitButler 0.12 - "Stingy Baker" The Birth of THE MERGE GitButler for Windows Fixing up Git with Autosquash The Git Zeitgeist Git Worktrees and GitButler DevWorld Git Slides Git Tips and Tricks Git Tips 1: Oldies but Goodies Git Tips 2: New Stuff in Git Git Tips 3: Really Large Repositories FOSDEM Git Talk Opening Up GitButler Debugging Tauri in VS Code Advent of GitButler Code Signing Commits in Git, Explained Virtual Branches Alpha Our We Are Developers Adventure Building Virtual Branches DevDays in Vilnius The Future of Software and Open Source Introducing GitButler
A Responsive Item Counter with CSS only
Pavel Laptev · 2025-09-21 · via Butler's Log

Learn to create dynamic "+X more" counters that update automatically without JavaScript, using CSS Container Queries, Custom Properties, and Counters for responsive components that adapt to container width.

A Responsive Item Counter with CSS only

How many times have you built a component that displays a list of items with a "+X more" indicator? The typical approach involves JavaScript event listeners, ResizeObserver APIs, and manual calculations to track container dimensions and update the counter accordingly.

At GitButler, we recently launched a new Agents tab where we needed a clean way to display lists of tool calls while limiting visible items based on available space. The challenge? There could be hundreds of these call groups, and we didn't want to manage resize event listeners for each one. The solution? A pure CSS approach that's more elegant, performant, and updates automatically without any JavaScript.

repl-resize-example.gif

GitButler app. Responsive item counter in action

This technique combines three modern CSS features to create something that feels like magic. CSS Container Queries provide responsive breakpoints based on component width rather than viewport size. CSS Custom Properties act as a bridge for passing data between JavaScript and CSS layers. Finally, CSS Counters handle the mathematical calculations needed to display the correct "+X more" count.

The result? A component that shows a limited number of items initially, hides additional items based on container width, and displays a dynamic "+X more" counter that updates automatically—all without JavaScript handling the responsive behavior.

The architecture separates concerns cleanly between JavaScript and CSS. On the JavaScript side, we establish the basic parameters and prepare the initial display:

JAVASCRIPT

const totalItems = 8;
const displayLimit = 5;
const itemsToDisplay = items.slice(0, displayLimit);
const baseHiddenCount = Math.max(0, totalItems - displayLimit);

This is all the JavaScript logic we need—no event listeners or resize observers required. The real intelligence happens in the CSS layer.

The markup structure is straightforward, using CSS custom properties to communicate between JavaScript and CSS:

SVELTE

<div class="items-list" style="--base-hidden: {baseHiddenCount}">
	{#each itemsToDisplay as item, idx}
		<div class="item" class:hidable={totalItems >= displayLimit}>
			<span class="name">{item.name}</span>
		</div>
	{/each}

	<!-- Check if we need to show the counter -->
	{#if totalItems >= displayLimit}
		<span class="more-text">+<span class="count"></span> more</span>
	{/if}
</div>

Notice how the --base-hidden CSS custom property passes the base hidden count to CSS, while the hidable class marks items that can be hidden responsively. The .count element will be populated entirely by CSS calculations.

An important detail: we use totalItems >= displayLimit rather than totalItems > displayLimit for the hidable class and counter visibility. This ensures that even when all items fit initially (making baseHiddenCount zero), the counter can still appear and update correctly when responsive hiding kicks in due to container width constraints.

Now for the responsive magic. Container queries allow us to hide items based on the component's width rather than the entire viewport:

CSS

@container demo-container (max-width: 550px) {
  .items-list {
    --hidden-items: 1; /* Track responsive hiding */
  }
  .hidable.item:nth-child(4) {
    display: none; /* Hide specific item */
  }
}

@container demo-container (max-width: 440px) {
  .items-list {
    --hidden-items: 2;
  }
  .hidable.item:nth-child(3) {
    display: none;
  }
}

Each breakpoint serves a dual purpose: it sets --hidden-items to track how many items are hidden responsively, and it hides specific items using :nth-child() selectors. Since CSS cannot perform arithmetic operations directly, we use the custom property to pass the count of hidden items. Only items with the hidable class are affected by these responsive rules—we can't use conditional rendering because :nth-child() selectors require actual DOM elements to count.

The final piece brings everything together through CSS counters:

CSS

.count::after {
  content: counter(hidden-count);
  counter-reset: hidden-count calc(var(--base-hidden) + var(--hidden-items, 0));
}

The counter automatically calculates the total hidden count by combining the base hidden items (set by JavaScript) with the responsively hidden items (set by CSS). Since the content property only works with strings and cannot perform arithmetic directly, we use counter-reset with calc() to achieve the mathematical calculation.

To provide a clean user experience, the counter is automatically hidden when there are no hidden items:

CSS

/* Hide by default when base-hidden is 0 */
.items-list[style*='--base-hidden: 0'] .more-text {
  display: none;
}

This ensures that "+0 more" never appears—the counter only shows when there are actually hidden items, whether due to the initial display limit or responsive behavior.

This approach delivers significant performance advantages. There are no JavaScript event listeners or ResizeObserver overhead, no DOM manipulation for hiding and showing items, and the pure CSS calculations are highly optimized by the browser with automatic updates without manual state management.

You can extend this pattern with additional sophisticated features. For content-aware hiding, you might want to hide items based on their content characteristics rather than just position:

CSS

.hidable.item[data-length='long']:nth-child(n + 3) {
  display: none;
}

Adding smooth animations creates a more polished user experience. Instead of items disappearing abruptly, they can fade out gracefully:

CSS

.hidable.item {
  transition: opacity 0.2s ease;
}

@container demo-container (max-width: 550px) {
  .hidable.item:nth-child(4) {
    opacity: 0;
    pointer-events: none;
  }
}

This approach maintains the layout while providing visual feedback that items are being hidden due to space constraints.

Explore the interactive demo: Responsive Item Counter REPL

Oh, and did we mention this technique is also coincidentally powering some shiny new features in GitButler? 😉 Download GitButler to see what we've been cooking up.

Pavel Laptev

Written by Pavel Laptev

Quack! A digital designer who loves open source. Flaps around making interfaces nice and helps the design and frontend pond whenever he can.