Skip to main content
Ben Nadel at CF Summit West 2024 (Las Vegas) with: Mark Metcalf
Ben Nadel at CF Summit West 2024 (Las Vegas) with: Mark Metcalf

Four-Sided Positioning Plays Nicely With Scale() Transformations In CSS

By
Published in , Comments (1)

A decade ago, Ryan Jeffords changed my life forever when he introduced me to the concept of four-sided positioning in CSS. Since then, four-sided positioning - along with CSS Flexbox - have become a mainstay of my modal-window content strategy. As much as I love positioning in CSS, I've never felt very comfortable using the transform property; and, I wasn't sure how something like transform: scale() would work in conjunction with four-sided positioning in CSS. So, I wanted to give it a quick exploration.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

In today's web application landscape, I believe most use of animation is overkill. I think it represents a general lack of empathy on behalf of the designers; and, does little more than slow down user interactions that would otherwise be instantaneous. That said, one place that I do appreciate subtle animation is when bringing a modal window into view.

Since a modal window opens on top of other content, it can be a little jarring, even disorienting; especially if the modal window is "full screen" and completely eclipses the content that the user was just viewing. By animating a modal window into view (just shy of instantaneously), we can foster a more organic understanding of the user interface (UI) layering.

This is where CSS transform: scale() comes into play. We can use scale() to "grow" the modal window into view. And, I'm excited to see that this works seamlessly with my use of four-sided positioning. To see this in action, I've put together a demo in which we can toggle the rendering of a modal window that uses both four-sided positioning and a @keyframes animation containing scale():

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8" />
	<title>
		Four-Sided Positioning Plays Nicely With Scale() Transformations In CSS
	</title>
	<link rel="stylesheet" type="text/css" href="./demo.css">
	<style type="text/css">

		.modal {
			/* Four-sided positioning. */
			bottom: 0px ;
			left: 0px ;
			position: fixed ;
			right: 0px ;
			top: 0px ;

			/*
				Animating the modal element into view: our modal-enter keyframes are
				going to use SCALE() (and opacity) to gradually transition the modal
				element into its fixed position layout.
			*/
			animation-duration: 1s ; /* NOTE: Absurdly SLOW for demo purposes. */
			animation-fill-mode: both ;
			animation-iteration-count: 1 ;
			animation-name: modal-enter ;
			animation-timing-function: ease-out ;
		}

		@keyframes modal-enter {
			from {
				opacity: 0 ;
				transform: scale( 0.7 ) ;
			}
			to {
				opacity: 1 ;
				transform: scale( 1.0 ) ;
			}
		}

	</style>
</head>
<body>

	<h1>
		Four-Sided Positioning Plays Nicely With Scale() Transformations In CSS
	</h1>

	<p>
		<a class="toggle">Open modal</a>
	</p>

	<!--
		This modal window will use FIXED positioning and have a four-sided (top, right,
		bottom, left) arrangement. It will also fade into view using CSS transitions.
	-->
	<template>
		<div class="modal">
			<a class="toggle">Close modal</a>
		</div>
	</template>


	<!-- Load scripts. -->
	<script type="text/javascript" src="../../vendor/jquery/3.6.0/jquery-3.6.0.min.js"></script>
	<script type="text/javascript">

		var modal = null;
		var template = $( "template" );

		// We'll use event-delegation so that we can capture the click event in the
		// modal, which isn't even rendered yet.
		$( document ).on( "click", ".toggle", toggleModal );

		// I show / hide the modal window by adding it to or removing it from the DOM
		// (Document Object Model) tree, respectively.
		function toggleModal() {

			if ( modal ) {

				modal.remove();
				modal = null;

			} else {

				modal = $( template.prop( "content" ).firstElementChild.cloneNode( true ) )
					.appendTo( document.body )
				;

			}

		}

	</script>

</body>
</html>

As you can see, when the modal window element is added to the DOM, our @keyframes animation transitions the element from scale(.7) to scale(1). That, along with our four-sided positioning, makes for a pleasant rendering experience:

NOTE: The duration here is absurdly slow for the purposes of the demonstration. In production, this timing should be just shy of instantaneous.

A modal window being animated into view using both four-sided position and transform:scale in CSS.

It's great that four-sided positioning and transform:scale() play so nicely together in CSS. It will make for much easier modal-window authoring. Especially when you throw in CSS Flexbox, which is one of the greatest things since sliced-bread.

Epilogue on Animating Elements Out of View

CSS @keyframes are great because they make many types of entry animations dead simple! However, since the element-in-question needs to be in the DOM in order to animate, @keyframes don't work seamlessly with exit animations. The goods news is, most things don't need exit animations.

The reason entry animations can be nice is that it gives the user time to construct a mental model of how the elements on the page relate to each other. Removing an element from the page - in response to a user-interaction - does not require the same form of hand-holding. When a user goes to "close" something, that thing can be closed instantaneously - the user already understands what it is they are trying to do; there is no enhanced UX by slowly (and painfully) removing that element from view.

Want to use code from this post? Check out the license.

Reader Comments

15,902 Comments

@All,

After posting this, I got to thinking about the prefers-reduced-motion media query; and, how we might alter the entry-animation of the modal window using that media query:

www.bennadel.com/blog/4132-applying-multiple-animation-keyframes-to-support-prefers-reduced-motion-in-css.htm

I outline three different approaches; but, ultimately, I think I prefer one that applies multiple @keyframes animations to the same element (using progressive enhancement).

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel