Shrink the Header Logo on Scroll in WordPress

A big logo looks good at the top of a WordPress page, but once the visitor scrolls, a tall sticky header eats the screen. This snippet shrinks the header logo on scroll: as soon as the page moves, the header gets the class header-alt and the logo animates to a smaller height. Scroll back to the top and it grows again.

It is plain JavaScript and CSS. No jQuery and no library.

The markup

Add the class header to your header and brand to the logo. In the block editor or Site Editor, use Advanced → Additional CSS class(es) on the header Group and on the Site Logo or Image block; the CSS then sizes the image inside that block. In hand-written markup, put brand on the <img>:

<header class="header">
	<a href="/">
		<img class="brand" src="/wp-content/uploads/logo.svg" alt="Site name" width="400" height="120">
	</a>
</header>

The CSS

/* img.brand: a plain image; .brand img: a Site Logo or Image block with the class. */
.header img.brand,
.header .brand img {
	display: block;
	width: auto;
	height: auto;
	max-height: 120px;
	transition: max-height 0.4s ease;
}

.header.header-alt img.brand,
.header.header-alt .brand img {
	max-height: 50px;
}

@media (prefers-reduced-motion: reduce) {
	.header img.brand,
	.header .brand img {
		transition: none;
	}
}

The JavaScript

(function () {
	var offset = 1; // Pixels scrolled before the header gets the class.
	var headers = document.querySelectorAll('.header');
	if (!headers.length) {
		return;
	}

	var ticking = false;

	function update() {
		var scrolled = window.scrollY >= offset;
		headers.forEach(function (header) {
			header.classList.toggle('header-alt', scrolled);
		});
		ticking = false;
	}

	window.addEventListener('scroll', function () {
		if (!ticking) {
			ticking = true;
			window.requestAnimationFrame(update);
		}
	}, { passive: true });

	update();
})();

Add it with Scripts Organizer

In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Conditions and leave Template on All. Under Script location tick Header and Footer.

  • Header: set Header Mode to CSS and paste the CSS.
  • Footer: set Footer Mode to Javascript and paste the JavaScript.

Publish and enable the block. Scripts Organizer prints Header and Footer code on the front end only with the Conditions trigger, not with Everywhere.

How it works

  • The script adds header-alt to every .header when window.scrollY is at least offset pixels, and removes it again near the top.
  • The scroll listener is passive and runs the class update at most once per frame with requestAnimationFrame, so scrolling stays smooth.
  • update() also runs once on load. A visitor who reloads halfway down the page gets the small logo right away.
  • The CSS animates max-height, so the logo keeps its aspect ratio. With reduce motion turned on in the operating system, the logo switches size without animating.
  • The older version used $(function () { … }). WordPress loads jQuery in noConflict mode, so $ is undefined and the script stopped with an error.

Customise it

  • Shrink later: set var offset = 100; so the logo changes after 100px of scrolling.
  • Sizes and speed: change 120px, 50px and 0.4s in the CSS.
  • Make the header itself sticky with .header { position: sticky; top: 0; z-index: 10; }. With the admin bar, add top: var(--wp-admin--admin-bar--height, 0px).
  • More effects on the same class: change the header background or padding under .header.header-alt. For a header that hides on scroll down, see Show navigation on scroll up.

Gotchas

  • .header is a common class name. If your theme already uses it for something else, rename it in the markup, the CSS and the querySelectorAll() call.
  • An SVG logo without width and height attributes can collapse to zero width with width: auto. Give the image its real dimensions.
  • Animating height moves the content under a non-sticky header. With a sticky header it does not.

In the Scripts Organizer library Import it with one click from Scripts Organizer.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.