<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<div class="container">
	<h2 data-splitting>I am animating on a path</h2>
</div>
	<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
@import url("https://fonts.googleapis.com/css?family=Inconsolata:700");

* {
	box-sizing: border-box;
}

body {
	min-height: 100vh;
	background-color: black;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-wrap: wrap;
	color: white;
	padding: 2rem;
	overflow-x: hidden;
}

.container {
	max-width: 100%;
	width: 80rem;
}

h2 {
	position: relative;
	font-family: Inconsolata, monospace;
	font-size: 1.8rem;
	text-transform: uppercase;
	
	// Dimensions of original path
	width: 515px;
	height: 168px;
	
	transform: scale(var(--x, 1));
	transform-origin: var(--o, center);
	margin: 0 auto;
	color: coral;
}

.char {
	--i: calc(50% / var(--char-total));
	transform: scale( calc( 1 / var( --x)  ) );
	offset-path: path('M.4 84.1s127.4 188 267.7 0 247.3 0 247.3 0');
	offset-distance: calc(var(--char-index) * 1.2rem);
	position: absolute;
	animation: move 1500ms infinite alternate forwards var(--delay, 0ms);
}


@keyframes move {
	100% {
		--i: 2rem;
		offset-distance: calc((var(--char-index) * 1.2rem) + 12rem);
	}
}
View Compiled
const container = document.querySelector('.container')

const split = Splitting({
	whitespace: true
})

const update = () => {
	
	const { el } = split[0]
	const originalPathWidth = el.clientWidth
	const originalPathHeight = el.clientHeight
	
	console.log(el.clientWidth)
	
	const m = container.clientWidth / originalPathWidth
	const containerLeft = container.getBoundingClientRect().left
	const elLeft = el.getBoundingClientRect().left
	
	// If same width, do nothing
	if (m === 1) return
	
	// Scale
	el.style.setProperty('--x', m)
	
	// Set transform origin
	if (container.clientWidth < originalPathWidth) {
		el.style.setProperty('--o', 'left')
	} else {
		el.style.setProperty('--o', 'center')
	}
}

const observer = new ResizeObserver(update)
observer.observe(container)

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.com/splitting@1.0.6/dist/splitting.min.js